Javascript 为什么模数运算符在javascript中返回小数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3966484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does modulus operator return fractional number in javascript?
提问by Edgar
Why does 49.90 % 0.10
in JavaScript return 0.09999999999999581
? I expected it to be 0.
为什么49.90 % 0.10
在 JavaScript 中返回0.09999999999999581
?我预计它是0。
回答by Aaron Digulla
Because JavaScript uses floating point math which can lead to rounding errors.
因为 JavaScript 使用浮点数学,这会导致舍入错误。
If you need an exact result with two decimal places, multiply your numbers with 100
before the operation and then divide again afterwards:
如果您需要带有两位小数的精确结果,请100
在运算前乘以您的数字,然后再除以:
var result = ( 4990 % 10 ) / 100;
Round if necessary.
必要时圆。
回答by kennytm
Javascript's Number is using "IEEE double-precision" to store the values. They are incapable of storing all decimal numbers exactly. The result is not zero because of round-off error when converting the decimal number to binary.
Javascript 的 Number 使用“IEEE 双精度”来存储值。它们无法准确存储所有十进制数。将十进制数转换为二进制数时,由于舍入错误,结果不为零。
49.90 = 49.89999999999999857891452848...
0.10 = 0.10000000000000000555111512...
Thus floor(49.90 / 0.10) is only 498, and the remainder will be 0.09999....
因此 floor(49.90 / 0.10) 只有 498,余数将是 0.09999....
It seems that you are using numbers to store amount of dollars. Don't do this, as floating point operations propagate and amplify the round-off error. Store the number as amount of centsinstead. Integer can be represented exactly, and 4990 % 10
will return 0.
您似乎正在使用数字来存储美元金额。不要这样做,因为浮点运算会传播并放大舍入误差。将数字存储为美分数量。Integer 可以精确表示,并且4990 % 10
会返回 0。
回答by TheSharpieOne
I'll just leave this here for future reference, but here is a handy function that can more precisely handle Remainder(since JS doesn't have a modulo operator) involving floats.
我将把它留在这里以供将来参考,但这里有一个方便的函数,可以更精确地处理涉及浮点数的Remainder(因为JS 没有模运算符)。
function floatSafeRemainder(val, step){
var valDecCount = (val.toString().split('.')[1] || '').length;
var stepDecCount = (step.toString().split('.')[1] || '').length;
var decCount = valDecCount > stepDecCount? valDecCount : stepDecCount;
var valInt = parseInt(val.toFixed(decCount).replace('.',''));
var stepInt = parseInt(step.toFixed(decCount).replace('.',''));
return (valInt % stepInt) / Math.pow(10, decCount);
}
$(function() {
function floatSafeModulus(val, step) {
var valDecCount = (val.toString().split('.')[1] || '').length;
var stepDecCount = (step.toString().split('.')[1] || '').length;
var decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount;
var valInt = parseInt(val.toFixed(decCount).replace('.', ''));
var stepInt = parseInt(step.toFixed(decCount).replace('.', ''));
return (valInt % stepInt) / Math.pow(10, decCount);
}
$("#form").submit(function(e) {
e.preventDefault();
var safe = 'Invalid';
var normal = 'Invalid';
var var1 = parseFloat($('#var1').val());
var var2 = parseFloat($('#var2').val());
if (!isNaN(var1) && !isNaN(var2)) {
safe = floatSafeModulus(var1, var2);
normal = var1 % var2
}
$('#safeResult').text(safe);
$('#normalResult').text(normal);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="form" novalidate>
<div>
<input type="number" id="var1">%
<input type="number" id="var2">
</div>
<div>safe: <span id="safeResult"></span><div>
<div>normal (%): <span id="normalResult"></span></div>
<input type="submit" value="try it out">
</form>
回答by Stefan Mondelaers
Cause
原因
Floating point can't store all decimal values exactly. So when using floating point formats there will always be rounding errors on the input values. The errors on the inputs of course results on errors on the output. In case of a discrete function or operator there can be a big difference on the output around the point where the function or operator is discrete. The modula operator is discrete and your case is clearly an example of this problem.
浮点不能准确存储所有十进制值。因此,当使用浮点格式时,输入值总是会出现舍入错误。输入上的错误当然会导致输出上的错误。在离散函数或运算符的情况下,函数或运算符离散的点周围的输出可能会有很大差异。模运算符是离散的,您的情况显然是此问题的一个示例。
Input and output for floating point values
浮点值的输入和输出
So, when using floating point variables, you should always be aware of this. And whatever output you want from a calculation with floating points should always be formatted/conditioned before displaying with this in mind.
When only continuous functions and operators are used, rounding to the desired precision often will do (don't truncate). Standard formatting features used to convert floats to string will usually do this for you.
To have a correct output based on expected precision of inputs and desired precision of output, you should also
因此,在使用浮点变量时,您应该始终注意这一点。并且无论您想要从浮点计算中获得的任何输出,在显示之前都应始终进行格式化/条件化。
当只使用连续函数和运算符时,四舍五入到所需的精度通常会这样做(不要截断)。用于将浮点数转换为字符串的标准格式功能通常会为您执行此操作。
要根据输入的预期精度和输出的期望精度获得正确的输出,您还应该
- Round inputs to the expected precision or make sure no values can be entered with higher precision.
- Add a small value to the outputs before rounding/formatting them which is smaller than or equal to 1/4 of the desired precision and bigger than the maximum expected error caused by rounding errors on input and during calculation. If that is not possible the combination of the precision of the used data type isn't enough to deliver the desired output precision for your calculation.
- 将输入舍入到预期精度或确保不能以更高的精度输入任何值。
- 在舍入/格式化输出之前向输出添加一个小值,该值小于或等于所需精度的 1/4,并大于输入和计算过程中舍入误差引起的最大预期误差。如果这是不可能的,则所用数据类型的精度组合不足以为您的计算提供所需的输出精度。
These 2 things are often not done and in most cases the differences caused by not doing them are too small to be important for most users, but I already had a project where output wasn't accepted by the users without those corrections.
这 2 件事通常没有完成,并且在大多数情况下,由于不执行它们而导致的差异对于大多数用户来说太小以至于不重要,但是我已经有一个项目,如果没有这些更正,用户就不会接受输出。
Discrete functions or operators (like modula)
离散函数或运算符(如模数)
When discrete operators or functions are involved, extra corrections might be required to make sure the output is as expected. Rounding and adding small corrections before rounding can't solve the problem.
A special check/correction on intermediate calculation results, immediately after applying the discrete function or operator might be required.
当涉及离散运算符或函数时,可能需要额外的修正以确保输出符合预期。四舍五入和在四舍五入之前添加小的更正不能解决问题。
可能需要在应用离散函数或运算符后立即对中间计算结果进行特殊检查/更正。
Specific case of this question
这个问题的具体案例
In this case, you expect input with a certain precision, so it is possible to correct output for impact of rounding errors which are a lot smaller than the desired precision.
在这种情况下,您希望输入具有一定的精度,因此可以针对比所需精度小很多的舍入误差的影响来校正输出。
If we say the precision of your data type is e.
Your input will not be stored as the values a and b you entered, but as a*(1+/-e) and b*(1+/-e)
The result of a division a*(1+/-e) by b*(1+/-e) would result in (a/b)(1+/-2e).
The modula function has to truncate the result and multiply again.
So the result will be (a/bb)(1+/-3e) = a(1+/-3e) resulting in an error of a*3e.
The mod adds a*e to the possible error of a*3e because of the subtraction of 2 values with a possible errors of a*3e and a*e.
So you should check that the total possible error a*4e is smaller than the desired precision and if that condition is met and the result differs no more from b than that maximum possible error, you can safely replace it by 0.
如果我们说您的数据类型的精度是 e。
您的输入不会存储为您输入的值 a 和 b,而是存储为 a*(1+/-e) 和 b*(1+/-e)
除法的结果 a*(1+/-e)通过 b*(1+/-e) 将导致 (a/b) (1+/-2e)。
modula 函数必须截断结果并再次相乘。所以结果将是 (a/bb)(1+/-3e) = a(1+/-3e) 导致 a*3e 的误差。
该 mod 将 a*e 添加到 a*3e 的可能误差中,因为减去了 2 个值,可能的误差为 a*3e 和 a*e。
因此,您应该检查可能的总误差 a*4e 是否小于所需的精度,如果满足该条件并且结果与 b 的差异不超过最大可能误差,则可以安全地将其替换为 0。
Better avoid having the problem
最好避免出现问题
It is often more efficient to avoid these problems by using data types (integer or fixed point formats) for calculations like this which can store the expected input without rounding errors. An example of that is that you should never use floating point values for financial calculations.
通过使用数据类型(整数或定点格式)进行这样的计算,可以更有效地避免这些问题,这样可以存储预期的输入而不会出现舍入错误。一个例子是你永远不应该使用浮点值进行财务计算。
回答by oezi
Take a look at floating pointsand its disadvantages - a number like 0.1
can't be saved correctly as floating point, so there will always be such problems. Take your numbers *10 or *100 and do the calculations with integers instead.
看看浮点数和它的缺点——像这样的数字0.1
不能正确保存为浮点数,所以总会出现这样的问题。取你的数字 *10 或 *100 并用整数进行计算。
回答by MatTheCat
http://en.wikipedia.org/wiki/Modulo_operationDon't be angry modulo is used with integers ^^ So floating values occure some errors.
http://en.wikipedia.org/wiki/Modulo_operation不要生气模数与整数一起使用^^ 所以浮点值会出现一些错误。
回答by Viranga
This is not a perfect answer but it works.
这不是一个完美的答案,但它有效。
function format_float_bug(num)
{
return parseFloat( num.toFixed(15) );
}
you can use as follows,
你可以使用如下,
format_float_bug(4990 % 10);
because below number (49.89999999999999857891452848) first 15 decimal places are like 9999999
因为下面的数字 (49.8999999999999857891452848) 前 15 个小数位就像 9999999