Когда вы используете поплавок и когда вы используете двойной

194

Часто в моем опыте программирования мне нужно принять решение, использовать ли мне float или double для моих реальных чисел. Иногда я иду на поплавок, иногда я иду на двойной, но на самом деле это кажется более субъективным. Если бы мне пришлось встать на защиту моего решения, я бы, вероятно, не привел веских причин.

Когда вы используете float и когда вы используете double? Всегда ли вы используете double, только при наличии ограничений памяти вы идете на float? Или вы используете всегда float, если требование точности не требует двойного? Есть ли существенные различия в вычислительной сложности базовой арифметики между float и double? Каковы плюсы и минусы использования float или double? И ты даже использовал длинный двойной?

Якуб Заверка
источник
28
Во многих случаях вы хотите использовать ни один, а десятичный тип с плавающей или фиксированной точкой. Двоичные типы с плавающей запятой не могут точно представлять большинство десятичных дробей.
CodesInChaos
3
Связано с Что вызывает ошибки округления с плавающей запятой? , @CodesInChaos Мой ответ там предлагает ресурсы, которые помогут вам сделать это определение, не существует единого решения для всех .
Марк Бут
Очень хороший ответ найден по адресу: Переполнение стека
Харис
5
Что именно вы подразумеваете под "десятичными числами". Если вам необходимо точно представить значения, такие как 0,01 (скажем, для денег), то (двоичная) с плавающей точкой не является ответом. Если вы просто подразумеваете нецелые числа, то с плавающей точкой, скорее всего, все в порядке, но тогда «десятичные дроби» - не лучшее слово для описания того, что вам нужно.
Кит Томпсон
1
У тебя не всегда есть выбор. Например, на платформе Arduino значения double и float равны числу float. Вам нужно найти библиотеку надстроек, чтобы обрабатывать реальные двойники.
Кивирон

Ответы:

187

Выбор по умолчанию для типа с плавающей точкой должен быть double. Это также тип, который вы получаете с литералами с плавающей точкой без суффикса или (в C) стандартными функциями, которые работают с числами с плавающей точкой (например exp, sinи т. Д.).

float следует использовать только в том случае, если вам нужно оперировать множеством чисел с плавающей точкой (думайте в порядке тысяч или более), и анализ алгоритма показал, что уменьшенный диапазон и точность не представляют проблемы.

long doubleможет использоваться, если вам нужен больший диапазон или точность, чем double, и если это обеспечивает это на вашей целевой платформе.

Таким образом, floatи long doubleдолжны быть зарезервированы для использования специалистами, doubleдля "повседневного" использования.

Барт ван Инген Шенау
источник
10
Я бы, вероятно, не рассматривал float для нескольких тысяч значений, если бы не было проблемы с производительностью, связанной с кэшированием с плавающей запятой и передачей данных. Обычно анализ требует значительных затрат, чтобы показать, что поплавок достаточно точен.
Патриция Шанахан
4
В качестве дополнения, если вам нужна совместимость с другими системами, может быть выгодно использовать те же типы данных.
zzzzBov
15
Я бы использовал поплавки для миллионов чисел, а не для тысяч. Кроме того, некоторые графические процессоры лучше работают с поплавками, в этом специализированном случае используются поплавки. Иначе, как вы говорите, используйте удвоения.
user949300
4
@PatriciaShanahan - «проблема с производительностью, связанная с ...». Хороший пример: если вы планируете использовать SSE2 или аналогичные векторные инструкции, вы можете сделать 4 операции на вектор в поплавке (против 2 на удвоение), что может дать значительное улучшение скорости ( вдвое меньше операций и вдвое меньше данных для чтения и записи). Это может значительно снизить порог, когда использование чисел с плавающей точкой становится привлекательным, и стоит потрудиться разобраться с числовыми проблемами.
Грегго
12
Я подтверждаю этот ответ одним дополнительным советом: когда кто-то работает со значениями RGB для отображения, его можно использовать float(и иногда с половинной точностью), потому что ни человеческий глаз, ни дисплей, ни цветовая система не обладают такой большой точностью , Этот совет применим, скажем, к OpenGL и т. Д. Этот дополнительный совет не относится к медицинским изображениям, которые предъявляют более строгие требования к точности.
14:00
42

В кодах, ориентированных на современные компьютеры, редко встречается причина использовать float вместо double. Дополнительная точность снижает (но не исключает) вероятность ошибок округления или других неточностей, вызывающих проблемы.

Основные причины, по которым я могу использовать float:

  1. Вы храните большие массивы чисел, и вам нужно уменьшить потребление памяти вашей программой.
  2. Вы нацелены на систему, которая изначально не поддерживает с плавающей запятой двойной точности. До недавнего времени многие видеокарты поддерживали только плавающие точки одинарной точности. Я уверен, что есть много маломощных и встроенных процессоров, которые также имеют ограниченную поддержку с плавающей запятой.
  3. Вы ориентируетесь на оборудование, где одинарная точность быстрее, чем двойная, и в вашем приложении интенсивно используется арифметика с плавающей запятой. Я полагаю, что на современных процессорах Intel все вычисления с плавающей запятой выполняются с двойной точностью, поэтому здесь вы ничего не получите.
  4. Вы выполняете низкоуровневую оптимизацию, например, используя специальные инструкции процессора, которые работают с несколькими номерами одновременно.

Таким образом, в основном, двойным является путь, если у вас нет аппаратных ограничений или если анализ не показал, что хранение чисел с двойной точностью вносит значительный вклад в использование памяти.

user611910
источник
2
«Современные компьютеры» означает процессоры Intel x86. Некоторые из машин, которые использовались Древними, обеспечивали совершенно адекватную точность с основным типом поплавка. (CDC 6600 использовал 60-битное слово, 48 битов нормализованной мантиссы с плавающей запятой, 12 битов показателя степени. Это почти то, что x86 дает вам для двойной точности.)
Джон Р. Стром
@ John.R.Strohm: согласен, но компиляторы C не существуют на CDC6600. Это был Фортран IV ...
Василий Старынкевич
Под «современными компьютерами» я подразумеваю любой процессор, созданный за последние десять или два года, или действительно, с тех пор, как широко применялся стандарт IEEE с плавающей запятой. Я прекрасно знаю, что существуют архитектуры, отличные от x86, и имел в виду мой ответ - я упомянул графические процессоры и встроенные процессоры, которые обычно не являются x86.
user611910
Это просто неправда. SSE2 может манипулировать 4-мя числами с плавающей запятой или 2-мя двойными за одну операцию, AVX может обрабатывать 8-ми числами с плавающей запятой или 4-мя двойными, AVX-512 может управлять 16-ю числами с плавающей запятой или 8-ю. Для любого вида высокопроизводительных вычислений математику с плавающей запятой следует рассматривать как удвоенную скорость тех же операций на удвоениях в x86.
Ларри Гриц,
1
И это еще хуже, поскольку вы можете разместить в кэш-памяти процессора в два раза больше, чем вы можете, используя удвоения, и задержка памяти, вероятно, будет основным узким местом во многих программах. Сохранение в кеше целого рабочего набора чисел с плавающей точкой может быть буквально на порядок быстрее, чем использование удвоений и их разлив в ОЗУ.
Ларри Гриц,
10

Используйте doubleдля всех ваших расчетов и временных переменных. Используйте, floatкогда вам нужно поддерживать массив чисел - float[](если точность достаточна), и вы имеете дело с более чем десятками тысяч floatчисел.

Многие / большинство математических функций или операторов конвертируют / возвращают double, и вы не хотите приводить числа обратно к floatлюбым промежуточным шагам.

Например, если у вас есть 100 000 номеров из файла или потока и вам нужно их отсортировать, введите числа в float[].

Фай Нг
источник
5

Некоторые платформы (ARM Cortex-M2, Cortex-M4 и т. Д.) Не поддерживают double (это всегда можно проверить в справочном руководстве по вашему процессору. Если нет предупреждений или ошибок компиляции, это не означает, что код является оптимальным. двойной можно подражать.) Вот почему вам может понадобиться придерживаться int или float .

Если это не так, я бы использовал double .

Вы можете проверить знаменитую статью Д. Голдберга («Что должен знать каждый компьютерщик об арифметике с плавающей точкой»). Вы должны дважды подумать, прежде чем использовать арифметику с плавающей точкой. Существует довольно большой шанс, что они не нужны вообще в вашей конкретной ситуации.

http://perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf

staroselskii
источник
3
На этот вопрос уже довольно хорошо ответили год назад ... но в любом случае, я бы сказал, что всякий раз, когда вы используете двойную на платформах с ускорением FPU двойной точности, вы должны использовать его на любой другой, даже если это означает позволяя компилятору эмулировать его, вместо того чтобы использовать преимущества FPU только с плавающей запятой (обратите внимание, что FPU не требуются и на всех платформах, фактически, архитектура Cortex-M4 определяет их как дополнительную функцию [была ли M2 опечаткой?] ).
Селали Адобор
Ключом к этой логике является то, что, хотя это и правда, надо устать от арифметики с плавающей запятой, и это много «причуд», определенно не учитывающих наличие поддержки FPU для double, что означает просто использование double вместо float. Плавания, как правило, быстрее, чем удваиваются, и занимают меньше памяти (возможности FPU различаются). Объем использования не позволяет этой точке преждевременной оптимизации. Как и тот факт, что двойники явно избыточны для многих (может быть, даже для большинства) приложений. Действительно ли необходимо, чтобы элементы на этой странице имели свои относительные позиции и размеры, рассчитанные с точностью до 13 знаков после запятой?
Селали Адобор
2
При включении ссылки на стороннюю страницу или документ, пожалуйста, скопируйте соответствующую информацию или резюме из документа в свой ответ. Ссылки вне сайта имеют тенденцию исчезать со временем.
Адам Цукерман
3

Для реальных проблем порог выборки ваших данных важен при ответе на этот вопрос. Аналогично, уровень шума также важен. Если какой-либо из них будет превышен при выборе типа данных, увеличение точности не принесет никакой пользы.

Большинство реальных сэмплеров ограничены 24-битными ЦАП. Предполагается, что 32 бита точности в реальных вычислениях должны быть адекватны, если значение составляет 24 бита.

Двойная точность достигается за счет 2-кратной памяти. Поэтому ограничение использования двойных чисел над числами с плавающей запятой может резко сократить объем памяти / пропускную способность работающих приложений.

user3034617
источник
-3

Выбор того, какую переменную использовать между float и double, зависит от точности требуемых данных. Если требуется, чтобы ответ имел незначительную разницу с фактическим ответом, количество требуемых десятичных разрядов будет много, поэтому будет требоваться использование этого двойного числа. Поплавок отрежет часть десятичных разрядов, что снизит точность.

Давид Монянча
источник
3
Этот ответ не добавляет ничего нового к вопросу и не говорит ничего о реальном использовании.
Мартин Питерс
-5

Обычно я использую floatтип, когда мне не нужна большая точность - например, для денег - что неправильно, но я привык делать неправильно.

С другой стороны, я использую, doubleкогда мне нужно больше точности, например, для сложных математических алгоритмов.

Стандарт C99 говорит об этом:

Существует три типа с плавающей точкой: float, double и long double. Тип double обеспечивает, по крайней мере, такую ​​же точность, как и float, а тип long double обеспечивает, по крайней мере, такую ​​же точность, что и double. Набор значений типа float является подмножеством набора значений типа double; набор значений типа double является подмножеством набора значений типа long double.

Я никогда не использовал long double, но я не так часто использую C / C ++. Обычно я использую динамически типизированные языки, такие как Python, где вам не нужно заботиться о типах.

Для получения дополнительной информации о Double vs Float , смотрите этот вопрос в SO .

Аддисон Монтгомери
источник
25
Использование плавающей запятой для серьезных денежных расчетов, вероятно, является ошибкой.
Барт ван Инген Шенау
17
float - это совсем не тот тип денег. Вы должны использовать максимально возможную точность.
ChrisF
8
@BartvanIngenSchenau С плавающей точкой для денег обычно все в порядке, двоичная с плавающей точкой - нет. Например, .net Decimal- это тип с плавающей запятой, и, как правило, это хороший выбор для расчета денег.
CodesInChaos
13
@ChrisF Вам не нужна «высокая точность» для денег, вам нужны точные значения.
Шон МакSomething
2
@SeanMcSomething - Честная точка зрения. Тем не менее, числа с плавающей точкой по-прежнему имеют неправильный тип, и, учитывая типы с плавающей точкой, доступные в большинстве языков, вам нужна «высокая точность», чтобы получить «точные значения».
ChrisF