Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
nill
10 / 10 / 0
Регистрация: 16.08.2009
Сообщений: 417
#1

Ошибка в переменной типа double - C++

23.12.2009, 07:03. Просмотров 585. Ответов 5
Метки нет (Все метки)

Не могу понять в чем проблема
делаю такие вычисления

C++
1
2
3
4
5
6
7
8
9
10
11
#include <iomanip>
summ5=0;
summ5+=((double) 1/1035*2);
summ5+=((double) 1/1035*15);
summ5+=((double) 1/1035*108);
summ5+=((double) 1/1035*405);
summ5+=((double) 1/1035*351);
myfile << std::fixed << std::setprecision(20) << "summ5 "<< summ5<<"\n";
 
summ6=((double) 881/1035);
myfile << std::fixed << std::setprecision(20) << "summ6 "<< summ6<<"\n";
получаю summ5 равно 0.85120772946859913000
а summ6 равно 0.85120772946859902000


хотя summ5 должно быть равно summ6 так как (2+15+108+405+351=881)

если summ5 состоит из большего количества элементов то разница еще больше
а учитывая что таких элементов в программе может быть очень и очень много я боюсь что результаты вычислений будут совсем не корректными

В чем проблема ? ведь чисто математически числа не могут быть разными
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.12.2009, 07:03
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Ошибка в переменной типа double (C++):

Сравнение переменной типа double c подстрокой из вектора - C++
Здравствуйте! Я с помощью getline считываю из файла текст. Файл в определенном формате. Кладу его построчно в vector&lt;string&gt; name. ...

Запись переменной типа double в бинарный файл - C++
Помогите справится с проблемой! допустим а меня есть переменная: double d=0.123456789; (8байт) задача состоит в том чтобы записать...

В массив типа double записываю целые числа (типа int), но ошибка не вылазиет! - C++
Вот программулька: #include &lt;iostream&gt; using namespace std; #include &lt;conio.h&gt; int main() { double arr={1,2,3,4,5}; ...

Вывод числа после запятой переменной типа double - C++
Здравствуйте!!! У меня есть 2 программы, одну мне дали вторую написал. Та программа которая была написана мной работает чуть чуть...

Аргумент типа double несовместим с параметром типа double* - C++
Функция function должна возвращать количество элементов массива, значение которые превышает значение средне арифметического элементов...

Аргумент типа double несовместим с параметром типа double - C++
#include &lt;iostream&gt; #include &lt;cmath&gt; #include &lt;math.h&gt; using namespace std; #define c 40 #define n 5 double po(double...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Yurii_74
paladin
279 / 179 / 3
Регистрация: 25.02.2009
Сообщений: 592
23.12.2009, 07:56 #2
Проблема в том, что даже double дискретен. Если уж приходится складывать ряд, то нужно проделывать это от меньшего к большему (иногда желательно сначала подсчитать промежуточные суммы очень малых элементов). В вашем случае 15 знаков совпадают. Для double 16 значащих десятичных знаков - предел.
И именно из-за этого для проверки разности двух (вычисляемых) чисел с нулем они сравниваются по модулю с некоторым небольшим (относительно их самих) числом.

Wikipedia о double
1
TanT
эволюционирую потихоньку
465 / 463 / 43
Регистрация: 30.06.2009
Сообщений: 1,399
23.12.2009, 08:22 #3
Цитата Сообщение от nill Посмотреть сообщение
В чем проблема ? ведь чисто математически числа не могут быть разными
накапливается ошибка округления, что здесь необычного?
может нужно поискать пути её уменьшения за счёт иного способа вычислений компонент, например вынести общий делитель
1
nill
10 / 10 / 0
Регистрация: 16.08.2009
Сообщений: 417
23.12.2009, 08:28  [ТС] #4
Yurii_74,
сложил от меньшего к большему и цифры ПОЛНОСТЬЮ сошлись
придеться делать сортировку а это думаю не очень хорошо скажеться на производительности

непонял что значит подсчитать промежуточные суммы очень малых элементов ?
0
Yurii_74
paladin
279 / 179 / 3
Регистрация: 25.02.2009
Сообщений: 592
23.12.2009, 08:41 #5
Пусть у тебя есть числа 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.1, 0.2, 100.
Сначала складываем 1 со 2, 3 с 4, 5 с 6, 7 с 8:
0.002, 0.002, 0.002, 0.002, 0.1, 0.2, 100.
0.004, 0.004, 0.1, 0.2, 100.
0.008, 0.1, 0.2, 100.
Затем уже по порядку.
Делается это для выравнивания порядка складываемых элементов (попробуй прибавить 10^-6 к 10^15).
И как сказал TanT, лучше сначала подсчитать сумму в int'ах. Если такая возможность вообще есть.
1
nill
10 / 10 / 0
Регистрация: 16.08.2009
Сообщений: 417
23.12.2009, 08:47  [ТС] #6
точно как это я сразу не додумался
просто постчитал сумму интов и делаю все вычисления за пределами цикла и все сходиться


Yurii_74,
TanT, спасибо еще раз
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.12.2009, 08:47
Привет! Вот еще темы с ответами:

Ошибка вывода значения 0 типа double - C++
При выполнении этого кода при значении x=0 не выводится четкий ноль. Почему? Я так понимаю нужно проводить округление? С printf такого нет....

Ошибка: error LNK2001: unresolved external symbol "double __cdecl Akk(double,double,double)" - C++
#include &lt;iostream&gt; #include &lt;cmath&gt; using namespace std; double Akk(double x, double y, double z); int main() { int a, b, c; ...

Странная ошибка похожая на выход из диапазона у типа(long double) - C++
Добрый день! Тестирую на строке $1,234,567,890,123.99 В результате, на выходе из функции mstold получаю что-то очень похожее на...

Ошибка C2679: бинарный '=': не найден оператор, принимающий правый операнд типа 'double' - C++
// ConsoleApplication2.cpp : Defines the entry point for the console application. // #include &quot;stdafx.h&quot; #include &quot;math.h&quot; ...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
23.12.2009, 08:47
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru