1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60

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

14.09.2025, 12:13. Показов 5298. Ответов 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
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6318 / 3043 / 1054
Регистрация: 01.06.2021
Сообщений: 11,601
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
 Аватар для Наталья8
623 / 381 / 67
Регистрация: 09.03.2016
Сообщений: 4,259
15.09.2025, 23:12
Название: NewPicture7.png
Просмотров: 213

Размер: 10.3 Кб
Если вы все пишете, что это действительно необходимо.
Как нибудь... Спасибо автору конечно...
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38210 / 21143 / 4313
Регистрация: 12.02.2012
Сообщений: 34,757
Записей в блоге: 14
16.09.2025, 16:06
Royal_X, спасибо за добрые слова!
1
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,131
Записей в блоге: 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
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,131
Записей в блоге: 2
17.09.2025, 12:02
И вот мелочь, легко забыть (и забыл). В лекции не упоминается волшебное слово/термин GPU, а сейчас так нельзя. Этот гад double не любит. И "расширенные" команды процессора (sse и все такое) - вроде там double и есть, но, судя по коду библиотек, 4-байтовые доминируют.
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38210 / 21143 / 4313
Регистрация: 12.02.2012
Сообщений: 34,757
Записей в блоге: 14
17.09.2025, 14:40
Цитата Сообщение от Igor3D Посмотреть сообщение
На какой радиус мы можем рассчитывать?
- не знаю... Вычислительная схема требует анализа. Я этой схемой не занимался.

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

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

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

При этом исходные точки могут иметь координаты далеко не единичные. Мульены вряд ли, таких сцен избегают. А вот тыщи или даже 10 тыс - вполне. Также известно как задавалась точка прицела p1: она в плоскости с нормалью N проходящей через базовую точку p
1
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6318 / 3043 / 1054
Регистрация: 01.06.2021
Сообщений: 11,601
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
338 / 130 / 10
Регистрация: 19.07.2024
Сообщений: 708
17.09.2025, 17:34
Цитата Сообщение от Royal_X Посмотреть сообщение
А вот во всяких API игровых движков и вправду используется float, поскольку, как написал выше, для GPU это предпочтительнее.
Не только GPU. Микроконтроллерные CPU многие аппаратно поддерживают только float. double - только программная эмуляция (на порядки более тормозная). Даже в тех CPU или DSP, где есть аппаратный double - на многих он требует бОльшего времени для операций.

Но если речь только про ПК - то да, на ПК лучше всегда использовать double. Насколько знаю - на ПК нет разницы в скорости double vs float. (Хотя тут нет полной уверености)
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6318 / 3043 / 1054
Регистрация: 01.06.2021
Сообщений: 11,601
17.09.2025, 18:00
Цитата Сообщение от jcxz Посмотреть сообщение
Насколько знаю - на ПК нет разницы в скорости double vs float.
на современных CPU абсолютно нет никакой разницы, только в памяти. Но у современных процессоров кеши тоже большие.
0
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,131
Записей в блоге: 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
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6318 / 3043 / 1054
Регистрация: 01.06.2021
Сообщений: 11,601
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
338 / 130 / 10
Регистрация: 19.07.2024
Сообщений: 708
17.09.2025, 19:57
Цитата Сообщение от Royal_X Посмотреть сообщение
Второй абзац уже о 4 байтах.
Вообще изначально топикстартер пёкся о точности вычислений, а не о скорости. Зачем тогда на скорость свернули?

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

Ну или (как уже выше писал) - создать тип fixed point большой длины. Такой, чтобы вмещал весь диапазон чисел, необходимый в его расчётах. Это если сложно реализовать свой QuadFloat.
0
-72 / 65 / 2
Регистрация: 23.11.2024
Сообщений: 816
17.09.2025, 21:00
Цитата Сообщение от jcxz Посмотреть сообщение
назовём его QuadFloat
https://stackoverflow.com/ques... n-in-c-gcc
0
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,131
Записей в блоге: 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
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8675 / 4512 / 1670
Регистрация: 01.02.2015
Сообщений: 13,943
Записей в блоге: 13
18.09.2025, 19:30
Существуют алгоритмы, повышающие точность вычислений с плавучкой.
По большому счёту, это подобие длинной арифметики, когда за счёт дополнительной переменной увеличивается разрядность.
Ну и время выполнения - тоже увеличивается.

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

Также встречал правила изменения порядка вычислений - чтобы избежать "потерю" маленького числа на фоне значительно большего.
Для этого есть множество формул преобразования и они подбираются под каждый уникальный случай.
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6318 / 3043 / 1054
Регистрация: 01.06.2021
Сообщений: 11,601
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
2469 / 1615 / 741
Регистрация: 17.03.2022
Сообщений: 5,264
18.09.2025, 21:18
Цитата Сообщение от Royal_X Посмотреть сообщение
А как оценишь погрешность для данного выражения?
А зачем?

Просто нормальному программисту-вычислителю попытки счета подобного "в лоб" должны разве что сниться в качестве ночных кошмаров. А если делать все нормально, то содержательных проблем не возникнет.
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6318 / 3043 / 1054
Регистрация: 01.06.2021
Сообщений: 11,601
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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
Знание — сила: Доктрина интенциональности знаний, углубление в формулу
Hrethgir 01.08.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11957&stc=1&d=1785567302 Знаменитый афоризм Фрэнсиса Бэкона «Знание — сила» (Scientia potentia est) в массовой культуре принято понимать. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru