Интересно, можете ли вы объяснить переполнение в типах с плавающей точкой.
float.MaxValue == float.MaxValue + 1 // returns true
Интересно, можете ли вы объяснить переполнение в типах с плавающей точкой.
float.MaxValue == float.MaxValue + 1 // returns true
Потому что 1
слишком мал, чтобы сделать вмятину в значении float.MaxValue
.
Все, что меньше 1e32, опустится ниже точности поплавка, так что это фактически то же самое, что и добавление нуля.
ulrichb показал, что значение 1e23 действительно влияет на float.MaxValue, что должно означать, что вы вообще не сравниваете поплавки, но удваиваете. Компилятор преобразует все значения в парные числа перед добавлением и сравнением.
Это очень интересно:
float fMax = float.MaxValue;
double dMax = double.MaxValue;
Console.WriteLine("{0}, {1}", fMax == fMax + 1E22f, fMax + 1E22f);
Console.WriteLine("{0}, {1}", fMax == fMax + 1E23f, fMax + 1E23f);
Console.WriteLine("{0}, {1}", dMax == dMax + 1E291d, dMax + 1E291d);
Console.WriteLine("{0}, {1}", dMax == dMax + 1E292d, dMax + 1E292d);
печатает:
True, 3.402823E+38 False, 3.402823E+38 True, 1.79769313486232E+308 False, Infinity
Итак,... как отметил Гуффа, fMax + 1E23f
преобразуется в double и dMax + 1E292d
добавляет до Infinity
.
Проблема здесь - точность с плавающей запятой. float.MaxValue
соответствует 3,40282e + 038f. Но float
имеет гораздо меньшую точность, которая на самом деле составляет всего 7 цифр точности.
Все, что выше этой точности, "заполнено нулями", и добавление 1 к этому большому числу не изменит его.
Вкратце, разница в 39-й цифре, а float
хранит только первые 7 (ish). Это характеристика арифметики с плавающей запятой.
Чтобы получить временную переменную типа float, чтобы фактически сохранить одно значение точности, она должна быть загружена из переменной float в памяти. Компилятору обычно разрешено представлять значения с одной точностью с большей точностью, чем требуется, и имеет тенденцию делать это, пока значение находится в регистре. Когда он возвращается в память, дополнительная точность теряется.