Неверные значения для двойного расчета

Я делаю простой расчет в VB.Net, следующий код.

Dim total As String = "192.04"
Dim paid As String = "200"
Dim change As String = "7.96"
'//This prints -7.99360577730113E-15 (Incorrect)
MsgBox((CDbl(total) - CDbl(paid)) + CDbl(change))

Ответ, который я ожидаю из этого расчета, равен 0, но я получаю -7.99360577730113E-15. Я не знаю точную причину этого, я не мог понять причину, объясненную на MSDN. Любое разъяснение будет очень полезно.

И я сделал Math.Round до 2 десятичных знаков, и проблема была решена, поэтому мне нужно использовать Math.Round везде, где я делаю вычисления с десятичными знаками?

2 ответа

Решение

Это из-за того, как double (или числа с плавающей запятой вообще) представлены в памяти. Вы должны использовать decimal для финансовых расчетов вместо double:

double total = 192.04;
double paid = 200;
double change = 7.96;

double result = (total - paid) + change;   // -7.99360577730113E-15
decimal total = 192.04m;
decimal paid = 200m;
decimal change = 7.96m;

decimal result = (total - paid) + change;   // 0.00

Я знаю, что это C#, но вы все равно должны увидеть разницу.

Ты можешь использовать Decimal.Parse чтобы получить decimal от string:

Dim total As String = "192.04"
Dim paid As String = "200"
Dim change As String = "7.96"

MsgBox((Decimal.Parse(total) - Decimal.Parse(paid)) + Decimal.Parse(change))

Эта ошибка точности связана с тем, как числа с плавающей запятой работают в компьютерах (более конкретно, стандарт IEEE, см. WikiPedia). Короче говоря, числа с плавающей запятой хранятся как "двоичные числа с десятичными точками", а затем увеличиваются до некоторой степени 2. Поэтому они не могут хранить точные десятичные цифры. Эта проблема является общей для всех языков программирования, а не только для.NET.

Чтобы преодолеть эту проблему, Decimal Тип используется при расчете платежей, которые требуют точности базы 10. За исключением.NET, почти все современные среды программирования также предоставляют этот тип переменной.

Другие вопросы по тегам