Ошибка округления в c #? [Дубликат]

1

У меня проблемы с проблемой округления в С#. Я хотел бы округлить результат вычисления до 4 десятичных знаков (awayfromzero). Если я использую Math.Round (переменная,...), он округляется, если я введу результат вручную, он округляется. Я понятия не имею, почему..

Что я делаю не так? Результат приведенного ниже кода: Округление: 591.24575 591.2457 - 591.2458

double number1 = 1136.81;
double number2 = 4.00;
double number3 = 2182.257;
double result = (number1 * number2 - number3) / 4;
Console.WriteLine("Rounded: " +result+" " + Math.Round(result, 4, MidpointRounding.AwayFromZero) + " - " + Math.Round(591.24575, 4, MidpointRounding.AwayFromZero));
Console.ReadLine();
  • 4
    потому что double - это двоичный тип данных с плавающей запятой, который не на 100% точен при преобразовании в / из чисел base-10 (с использованием Round , Floor и т. д.). Используйте decimal если вам нужна точность по основанию-10.
  • 3
    Меня всегда поражает, что в фреймворке или C # есть ошибка, когда что-то не работает, как кто-то ожидает.
Показать ещё 3 комментария
Теги:
rounding

3 ответа

4

Если вы используете мой DoubleConverter, вы можете увидеть точное значение result:

Console.WriteLine(DoubleConverter.ToExactString(result));

Это печатает:

591.2457499999999299689079634845256805419921875

... который округляется до 591.2457 при округлении до 4 знаков после запятой. Когда вы просто печатаете result, он печатает его уже округленным до определенного количества десятичных знаков, что может повлиять на результат, если вы тогда (мысленно) округлились до 4 DP.

Вы можете увидеть это без каких-либо "нормальных" странностей двоичной с плавающей запятой. Рассмотрим этот код:

decimal exact = 1.2345m;
decimal rounded2 = Math.Round(exact, 2, MidpointRounding.AwayFromZero);
decimal rounded3 = Math.Round(exact, 3, MidpointRounding.AwayFromZero);
decimal rounded3Then2 = Math.Round(rounded3, 2, MidpointRounding.AwayFromZero);
Console.WriteLine(rounded2); // 1.23
Console.WriteLine(rounded3); // 1.235
Console.WriteLine(rounded3Then2); // 1.24

В вашем коде вы фактически не выполняли "два закругления", но вы мысленно делали это, беря печатную величину result (591.24575) и предполагая, что вы можете считать это точным, чтобы округлить его дальше.

3

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

Если вы имеете дело с цифрами, имеющими известное фиксированное число базовых 10 цифр, и важно, чтобы у вас не было таких ошибок точности, как это может быть целесообразно использовать Decimal в этом контексте.

  • 0
    Ах, избили на полминуты :)
  • 0
    Кроме того, для решения проблемы такого рода вы можете поставить точку останова в своем коде сразу после присвоения результата. Отладьте ваше приложение и результат наведения мыши, чтобы увидеть его реальное значение
2

result не имеет значения, которое, по вашему мнению, он делает, оно усекается, помещая его в строковое представление. Что касается того, почему это так, прочитайте " Что каждый компьютерный ученый должен прочитать о плавающей точке"

Взгляните во время отладки:

result: 591.24574999999993
result.ToString(): "591,24575"

Ещё вопросы

Сообщество Overcoder
Наверх
Меню