C#算术问题

时间:2011-03-09 15:14:50

标签: c# math overflow

下午好,

从未使用C#做重要的数学工作,我刚刚注意到让我困惑的事情......如果确实如此

double Test = Math.Sqrt(UInt64.MaxValue)

等于4294967296.0,即UInt32.MaxValue + 1,为什么呢

ulong Test2 = UInt32.MaxValue * UInt32.MaxValue;

等于1?乍一看,在我看来溢出发生在这里......但是为什么那个产品应该适合UInt64

非常感谢。

2 个答案:

答案 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是双,   重载决策选择运算符   *(双,双)作为最佳运算符。结束例子]