Как Excel успешно округляет числа с плавающей запятой, даже если они неточные? - PullRequest
22 голосов
/ 03 августа 2011

Например, этот блог говорит, что 0,005 не совсем 0,005, но округление этого числа дает правильный результат.

Я перепробовал все виды округления в C ++, и при округлении чисел до определенных десятичных знаков происходит сбой. Например, Round (x, y) округляет x до кратного y. Итак, раунд (37,785,0.01) должен дать вам 37,79, а не 37,78.

Я снова открываю этот вопрос, чтобы обратиться к сообществу за помощью. Проблема заключается в неточности чисел с плавающей запятой (37,785 представляется как 37,78499999999).

Вопрос в том, как Excel справляется с этой проблемой?

Решение в этом round () для float в C ++ неверно для вышеуказанной проблемы.

Ответы [ 12 ]

0 голосов
/ 23 августа 2011

Так же, как числа-10 должны округляться при их преобразовании в основание-2, можно округлить число при преобразовании из основания-2 в основание-10. Как только у числа есть представление с основанием-10, его можно снова округлить простым способом, посмотрев на цифру справа от той, которую вы хотите округлить.

Хотя в вышеприведенном утверждении нет ничего плохого, есть гораздо более прагматичное решение. Проблема заключается в том, что двоичное представление пытается максимально приблизиться к десятичному числу, даже если этот двоичный файл меньше десятичного. Величина ошибки находится в пределах [-0,5,0,5] младших значащих бит (LSB) от истинного значения. Для округления вы бы предпочли, чтобы он был в пределах [0,1] LSB, чтобы ошибка всегда была положительной, но это невозможно без изменения всех правил математики с плавающей запятой.

Единственное, что вы можете сделать, это добавить 1 LSB к значению, чтобы ошибка находилась в пределах [0.5,1.5] LSB от истинного значения. Это менее точно в целом, но только на очень маленькое количество; когда значение округляется для представления в виде десятичного числа, гораздо более вероятно, что оно будет округлено до правильного десятичного числа, поскольку ошибка всегда положительна.

Чтобы добавить 1 LSB к значению перед округлением, см. Ответы на этот вопрос . Например, в Visual Studio C ++ 2010 процедура будет такой:

Round(_nextafter(37.785,37.785*1.1),0.01);
0 голосов
/ 23 августа 2011

Как говорит mjfgates, Excel делает тяжелую работу, чтобы получить это "право". Первое, что нужно сделать, когда вы пытаетесь переопределить это, это определить, что вы подразумеваете под «правильным». Очевидные решения: - реализовать рациональную арифметику Медленно, но надежно. - реализовать кучу эвристик Быстро, но сложно разобраться (подумайте «годы сообщений об ошибках»).

Это действительно зависит от вашего приложения.

...