Почему «f» требуется при объявлении float?

Пример:

float timeRemaining = 0.58f; 

Почему f требуется в конце номера?

Ваше объявление о поплавке содержит две части:

  1. Он объявляет, что переменная timeRemaining имеет тип float .
  2. Он присваивает этому значению значение 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.

Увы, правила преобразования – это то, что они есть, поэтому нужно жить с использованием глупых приемов и суффиксов при преобразовании значений в «безопасном» направлении и будьте осторожны с неявными приведениями в опасном направлении, которое часто дает фиктивные результаты.

  • Алгоритм преобразования двоичного кода IEEE 754 в строку?
  • Почему GCC не оптимизирует a * a * a * a * a * a to (a * a * a) * (a * a * a)?
  • поплавковые биты и строгий псевдоним
  • Как вы печатаете EXACT значение числа с плавающей запятой?
  • Как хранится плавающая запятая? Когда это имеет значение?
  • Странная проблема сравнения поплавков в объективе-C
  • Когда следует использовать double вместо десятичного?
  • Как красиво форматировать плавающие числа в String без ненужного десятичного числа 0?
  • Сделать поплавок показывать только два десятичных знака
  • Как отобразить двоичное представление float или double?
  • Почему изменение 0.1f to 0 замедляет производительность на 10x?
  • Давайте будем гением компьютера.