Страницы

5 апреля 2012 г.

Округление числа. Когда нету Round()...

       Доброго времени суток в блоге "Будни программиста".
       Сегодня что-то стало скучно решил что-нибудь почитать. Взял в руки учебник по математике. :) Читал раздел про обыкновенные дроби, и десятичные дроби с бесконечной периодичностью.
       Сразу же вспомнилась простая операция округления чисел в большую сторону. А именно, заинтересовал вопрос, есть ли какая-либо математическая формула для преобразования числа к необходимой точности? Единой формулы я, к сожалению, не нашел. Конечно я далеко не математик, но навскидку накидал алгоритм преобразования:

Даны 2 параметра:
Первый - число с плавающей точкой (назовем параметр - D).
Второй - параметр точности (назовем его - P).
Для примера возьмем число 0.557, и точность 2. Т.е. в итоге должно получиться 0.56.
Разложим решение задачи на этапы:
1) Умножение исходного числа D на 10 в степени P.

R = D * 10^P = 0.557 * 100 = 55.7

2) Из результата операции 1 (R) вычтем целую часть того же результата. Таким образом мы отделяем дробную часть от целой:

C = int(R) = int(55.7) = 55;

M =  R - C = 55.7 - 55 = 0.7

3) Главное действие округления.

Y = C + N,

где N - коэффициент преобразования.
N = 1 при 0.5 <= M <= 0.9;
N = 0 при 0 <= M< 0.5;

Y = 55 + 1 = 56;

4) Результат предыдущего преобразования делим на 10 в степени P:

Result = Y/10^P = 56/100 = 0.56

Что соответствует ожидаемому результату.

Данный алгоритм, для проверки, я реализовал на C++:

double MyRound(double Value, int Precision)
{
    if (Precision <= 0)
        return (int)Value;
    int PreQ;
    PreQ = powl(10, Precision);
    double Tmp = Value * PreQ;
    int IntPart = (int)Tmp;
    Tmp -=IntPart;
    if ((Tmp>=0.5) && (Tmp<=0.9))
        IntPart++;
    return (double)IntPart/(double)PreQ;
}

Что-то математика начинает затягивать... :)

p.s. Алгоритм - просто развлекуха, в боевых условиях не проверял...

1 комментарий:

  1. Если это этот код выполнять на сопроцессоре x87 результат может быть неверным как т.к. тип double расширяется в родной тип сопроцессора extented. Способ расширения задается в настройках сопроцессора, и может отличаться от предполагаемого, например 5.01 double можно превратить в 4.99999991 extented в регистре (повышение точности)

    ОтветитьУдалить