具有大UInt64整数的产品的模数不正确

时间:2015-07-24 21:34:11

标签: c#

为什么最后一行输出返回51?第一行证明mod b为零。我希望第三行也是零,因为我只是将数字乘以相同的B。

没有抛出异常。我认为这是一个溢出但为什么?以及如何避免这种情况?

UInt64 A = 749243140505953395;
UInt64 B = 71;

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

2 个答案:

答案 0 :(得分:2)

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

但是你无法解决。确保选择了Debug配置,然后使用Project&gt;属性&gt;构建标签&gt;高级按钮&gt;勾选“检查算术溢出/下溢”选项。再次运行您的程序,您现在可以获得:

  

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

您可以为Release版本关闭选项,假设您对代码有足够的信心,溢出检查非常昂贵。添加纳秒,给予或接受。不是你在Debug版本中担心的那种费用。

答案 1 :(得分:2)

最后一个输出行返回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(在修正高位后,前导十六进制&#34; 2&#34;或&#34; 10&# 34;二进制被丢弃)。供您参考,十六进制的desination类型64位无符号整数的最大值为FF FF FF FF FF FF FF

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

最后,16302774828503587813%71 = 51

正如@EZI所指出的那样,通过大笔整数,你最好使用BigInteger结构。