C # Арифметический вопрос - PullRequest
4 голосов
/ 09 марта 2011

Добрый день,

Никогда не используя C # для серьезной математической работы, я только что заметил что-то, что оставило меня в замешательстве ... Если правда, что

double Test = Math.Sqrt(UInt64.MaxValue)

равно4294967296.0, то есть UInt32.MaxValue + 1, почему

ulong Test2 = UInt32.MaxValue * UInt32.MaxValue;

равно 1?На первый взгляд мне кажется, что здесь происходит переполнение ... Но почему это так, поскольку этот продукт должен соответствовать UInt64?

Большое спасибо.

Ответы [ 2 ]

10 голосов
/ 09 марта 2011

первое происходит потому, что в double нет 64 битов мантиссы, а только около 53. Таким образом, UInt64.MaxValue будет округлено до UInt64.MaxValue+1 во время преобразования в doubleSqrt этого, очевидно, 2 ^ 32.double может точно представлять любое значение из (U)Int32, но некоторые из больших 64-битных целых не могут быть представлены как double.

Второе происходит, потому что вы выполняете умножение перед приведением к UInt64, то есть это происходит как UInt32, что явно переполняется.Приведите хотя бы один из ваших операндов к UInt64, и проблема исчезнет.

4 голосов
/ 09 марта 2011
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;

И будет работать.

Правила приведены в разделе 16.4.2 нормы C #:

Числовое продвижение состоит из автоматически выполняет определенные неявные преобразования операндов предопределенных одинарных и двоичных числовые операторы. Числовое продвижение не является четким механизмом, но скорее эффект применения перегрузки разрешение до предопределенного операторы. Числовое продвижение конкретно не влияет оценка пользовательских операторов, хотя пользовательские операторы могут быть реализован, чтобы показать аналогичные последствия.

В качестве примера числового продвижения, рассмотреть предопределенный реализации бинарного * оператор:

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, где я является INT и D является двойным, разрешение перегрузки выбирает оператор * (двойной, двойной) как лучший оператор. конец примера]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...