округление десятичной дроби отключено для (276/304) * 304 - PullRequest
7 голосов
/ 17 февраля 2011

Если вы поместите следующий код в ваш компилятор, результат будет немного странным:

decimal x = (276/304)*304;
double y = (276/304)*304;

Console.WriteLine("decimal x = " + x);
Console.WriteLine("double y = " + y);

Результат:

десятичный х = 275,99999999999999999999999

двойной у = 276,0

Может кто-нибудь объяснить это мне? Я не понимаю, как это может быть правильно.

Ответы [ 3 ]

10 голосов
/ 17 февраля 2011

276/304 = 69/76 - это повторяющееся десятичное число как для основания 10, так и для основания 2.

  • десятичное число: 0,90 (789473684210526315)
  • двоичный: 0,11 (101000011010111100)

Таким образом, результат округляется, и умножение на знаменатель может не привести к оригинальному числителю. Более распространенным примером такой ситуации является 1/3 * 3 = 0,33333333 * 3 = 0,999999999.

То, что версия double дает точный ответ, является просто совпадением. Ошибка округления в умножении как раз и устраняет ошибку округления в делении.

Если этот результат сбивает с толку, возможно, вы слышали, что «double имеет ошибки округления и decimal является точным». Но decimal является точным только при представлении десятичных дробей, таких как 0,1 (что составляет 0,0 0011 0011 ... в двоичном виде). Если у вас в знаменателе коэффициент 19, это вам не поможет.

4 голосов
/ 17 февраля 2011

Ну, точность с плавающей запятой не равна 100%.
См. Например: http://effbot.org/pyfaq/why-are-floating-point-calculations-so-inaccurate.htm

0 голосов
/ 17 февраля 2011

Ну, математически 0.99999 ... == 1. Посмотрите на http://en.wikipedia.org/wiki/0.999... Я знаю, что программно это создает некоторые проблемы, но это не совсем проблема с плавающей точкой.

...