Ну, первое, что можно сказать, это то, что вы играете здесь с огнем. Вы смешиваете Integer
, Double
и Currency
в том же заявлении. Эта нечестивая смесь, честно говоря, просит неприятностей.
Кроме того, если вы еще не знаете, вы должны знать, что не все ваши значения являются представляемыми. Вот исходные значения:
a
имеет тип Double
, значение 30.1
. Это значение не точно представлено в двоичной с плавающей запятой. Номер closest Double
value: 30.10000000000000142108547152020037174224853515625
.
b
тип Integer
, стоимость 10
. Здесь нет сюрпризов.
c
есть тип Currency
, value 20.1
. Это представлено как 64-битное целое число со значением 201000. Это тип данных с фиксированной точкой. Представление включает неявный сдвиг 10000.
Следующее ваше выражение, a - b - c
. Он оценивается слева направо.
код под x86 выглядит следующим образом, с моими примечаниями:
// load b into the floating point unit, converting from 32 bit integer
fild dword ptr [$00423ef0]
// subtract b from a, as floating point
fsubr qword ptr [$00423ed8]
// multiply by 10000 to convert to currency
fmul dword ptr [$0041c5e0]
// load c into the floating point unit, converting from 64 bit integer
fild qword ptr [$00423ee8]
// subtract c from (b - a)
fsubp st(1)
// divide by 10000, that is convert the result to a floating point value
fdiv dword ptr [$0041c5e0]
// store this floating point value into d
fstp qword ptr [$00423ee0]
Значение, которое мы храним обратно в d
не равен нуль. По сути, это потому, что (a - b)*10000 <> 20100
. Теперь вы можете быть удивлены, узнав, что (a - b)*10000 <> 20100
, но это естественное следствие того факта, что a
не является точным изображением 30.1
, как мы видели в первом пункте выше.
Я думаю, что мораль этой истории не должна смешивать двоичные и десятичные операнды в тех же выражениях. Или, по крайней мере, если вам нужно это сделать, будьте ясными и точными о том, как вы это делаете. Например.
Итак, если вы выполняете свои расчеты полностью в Currency
, тогда вы получите ответ, который ожидаете. Это потому, что Currency
является десятичным представлением и может хранить все эти значения и все промежуточные значения точно.
«d» двойная переменная типа «30.1» фактически получает значение «30.10000000000000142108547152020037174224853515625« получение значения потрясающе! Логически я могу понять, что не нужно вводить преобразование? –
Я не уверен, что вы имеете в виду. Вы просите больше помощи? –
Я думаю, что OP может захотеть взглянуть на [Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). –