Jump to content

    

Усечение double с заданной дискретностью

Задача - ограничить вводимые значения с заданной дискретностью. Т.е. если задан шаг 0.2, то число xxx.19 должно превратиться в xxx, а xxx.21 - в xxx.2.

Беру очевидную формулу

result = (int)(value / discrete) * discrete;

Однако на значениях value, кратных discrete, она не работает - неправильно производится приведение к целому.

50.19 => 250.950000 => 250 => 50
50.2  => 251.000000 => 250 => 50 <---- почему-то 50.2/0.2 = 251.0, а (int)(50.2/0.2) = 250!
50.21 => 251.050000 => 251 => 50.2

Пытаюсь сделать проверку разности

if((value / discrete) - (int)(value / discrete) >= 1.0f)

, но в условие не попадаю! :dash2:

Собственно, вопроса два - почему так происходит, и как эту задачу все же решить?

PS. На всякий случай: платформа PowerPC - Linux, компилятор gcc

Edited by Harvester

Share this post


Link to post
Share on other sites

А discrete у вас float или double ? Должно быть тоже double.

Share this post


Link to post
Share on other sites
12 minutes ago, arhiv6 said:

А discrete у вас float или double ? Должно быть тоже double.

Все double

Share this post


Link to post
Share on other sites
1 час назад, Harvester сказал:

Собственно, вопроса два - почему так происходит, и как эту задачу все же решить?

Перейти на fixed-point и избавиться от этих ошибок округления.

1 час назад, Harvester сказал:

Беру очевидную формулу

result = (int)(value / discrete) * discrete;

В "очевидной формуле" округление double и float производится усечением до ближайшего меньшего целого. По правилам си. Если хочется округление до ближайшего целого, то пишут:

result = (int)(value / discrete + .5) * discrete;

Если значение может быть отрицательным, то немного по-другому. Подумайте сами как.

Share this post


Link to post
Share on other sites

1) потому что нету такого числа 50.2, есть ближайшее к нему 50.2000000000000028421709430404 как и 0.2 впрочем, вместо него есть 0.200000000000000011102230246252.

и если их поделить одно на другое то и 251 ровно тоже не получится, а может оказаться чуть-чуть меньше, что и округляется в 250.

2) double result = (int)(value / discrete + 1e-9*value) * discrete;

не то чтобы прям решит задачу, просто сместит эти проблемы немного в другое место, но если константы с точностью до 9 знаков вводить не будет, то никто и не заметит.

 

Share this post


Link to post
Share on other sites
18 minutes ago, jcxz said:

Перейти на fixed-point и избавиться от этих ошибок округления.

У меня на входе УЖЕ double. И далее в алгоритмах используется double.

Quote

 

В "очевидной формуле" округление double и float производится усечением до ближайшего меньшего целого. По правилам си. Если хочется округление до ближайшего целого, то пишут:

result = (int)(value / discrete + .5) * discrete;

В этом случае результат не соответствует исходным требованиям, 50.11 => 50.2, а должно быть 50.0! :)

12 minutes ago, _pv said:

1) потому что нету такого числа 50.2, есть ближайшее к нему 50.2000000000000028421709430404 как и 0.2 впрочем, вместо него есть 0.200000000000000011102230246252.

и если их поделить одно на другое то и 251 ровно тоже не получится, а может оказаться чуть-чуть меньше, что и округляется в 250.

2) double result = (int)(value / discrete + 1e-9*value) * discrete;

не то чтобы прям решит задачу, просто сместит эти проблемы немного в другое место, но если константы с точностью до 9 знаков вводить не будет, то никто и не заметит.

 

Хм, попробую. Возможно этого будет достаточно :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now