типы данных — В чем разница между float и double в Java?
Насколько я помню, float и double различаются диапазонами, что ведёт к разной точности и скорости вычислений. Однако сегодня заметил, что с разными числами округление происходит у этих типов данных по-разному. На скринах видно, что
- в первом случае float обрубает значение, а double округляет (example1)
- Во втором случае: float округляет, double обрубает значение(example2)
Какая еще есть разница между типами данных float и double или я что-то в упор не вижу?
- java
- типы-данных
Принципиальный нюанс здесь в том, что вы оперируете десятичными числами, а float и double — бинарные. Те числа, которые вы делите и получаете в результате, непредставимы в бинарной системе счисления без периодичных дробей. Подробнее:
Вычисления на числах с плавающей точкой не работают
То, что вы наблюдаете — это не округления и обрубания, а попытки компьютера впихать невпихуемое и сделать вид, что на самом деле всё в порядке. Так как количество битов у мантиссы и экспоненты типов float и double разная, то «округления» и «обрубания» будут происходить с вашей точки зрения «непредсказуемо». Эта ситуация усугубляется ещё и тем, что точность вычислений на совести процессора, который, вообще говоря, не обязан выдавать точность до последнего знака. На другом компьютере вы можете увидеть другие результаты — если не включите специальный «предсказуемый» режим, который медленнее. Но даже в этом случае вы получите только одинаковые, но «непредсказуемые» результаты на разных компьютерах.
Когда работаете с float и double, примите как данность, что они всегда с погрешностью.
Зарегистрируйтесь или войдите
Регистрация через Google Регистрация через Facebook Регистрация через почтуОтправить без регистрации
ПочтаНеобходима, но никому не показывается
Отправить без регистрации
ПочтаНеобходима, но никому не показывается
By clicking “Отправить ответ”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.
c++ — Как сравнить float и double?
Как правильно сравнивать два числа типа float
и double
? Следующий способ часто говорит, что одинаковые числа различны:
float a = 0.00001001; double b = 0.00001001; if (a == b) { std::cout << "equal"; // не выводит equal }
Мой вопрос отличается от дубликатов тем, что мне нужно знать, как правильно сравнить 2 числа типа
и double
на C++, а не почему (не только почему) простое сравнение не работает. В привидённых в дубликатах ответах либо ответы для 2 одинаковых типов, либо не сказано как выбирать epsilon
и т.д..
- c++
- float
- сравнение
- double
if (fabs(a - b) <= eps)
где eps
— некая маленькая величина, вообще говоря — зависящая от порядка самих чисел, поэтому более корректно
if (fabs(a - b)/ max(fabs(a) + eps, fabs(b) + eps) <= eps)
Пример задания
:
const FuzzFactor = 1000; SingleResolutionEps = 1E-7 * FuzzFactor; DoubleResolutionEps = 1E-15 * FuzzFactor;
Откуда это берётся — точность float 23 двоичных разряда или 7-8 десятичных, т. е. число имеет 7 верных десятичных цифр, поэтому меньше 1E-7
eps смысла нет делать.
Почему используется множитель FuzzFactor = 1000;
— это расширение допуска, чёткого критерия его выбора нет, разработчики этой библиотеки решили так сделать, а вообще множитель можно выбирать в зависимости от желаемой погрешности в младших разрядах.
Для сравнения float и double по правилам сложения погрешностей следует использовать погрешность для менее точных float, т.е. порядка
даже при приведении float к double, как предложил в комментарии @Grundy — ведь при этом приведении возникают дополнительные ничем не обеспеченные разряды с погрешностью в пределах всё тех же 1E-7
.
Труды по точности float-арифметики: 1 2 Goldberg
14Машинный эпсилон это одно,а точность входных данных в задаче это совсем другое.
Редко бывает, чтобы точность входных данных в задаче была равна машинному эпсилону.
Обычно точность входных данных в задаче гораздо меньше, чем машинный эпсилон.
Есть целая наука об правилах округления и отбрасывания незначащих цифр.
Исходя из этой науки и выбирается в каждом конкретном случае эпсилон для каждой конкретной задачи.
А машинный эпсилон это характеристика данной вычислительной системы.
Зарегистрируйтесь или войдите
Регистрация через Google Регистрация через Facebook Регистрация через почтуОтправить без регистрации
ПочтаНеобходима, но никому не показывается
Отправить без регистрации
ПочтаНеобходима, но никому не показывается
By clicking “Отправить ответ”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.
С++ — Должен ли я использовать двойное число или число с плавающей запятой?
Изменено 6 лет, 5 месяцев назад
Просмотрено 112 тысяч раз
Каковы преимущества и недостатки использования одного вместо другого в C++?
- c++
- типы
- с плавающей запятой
- с двойной точностью
Если вы хотите узнать верный ответ, прочтите «Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой».
Короче говоря, хотя двойное
допускает более высокую точность в своем представлении, для некоторых вычислений это может привести к большим ошибкам . «Правильный» выбор: используйте столько точности, сколько вам нужно, но не более и выбирают правильный алгоритм .
Многие компиляторы все равно выполняют расширенную математику с плавающей запятой в «нестрогом» режиме (т. е. используют более широкий тип с плавающей запятой, доступный в аппаратном обеспечении, например, 80-битное и 128-битное плавающее), это также следует учитывать. На практике
Если у вас нет особой причины поступить иначе, используйте double.
Как ни странно, именно тип double, а не float является «нормальным» типом с плавающей запятой в C (и C++). Стандартные математические функции, такие как sin и log , принимают двойные числа в качестве аргументов и возвращают двойные числа. Обычный литерал с плавающей запятой, например, когда вы пишете 3.14 в своей программе, имеет тип double.
На типичных современных компьютерах двойные числа могут быть такими же быстрыми, как числа с плавающей запятой, или даже быстрее, поэтому производительность обычно не имеет значения даже для больших вычислений. (И их должно быть большие расчеты или производительность даже не должны приходить вам в голову. Мой новый настольный компьютер i7 может выполнять шесть миллиардов операций умножения за одну секунду.)
На этот вопрос невозможно ответить, поскольку он не имеет контекста. Вот некоторые вещи, которые могут повлиять на выбор:
Реализация компилятором float, double и long double. Стандарт С++ гласит:
Существует три типа чисел с плавающей запятой: float, double и long double. Тип double обеспечивает по крайней мере такую же точность, как float, а тип long double обеспечивает по крайней мере такую же точность, как и double.
Таким образом, все три могут иметь одинаковый размер в памяти.
Наличие FPU. Не все ЦП имеют FPU, и иногда типы с плавающей запятой эмулируются, а иногда типы с плавающей запятой просто не поддерживаются.
Архитектура FPU. FPU IA32 имеет внутреннюю 80-битную разрядность — 32-битные и 64-битные числа с плавающей запятой расширяются до 80-битных при загрузке и уменьшаются при сохранении. Существует также SIMD, который может выполнять четыре 32-битных или два 64-битных числа с плавающей запятой параллельно. Использование SIMD не определено в стандарте, поэтому потребуется компилятор, который выполняет более сложный анализ, чтобы определить, можно ли использовать SIMD, или требует использования специальных функций (библиотек или встроенных функций). Результат 80-битного внутреннего формата заключается в том, что вы можете получить несколько разные результаты в зависимости от того, как часто данные сохраняются в ОЗУ (таким образом, теряется точность). По этой причине компиляторы не очень хорошо оптимизируют код с плавающей запятой.
Пропускная способность памяти. Если двойное значение требует больше памяти, чем число с плавающей запятой, чтение данных займет больше времени. Это наивный ответ. На современном IA32 все зависит от того, откуда поступают данные. Если он находится в кеше L1, нагрузка незначительна при условии, что данные поступают из одной строки кеша. Если он охватывает более одной строки кэша, возникают небольшие накладные расходы. Если это из L2, это занимает больше времени, если это в ОЗУ, то это еще дольше и, наконец, если это на диске, это занимает огромное время. Таким образом, выбор float или double менее важен, чем способ использования данных. Если вы хотите выполнить небольшие вычисления с большим количеством последовательных данных, предпочтительнее использовать небольшой тип данных. Выполнение большого количества вычислений с небольшим набором данных позволит вам использовать более крупные типы данных со значительным эффектом. Если вы обращаетесь к данным очень случайным образом, то выбор размера данных неважен — данные загружаются в страницах/строках кеша. Таким образом, даже если вам нужен только байт из ОЗУ, вы можете передать 32 байта (это очень зависит от архитектуры системы). Вдобавок ко всему этому, CPU/FPU могут быть суперскалярными (также известными как конвейерные). Таким образом, даже если загрузка может занять несколько циклов, CPU/FPU может быть занят чем-то другим (например, умножением), что в некоторой степени скрывает время загрузки.
Стандарт не требует какого-либо конкретного формата для значений с плавающей запятой.
Если у вас есть спецификация, то она поможет вам сделать оптимальный выбор. В противном случае все зависит от опыта, что использовать.
Double более точен, но кодируется 8 байтами. float составляет всего 4 байта, поэтому меньше места и меньше точности.
Вы должны быть очень осторожны, если в вашем приложении есть значения типа double и float. У меня была ошибка из-за этого в прошлом. Одна часть кода использовала float, а остальная часть кода использовала double. Копирование double в float, а затем float в double может привести к ошибке точности, которая может иметь большие последствия. В моем случае это был химический завод… надеюсь, обошлось без драматических последствий 🙂
Я думаю, что именно из-за такой ошибки несколько лет назад взорвалась ракета «Ариан-6»!!!
Тщательно продумайте тип, который будет использоваться для переменной
2Лично я всегда беру двойку, пока не вижу узких мест. Затем я думаю перейти на float или оптимизировать какую-то другую часть
Это зависит от того, как компилятор реализует double. Двойной тип и число с плавающей запятой могут быть одного и того же типа (и это возможно в некоторых системах).
При этом, если они действительно разные, главная проблема заключается в точности. Двойник имеет гораздо более высокую точность из-за разницы в размере. Если числа, которые вы используете, обычно превышают значение с плавающей запятой, используйте двойное число.
Несколько человек упомянули о проблемах с производительностью. Это было бы точно последним в моем списке соображений. Правильность должна быть вашим соображением №1.
Я думаю, независимо от различий (которые, как все отмечают, числа с плавающей запятой занимают меньше места и в целом работают быстрее)… у кого-нибудь когда-либо возникали проблемы с производительностью при использовании double? Я говорю, используйте double… и если позже вы решите «вау, это очень медленно»… найдите узкое место в производительности (вероятно, это не тот факт, что вы использовали double). ТОГДА, если это все еще слишком медленно для вас, посмотрите, где вы можете пожертвовать некоторой точностью и использовать поплавок.
Используйте любую точность, необходимую для достижения надлежащих результатов. Если затем вы обнаружите, что ваш код не работает так, как вам хотелось бы (вы правильно использовали профилирование?), взгляните на:
- Справочное руководство по оптимизации архитектур Intel 64 и IA-32
- Оптимизация программного обеспечения для процессора AMD64
Сильно зависит от ЦП, наиболее очевидный компромисс — между точностью и памятью. С ГБ ОЗУ память не представляет особой проблемы, поэтому обычно лучше использовать двойной
с.
Что касается производительности, то она сильно зависит от процессора. float
s обычно обеспечивают лучшую производительность, чем double
s на 32-битной машине. В 64-битной системе double
иногда быстрее, поскольку это (обычно) исходный размер. Тем не менее, гораздо большее значение, чем выбор типов данных, имеет то, сможете ли вы воспользоваться SIMD-инструкциями вашего процессора.
double имеет более высокую точность, тогда как числа с плавающей запятой занимают меньше памяти и работают быстрее. В общем, вы должны использовать float, если у вас нет случая, когда он недостаточно точен.
1Основное различие между float и double заключается в точности. В Википедии есть больше информации о Одинарная точность (с плавающей запятой) и двойная точность.
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя адрес электронной почты и парольОпубликовать как гость
Электронная почтаОбязательно, но не отображается
Опубликовать как гость
Электронная почтаТребуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Что такое Double в C?
В программировании мы часто сталкиваемся с десятичными значениями. Но часто мы сталкиваемся с десятичными значениями, которые велики с точки зрения точности (например, 5,11647e-75,11647e-75,11647e-7). В языке C такие числа не могут храниться в предопределенном типе данных для десятичных дробей (например, с плавающей запятой). Таким образом, вводится новый тип данных для хранения таких больших значений десятичных знаков.
double в C — это тип данных, который используется для хранения высокоточных данных или чисел с плавающей запятой (до 15–17 цифр). Он используется для хранения больших значений десятичных чисел.
Сохраняемые значения в два раза превышают размер данных, которые могут быть сохранены в типе данных float. Таким образом, он называется двойным типом данных.
Любая переменная, объявленная с использованием типа данных double в C, имеет размер 8 байтов (или 64 бита).
Примечание:
В типе данных double 1 бит используется для представления знака, 11 бит — для экспоненты, а оставшиеся 52 бита — для мантиссы.
Двойное число в c находится в диапазоне от 1.7E-308 до 1.7E+308 . Double может использоваться для представления данных действительных чисел, десятичных дробей, отрицательных значений и т. д.
Синтаксис объявления
Переменные типа double в c объявляются с использованием ключевого слова double, за которым следует имя переменной.
Инициализация двойной переменной
Когда мы объявляем переменную, она в основном содержит мусорное значение. Таким образом, чтобы наша переменная имела определенное значение, нам нужно инициализировать переменную double этим определенным значением.
Есть два способа инициализировать двойник в C:
Присвоив объявленной двойной переменной значение с помощью оператора присваивания:
Примечание: Может хранить до 15-17 цифр.
Присвоив переменной double значение во время объявления с помощью оператора присваивания:
Пример Double в C
В этом разделе мы обсудим несколько примеров double в C.
В приведенном выше примере объявляется temp1 и ему присваивается значение 98,4. temp2 объявлен, но ему не присвоено какое-либо значение, поэтому он будет содержать значение мусора, а temp3 объявлен, поэтому имеет значение мусора, но позже ему будет присвоено значение 97,88.
Как напечатать двойное значение в C?
Теперь, когда мы узнали, как объявить двойник в C и инициализировать двойник в C, возникает вопрос, как отобразить двойник в C?
Двойник в c может быть напечатан как с использованием %f, так и %lf. И спецификатор формата %f, и спецификатор формата %lf представляют float и double. printf() в c обрабатывает как float, так и double одинаково.
Вывод:
Примечание:
В случае общего спецификатора (например, int) значение будет приведено к типу, и будет напечатано целочисленное значение. Это связано с тем, что эти общие спецификаторы уже предполагают, что значение имеет целочисленный тип.
Представление Double в C
Точность double в c зависит от его реализации в коде. В общем, современные компиляторы используют стандарт IEEE-754 .
Стандарт IEEE для вычислений с плавающей запятой (IEEE 754) — это технический стандарт для вычислений с плавающей запятой, который был установлен в 1985 году Институтом инженеров по электротехнике и электронике (IEEE). Стандарт решил многие проблемы, обнаруженные в различных реализациях с плавающей запятой, которые затрудняли их надежное использование и снижали их переносимость.
В таких компиляторах числа представляются с использованием 64-битного кода следующим образом:
- Первый бит обозначает знак. Положительное значение представлено 0, а отрицательное — 1.
- 52 бита мантиссы (мантисса).
- 11 бит экспоненты.
Может хранить значение до 15-16 цифр.
Ниже приводится графическое описание представления double в C:
Некоторые программы типа Double Date в C
В этом разделе мы увидим несколько программ, в которых используется double в C.
Программа для получения размера типов данных с использованием функции sizeof()
Функцию sizeof() можно использовать для определения размера различных типов данных в c. Эта функция примет тип данных в качестве параметра и вернет размер в байтах.
Код:
Вывод:
Пояснение к примеру:
В приведенном выше примере мы передаем типы данных int, char, float и double в размер функции. printf используется для отображения их вывода.
Программа для преобразования футов в метры с использованием типа данных Double
Мы можем преобразовать единицы измерения, используя double в C. Это можно сделать, взяв входные данные в футах и разделив значение на 3,28. Поскольку результатом может быть большое десятичное значение, он будет сохранен в типе данных double.
Код:
Вывод:
Объяснение примера:
В приведенном выше коде мы определили функцию ‘functionToMeter’ , который принимает двойное значение в качестве параметра. FootInput / 3.28 преобразует значение футов в метры и возвращает значение.
Программа для преобразования целочисленных данных в тип данных Double
В этом разделе мы узнаем, как преобразовать тип данных в c.
Код:
Вывод:
В приведенном выше примере у нас есть числитель и знаменатель целочисленного типа. Мы создали оставшуюся переменную типа double. Числитель/знаменательчислитель/знаменательчислитель/знаменатель выведет целое значение как целое число / целое число вернет целое число .
Таким образом, мы преобразуем тип данных числителя в двойной с (двойным) числителем. Теперь числитель/знаменатель, числитель/знаменатель, числитель/знаменатель вернет двойное значение, которое можно сохранить в остатке.
Программа для преобразования температуры по Цельсию в градусы Фаренгейта
Вывод:
Программа для вывода суммы двух двойных чисел с помощью функции
В этом разделе мы узнаем, как сложить два двойных числа с помощью функции. Для этого мы объявим функцию суммы, которая будет принимать два двойных входа.
Код:
Вывод:
Объяснение примера:
В приведенном выше примере мы передаем функции sum() два двойных значения num1 и num2, имеющие значения 9,459 и 3,45. Функция суммы вернет число1 + число2.
Типы данных Float и Double в C
Ниже приведены несколько различий между float и double в C:
Плавающая | Двойная |
---|---|
Тип данных float содержит 32-битное значение с плавающей запятой. |