1

Ok, so we all know of the floating point number problem, such as:

0.23 - 1 + 1 = 0.22999999999999998

And since in javascript, unlike other languages, all numbers are actually floating points and there's no int/decimal there are all kinds of libraries and workarounds such as BigDecimal to handle this problem. This is best discussed here.

I was creating a "numeric spinner" control that supports floating point numbers, and obviously I wouldn't want the user to click "up" and then "down" and get a different number from what he started with, so I tried writing a workaround - a "addPrecise" method of sorts.

My idea was the following:

  1. Take the two numbers I'm about to add, and figure out their "precision" - how many digits they have after the decimal point.
  2. Add the two numbers as floats
  3. Apply toFixed() on the result with the max precision of the two

For example:

float #1: 1.23
float #2: -1

adding them normally would result in 0.22999999999999998 but if I'm taking the maximal number of decimal places, which is #1's 2 digits, and apply toFixed(2) I get 0.23 as I wanted.

I've done this with the following piece of code but I'm not happy with it.

function addPrecise(f1, f2){
    var floatRegex = /[^\d\-]/;
    var f1p =  floatRegex.exec(f1.toString()) ? f1.toString().split(floatRegex.exec(f1.toString()))[1].length : 0;
    var f2p =  floatRegex.exec(f2.toString()) ? f2.toString().split(floatRegex.exec(f2.toString()))[1].length : 0;
    var precision = Math.max(f1p,f2p);
    return parseFloat((parseFloat(f1) + parseFloat(f2)).toFixed(precision));
}

(It's worth noting that I'm using the regex to find the 'floating point' because in other locales it might be a comma instead of a period. I'm also taking into account the possibility that I got an Int (with no point) in which case it's precision is 0.)

Is there a cleaner/simpler/better way to do this?

Edit: I'd also like to point out that finding a reliable way to extract the number of decimal digits is also part of the question. I'm unsure about my method there.

4

1 回答 1

1

此问题的适当解决方案是:

  1. 确定小数点后需要多少位数,例如d 。
  2. 从用户读取输入并将它们转换为按 10 d缩放的整数。
  3. 使用整数进行所有算术运算。
  4. 为用户显示值时,除以 10 d进行显示。

更多细节:

  1. 如果所有工作都以用户输入数据的整数为单位,则小数点后所需的位数d与要从用户接受的位数相同。(例如,如果要使用步长的分数进行一些算术运算,则可能需要更多的数字。)
  2. 当用户输入输入时,它应该被转换为缩放的整数。请注意,用户输入一个字符串(不是浮点数;当用户键入它时它只是一个字符串),并且该字符串应该是一个数字(表示数字的字符)。处理此输入的一种方法是调用库例程将此数字转换为浮点数,然后乘以 10 d,然后将浮点结果四舍五入到最接近的整数(以补偿浮点舍入误差)。对于合理大小的数字,这将始终产生所需的结果;浮点舍入错误不会成为问题。(应拒绝过大的用户输入。)处理此输入的另一种方法是编写自己的代码,将数字直接转换为缩放整数,完全避免浮点。
  3. 只要仅使用加法、乘法和减法(例如,将步长乘以步数并添加到先验值),并且不超出整数范围,那么所有算术都是精确的;没有舍入误差。如果使用除法,则必须重新考虑这种方法。
  4. 与读取输入一样,可以在浮点和库例程的帮助下或通过编写自己的代码直接转换来执行显示输出。要使用浮点,请将整数转换为浮点,除以 10 d,然后使用库例程对其进行格式化,小数点后不超过d位。(在库例程中使用默认格式转换可能会导致显示多于d位。如果仅显示d位,并且d是一个相当小的数字,那么格式化期间发生的浮点舍入错误将不可见。)

只要注意确保算术在合理范围内完全使用整数(或以浮点格式精确表示的其他值),就可以仅使用浮点来实现上述所有内容。

于 2013-08-14T13:21:45.777 回答