Если пользователь хочет «сравнить два числа с плавающей точкой, используя заданное количество десятичных знаков (значащих цифр)», и это фактически означает, что у нас есть функция
Почти эквалайзеры (14.3XXXXXXXX, 14.3YYYYYYY, 1) == true для всех возможных XXX и YYY и
последний параметр - это десятичное число после десятичной точки.
есть простой, но неудачный ответ:
Невозможно запрограммировать эту функцию, которая будет выполнять этот контракт. Может быть возможно запрограммировать что-то, что будет часто давать правильный результат, но вы не можете предвидеть, когда это произойдет, поэтому функция фактически бесполезна.
Приведенные здесь решения уже ломаются с Почти Эквивалентами (0.06f, 0.14f, 1) = true, но 0! = 1.
Почему?
Первая причина - чрезвычайная чувствительность. Например: 0.0999999999 .... и 0.100000 ... 1
Во-первых, у них разные цифры, но в разнице они почти неразличимы, они практически точно совпадают. Что бы ни делала мифическая функция, она не может допустить даже небольших различий в вычислениях.
Вторая причина в том, что мы хотим на самом деле рассчитывать с числами.
Я использовал VC 2008 с C #, чтобы распечатать правильные значения функции Math.pow. Первый - это параметр точности, второй - шестнадцатеричное значение результирующего числа с плавающей запятой, а третий - точное десятичное значение.
1 3dcccccd 0.100000001490116119384765625
2 3c23d70a 0,00999999977648258209228515625
3 3a83126f 0,001000000047497451305389404296875
4 38d1b717 0,0000999999974737875163555145263671875
5 3727c5ac 0,00000999999974737875163555145263671875
6 358637bd 9.999999974752427078783512115478515625E-7
Как видите, последовательность 0.1, 0.01, 0.001 и т. Д. Дает числа, которые являются превосходными приближениями, но либо немного слишком малы, либо слишком велики.
Что если мы обеспечим, чтобы в данном месте была правильная цифра?
Давайте перечислим 16 двоичных значений для 4 битов
0.0
0.0625
0.125
0.1875
0.25
0.3125
0.375
0.4375
0.5
0.5625
0.625
0.6875
0.75
0.8125
0.875
0.9375
16 различных двоичных чисел должно быть достаточно для десяти десятичных чисел, если мы хотим вычислять только с одним местом после десятичной точки. В то время как 0,5 в точности равняется, принудительное использование одной и той же десятичной цифры означает, что 0,4 требуется 0,4375, а 0,9 - 0,9375, что приводит к серьезным ошибкам.
Нарушение первого условия чрезвычайной чувствительности означает, что вы не можете сделать ничего разумного с такими числами. Если вы знаете, что десятичное число имеет определенное значение, вам не нужно вычислять в первую очередь.
Документация C # даже приводит пример:
http://msdn.microsoft.com/en-us/library/75ks3aby.aspx
Примечания для абонентов
Из-за потери точности, которая может возникнуть в результате представления
десятичные значения как числа с плавающей запятой или арифметика
операции со значениями с плавающей точкой, в некоторых случаях Round (Double,
Метод Int32) может не отображаться для округления значений средней точки до ближайшего
четное значение в десятичной позиции цифр. Это иллюстрируется в
следующий пример, где 2,135 округляется до 2,13 вместо 2,14.
Это происходит потому, что внутри метода метод умножает значение на
10 цифр, и операция умножения в этом случае страдает от
потеря точности.