Одна вещь , которую я хотел бы видеть , было бы признание того, что double
к float
следует рассматривать как расширяющийся преобразования, в то время как float
в double
сужении (*). Это может показаться нелогичным, но подумайте, что на самом деле означают типы:
- 0,1f означает «13 421 773,5 / 134 217 728, плюс или минус 1/268 435 456 или около того».
- 0,1 действительно означает 3 602 879 701 896 397/36 028 797 018 963 968, плюс или минус 1/72 057 594 037 927 936 или около того "
Если кто-то double
имеет наилучшее представление величины «одна десятая» и преобразует ее в float
, результат будет «13 421 773,5 / 134 217 728, плюс или минус 1/268 435 456 или около того», что является правильным описанием значения.
Напротив, если кто-то float
имеет наилучшее представление величины «одна десятая» и преобразует ее double
в результат, то получится «13 421 773,5 / 134 217 728 плюс или минус 1/72 057 594 037 927 936 или около того» - уровень подразумеваемой точности что неверно более чем в 53 миллиона раз.
Хотя стандарт IEEE-744 требует, чтобы математика с плавающей запятой выполнялась так, как если бы каждое число с плавающей запятой представляло точную числовую величину точно в центре его диапазона, это не должно подразумевать, что значения с плавающей запятой фактически представляют эти точные значения. числовые величины. Скорее, требование, чтобы значения считались в центре их диапазонов, вытекает из трех фактов: (1) вычисления должны выполняться так, как будто операнды имеют некоторые конкретные точные значения; (2) согласованные и документированные предположения более полезны, чем противоречивые или недокументированные; (3) если кто-то собирается сделать последовательное допущение, никакое другое непротиворечивое допущение не может быть лучше, чем допущение, что величина представляет центр его диапазона.
Кстати, я помню, примерно 25 лет назад кто-то придумал числовой пакет для C, который использовал «типы диапазонов», каждый из которых состоял из пары 128-битных чисел с плавающей запятой; Все расчеты будут выполняться таким образом, чтобы вычислить минимальное и максимальное возможное значение для каждого результата. Если выполнить большой итеративный расчет и получить значение [12.53401391134 12.53902812673], можно быть уверенным, что хотя многие цифры точности были потеряны из-за ошибок округления, результат все равно можно было бы разумно выразить как 12,54 (и это не было т действительно 12,9 или 53,2). Я удивлен, что не видел никакой поддержки таких типов ни в одном из основных языков, тем более что они выглядели бы подходящими для математических модулей, которые могут работать с несколькими значениями параллельно.
(*) На практике часто бывает полезно использовать значения двойной точности для хранения промежуточных вычислений при работе с числами одинарной точности, поэтому необходимость использования преобразования типов для всех таких операций может раздражать. Языки могли бы помочь, имея тип "нечеткого двойного", который выполнял бы вычисления как двойные, и мог бы свободно приводиться к и от одиночного; это было бы особенно полезно, если бы функции, которые принимают параметры типа double
и возврата, double
могли быть помечены так, чтобы они автоматически генерировали перегрузку, которая вместо этого принимает и возвращает «нечеткий двойной».