Здравствуйте, -Cheese-, Вы писали:
C>Я понимаю, что типа хранение чисел с плавающей точкой и всё такое... но как избежать этого?
Например использовать целочисленую арифметику до самого последнего момента;
C>Получаем: C>z1=4053.0000000 C>z2=4052.0000000
А что должны получить?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Здравствуйте, np9mi7, Вы писали:
N>Здравствуйте, -Cheese-, Вы писали:
C>>Я понимаю, что типа хранение чисел с плавающей точкой и всё такое... но как избежать этого?
N>Например использовать целочисленую арифметику до самого последнего момента;
C>>Получаем: C>>z1=4053.0000000 C>>z2=4052.0000000
N>А что должны получить?
4052.0000000
Объясняю смысл проблемы...
есть некоторые платежи для человека в некоторой валюте ,
например
1) 5.09
2) 31.091
3) 1.01
......
и есть итоговая сумма — например: 37.191
но с человека нужно брать в этом случае 37.20 = ceil(sum(x_i)), x_i — i-тый платёж
на может сложиться ситуация когда человек должен заплатить например ровно 12 у.е.,
а ceil(sum(x_i)) может равняться 12.01 у.е., что не есть хорошо...
#include <cmath>
int main ()
{
const int p = 1000;
long long x = 800000;
long long y = 5065;
double z = std::ceil ((x * y) / static_cast
<double> (p * p));
double q = (x * y) / static_cast
<double> (p * p);
return 0;
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Здравствуйте, np9mi7, Вы писали:
N>Например так:
N>
N>#include <cmath>
N>int main ()
N>{
N> const int p = 1000;
N> long long x = 800000;
N> long long y = 5065;
N> double z = std::ceil ((x * y) / static_cast
N> <double> (p * p));
N> double q = (x * y) / static_cast
N> <double> (p * p);
N> return 0;
N>}
N>
Хм... Думаю, должен быть велосипедный парк на тему вычислений с фиксированной точкой... В крайнем случае, можно (и нужно) написать самому.
Собственно, необходимых операторов-то: +, -, *, /, double().
Здравствуйте, -Cheese-, Вы писали:
N>>А что должны получить? C>4052.0000000
А напрасно! ceil — это округление вверх до целого! floor, соответственно — вниз.
C>Объясняю смысл проблемы... C>есть некоторые платежи для человека в некоторой валюте , C>например C>1) 5.09 C>2) 31.091 C>3) 1.01 C>......
C>и есть итоговая сумма — например: 37.191 C>но с человека нужно брать в этом случае 37.20 = ceil(sum(x_i)), x_i — i-тый платёж
Здесь нужно округление вверх до 0.01 — это ceil(the_sum/0.01)*0.01
C>на может сложиться ситуация когда человек должен заплатить например ровно 12 у.е., C>а ceil(sum(x_i)) может равняться 12.01 у.е., что не есть хорошо...
Видимо, нужно округление к ближайшему 0.01 — это floor(the_sum/0.01 + 0.5)*0.01
Но вообще говоря, плавающая арифметика — не лучшее решение для представления денег.
Особенно — арифметика с двоичной дробной частью (поскольку десятичные дроби оказываются непредставимы и хранятся в приближённом виде — там стремительно набегают ошибки округления). К этому добавляются ошибки нормализации, присущие плавающей арифметике вообще, не только двоичной.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, -Cheese-, Вы писали:
N>>>А что должны получить? C>>4052.0000000
К>А напрасно! ceil — это округление вверх до целого! floor, соответственно — вниз.
дело в том, что если в столбик умножить , то получится 4052
Здравствуйте, -Cheese-, Вы писали:
C>дело в том, что если в столбик умножить , то получится 4052
В какой системе умножаешь в столбик ты, и в какой — компьютер.
5.065 непредставимо в виде double — там, на самом деле, что-то наподобие 5.0650000000001. При умножении эта ошибка вылезает.
Здравствуйте, Кодт, Вы писали: К>В какой системе умножаешь в столбик ты, и в какой — компьютер. К>5.065 непредставимо в виде double — там, на самом деле, что-то наподобие 5.0650000000001. При умножении эта ошибка вылезает.
в том то и проблема...
объясни попробуй клиенту про двоичное представление числа с плавающей точкой много нового о себе услышишь
ну да ладно... будем вводить эпсилон промежуток
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Округление с помощью ceil...
От:
Аноним
Дата:
17.10.06 15:38
Оценка:
Здравствуйте, Axc, Вы писали:
Axc>Здравствуйте, -Cheese-
Axc>Я бы делал так: Axc>
Axc> const double accuracy = 1E-6;
Axc> double x = 800.0;
Axc> double y = 5.065;
Axc> double z1 = ceil(x * y * (1 - accuracy));
Axc> double z2 = x * y;
Axc> double z3 = floor(x * y * (1 + accuracy));
Axc>
Ну будет ли так любезен уважаемый -Cheese- ответить пару "почему"?
А именно, интерисует:
1) почему accuracy = 1E-6
2) почему в одном случае 1-accuracy, а в другом 1+accuracy.
Здравствуйте, -Cheese-, Вы писали:
C>объясни попробуй клиенту про двоичное представление числа с плавающей точкой много нового о себе услышишь C>ну да ладно... будем вводить эпсилон промежуток
А может быть, сделать арифметику с фиксированной точкой? Грубо говоря, считать всё в int64 в копейках.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: Округление с помощью ceil...
От:
Аноним
Дата:
17.10.06 21:10
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Axc, Вы писали:
Axc>>Здравствуйте, -Cheese-
...
А>Ну будет ли так любезен уважаемый -Cheese- ответить пару "почему"?
Черт... Ошибочка вышла. Следует читать:
Ну будет ли так любезен уважаемый axc ответить пару "почему"?
Здравствуйте, -Cheese-, Вы писали:
C>Объясняю смысл проблемы... C>есть некоторые платежи для человека в некоторой валюте , C>например C>1) 5.09 C>2) 31.091 C>3) 1.01 C>......
C>и есть итоговая сумма — например: 37.191 C>но с человека нужно брать в этом случае 37.20 = ceil(sum(x_i)), x_i — i-тый платёж
C>на может сложиться ситуация когда человек должен заплатить например ровно 12 у.е., C>а ceil(sum(x_i)) может равняться 12.01 у.е., что не есть хорошо...
Ну-ну. Один знакомый программист рассказывал, как они 2 ночи подряд искали почему годовой баланс банка не сходится на 4 копейки, где же они неправильно округлили число с плавающей запятой
Здравствуйте, Кодт, Вы писали: К>Здравствуйте, -Cheese-, Вы писали: C>>объясни попробуй клиенту про двоичное представление числа с плавающей точкой много нового о себе услышишь C>>ну да ладно... будем вводить эпсилон промежуток К>А может быть, сделать арифметику с фиксированной точкой? Грубо говоря, считать всё в int64 в копейках.
Вообще-то все расчёты и ведутся в копейках, но увы может быть такое, что нужно нецелое число копеек (например обмен валюты по курсу 5.065234152).