分割时的Javascript精度

分割时的Javascript精度,javascript,floating-point,Javascript,Floating Point,有没有一种方法可以确定在JavaScript中用一个数字除以另一个数字是否会得到整数?像18.4/0.002给了我们9200,但是18.4/0.1给了我们183.99999999997。问题是,它们都可能是任何浮点数(如0.1、0.01、1、10等),这使得不可能使用标准函数模或尝试减法,而浮点精度问题意味着我们有时会得到本应为整数的数字的非整数结果,或者不应该是的整数结果。我认为JavaScript的双精度浮点数无法做到这一点,不能在整个范围内可靠地实现。也许在某些限制条件下,您可以(尽管精度

有没有一种方法可以确定在JavaScript中用一个数字除以另一个数字是否会得到整数?像
18.4/0.002
给了我们
9200
,但是
18.4/0.1
给了我们
183.99999999997
。问题是,它们都可能是任何浮点数(如0.1、0.01、1、10等),这使得不可能使用标准函数模或尝试减法,而浮点精度问题意味着我们有时会得到本应为整数的数字的非整数结果,或者不应该是的整数结果。

我认为JavaScript的双精度浮点数无法做到这一点,不能在整个范围内可靠地实现。也许在某些限制条件下,您可以(尽管精度错误会在各种各样——对我来说——意外的位置出现)


我看到的唯一方法是使用JavaScript的几个“大十进制”库中的任何一个,它们根本不使用
Number
。它们速度较慢,但…

将第一个数字除以第二个数字,然后检查结果是否为整数

仅当检查结果是否为整数时,需要指定舍入阈值。 在javascript中,3.39/1.13略大于3

例如:

/**
* Returns true iif a is an integer multiple of b
*/
function isIntegerMultiple(a, b, precision) {
    if (precision === undefined) {
        precision = 10;
    }

    var quotient = a / b;
    return Math.abs(quotient - Math.round(quotient)) < Math.pow(10, -precision);
}

console.log(isIntegerMultiple(2, 1)); // true
console.log(isIntegerMultiple(2.4, 1.2)); // true
console.log(isIntegerMultiple(3.39, 1.13)); // true
console.log(isIntegerMultiple(3.39, 1.13, 20)); // false
console.log(isIntegerMultiple(3, 2)); // false
/**
*如果a是b的整数倍,则返回true
*/
函数为整数倍(a、b、精度){
如果(精度===未定义){
精度=10;
}
var商=a/b;
返回Math.abs(商-Math.round(商))

有关浮点舍入问题的更多详细信息,请参阅此部分:

我假设您希望在执行除法时提醒为零

检查除数的精度,并将除数和divident乘以10的幂

比如说


您需要检查
2.14/1.245
将divident和divisor都乘以
1000
,因为
1.245
有3位精度,现在您需要像
2140/1245
这样的整数来执行模运算

  • 使用
    toString()
  • 通过去除
    前面的字符(包括
    )并计算剩余部分的长度来计算精度点(N)
  • 与10^N相乘,使它们成为整数
  • 做模运算,得到结果
  • 更新的演示:


    你可以简单地进行除法,看看结果是否是整数。不过,要小心使用浮点数,这样会丢失一些精度,而应该是整数的值实际上可能非常接近。@MikeW这就是问题所在。我无法定义“非常接近”一词。想象一下18.4除以0.1的情况。虽然0.1不能用浮点精确表示,但结果永远不会是184,而是“非常接近”。但如何识别,它是否足够接近?@T.J.Crowder我的意思是可除且无余数:)。就像18.4可以被0.002整除一样,但是18.1不能被1.03整除当你使用小数点时,提醒的概念是没有意义的。不是吗?一切都可以被一切所分割。@arahusky:我编辑了你的问题,想表达我认为你的意思。显然,如果我弄错了,请还原编辑。“乘以10^N使其成为整数”如果您可以将十进制表示的浮点数乘以100,再乘以X.XX,得到整数XXX,那么您首先就不会遇到问题集。结果很可能是XXX,因为至少100用二进制浮点表示,但仍然存在一些结果不是整数的值。在计算
    u%d
    之前,您可能还希望将
    u
    d
    四舍五入为整数。要了解为什么这是必要的,请尝试
    u=0.21
    d=0.07
    。此外,即使忽略二进制内部表示的困难,这里的逻辑也是有缺陷的。考虑<代码> u=7 < /代码>和<代码> d=3.5 < /代码>。您将检查
    7%35==0
    。您想将这两个值乘以10的相同幂。@MarkDickinson-您说得对。这(错误地)假设两者都是非整数。正如我所说的,它很粗糙,没有经过很好的测试,不适合生产。:-)与
    u
    d
    是否为整数无关:例如
    u=0.20
    d=0.04
    会出现相同的问题。不过,你可以很容易地修正你的答案:只需取计算出的两个长度中的最大值,并将两个数字按10的比例放大到该幂。(并将舍入添加到整数步长。)
    function isDivisible(u, d) {
        var numD = Math.max(u.toString().replace(/^\d+\./, '').length, 
                            d.toString().replace(/^\d+\./, '').length);
        u = Math.round(u * Math.pow(10, numD));
        d = Math.round(d * Math.pow(10, numD));
        return (u % d) === 0;
    }