1

所以,我从理论上读到,Ruby 中的整数没有最大值,它们可以任意大。然而,当我乘以下面的结果是一个负值(我认为这是溢出的标志?):

44404051714 * 44404051714 => -2081807267335685116

谁可以给我解释一下这个?

4

1 回答 1

3

这看起来像是 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 代码中的错误。

于 2012-11-06T20:54:17.183 回答