Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60

Как обнаружить потерю точности при умножении двух double

14.09.2025, 12:13. Показов 5118. Ответов 66
Метки c++ (Все метки)

Добрый день,

Пытаюсь разобраться для себя с такими интересными тонкостями вещественной арифметики, как потеря точности и переполнения. Со сложением и вычитанием ясно: если одно из чисел не равно 0, а результат равен второму - значит произошла потеря точности. Но как быть с умножением? Ведь там при потери точности произведение будет равно не одному из множителей, а просто некоему неправильному числу???
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.09.2025, 12:13
Ответы с готовыми решениями:

[Error] cannot convert 'double (*)(double)' to 'double' for argument '1' to 'double pow(double, double)'
#include <iostream> #include <math.h> using namespace std; int main () { system("cls"); ...

Найти все двузначные числа, которые при умножении на 2 заканчиваются на 8, а при умножении на 3 - на 4.
Привет мозги, нужно решить задачу по Си++. Найти все двузначные числа, которые при умножении на 2...

Ошибка: error LNK2001: unresolved external symbol "double __cdecl Akk(double,double,double)"
#include <iostream> #include <cmath> using namespace std; double Akk(double x, double y, double...

66
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6279 / 3003 / 1051
Регистрация: 01.06.2021
Сообщений: 11,251
15.09.2025, 15:55
Цитата Сообщение от Storm Screamer Посмотреть сообщение
тип данных decimal, чтобы избежать потерь
даже в arbitrary precision есть потери, но там просто вручную контролируют точность и теоретически она не ограничена (практически ограничена памятью и временем вычисления). Автоконтроль точности тоже иногда реализовывают, но он все равно дает сбои.
Как ни крути, если что-то серьезное, все равно нужно перейти на дроби с целыми числами и все вычисления делать в целых числах.
0
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60
15.09.2025, 18:59  [ТС]
Цитата Сообщение от Catstail Посмотреть сообщение
Пользуясь случаем, рекомендую свою (длинную!) лекцию о плавающей точке вот
Лекция шикарна, появилось ощущение целостного понимания работы с плавающей точкой. Ну а Ваши слова "Программа-то правильная и она даже местами правильно работает" я себе в цитатник записал. Еще пригодятся!
1
Нарушитель
622 / 380 / 67
Регистрация: 09.03.2016
Сообщений: 4,166
15.09.2025, 23:12
Название: NewPicture7.png
Просмотров: 213

Размер: 10.3 Кб
Если вы все пишете, что это действительно необходимо.
Как нибудь... Спасибо автору конечно...
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38207 / 21140 / 4311
Регистрация: 12.02.2012
Сообщений: 34,752
Записей в блоге: 14
16.09.2025, 16:06
Royal_X, спасибо за добрые слова!
1
1976 / 832 / 115
Регистрация: 01.10.2012
Сообщений: 5,063
Записей в блоге: 2
16.09.2025, 22:02
Цитата Сообщение от Catstail Посмотреть сообщение
Пользуясь случаем, рекомендую свою (длинную!) лекцию о плавающей точке вот
Увлекательно, да. Ладно, попробуем применить на практике

Рендерим 3D сцену, есть точка L, например, возможно, источник света. Из нее выбрасываем луч в направлении dir (вектор 3 флота). Луч пересекает какой-то объект в точке p. Известна нормаль N в этой точке (необязательно она нужна). Все хорошо. Теперь мы хотим как бы "ощупать лучами" окрестность точки p. Для этого генерируем напр 100 случайных точек (p1..p100) в радиусе R, для каждой вычисляем направление, напр

Vec3f dir1 = (p1 - L).normallized();

Ну и бросаем лучи в этих направлениях из той же точки L. Да, но есть погрешность флота, и dir1 не будет вычислено точно, возможно при достаточно большом расстоянии между L и p в радиус R мы даже не попадем. На какой радиус мы можем рассчитывать?

Все флоты 4 байта, увы, изменить это не можем
0
1976 / 832 / 115
Регистрация: 01.10.2012
Сообщений: 5,063
Записей в блоге: 2
17.09.2025, 12:02
И вот мелочь, легко забыть (и забыл). В лекции не упоминается волшебное слово/термин GPU, а сейчас так нельзя. Этот гад double не любит. И "расширенные" команды процессора (sse и все такое) - вроде там double и есть, но, судя по коду библиотек, 4-байтовые доминируют.
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38207 / 21140 / 4311
Регистрация: 12.02.2012
Сообщений: 34,752
Записей в блоге: 14
17.09.2025, 14:40
Цитата Сообщение от Igor3D Посмотреть сообщение
На какой радиус мы можем рассчитывать?
- не знаю... Вычислительная схема требует анализа. Я этой схемой не занимался.

Цитата Сообщение от Igor3D Посмотреть сообщение
Все флоты 4 байта, увы, изменить это не можем
- в лекции явно сказано "забудьте о float, используйте double"; скорость от этого не должна пострадать, а точность вырастет.

Цитата Сообщение от Igor3D Посмотреть сообщение
Этот гад double не любит.
- Если GPU "не любит double", то что же делать... Придётся либо отказываться от GPU, либо от double. Но это вряд ли можно поставить мне в вину.
0
1976 / 832 / 115
Регистрация: 01.10.2012
Сообщений: 5,063
Записей в блоге: 2
17.09.2025, 16:55
Цитата Сообщение от Catstail Посмотреть сообщение
- Если GPU "не любит double", то что же делать... Придётся либо отказываться от GPU, либо от double. Но это вряд ли можно поставить мне в вину.
Да я ничего и не ставлю Но программист не только "имеет право", но и обязан использовать все вычислительные мощности, поэтому гонорировать аспект GPU в наше время, мягко говоря, недальновидно/инфантильно
Цитата Сообщение от Catstail Посмотреть сообщение
не знаю... Вычислительная схема требует анализа. Я этой схемой не занимался.
Я тоже нет. Так давайте займемся, не все же задачи "те что уже решали". Может лучше сформулировать так

- Бросаем луч из исходной точки L в точку "прицела" p1. Насколько луч отклонится от p1 за счет погрешности float?

При этом исходные точки могут иметь координаты далеко не единичные. Мульены вряд ли, таких сцен избегают. А вот тыщи или даже 10 тыс - вполне. Также известно как задавалась точка прицела p1: она в плоскости с нормалью N проходящей через базовую точку p
1
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6279 / 3003 / 1051
Регистрация: 01.06.2021
Сообщений: 11,251
17.09.2025, 17:10
Igor3D, при чем тут вообще GPU? Тема в разделе С++. В этом языке вычисления с числами с плавающей запятой выполняются на CPU.
Вычисления могут быть выполнены на GPU, если используется специальная библиотека или фреймворк для параллельных вычислений, например, CUDA или OpenCL, которые позволяют перенести вычисления на графический процессор.
Но если мы говорим просто о С++, то все вычисления там осуществляются на CPU с использованием набора инструкций FPU (Floating Point Unit) или SSE/AVX (для векторизации - оптимизации программы с использованием векторных расширений системы команд процессора).
Грубо говоря, все обычные вычисления с плавающей запятой выполняются на FPU процессора.
И то, что 4-байтовый float предпочтительнее, чем double, актуально только для вычислений на GPU, поскольку всякие CUDA действительно лучше работают с 4-байтовыми числами.
Однако, для современных CPU, не будет никакой разницы - float или double, особенно, если нет ограничений по памяти.
Поэтому, Catstail правильно говорит, что в С++ дефолтно нужно выбирать double и не морочиться с низкой точностью float.
Цитата Сообщение от Catstail Посмотреть сообщение
"забудьте о float, используйте double"; скорость от этого не должна пострадать, а точность вырастет.
А вот во всяких API игровых движков и вправду используется float, поскольку, как написал выше, для GPU это предпочтительнее.
1
359 / 121 / 8
Регистрация: 19.07.2024
Сообщений: 627
17.09.2025, 17:34
Цитата Сообщение от Royal_X Посмотреть сообщение
А вот во всяких API игровых движков и вправду используется float, поскольку, как написал выше, для GPU это предпочтительнее.
Не только GPU. Микроконтроллерные CPU многие аппаратно поддерживают только float. double - только программная эмуляция (на порядки более тормозная). Даже в тех CPU или DSP, где есть аппаратный double - на многих он требует бОльшего времени для операций.

Но если речь только про ПК - то да, на ПК лучше всегда использовать double. Насколько знаю - на ПК нет разницы в скорости double vs float. (Хотя тут нет полной уверености)
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6279 / 3003 / 1051
Регистрация: 01.06.2021
Сообщений: 11,251
17.09.2025, 18:00
Цитата Сообщение от jcxz Посмотреть сообщение
Насколько знаю - на ПК нет разницы в скорости double vs float.
на современных CPU абсолютно нет никакой разницы, только в памяти. Но у современных процессоров кеши тоже большие.
0
1976 / 832 / 115
Регистрация: 01.10.2012
Сообщений: 5,063
Записей в блоге: 2
17.09.2025, 18:10
Цитата Сообщение от Royal_X Посмотреть сообщение
в С++ дефолтно нужно выбирать double и не морочиться с низкой точностью float.
То что double - благо я писал выше, не надо агитировать большевика за революцию Только спокойно работать в double удается весьма редко. Тот же пример выше, луч-то не пальцем надо бросать, а либа юзает float. Тот же движок физики и др
Цитата Сообщение от Royal_X Посмотреть сообщение
А вот во всяких API игровых движков и вправду..
Да как будто это так, какая-то мелочь Наоборот, львиная доля людей занимается именно этим, не Вы ли работаете с Годот?

Добавлено через 4 минуты
Цитата Сообщение от jcxz Посмотреть сообщение
Насколько знаю - на ПК нет разницы в скорости double vs float. (Хотя тут нет полной уверености)
По-моему нативные вычисления производятся на 8-байтных регистрах, при их загрузке/сохранении float из/в памяти автоматом конвертится в double. Хотя может это уже и устарело
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6279 / 3003 / 1051
Регистрация: 01.06.2021
Сообщений: 11,251
17.09.2025, 18:13
Цитата Сообщение от Igor3D Посмотреть сообщение
не Вы ли работаете с Годот
с чем я только не работаю, есть и Godot, и Unity, и UE. Но я пишу обычно на С++ десктопные приложения для винды.

Godot как раз исключение - встроенный float это 64-битный плюсовый double (годот написан на плюсах).

Вот тут об этом сказано: https://docs.godotengine.org/e... float.html


The float built-in type is a 64-bit double-precision floating-point number, equivalent to double in C++. This type has 14 reliable decimal digits of precision. The maximum value of float is approximately 1.79769e308, and the minimum is approximately -1.79769e308.

Many methods and properties in the engine use 32-bit single-precision floating-point numbers instead, equivalent to float in C++, which have 6 reliable decimal digits of precision. For data structures such as Vector2 and Vector3, Godot uses 32-bit floating-point numbers by default, but it can be changed to use 64-bit doubles if Godot is compiled with the precision=double option.
Второй абзац уже о 4 байтах.
0
359 / 121 / 8
Регистрация: 19.07.2024
Сообщений: 627
17.09.2025, 19:57
Цитата Сообщение от Royal_X Посмотреть сообщение
Второй абзац уже о 4 байтах.
Вообще изначально топикстартер пёкся о точности вычислений, а не о скорости. Зачем тогда на скорость свернули?

PS: А если в приоритете точность, и скоростью вычислений можно пожертвовать, то может имеет смысл топикстартеру озаботиться созданием своего (нового) численного типа: скажем назовём его QuadFloat. 16-байтного размера. Или даже ещё бОльшего размера. С увеличенной соответственно мантиссой (а может и экспонентой). И все расчёты выполнять на нём.

Ну или (как уже выше писал) - создать тип fixed point большой длины. Такой, чтобы вмещал весь диапазон чисел, необходимый в его расчётах. Это если сложно реализовать свой QuadFloat.
0
-73 / 64 / 2
Регистрация: 23.11.2024
Сообщений: 805
17.09.2025, 21:00
Цитата Сообщение от jcxz Посмотреть сообщение
назовём его QuadFloat
https://stackoverflow.com/ques... n-in-c-gcc
0
1976 / 832 / 115
Регистрация: 01.10.2012
Сообщений: 5,063
Записей в блоге: 2
17.09.2025, 21:19
Цитата Сообщение от Royal_X Посмотреть сообщение
but it can be changed to use 64-bit doubles if Godot is compiled with the precision=double option.
Аналогичная опция в движке Bullet. Откомпилил с double - полезло изо всех щелей, почти все сцены перестали работать. Быстро "вернул взад" и больше не трогал Справедливости ради, это было лет 15 назад, не исключено что сейчас уже работает.
Цитата Сообщение от Royal_X Посмотреть сообщение
с чем я только не работаю, есть и Godot, и Unity, и UE. Но я пишу обычно на С++ десктопные приложения для винды.
Ну и скажите где НЕТ 4-байтных флотов? Может только в десктопных приложениях без вычислений
Цитата Сообщение от jcxz Посмотреть сообщение
..все расчёты выполнять на нём.
Это нереально т.к. практически всегда есть зависимости от сторонних библиотек. Да и "пожертвовать скоростью" никто не позволит. И обычно какой-то код уже написан и “местами работает”, возможно часть расчетов выполняется на злополучном GPU. Короче, “просто везде использовать бОльшую точность” обычно нереально.
Гораздо полезнее уметь оценить погрешность/ошибку (см задачу выше), но этим заниматься никто не хочет, и понятно почему: думать надо, легко ошибиться. А вот рассказывать что 8 байт лучше чем 4 - легко и приятно
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8668 / 4505 / 1670
Регистрация: 01.02.2015
Сообщений: 13,935
Записей в блоге: 13
18.09.2025, 19:30
Существуют алгоритмы, повышающие точность вычислений с плавучкой.
По большому счёту, это подобие длинной арифметики, когда за счёт дополнительной переменной увеличивается разрядность.
Ну и время выполнения - тоже увеличивается.

Для сложения - алгоритм Коха.
Для умножения я не знаю, но, наверняка, есть.

Также встречал правила изменения порядка вычислений - чтобы избежать "потерю" маленького числа на фоне значительно большего.
Для этого есть множество формул преобразования и они подбираются под каждый уникальный случай.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6279 / 3003 / 1051
Регистрация: 01.06.2021
Сообщений: 11,251
18.09.2025, 21:09
Цитата Сообщение от Igor3D Посмотреть сообщение
Гораздо полезнее уметь оценить погрешность/ошибку (см задачу выше), но этим заниматься никто не хочет, и понятно почему: думать надо, легко ошибиться
Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
Также встречал правила изменения порядка вычислений - чтобы избежать "потерю" маленького числа на фоне значительно большего.
Для этого есть множество формул преобразования и они подбираются под каждый уникальный случай.
А как оценишь погрешность для данного выражения?

https://www.cyberforum.ru/cgi-bin/latex.cgi?1-\sqrt{1-{\mathrm e}^{-1000}}

Даже если использовать арифметику произвольной точности, то на первый взгляд покажется, что ответ 0. Потому что всем лень что-то там оценивать.

Можете сами попробовать вычислить значение данного выражения в Maxima, Maple, Mathematica. Последняя СКА хотя бы предупреждает, что не хватает машинной точности (точности для внутренних расчетов), хотя реализация n-digit точности в WM просто ломается. Ломается она и в Maple.
Для тех, кто не знает, объясняю. В программах арифметики произвольной точности используется machine precision. Именно этот вид точности, например, указывается во многих СКА. machine precision это точность внутренних расчетов.
Однако, в Mathematica и Maple решили пойти дальше и кроме machine precision, они реализовали еще более удобную фичу: n-digit precision - это когда ты указываешь, сколько значащих цифр должны быть корректны.
n-digit precision можно использовать, например, в функции N[] или evalf.
Однако, выражение выше - яркий пример того, что реализация n-digit precision данных СКА не справляется.
Но даже в документации WM написано, что:
N[expr,n]
attempts to give a result with n-digit precision.
данный метод всего лишь пытается выдать результат с n-digit precision. То есть ничего не гарантируется. А почему не гарантируется? А потому, что на сегодняшний момент точно угадать какая машинная точность нужна для получения n корректных цифр невозможно, иначе можно было бы сказать, что решили zero-equivalence problem - одну из нерешенных человечеством проблем.

Программы просто выводят 0.
У человека могут возникнуть сомнения, что ответ 0, поэтому он может попробовать увеличить машинную точность. Но даже если выбрать точность в 400 знаков, он все равно получит 0. Тут он подумает "ну значит результат и вправду 0" и тем самим совершит ошибку.

Code
1
2
evalf[400](1 - sqrt(1 - exp(-1000)))
bfloat(1-sqrt(1-exp(-1000))),fpprec:400;
А все потому, что для вычисления данного выражения нужно работать с числами, которые могут хранить как минимум 434 цифр. Т.е. машинная точность должна быть не меньше 434. Однако, чтобы получить несколько правильных цифр после запятой, нужно еще увеличить точность. При машинной точности 450 уже можно получить 16 значащих цифр.

Code
1
2
evalf[4500](1 - sqrt(1 - exp(-1000)))
bfloat(1-sqrt(1-exp(-1000))),fpprec:450;
Кстати, в Wolfram Mathematica вычислить это выражение следующими способами не получится:
Code
1
2
N[1 - Sqrt[1 - 1/E^1000], 450]
N[1 - Sqrt[1 - 1/E^1000], WorkingPrecision -> 450]
Нужно писать как-то так:
Code
1
Block[{$MaxExtraPrecision = 450}, N[1 - Sqrt[1 - Exp[-1000]], 16]]
беру в Block, чтобы не менять дефолтное значение $MaxExtraPrecision = 50
0
 Аватар для Pphantom
2450 / 1595 / 738
Регистрация: 17.03.2022
Сообщений: 5,166
18.09.2025, 21:18
Цитата Сообщение от Royal_X Посмотреть сообщение
А как оценишь погрешность для данного выражения?
А зачем?

Просто нормальному программисту-вычислителю попытки счета подобного "в лоб" должны разве что сниться в качестве ночных кошмаров. А если делать все нормально, то содержательных проблем не возникнет.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6279 / 3003 / 1051
Регистрация: 01.06.2021
Сообщений: 11,251
18.09.2025, 21:25
Цитата Сообщение от Pphantom Посмотреть сообщение
А зачем?
товарищи выше говорят, что полезнее оценить погрешность. Ну вот интересно узнать, как они будут оценивать эту погрешность и что это даст?
на мой взгляд, как ни крути, машинную точность нужно подбирать методом тыка.

Конечно, я бы хотел подать на ввод программе выражение и количестве значащих цифр, которые я хочу получить в результате, и чтобы она в ответ указала какую машинную точность мне нужно использовать в расчётах. Но как я написал выше, такую программу не создать.

Цитата Сообщение от Royal_X Посмотреть сообщение
на сегодняшний момент точно угадать какая машинная точность нужна для получения n корректных цифр невозможно, иначе можно было бы сказать, что решили zero-equivalence problem - одну из нерешенных человечеством проблем.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
18.09.2025, 21:25

Ошибки error C2296: -: недопустимо, левый операнд имеет тип "double (__cdecl *)(double,double,double
Думаю из-за polp #include<iostream> #include<cmath> #include<cstdlib> using namespace std;...

Создать функцию с параметрами GetFunctionValue(double& a, double& b, double& c, double& x)...
Есть код что считает нужно сделать пару манипуляций что у не могу реализовать 1) создать функцию...

Реализовать в виде GetFunctionValue(double& a, double& b, double& c, double& x)
Реализовать в виде GetFunctionValue(double& a, double& b, double& c, double& x). Задание по...

Реализовать в виде GetFunctionValue(double& a, double& b, double& c, double& x)
Реализовать в виде GetFunctionValue(double& a, double& b, double& c, double& x).

Реализовать в виде GetFunctionValue(double& a, double& b, double& c, double& x)
Реализовать в виде GetFunctionValue(double& a, double& b, double& c, double& x). #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
[golang] Worker Pool
alhaos 09.06.2026
Worker Pool Worker Pool — паттерн конкурентной обработки задач в Go. Суть: фиксированное количество горутин-воркеров читают задачи из общего канала и пишут результаты в общий канал результатов. . . .
[golang] Pipeline
alhaos 08.06.2026
Pipeline Pipeline — паттерн конкурентной обработки данных в Go. Суть: данные проходят через цепочку независимых стадий, каждая из которых работает в своей горутине и общается с соседями через. . .
Свет внутри себя
kumehtar 07.06.2026
Пусть это будет здесь lIs4oanZS9Y
Программа для com-порта
Uhbif79 05.06.2026
Всем привет, давно хотел изучить Qt, начинал, бросал, потом снова начинал. И сейчас вот смог написать свою первую программу. До этого имел опыт программирования микроконтроллеров, писал прошивки на. . .
Транскрипция 55-минутного видео через Whisper: WhisperDesktop облажался, спас Google Colab[
anaschu 01.06.2026
Понадобилось получить текст из свежезагруженного видео на YouTube. Казалось бы, задача на пять минут. Заняла полтора часа. Делюсь опытом — может кому пригодится последовательность решений. . . .
21 мат мед. Планы на развитие модели здравоСохранения
anaschu 01.06.2026
AnyLogic: план развития симуляционной модели рабочего коллектива — динамический абсентеизм, реальные данные, три сценария сравнения Продолжаю серию постов о дискретно-событийной модели рабочего. . .
20. Мат мед. Абсентеизм как отдельный тип простоя
anaschu 29.05.2026
Апдейт модели: исправленные баги, абсентеизм и новые механизмы Продолжаю развивать ранее описанную модель рабочего коллектива на AnyLogic. За последние несколько дней был проведён серьёзный. . .
19. здоровье, усталость и психотип работника влияют на производительность предприятия, и наоборот, производительность на здоровье, усталось и психотип
anaschu 28.05.2026
Дискретно-событийная модель рабочего коллектива на AnyLogic: здоровье, выгорание, психотипы и микростимуляция Привет, коллеги. Хочу поделиться итогами нескольких недель работы над симуляционной. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru