2011-03-09 92 views
4

下午好,C#算术问题

从未使用过C#做严肃的数学工作,我刚才注意到一些东西,给我留下了困惑......如果这是真的,

double Test = Math.Sqrt(UInt64.MaxValue) 

等于4294967296.0,就是UInt32.MaxValue + 1,那为什么

ulong Test2 = UInt32.MaxValue * UInt32.MaxValue; 

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

非常感谢。

回答

10

第一个发生是因为double没有64个尾数位,但只有53个左右。所以在转换为double期间,UInt64.MaxValue将四舍五入为UInt64.MaxValue+1。而那个Sqrt显然是2^32。 double可以完全代表(U)Int32中的任何值,但某些较大的64位整数不能表示为double

第二个发生是因为您在投射到UInt64之前进行了乘法运算,即发生为UInt32,这明显溢出。将至少一个操作数抛到UInt64,问题就会消失。

+0

是的。请给我的问题-1。非常感谢你。 – Miguel 2011-03-09 15:19:05

+0

这个问题没有错? – Spooks 2011-03-09 15:20:38

+6

@Miguel:我不认为你需要-1。你犯了一个诚实的错误。这个问题已经得到解答,就是这样。 – siride 2011-03-09 15:20:42

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是短的,重载分辨率 选择运算符*(int,int)作为 最佳运算符。因此,效果是 ,b和s被转换为int,并且 结果的类型是int。 同样,对于操作i * d, (其中i是一个int并且d是双精度), 重载决议选择运算符 *(double,double)作为最佳运算符。 end example]