为什么模数运算符在javascript中返回小数?

为什么模数运算符在javascript中返回小数?,javascript,floating-point,modulus,Javascript,Floating Point,Modulus,为什么JavaScript中的49.90%0.10返回0.099999999581?我希望它是0。因为JavaScript使用浮点数学,这可能导致舍入错误 如果需要小数点后两位的精确结果,请在操作前将数字乘以100,然后再除以: var result = ( 4990 % 10 ) / 100; 如有必要,将其舍入。 不要生气模与整数一起使用^^ 因此,浮点值会出现一些错误。请看一看它的缺点-像0.1这样的数字不能正确地保存为浮点值,因此总会出现这样的问题。取你的数字*10或*100,用整数代

为什么JavaScript中的
49.90%0.10
返回
0.099999999581
?我希望它是0。

因为JavaScript使用浮点数学,这可能导致舍入错误

如果需要小数点后两位的精确结果,请在操作前将数字乘以
100
,然后再除以:

var result = ( 4990 % 10 ) / 100;
如有必要,将其舍入。

不要生气模与整数一起使用^^
因此,浮点值会出现一些错误。

请看一看它的缺点-像
0.1
这样的数字不能正确地保存为浮点值,因此总会出现这样的问题。取你的数字*10或*100,用整数代替。Javascript的数字使用“IEEE双精度”来存储值。它们不能准确地存储所有十进制数。由于将十进制数转换为二进制时存在舍入错误,因此结果不是零

49.90 = 49.89999999999999857891452848...
 0.10 =  0.10000000000000000555111512...
因此,楼层(49.90/0.10)仅为498,其余为0.09999



看来你是在用数字来存储美元的数量,因为浮点运算会传播并放大舍入误差。将数字存储为美分。整数可以精确表示,并且
4990%10
将返回0。

这不是一个完美的答案,但它是有效的

function format_float_bug(num)
{
   return parseFloat( num.toFixed(15) ); 
} 
您可以使用以下命令:

format_float_bug(4990 % 10);

因为下面的数字(49.8999999999999857891452848)前15位小数点类似于9999999,所以我将其留在这里以供将来参考,但这里有一个方便的函数,可以更精确地处理(因为)涉及浮点数的问题

  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);
  }
$(函数(){
函数模量(val,阶跃){
var valDecCount=(val.toString().split('.')[1]| |').length;
var stepDecCount=(step.toString().split('.')[1]| |').length;
var decCount=VALDECOUNT>STEPDECOUNT?VALDECOUNT:STEPDECOUNT;
var valInt=parseInt(val.toFixed(decCount).replace('.','');
var stepInt=parseInt(step.toFixed(decCount).replace('.','');
返回值(有效%stepInt)/Math.pow(10,decCount);
}
$(“#表格”)。提交(功能(e){
e、 预防默认值();
var safe='无效';
var normal='无效';
var var1=parseFloat($('#var1').val());
var var2=parseFloat($('#var2').val());
如果(!isNaN(var1)和&!isNaN(var2)){
安全系数=浮动安全系数(var1,var2);
正常=var1%var2
}
$(“#安全结果”).text(安全);
$('#normalResult').text(正常);
});
});

%
安全:
正常值(%):
原因

浮点不能准确地存储所有十进制值。因此,当使用浮点格式时,输入值总是会有舍入错误。 输入上的错误当然会导致输出上的错误。 对于离散函数或运算符,函数或运算符离散点附近的输出可能存在较大差异。 模算子是离散的,你的例子就是这个问题

浮点值的输入和输出

因此,在使用浮点变量时,您应该始终注意这一点。无论您希望从浮点计算中获得什么样的输出,在显示之前都应该对其进行格式化/调节。
当只使用连续函数和运算符时,舍入到所需的精度通常可以(不要截断)。用于将浮点数转换为字符串的标准格式功能通常可以为您实现这一点。
要根据输入的预期精度和输出的预期精度获得正确的输出,还应

  • 将输入四舍五入到预期精度,或确保不能输入精度更高的值
  • 在对输出进行舍入/格式化之前,向输出中添加一个小值,该值小于或等于所需精度的1/4,并且大于输入和计算过程中舍入误差引起的最大预期误差。如果不可能,所用数据类型的精度组合不足以为您的计算提供所需的输出精度
这两件事通常没有完成,在大多数情况下,没有完成它们所造成的差异太小,对大多数用户来说都不重要,但我已经有一个项目,在没有这些更正的情况下,用户不接受输出

离散函数或运算符(如模)

当涉及离散运算符或函数时,可能需要进行额外的校正,以确保输出符合预期。舍入和在舍入之前添加小的修正不能解决问题。
可能需要在应用离散函数或运算符后立即对中间计算结果进行特殊检查/校正

此问题的具体案例

在这种情况下,您希望输入具有一定的精度,因此可以针对舍入误差的影响对输出进行校正,舍入误差远远小于所需的精度

如果我们说您的数据类型的精度为e.
您的输入将不会存储为您输入的值a和b,而是存储为a*(1+/-e)和b*(1+/-e)
a*(1+/-e)除以b*(1+/-e)的结果将导致(a/b)(1+/-2e)。
模函数必须截断结果并再次相乘。 因此,结果将是(a/bb)(1+/-3e)=a(1+/-3e),导致a*3e的误差。
mod将a*e添加到a*3e的可能误差中,因为减去2个可能误差为a*3e和a*e的值。
因此,您应该检查总的可能误差a*4e是否小于所需的精度,如果满足该条件,并且结果与b的差异不超过最大可能误差,则可以安全地将其替换为0

最好避免出现问题