下午好,
从未使用C#做重要的数学工作,我刚刚注意到让我困惑的事情......如果确实如此
double Test = Math.Sqrt(UInt64.MaxValue)
等于4294967296.0,即UInt32.MaxValue + 1
,为什么呢
ulong Test2 = UInt32.MaxValue * UInt32.MaxValue;
等于1?乍一看,在我看来溢出发生在这里......但是为什么那个产品应该适合UInt64
?
非常感谢。
答案 0 :(得分:10)
第一个发生因为double没有64个尾数位,但只有大约53个。所以UInt64.MaxValue
在转换为UInt64.MaxValue+1
期间将四舍五入为double
。而Sqrt
显然是2 ^ 32。 double
可以完全代表(U)Int32
中的任何值,但某些较大的64位整数不能表示为double
。
第二个发生是因为你在转换为UInt64
之前进行乘法运算,即它发生在UInt32
,显然会溢出。将至少一个操作数强制转换为UInt64
,问题就会消失。
答案 1 :(得分:4)
ulong Test2 = UInt32.MaxValue * UInt32.MaxValue
可翻译为:
UInt32 __temp = UInt32.MaxValue * UInt32.MaxValue; // Overflow
ulong Test2 = (ulong)__temp;
因为=符号左边的操作始终没有对右边的类型进行任何推断,显然不是你想要的...
应该是
ulong Test2 = (long)UInt32.MaxValue * UInt32.MaxValue;
将被视为:
ulong Test2 = (long)UInt32.MaxValue * (long)UInt32.MaxValue;
并且会奏效。
规则在C#规范的第16.4.2节中:
数字促销包括 自动执行某些 操作数的隐式转换 预定义的一元和二元的 数字运算符。数字促销 不是一个独特的机制,但是 而是应用过载的效果 解析到预定义的 运营商。数字促销 具体不影响 评估用户定义的运算符, 虽然用户定义的运算符可以 实施以展示类似 效果。
作为数字推广的一个例子, 考虑预定义的 二进制的实现* 运营商:
int operator *(int x, int y); uint operator *(uint x, uint y); long operator *(long x, long y); ulong operator *(ulong x, ulong y); void operator *(long x, ulong y); void operator *(ulong x, long y); float operator *(float x, float y); double operator *(double x, double y); decimal operator *(decimal x, decimal y);
当重载决策规则时 (§14.4.2)适用于这套 运营商,效果就是选择了 第一个运营商 隐含转换存在于 操作数类型。 [例如:对于 操作b * s,其中b是一个字节 s是一个简短的重载决策 选择operator *(int,int)作为 最佳运营商。因此,效果是 b和s转换为int,和 结果的类型是int。 同样,对于操作i * d, 其中我是一个int,d是双, 重载决策选择运算符 *(双,双)作为最佳运算符。结束例子]