@Acaunt

Как правильно округлять числа с плавающей точкой с заданной точностью?

Пытаюсь округлить числа данным способом:
#include <iostream>
#include <iomanip>
#include <cmath>

int main() {
    double A = 1.46746884;
    A = std::round(A * 1000.0) / 1000.0;
    std::cout << std::fixed << std::setprecision(25) << A << std::endl;
    
    float B = 1.46548927f;
    B = std::roundf(B * 1000.0f) / 1000.0f;
    std::cout << std::fixed << std::setprecision(25) << B;
    
    return 0;
}

Выводит следующее:
1.4670000000000000817124146
1.4650000333786010742187500

Я сейчас склоняюсь к тому, что нормально их нельзя округлить из-за самого представления этих чисел в компьютере. Но вдруг есть нормальный способ округления.
П.С.
Я не пытаюсь их вывести я просто хотел показать вам пример того что они не округляются нормально.
  • Вопрос задан
  • 1033 просмотра
Пригласить эксперта
Ответы на вопрос 2
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Очень многие числа нельзя записать в виде числа с плавающей запятой, потому что они не представимы в виде доичной дроби с заданным количеством знаков. Например вы 1/3 как десятичную дробь не запишите. Ибо там 0.3333... - бесконечная последовательность троек. Для хранения double выделенно сколько-то бит под мантиссу, но их сильно меньше бесконечности.
Поэтому ни 1/10, ни 3/100, ни 1467/1000 и почти любая дробь будет непредставима в виде float. Поэтому, если вам нужна точность, то вы округляете до целого и храните количество, скажем, тысячных долей в целых числах. Как сумму денег вы храните не долларах, округленных до 2 знаков, а как целое число центов.
Ответ написан
Комментировать
@Mercury13
Программист на «си с крестами» и не только
Гуглите GRISU2 — и, возможно, переделайте этот код под свои нужды.
Он работает на целой арифметике и делает вот что: находит самое круглое десятичное число, переводимое в компьютерное дробное x.

Допустим, мне приходилось добавлять такое.
1. В случае не очень большого числа, большего 1/относительная_погрешность — поднять точность до единиц.
Например, переходить в экспоненциальный формат, когда у нас больше 5 цифр, а точность 3 цифры — то 0,00123, 0,0123, 0,123, 1,23, 12,3, 123, 1234, 12345, 1,23e5.

2. Большее из абсолютной и относительной погрешности.
Если у нас ещё две цифры абсолютной погрешности — то 0, 0,01, 0,12, 1,23, 12,3…

3. Формат с фиксированной длиной дробной части по принципу «всё или ничего».
С теми же двумя цифрами абсолютной погрешности — 0, 0,01, 0,12, 1,23, 12,34, 123…

4. Работу с локалями.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы