Почему «f» требуется при объявлении float?
Пример:
float timeRemaining = 0.58f;
Почему f
требуется в конце номера?
- Значение синуса 180 выходит как 1.22465e-16
- Почему преобразование из float в double изменяет значение?
- C: Приведение минимального 32-битного целого числа (-2147483648) к float дает положительное число (2147483648.0)
- Библиотека высокой точности с плавающей запятой Java
- Сравнение с плавающей точкой `a! = 0.7`
- Разница в арифметике с плавающей запятой между x86 и x64
- Деление с плавающей запятой против умножения с плавающей запятой
- Каков всеобъемлющий диапазон float и double в Java?
- Какова максимальная длина в символах, необходимых для представления любого двойного значения?
- Как может примитивное значение float быть -0.0? Что это значит?
- Преобразование String для плавания в Apple Swift
- Приведение float в int (побитовое) в C
- Сравнение с плавающей точкой
Ваше объявление о поплавке содержит две части:
- Он объявляет, что переменная
timeRemaining
имеет типfloat
. - Он присваивает этому значению значение
0.58
.
Проблема возникает в части 2.
Правая часть оценивается сама по себе. Согласно спецификации C #, число, содержащее десятичную точку, не имеющую суффикса, интерпретируется как double
.
Итак, теперь у нас есть double
значение, которое мы хотим присвоить переменной типа float
. Для этого должно быть неявное преобразование из double
в float
. Такое преобразование отсутствует, потому что вы можете (и в этом случае делать) потерять информацию в конверсии.
Причина в том, что значение, используемое компилятором, на самом деле не 0.58, но значение с плавающей запятой, ближайшее к 0.58, которое равно 0.57999999999999978655962351581366 … для double
и ровно 0,579999946057796478271484375 для float
.
Строго говоря, f
не требуется. Вы можете избежать использования суффикса f
, поместив значение в float
:
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
значение float
которое ближе всего к той же самой величине. Существует несколько угловых случаев, таких как значение 9 007 199 691 611 905; лучшее float
представление было бы 9 007 200 328 482 816 (что на 536 870 911), но литье лучшего double
представления (т.е. 9 007 199 691 611 904) для выплат 9,007,199,254,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.
Увы, правила преобразования – это то, что они есть, поэтому нужно жить с использованием глупых приемов и суффиксов при преобразовании значений в «безопасном» направлении и будьте осторожны с неявными приведениями в опасном направлении, которое часто дает фиктивные результаты.