PavelK
@PavelK

C++ Муки округления. Как «красиво» сделать следующие функции?

Приветствую!
Есть, к примеру, число типа double 43.210002
требуется
привести число к виду 43.2100000000
т.е. оставить число до сотых, остальное забить нулями (например до 4 после сотых).

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

Сделал через строку, но это напоминает адцкий костыль.
Подскажите, пожалуйста, как правильнее?
  • Вопрос задан
  • 2741 просмотр
Решения вопроса 4
@ColdSpirit
stackoverflow.com/questions/14369673/c-round-doubl...

#дополнено:
Извините, вопрос неправильно понял.

Я бы создал класс или структуру с double, который содержит число 43,21 и int, содержащее количество нулей после запятой. Ну и прочие функции преобразования стандартных типов в ваш и наоборот.

Ну или просто напишите набор функций преобразования из одного типа в другой, если вам не нужно выполнять операции с данным типом чисел, а просто выводить.
Ответ написан
Комментировать
gbg
@gbg Куратор тега C++
Любые ответы на любые вопросы
Не будет у вас такой радости - не все числа можно точно представить с плавающей точкой.

Умножение с последующим round ни к чему хорошему не приведет.

Если вы собрались что-то там округлить во время вычислений, возможно, вы совершаете ошибку. (Деньги или складские остатки в double пытаетесь хранить)
Ответ написан
@Alexander1705
Так же как в десятичной системе счисления вы не можете представить число 1/3 в виде десятичной дроби, вы не можете представить в двоичной системе счисления некоторые дроби, которые можете представить в десятичной. Если всё же попытаетесь это сделать, получите бесконечную периодическую дробь.
Так, например если перевести число 0.4 из десятичной системы в двоичную, получите такую периодическую дробь: 0,0110011001100.. и так далее до бесконечности. 100 / 1010 = 0.(0110)

Однако это не означает, что ваша задача не решаема. Просто нужно подойти к решению с другой стороны:
class DecimalFixedPoint
{
public:

    static const int denominator = 100; // Affect on precison
    friend std::ostream& operator<<(std::ostream& stdout, DecimalFixedPoint dfp);

    DecimalFixedPoint()                  : numerator(0)               {}
    DecimalFixedPoint(int i, bool)       : numerator(i)               {}
    DecimalFixedPoint(int i)             : numerator(i * denominator) {}
    explicit DecimalFixedPoint(float f)  : numerator(f * denominator) {}
    explicit DecimalFixedPoint(double d) : numerator(d * denominator) {}

    DecimalFixedPoint operator+(const DecimalFixedPoint& right)
    {
        return DecimalFixedPoint(numerator + right.numerator, true);
    }

    DecimalFixedPoint operator-(const DecimalFixedPoint& right)
    {
        return DecimalFixedPoint(numerator - right.numerator, true);
    }

    DecimalFixedPoint operator*(const DecimalFixedPoint& right)
    {
        return DecimalFixedPoint(numerator * right.numerator / denominator, true);
    }

    DecimalFixedPoint operator/(const DecimalFixedPoint& right)
    {
        return DecimalFixedPoint(numerator * denominator / right.numerator, true);
    }


private:
    int numerator;
};


std::ostream& operator<<(std::ostream& stdout, DecimalFixedPoint dfp)
{
    stdout << dfp.numerator / DecimalFixedPoint::denominator
           << '.'
           << dfp.numerator % DecimalFixedPoint::denominator;
    return stdout;
}

Upd.
В конструкторе DecimalFixedPoint(int i, bool) : numerator(i) {} второй параметр нужен для того, чтоб сигнатура отличалась от конструктора
DecimalFixedPoint(int i) : numerator(i * denominator) {}
Если вызывается конструктор с параметром bool, подразумевается, что мы не приводим целое число к нашему типу, а передаём заранее вычисленный числитель нашей дроби. Это, конечно, костыль, но так как такой подход используется в самом стандарте C++ (перегрузка префиксных и постфиксных инкремента/декремента), то совесть моя чиста.
Ответ написан
Комментировать
PavelK
@PavelK Автор вопроса
Всем спасибо!
Вы были правы муки такие муки с этой плавающей точкой.
Ушёл от работы с ней почти полностью
использую только целочисленный тип и делитель для точки, т.е. например число 12.34 у меня оно представлено как 1234 и 100 так реально стало проще во всём. Осталось только разобраться с длинной арифметикой и всё ок =)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы