C # Arithmetic Question

Good afternoon,

Never using C # to do serious math work, I just noticed something that confused me ... If it's true that

double Test = Math.Sqrt(UInt64.MaxValue) 

equals 4294967296.0, i.e. UInt32.MaxValue + 1 , why is it

 ulong Test2 = UInt32.MaxValue * UInt32.MaxValue; 

equal to 1? At first glance it seems to me that an overflow is happening here ... But why is this so, since this product must comply with UInt64 ?

Thank you very much.

+4
source share
2 answers

the first is because double does not have a 64 mantissa bit, but only about 53. Thus, UInt64.MaxValue rounded to UInt64.MaxValue+1 during conversion to double . And Sqrt this is obviously 2 ^ 32. double can accurately represent any value from (U)Int32 , but some of the larger 64-bit integers cannot be represented as double .

The second happens because you are doing the multiplication before the cast to UInt64 , that is, it happens as UInt32 , which is clearly overflowing. Put at least one of your operands on UInt64 and the problem UInt64 away.

+10
source
 ulong Test2 = UInt32.MaxValue * UInt32.MaxValue 

Can be translated into:

 UInt32 __temp = UInt32.MaxValue * UInt32.MaxValue; // Overflow ulong Test2 = (ulong)__temp; 

since the operation to the left of the = sign is always performed without any type conclusions on the right, obviously not what you want ...

It should be

 ulong Test2 = (long)UInt32.MaxValue * UInt32.MaxValue; 

This will be considered as:

 ulong Test2 = (long)UInt32.MaxValue * (long)UInt32.MaxValue; 

And it will work.

The rules are given in section 16.4.2 of the C # norm:

Numeric promotion consists of automatically performing certain implicit conversions of operands of predefined unary and binary numeric operators. Numerical promotion is not a separate mechanism, but rather the effect of permission overloading on predefined operators. Numeric promotion is not specifically affected by the evaluation of user agents, although user agents may have similar effects introduced.

As an example of digital advertising, consider the predefined implementations of the binary * operator:

 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); 

When overload resolution rules (ยง14.4.2) are applied to this set of statements, the first of the statements should be selected for which implicit conversions exist from operand types. [Example: for operation b * s, where b is byte and s is short, overload resolution selects the * (int, int) operator as the best operator. Thus, the effect is that b and s are converted to int and the result type is int. Similarly, for operation I * d, where I am int and d is double, overload resolution selects the * (double, double) operator as the best operator. end of example]

+4
source

Source: https://habr.com/ru/post/1343020/


All Articles