【问题标题】:Modulo not working in Javascript模数在 Javascript 中不起作用
【发布时间】:2023-03-26 12:04:01
【问题描述】:

我试图理解为什么模运算不能按预期工作:

我需要验证一个 IBAN,算法包括做一个模数。

根据维基百科: enter link description here

3214282912345698765432161182 mod 97 = 1

根据我的 Windows 计算器 :: 3214282912345698765432161182 mod 97 = 1

但是当我在 JS 中执行此操作时,我得到 65:

var result = 3214282912345698765432161182 % 97;
console.log(result);
// result is 65

为什么我在 JS 中得到 65 而不是 1?

【问题讨论】:

  • 这是一个非常大的数字,我认为你已经溢出了。
  • 是的,那是一个 92 位的数字。您将需要比原始数字类型更高级的东西...
  • 试试console.log(3214282912345698765432161182)...你处于浮动的领域,你不能指望一个“正确”的结果。
  • Javascript 数字只有 56 位精度。
  • 请参阅IBAN Validation check 了解一些替代实现。

标签: javascript


【解决方案1】:

您的数字高于 (2^53)-1,因此无法正确表示。

您可以使用函数Number#isSafeInteger来检查使用这个号码是否安全

const isSafe = Number.isSafeInteger(3214282912345698765432161182);

console.log(isSafe);

【讨论】:

  • 下一个问题,当然是你如何计算这么大的数字的模数?
  • @NiettheDarkAbsol 我猜是使用处理 BigInteger 的外部库
  • @NiettheDarkAbsol - 有一些方法可以做到这一点,我在回答中描述了一种。 Source.
【解决方案2】:

JavaScript 不失精度的最高整数值是

+/- 9007199254740991

大小小于 2^53 的数字可以用 Number 类型表示。

您可以通过在浏览器控制台中运行 Number.MAX_SAFE_INTEGER 来检查。

如果直接存储,大于该值的整数将失去精度。

查看这篇博文,了解如何在 Javascript 中处理 BigIntegers。

http://2ality.com/2012/07/large-integers.html

【讨论】:

    【解决方案3】:

    这个library 可以解决您的问题或通过 npm 安装 npm install big-integer

    一个sn-p代码在节点中运行

    var bigInt = require("big-integer");
    var largeNumber = bigInt("3214282912345698765432161182");
    console.log(largeNumber.divmod(97).remainder.value)
    

    输出为 1

    【讨论】:

      【解决方案4】:

      查看解决您直接问题的其他答案。如果您想自己解决问题,以下是解决实际问题的方法。可能有一个库已经这样做了,但它有可能使用与下面描述的相同的方法。

      引用您链接到的the very wikipedia page

      任何用于直接计算 D mod 97 的计算机编程语言或软件包都必须具有处理超过 30 位整数的能力。实际上,这只能通过支持任意精度算术或可以处理 220 位(无符号)整数的软件来完成,这些功能通常不是标准的。如果正在使用的应用软件不提供处理这种大小的整数的能力,则可以以分段方式执行模运算(如 UN CEFACT TBG5 Javascript 程序的情况)。

      让我们通过一个示例来看看如何实现这种方法:

      D = 3214282912345698765432161182
      

      让我们把这个数字分成四部分:

      P1 = 321428291 // first 9 digits
      P2 = 2345698   // next 7 digits
      P3 = 7654321   // next 7 digits
      P4 = 61182     // last 5 digits
      

      然后,根据维基百科D % 97 == 1,如果以下步骤将您引导至N % 97 == 1

      1. 从 D (P1) 的前 9 位构造 N

        N = 321428291

      2. 计算 N mod 97 = 70

      3. 根据上述结果(步骤 2)构造一个新的 9 位 N,然后是 D 的下 7 位(P2)

        N = 702345698

      4. 计算 N mod 97 = 29
      5. 根据上述结果(第 4 步)构造一个新的 9 位 N,然后是 D(P3) 的下 7 位

        N = 297654321

      6. 计算 N mod 97 = 24
      7. 根据上述结果(第 6 步)构造一个新的 N,后跟 剩余的 5 位 D (P4)

        N = 2461182

      8. 计算 N mod 97 = 1

      从第 8 步开始,最终结果是 D mod 97 = 1 并且 IBAN 已通过 这个校验位测试。

      这是dfsq 提供的类似方法的简单 ES6 实现:

      function checkIBAN(iban) { 
        const parts = iban.match(/.{1,6}/g); 
        return parts.reduce((prev, curr) => Number(prev + curr) % 97, ''); 
      }
      console.log(checkIBAN("3214282912345698765432161182"));

      【讨论】:

      • 非常好!这里是这个算法的超级简单的实现:function checkIBAN(iban) { const parts = iban.match(/.{1,6}/g); return parts.reduce((prev, curr) => Number(prev + curr) % 97, '') }.
      猜你喜欢
      • 2023-03-08
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 2020-01-15
      • 2019-02-07
      • 2022-01-05
      • 2012-08-30
      • 2019-04-09
      相关资源
      最近更新 更多