Пример:
float timeRemaining = 0.58f;
Почему в конце номера требуется f
?
Пример:
float timeRemaining = 0.58f;
Почему в конце номера требуется f
?
Ваше объявление о поплавке содержит две части:
timeRemaining
имеет тип float
.0.58
этой переменной.Проблема возникает в части 2.
Правая часть оценивается сама по себе. Согласно спецификации С#, число, содержащее десятичную точку, которая не имеет суффикса, интерпретируется как double
.
Итак, теперь мы имеем значение double
, которое мы хотим присвоить переменной типа float
. Для этого должно быть неявное преобразование от double
до float
. Такое преобразование отсутствует, потому что вы можете (и в этом случае делать) потерять информацию при преобразовании.
Причина в том, что значение, используемое компилятором, на самом деле не 0,58, но значение с плавающей запятой, ближайшее к 0,58, которое составляет 0,57999999999999978655962351581366... для double
и ровно 0,579999946057796478271484375 для float
.
Строго говоря, f
не требуется. Вы можете избежать использования суффикса f
, задав значение :
float timeRemaining = (float)0.58;
Поскольку существует несколько числовых типов, которые компилятор может использовать для представления значения 0.58
: float
, double
и decimal
. Если вы не согласны с тем, что компилятор выбирает один для вас, вам необходимо устранить проблему.
В документации для double
указано, что если вы не укажете тип самостоятельно, компилятор всегда выбирает double
как тип любого действительного числового литерала:
По умолчанию действительный числовой литерал в правой части задания оператор рассматривается как двойной. Однако, если вы хотите, чтобы целое число для того, чтобы считаться двойным, используйте суффикс d или D.
Добавление суффикса f
создает float
; суффикс d
создает double
; суффикс m
создает decimal
. Все они также работают в верхнем регистре.
Однако этого все еще недостаточно, чтобы объяснить, почему это не скомпилируется:
float timeRemaining = 0.58;
Недопустимая половина ответа заключается в том, что преобразование из double
0.58
в float
timeRemaining
потенциально теряет информацию, поэтому компилятор отказывается применять его неявно. Если вы добавляете явное преобразование, выполняется преобразование; если вы добавите суффикс f
, то преобразование не потребуется. В обоих случаях код будет компилироваться.
Проблема заключается в том, что .NET, чтобы позволить выполнять некоторые типы неявных операций с использованием float
и double
, необходимо либо явно указать, что должно происходить во всех сценариях, связанных с смешанными операндами, либо разрешать неявные конверсии между типами, которые должны выполняться только в одном направлении; Microsoft предпочла следовать примеру Java, позволяя направление, которое иногда способствует точности, но часто приносит в жертву правильность и обычно создает проблемы.
Почти во всех случаях значение double
, которое ближе всего к определенной числовой величине и присваивает его float
, даст значение float
, которое ближе всего к той же самой величине. Существует несколько угловых случаев, таких как значение 9 007 199 691 611 905; наилучшее представление float
было бы 9 007 200 328 482 816 (которое отключено на 536 870 911), но отличное представление double
(т.е. 9 007 199 671 611 904) до float
дает 9 007 199 994 740 992 (что не соответствует 536 870 913). В общем случае преобразование наилучшего представления double
некоторой величины в float
либо даст наилучшее представление float
, либо одно из двух представлений, которые по существу одинаково хороши.
Обратите внимание, что это желаемое поведение распространяется даже на крайности; например, лучшее представление float
для величины 10 ^ 308 соответствует представлению float
, полученному путем преобразования наилучшего представления double
этой величины. Точно так же наилучшее представление float
10 ^ 309 соответствует представлению float
, достигаемому путем преобразования наилучшего представления double
этой величины.
К сожалению, конверсии в направлении, не требующем явного приведения, редко где-то близки к точности. Преобразование наилучшего представления float
значения в double
редко приведет к чему-либо, особенно близкому к лучшему представлению double
этого значения, и в некоторых случаях результат может быть отключен на сотни порядков (например, преобразование Лучшее float
представление от 10 ^ 40 до double
даст значение, которое сравнивается больше, чем лучшее double
представление 10 ^ 300.
Увы, правила конверсии - это то, что они есть, поэтому нужно жить с использованием глупых приемов и суффиксов при преобразовании значений в "безопасном" направлении и быть осторожным с неявными приведениями в опасном направлении, которые часто дают фиктивные результаты.