较大UInt64整数的乘积模数错误

本文关键字:错误 UInt64 整数 较大 | 更新日期: 2023-09-27 18:04:29

为什么最后一个输出行返回51?第一行证明a对b取模等于零。我希望第三行也是0因为我只是将数字乘以相同的b。

没有抛出异常。我猜是溢出了,但为什么呢?如何避免这种情况呢?

UInt64 A = 749243140505953395;
UInt64 B = 71;
Console.WriteLine((A % B) == 0);
Console.WriteLine((A*B) < UInt64.MaxValue); 
Console.WriteLine((A * B) % B);

较大UInt64整数的乘积模数错误

c#是一种非常好的语言,几乎没有未定义的行为。但是你在这里看到的是,你得到了一个非常不正确的值。更可悲的是,这种失败模式非常容易避免。微软把他们的项目模板搞砸了。

但没有什么是你不能解决的。确保Debug配置被选中,然后使用项目>属性>构建选项卡>高级按钮>勾选"检查算术溢出/下溢"选项。再次运行程序,您将得到:

类型为"System"的未处理异常。在Example.exe
中发生OverflowException'附加信息:算术运算导致溢出。

您可以在发布版本中关闭该选项,假设您对代码有足够的信心,溢出检查是相当昂贵的。增加了一纳秒。而不是你在Debug构建中所担心的那种开销。

最后一行返回51,原因如下:

首先,A*B会导致64位无符号整数溢出。原因如下。71 * 749243140505953395 = 53196262975922691045该产品大于UInt64。MaxValue,等于18446744073709551615

根据c#语言规范,在未检查的上下文中,溢出将被忽略,任何不适合目标类型的高阶位将被丢弃。因此53196262975922691045,十六进制2 E2 3F 17 54 AA 22 DB E5,变成E2 3F 17 54 AA 22 DB E5(在去除高阶位后,二进制中的前导十六进制"2"或"10"被丢弃)。目的类型64位无符号整数十六进制的最大值为FF FF FF FF FF FF FF FF FF FF FF FF FF

将高阶位(E2 3F 17 54 AA 22 DB E5)裁剪后转换为十进制的十六进制数为16302774828503587813。裁剪后的数字由一个无符号64位整数表示,不会导致溢出。

最后,16302774828503587813% 71 = 51

顺便说一句,正如@EZI刚才提到的,对于非常大的整数,您最好使用BigInteger结构。