2013-03-15 4 views
1

Результат должен быть 806603.77, но почему я получаю 806603.8?Поплавок неправильный расчет

float a = 855000.00f; 
float b = 48396.23f; 

float res = a - b; 
Console.WriteLine(res); 
Console.ReadKey(); 
+6

Если вы хотите получить точный результат, воспользуйтесь десятичным – Sergio

+6

[Что должен знать каждый компьютерный ученый о арифметике с плавающей точкой] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Oded

+0

Float и Double подвержены проблемам округления. Используйте 'Десятичный', как @Sergio рекомендуется. Вы можете найти дополнительную информацию [здесь] (http://stackoverflow.com/questions/618535/what-is-the-difference-between-decimal-float-and-double-in-c) – npinti

ответ

3

Вы должны использовать decimal вместо потому float имеет 32-bit с 7 цифр точность только поэтому результат отличается, с другой стороны decimal имеет 128-bit с 28-29 digit точность.

decimal a = 855000.00M; 
decimal b = 48396.23M; 

decimal res = a - b; 
Console.WriteLine(res); 
Console.ReadKey(); 

Выход: 806603.77

1

Потому что float имеет ограниченную точность (32 бит). Используйте double или decimal если хотите более точный.

3

A float (также называемый System.Single) имеет точность, эквивалентную приблизительно seven десятичные числа. Вам нужны reseight Значительные десятичные цифры. Поэтому следует ожидать, что в float недостаточно точности.

Сложение:

Некоторые дополнительная информация: Около 806000 (806000), float только имеет четыре бита влево для дробной части. Так res ему придется выбирать между

806603 + 12/16 == 806603.75000000, and 
806603 + 13/16 == 806603.81250000 

Он выбирает первый, так как он ближе всего к идеальному результату. Но оба этих значения выводятся как "806603.8" при вызове ToString() (который вызывает Console.WriteLine(float)). Показан максимум 7 значащих десятичных цифр с общим вызовом ToString. Для того, чтобы показать, что два числа с плавающей точкой различны, даже если они печатают то же самое со стандартным форматированием, используйте строку формата "R", например

Console.WriteLine(res.ToString("R")); 
0

Пожалуйста, обратите внимание, что только вслепую, используя Decimal не достаточно хорошо.

Читать ссылку размещенного Одедова: What Every Computer Scientist Should Know About Floating-Point Arithmetic

Только затем решение о соответствующем числовом типе использования.

Не попадайте в ловушку мышления о том, что просто использование десятичного числа даст вам точные результаты; это не всегда.

Рассмотрим следующий код: "! Yay"

Decimal d1 = 1; 
Decimal d2 = 101; 
Decimal d3 = d1/d2; 
Decimal d4 = d3*d2; // d4 = (d1/d2) * d2 = d1 

if (d4 == d1) 
{ 
    Console.WriteLine("Yay!"); 
} 
else 
{ 
    Console.WriteLine("Urk!"); 
} 

Если Десятичные вычисления были точны, что код должен печатать потому что d1 должен быть таким же, как d4, правильно?

Ну, это не так.

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

+0

Еще один забавный факт, заключающийся в том, что поскольку 'decimal.MaxValue'' '79228 ...', для чисел, чьи значащие цифры начинаются чем-то ниже этого, существует более высокая точность, чем число, значимые цифры которых выше. Чтобы понять, что я имею в виду, рассмотрим «800 м/3 м * 3 м» против «500 м/3 м * 3 м». Прежде всего отметим, что ни 800, ни 500 не равномерно смещаются на 3, поэтому у частного лица будет бесконечный хвост '666 ...', который 'System.Decimal' должен будет в конце концов завершить с' ... 667'. Тем не менее, поскольку 800 превысил предел '79228 ... ', а 500 находится под ним, точность отличается. –

+0

Я говорю о пороге '79228 ...', где точность изменяется от 29 до 28 значащих цифр. –

Смежные вопросы