Неточность десятичного в .NET.

Вчера во время отладки со мной произошло что-то странное, и я не могу это объяснить:

Десятичный расчет

Десятичные вычисления с помощью скобок

Так что, возможно, я не вижу здесь очевидного, или я неправильно понял что-то о десятичном значении в .NET, но не должен ли результат быть тем же самым?

Ответ 1

decimal не является магическим, все математические для меня типа. Он по-прежнему является числом с плавающей запятой - основное отличие от float заключается в том, что оно является десятичным числом с плавающей запятой, а не двоичным. Таким образом, вы можете легко представить 0.3 как десятичную (это невозможно как конечное двоичное число), но вы не имеете бесконечной точности.

Это заставляет его работать гораздо ближе к человеку, выполняющему те же вычисления, но вы все равно должны воображать, что кто-то делает каждую операцию индивидуально. Он специально разработан для финансовых расчетов, где вы не делаете то, что делаете в Maths - вы просто шаг за шагом ходите, округляя каждый результат в соответствии с довольно определенными правилами.

Фактически, для многих случаев decimal может работать намного хуже, чем float (или лучше, double). Это связано с тем, что decimal вообще не выполняет автоматического округления. Выполнение этого же с double дает вам 22, как ожидалось, потому что оно автоматически предполагало, что разница не имеет значения - в decimal, это делает - это одна из важных точек в decimal. Вы можете эмулировать это, введя руководство Math.Round s, конечно, но это не имеет большого смысла.

Ответ 2

Decimal может хранить только те значения, которые точно представлены в десятичной форме. Здесь 22/24 = 0,91666666666666666666666... который нуждается в бесконечной точности или рациональном типе для хранения, и он больше не равен 22/24 после округления. Если вы сначала сделаете умножение, тогда все значения будут точно представлены, следовательно, результат вы увидите.

Ответ 3

Добавляя скобки, вы убедитесь, что деление вычисляется до умножения. Это, как представляется, достаточно, чтобы повлиять на вычисления достаточно, чтобы ввести плавающая точность.

Поскольку компьютеры фактически не могут производить все возможные числа, вы должны убедиться, что вы учитываете это в своих расчетах

Ответ 4

Хотя Decimal имеет более высокую точность, чем Double, его основной полезной функцией является то, что каждое значение точно соответствует его читаемому человеку представлению. Хотя фиксированные десятичные типы, доступные на некоторых языках, могут гарантировать, что ни сложение, ни вычитание двух значений фиксированной точки с фиксированной точкой или умножение типа фиксированной точки на целое число никогда не вызовут ошибки округления, большие десятичные "типы, такие как найденные в Java, могут гарантировать, что никакое умножение никогда не вызовет ошибок округления, типы с плавающей запятой Decimal, подобные тем, которые были найдены в .NET, не предоставляют таких гарантий, и никакие десятичные типы не могут гарантировать, что операции деления могут быть выполнены без ошибок округления (у Java есть возможность выбросить исключение в случае необходимости округления).

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