Jump to content

    
Sign in to follow this  
Harvester

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

Recommended Posts

Задача - ограничить вводимые значения с заданной дискретностью. Т.е. если задан шаг 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
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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this