У меня проблемы с проблемой округления в С#. Я хотел бы округлить результат вычисления до 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();
Если вы используете мой 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) и предполагая, что вы можете считать это точным, чтобы округлить его дальше.
result
является не совсем 591.24575
, это некоторое число, которое очень близко к 591.24575
но оно немного меньше, что-то 591.24574999999999
на строки 591.24574999999999
, в результате того, что определенные числа, которые имеют конечное число цифр в базе 10, не могут быть представленным с конечным числом цифр в базе 2. Когда вы точно устанавливаете число, вы избегаете когда-либо double
набора к одному из этих значений в качестве промежуточного значения ваших вычислений.
Если вы имеете дело с цифрами, имеющими известное фиксированное число базовых 10 цифр, и важно, чтобы у вас не было таких ошибок точности, как это может быть целесообразно использовать Decimal
в этом контексте.
result
не имеет значения, которое, по вашему мнению, он делает, оно усекается, помещая его в строковое представление. Что касается того, почему это так, прочитайте " Что каждый компьютерный ученый должен прочитать о плавающей точке"
Взгляните во время отладки:
result: 591.24574999999993
result.ToString(): "591,24575"
double
- это двоичный тип данных с плавающей запятой, который не на 100% точен при преобразовании в / из чисел base-10 (с использованиемRound
,Floor
и т. д.). Используйтеdecimal
если вам нужна точность по основанию-10.