Округление с помощью ceil...
От: -Cheese-  
Дата: 17.10.06 10:54
Оценка:
Я понимаю, что типа хранение чисел с плавающей точкой и всё такое... но как избежать этого?
    double x=800.0;
    double y=5.065;
    double z1=ceil(x*y);
    double z2=x*y;

Получаем:
z1=4053.0000000
z2=4052.0000000
Re: Округление с помощью ceil...
От: np9mi7 Россия  
Дата: 17.10.06 11:10
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Я понимаю, что типа хранение чисел с плавающей точкой и всё такое... но как избежать этого?


Например использовать целочисленую арифметику до самого последнего момента;

C>Получаем:

C>z1=4053.0000000
C>z2=4052.0000000

А что должны получить?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[2]: Округление с помощью ceil...
От: -Cheese-  
Дата: 17.10.06 11:33
Оценка:
Здравствуйте, 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 у.е., что не есть хорошо...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Округление с помощью ceil...
От: np9mi7 Россия  
Дата: 17.10.06 11:53
Оценка: +1
Здравствуйте, -Cheese-, Вы писали:

C>4052.0000000


Например так:

#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) Теодор Рузвельт.
Re: Округление с помощью ceil...
От: Axc  
Дата: 17.10.06 11:53
Оценка:
Здравствуйте, -Cheese-

Я бы делал так:
    const double accuracy = 1E-6;
    double x = 800.0;
    double y = 5.065;
    double z1 = ceil(x * y * (1 - accuracy));
    double z2 = x * y;
    double z3 = floor(x * y * (1 + accuracy));
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Округление с помощью ceil...
От: Аноним  
Дата: 17.10.06 11:56
Оценка: +3
Здравствуйте, -Cheese-, Вы писали:

C>Объясняю смысл проблемы...

C>есть некоторые платежи для человека в некоторой валюте ,

Вот так наивно пользовать double для подсчета денег не стоит.
Тут нужна своя арифметика с числами с фиксированной точкой.
Re: Округление с помощью ceil...
От: SergH Россия  
Дата: 17.10.06 11:58
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Я понимаю, что типа хранение чисел с плавающей точкой и всё такое... но как избежать этого?

C>
C>    double x=800.0;
C>    double y=5.065;
C>    double z1=ceil(x*y);
C>    double z2=x*y;
C>

C>Получаем:
C>z1=4053.0000000
C>z2=4052.0000000

Написать функцию myCoolCeil, которая будет проверять значение. Примерно так:

double myCoolCeil(double x)
{
    if (x - floor(x) > 0.0001) return ceil(x);
    return floor(x);
}
Делай что должно, и будь что будет
Re[4]: Округление с помощью ceil...
От: Axc  
Дата: 17.10.06 12:03
Оценка:
Здравствуйте, 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().
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Округление с помощью ceil...
От: -Cheese-  
Дата: 17.10.06 12:16
Оценка:
Здравствуйте, np9mi7, Вы писали:

N>Здравствуйте, -Cheese-, Вы писали:


C>>4052.0000000


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>


в принципе я почти так и сделал (только перегонял их в int, а потом в double).... хотя некрасиво всё это
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Округление с помощью ceil...
От: Кодт Россия  
Дата: 17.10.06 13:12
Оценка:
Здравствуйте, -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

Но вообще говоря, плавающая арифметика — не лучшее решение для представления денег.
Особенно — арифметика с двоичной дробной частью (поскольку десятичные дроби оказываются непредставимы и хранятся в приближённом виде — там стремительно набегают ошибки округления). К этому добавляются ошибки нормализации, присущие плавающей арифметике вообще, не только двоичной.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: Округление с помощью ceil...
От: -Cheese-  
Дата: 17.10.06 13:54
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, -Cheese-, Вы писали:


N>>>А что должны получить?

C>>4052.0000000

К>А напрасно! ceil — это округление вверх до целого! floor, соответственно — вниз.


дело в том, что если в столбик умножить , то получится 4052
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Округление с помощью ceil...
От: Кодт Россия  
Дата: 17.10.06 14:24
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>дело в том, что если в столбик умножить , то получится 4052


В какой системе умножаешь в столбик ты, и в какой — компьютер.
5.065 непредставимо в виде double — там, на самом деле, что-то наподобие 5.0650000000001. При умножении эта ошибка вылезает.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: Округление с помощью ceil...
От: Warturtle  
Дата: 17.10.06 14:53
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, np9mi7, Вы писали:


N>>Здравствуйте, -Cheese-, Вы писали:


C>>>4052.0000000


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>>


C>в принципе я почти так и сделал (только перегонял их в int, а потом в double).... хотя некрасиво всё это


"красиво" =)
Re[6]: Округление с помощью ceil...
От: -Cheese-  
Дата: 17.10.06 14:55
Оценка:
Здравствуйте, Кодт, Вы писали:
К>В какой системе умножаешь в столбик ты, и в какой — компьютер.
К>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.

Александр
Re[7]: Округление с помощью ceil...
От: Кодт Россия  
Дата: 17.10.06 15:55
Оценка: +2
Здравствуйте, -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 ответить пару "почему"?
Re[3]: Ну-ну
От: remark Россия http://www.1024cores.net/
Дата: 18.10.06 04:04
Оценка:
Здравствуйте, -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 копейки, где же они неправильно округлили число с плавающей запятой


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[8]: Округление с помощью ceil...
От: -Cheese-  
Дата: 18.10.06 05:22
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, -Cheese-, Вы писали:
C>>объясни попробуй клиенту про двоичное представление числа с плавающей точкой много нового о себе услышишь
C>>ну да ладно... будем вводить эпсилон промежуток
К>А может быть, сделать арифметику с фиксированной точкой? Грубо говоря, считать всё в int64 в копейках.

Вообще-то все расчёты и ведутся в копейках, но увы может быть такое, что нужно нецелое число копеек (например обмен валюты по курсу 5.065234152).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Округление с помощью ceil...
От: -Cheese-  
Дата: 18.10.06 05:23
Оценка: :)
Здравствуйте, <Аноним>, Вы писали:

А>Ну будет ли так любезен уважаемый -Cheese- ответить пару "почему"?

Отвечаеть должен Axc (или Александр Друзь).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.