所以,我从理论上读到,Ruby 中的整数没有最大值,它们可以任意大。然而,当我乘以下面的结果是一个负值(我认为这是溢出的标志?):
44404051714 * 44404051714 => -2081807267335685116
谁可以给我解释一下这个?
所以,我从理论上读到,Ruby 中的整数没有最大值,它们可以任意大。然而,当我乘以下面的结果是一个负值(我认为这是溢出的标志?):
44404051714 * 44404051714 => -2081807267335685116
谁可以给我解释一下这个?
这看起来像是 Ruby 的类乘法实现中的一个错误Fixnum
。查看源代码,numeric.cfixmul
中函数的以下行(大量删减)跳出可疑:
...
2645: long a, b;
...
2663: c = a * b;
2664: r = LONG2FIX(c);
...
2667: if (FIX2LONG(r) != c || c/a != b) {
2668: r = rb_big_mul(rb_int2big(a), rb_int2big(b));
...
如果我没看错,那是来自进行Fixnum
乘法运算的代码,以及应该进行溢出检测以确定结果是否实际上应该重新计算为Bignum
. 问题在于它是糟糕的 C 代码: a
并且b
具有 long 类型,并且 ifa * b
溢出会根据 C 标准产生未定义的行为。一个好的编译器可以通过假设在正确的 C 程序中永远不会发生溢出来利用这一点,并且基于该逻辑可以优化溢出检查c / a != b
。
因此,如果您的 Ruby 版本是使用相当新的编译器编译的(最新版本的 Clang 就是一个很好的例子),那可能就是造成这种情况的原因。
无论如何,我认为值得报告错误:即使这不是您所看到的原因,上面的 C 代码也是可疑的。
编辑:Daniel Fischer 在评论中指出有一个volatile long c
声明。理论上,这应该可以防止溢出检查被优化掉。因此,如果这是问题的原因,那么这将使其成为编译器错误,而不是 Ruby 代码中的错误。