Приведите число с плавающей запятой в C #. Почему (десятичное) 0,1F == 0,1M не ложно из-за округления? - PullRequest
0 голосов
/ 06 ноября 2018

Если я оцениваю следующее в C #, это возвращает true:

(decimal)0.1F == 0.1M

Почему преобразование с плавающей точкой и обратно в десятичное не приводит к ошибкам округления?

1 Ответ

0 голосов
/ 06 ноября 2018

Причиной наблюдаемого поведения является то, что реализация Microsoft C # преобразует float в decimal, используя только семь десятичных цифр.

В реализации Microsoft C # используется .NET. Когда .NET преобразует число с плавающей запятой одинарной точности в десятичное, выдает не более семи значащих цифр , округляя любой остаток с использованием округления до ближайшего.

Исходный текст 0.1F становится значением одинарной точности 0.100000001490116119384765625. Когда он преобразуется в десятичную с семью значащими цифрами, результат равен точно 0,1. Таким образом, в Microsoft C # (decimal) 0.1F выдает 0.1, поэтому (decimal) 0.1F == 0.1M имеет значение true.

Мы можем сравнить это с реализацией не Microsoft, Mono C #. Онлайн-компилятор для этого доступен здесь . В нем Console.WriteLine((decimal)0.1F); печатает «0.100000001490116», а (decimal)0.1F == 0.1M оценивается как ложное. Mono C # при преобразовании float в decimal.

выдает более семи цифр.

Документация Microsoft C # для явных преобразований гласит: «При преобразовании float или double в decimal исходное значение преобразуется в десятичное представление и округляется до ближайшего числа после 28-го десятичного знака поместите, если требуется. »Я бы интерпретировал это как означающее, что истинное значение float, 0.100000001490116119384765625, точно преобразуется в decimal (так как для него требуется менее 28 цифр), но, очевидно, это не так.

Мы можем далее подтвердить это и проиллюстрировать, что происходит, преобразовав float в double, а затем в decimal. Microsoft C # преобразует double в decimal, используя 15 значащих цифр. Если мы конвертируем 0.1F в double, значение не меняется, поскольку double может точно представлять каждое float значение , Так что (double) 0.1F имеет точно такое же значение, как и 0.1F, 0.100000001490116119384765625. Однако теперь, когда он преобразуется в decimal, получается 15 цифр. В реализации Microsoft C # Console.WriteLine((decimal)(double) 0.1F); печатает «0.100000001490116», а (decimal)(double) 0.1F == 0.1M оценивается как ложное.

...