Что я должен использовать: double или float?


89

Каковы преимущества и недостатки использования одного вместо другого в C ++?


Кто-нибудь пробовал создать массив с плавающей запятой и массив с двойной точностью и посмотреть, действительно ли есть 4 байта между членами с плавающей запятой и 8 байтов между членами с двойной точностью? Возможно, что 64-битный компилятор / компьютер все еще может зарезервировать 8 байтов на член для чисел с плавающей запятой, даже если им это не нужно.
user3015682

Ответы:


104

Если вы хотите узнать истинный ответ, вам следует прочитать « Что должен знать каждый компьютерный ученый об арифметике с плавающей точкой» .

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

Многие компиляторы в любом случае выполняют расширенную математику с плавающей запятой в «нестрогом» режиме (т. Е. Используют более широкий тип с плавающей запятой, доступный в оборудовании, например, 80-битные и 128-битные с плавающей запятой), это также следует учитывать. На практике разницы в быстродействии практически не видно - они все равно не железо.


10
Да. С современными процессорами, которые предварительно выбирают все большие и большие блоки памяти, параллельными вычислительными устройствами и конвейерными архитектурами, проблема скорости действительно не является проблемой. Если вы имеете дело с огромным количеством чисел, возможно, разница в размерах между 4-байтовым числом с плавающей запятой и 8-байтовым двойным числом может иметь значение в объеме памяти.
lavinio 02

5
Что ж, SSE (или любой другой модуль с плавающей запятой) сможет обрабатывать в два раза больше операций с одинарной точностью по сравнению с двойной точностью. Если вы используете только x87 (или любой скаляр) с плавающей запятой, это, вероятно, не имеет значения.
Грег Роджерс

1
@ Грег Роджерс: компиляторы сейчас не настолько умны. Если вы не пишете сырую сборку, больших различий нет. И да, это может измениться по мере развития компилятора.
J-16 SDiZ

Дополнительные примечания: если вы абсолютно не знаете, как выглядят данные (или просто не имеете ни малейшего представления о математике в ссылках), просто используйте double- это в большинстве случаев безопаснее.
J-16 SDiZ

2
Эта статья не короткая.
jokoon

44

Если у вас нет особых причин поступить иначе, используйте double.

Возможно, удивительно, что это double, а не float, который является «нормальным» типом с плавающей запятой в C (и C ++). Стандартные математические функции, такие как sin и log, принимают двойные значения в качестве аргументов и возвращают двойные значения. Обычный литерал с плавающей запятой, например, когда вы пишете 3.14 в своей программе, имеет тип double. Не плавают.

На типичных современных компьютерах удвоения могут выполняться так же быстро, как и числа с плавающей запятой, или даже быстрее, поэтому производительность обычно не является важным фактором даже для больших вычислений. (И это должны быть большие вычисления, иначе производительность даже не должна приходить вам в голову. Мой новый настольный компьютер i7 может сделать шесть миллиардов умножений удвоений за одну секунду.)


26

На этот вопрос невозможно ответить, так как у вопроса нет контекста. Вот несколько вещей, которые могут повлиять на выбор:

  1. Реализация компилятором чисел с плавающей запятой, чисел двойной точности и длинных чисел двойной точности. Стандарт C ++ гласит:

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

    Итак, все три могут иметь одинаковый размер в памяти.

  2. Наличие FPU. Не все процессоры имеют FPU, и иногда типы с плавающей запятой эмулируются, а иногда типы с плавающей запятой просто не поддерживаются.

  3. Архитектура FPU. FPU IA32 внутренне 80-битный - 32-битные и 64-битные числа с плавающей запятой расширяются до 80 бит при загрузке и сокращаются при хранении. Также есть SIMD, который может выполнять четыре 32-битных или два 64-битных поплавка параллельно. Использование SIMD не определено в стандарте, поэтому потребуется компилятор, который выполняет более сложный анализ, чтобы определить, можно ли использовать SIMD, или требует использования специальных функций (библиотек или встроенных функций). Результатом 80-битного внутреннего формата является то, что вы можете получить несколько разные результаты в зависимости от того, как часто данные сохраняются в ОЗУ (что приводит к потере точности). По этой причине компиляторы не особенно хорошо оптимизируют код с плавающей запятой.

  4. Пропускная способность памяти. Если для числа double требуется больше памяти, чем для числа с плавающей запятой, чтение данных займет больше времени. Это наивный ответ. На современном IA32 все зависит от того, откуда берутся данные. Если он находится в кэше L1, нагрузка незначительна при условии, что данные поступают из одной строки кеша. Если он занимает более одной строки кэша, возникают небольшие накладные расходы. Если он из L2, это займет немного больше времени, если он в ОЗУ, то еще дольше и, наконец, если он на диске, это огромное время. Таким образом, выбор типа float или double менее важен, чем способ использования данных. Если вы хотите выполнить небольшой расчет на большом количестве последовательных данных, предпочтительнее использовать небольшой тип данных. Выполнение большого количества вычислений на небольшом наборе данных позволит вам использовать большие типы данных со значительным эффектом. Если ты' При повторном доступе к данным очень случайным образом выбор размера данных не имеет значения - данные загружаются в страницы / строки кэша. Таким образом, даже если вам нужен только байт из ОЗУ, вы можете передать 32 байта (это очень зависит от архитектуры системы). Вдобавок ко всему, CPU / FPU может быть суперскалярным (то есть конвейерным). Таким образом, даже если загрузка может занять несколько циклов, CPU / FPU может быть занят чем-то другим (например, умножением), что в некоторой степени скрывает время загрузки.

  5. Стандарт не требует какого-либо конкретного формата для значений с плавающей запятой.

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


16

Double является более точным, но кодируется 8 байтами. float составляет всего 4 байта, поэтому меньше места и меньше точности.

Вы должны быть очень осторожны, если в вашем приложении есть double и float. Из-за этого у меня раньше была ошибка. Одна часть кода использовала float, а остальная часть кода использовала double. Копирование double в float, а затем float в double может вызвать ошибку точности, которая может иметь большое влияние. В моем случае это был химический завод ... надеюсь, драматических последствий это не имело :)

Я думаю, что именно из-за этого жука несколько лет назад взорвалась ракета Ariane 6 !!!

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


3
Обратите внимание, что 4/8 байтов для float / double даже не гарантируется, это будет зависеть от платформы. Это может быть даже один и тот же тип ...
sleske

2
Код Ariane 5 пытался преобразовать 64-битное число с плавающей запятой, значение которого было больше 32 767, в 16-битное целое число со знаком. Это вызвало исключение переполнения, которое заставило ракету инициировать последовательность самоуничтожения. Рассматриваемый код был кодом, который был повторно использован от более старой, меньшей ракеты.
cmwt

5

Я лично все время иду на удвоение, пока не вижу узких мест. Затем я подумываю о переходе на плавание или оптимизации какой-либо другой части.


4

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

При этом, если они действительно разные, главный вопрос - точность. Двойник имеет гораздо более высокую точность из-за разницы в размере. Если используемые вами числа обычно превышают значение числа с плавающей запятой, используйте значение типа double.

Некоторые другие люди упомянули проблемы производительности. Это будет последнее в моем списке соображений. Правильность должна быть вашим соображением №1.


3

2

Я думаю, независимо от различий (которые, как все отмечают, с плавающей запятой занимают меньше места и в целом быстрее) ... кто-нибудь когда-либо сталкивался с проблемами производительности при использовании double? Я говорю: используйте double ... и если позже вы решите: "Вау, это действительно медленно" ... найдите узкое место в производительности (что, вероятно, не тот факт, что вы использовали double). ЗАТЕМ, если он все еще слишком медленный для вас, посмотрите, где вы можете пожертвовать точностью и использовать float.



1

Это сильно зависит от процессора, наиболее очевидный компромисс между точностью и памятью. С ГБ ОЗУ память не представляет особой проблемы, поэтому обычно лучше использовать doubles.

Что касается производительности, то она сильно зависит от процессора. floats обычно дает лучшую производительность, чем doubles на 32-битной машине. На 64-битной doubleверсии s иногда быстрее, так как это (обычно) собственный размер. Тем не менее, гораздо больше, чем ваш выбор типов данных, будет иметь значение, сможете ли вы воспользоваться инструкциями SIMD на своем процессоре.


0

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


5
На типичных современных компьютерах double работает так же быстро, как и float.
Томас Падрон-Маккарти,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.