admin管理员组文章数量:1122846
Consider this function:
function DollarsToCents(dollars: Currency): Integer;
begin
result := Trunc(dollars * 100);
end;
The expression dollars * 100
will get converted to an Extended
, I believe, which is a binary floating point type, and as a general rule money should not be put into binary floating point due to the possibility of "representation error".
So, my question is: is this code safe? In our case we have no fractional cents, and a typical input to the function might be something like 1.23
.
Or is there a better way to do it?
Consider this function:
function DollarsToCents(dollars: Currency): Integer;
begin
result := Trunc(dollars * 100);
end;
The expression dollars * 100
will get converted to an Extended
, I believe, which is a binary floating point type, and as a general rule money should not be put into binary floating point due to the possibility of "representation error".
So, my question is: is this code safe? In our case we have no fractional cents, and a typical input to the function might be something like 1.23
.
Or is there a better way to do it?
Share Improve this question edited Nov 22, 2024 at 11:44 AmigoJack 5,9481 gold badge19 silver badges33 bronze badges asked Nov 22, 2024 at 8:35 dan-gphdan-gph 16.9k13 gold badges64 silver badges80 bronze badges2 Answers
Reset to default 5Currency
is internally a 64-bit integer expressed in units of 0,01 cents, so $1.00 = 10000 Currency
. Taking advantage of this knowledge, you can do it this way:
function DollarsToCents(dollars: currency): integer;
var
I64 : Int64 ABSOLUTE dollars;
begin
Result:=I64 DIV 100;
end;
The ABSOLUTE
keyword overlays the I64
variable on top of the dollars
parameter, so you can access it as the underlying 64-bit integer.
@HeartWare has given the best answer, but I want to answer the part of the question about whether or not the original DollarsToCents
function is safe. I did a test, and I think the answer is "probably yes".
If anyone is wondering about why it might not be safe, 0.03
for example, as a double is actually 0.0299999999999999988897769753748434595763683319091796875
because that value can't be represented exactly in binary floating point.
And if we multiplied 0.02999...
by 100
and did a Trunc
, we might expect to get 0.02
instead of 0.03
. So converting $0.03 to cents would incorrectly give us 2 cents.
But in the real world it seems that we actually do get 3 cents. There must be some rounding happening somewhere along the way.
Here's my test. I compared the old DollarsToCents
to HeartWare's version for each cent value from 1.00 to 1.99, and they agreed with each other.
program centsTest;
{$APPTYPE CONSOLE}
uses
SysUtils;
function DollarsToCents_Old(dollars: Currency): Integer;
begin
result := Trunc(dollars * 100);
end;
function DollarsToCents(dollars: currency): integer;
var
I64 : Int64 ABSOLUTE dollars;
begin
Result:=I64 DIV 100;
end;
var
i: integer;
dollars: currency;
oneCent: currency;
oneCentI64: Int64 absolute oneCent;
begin
oneCentI64 := 0100;
dollars := 1;
for i := 0 to 99 do
begin
if DollarsToCents_Old(dollars) <> DollarsToCents(dollars) then
raise Exception.CreateFmt('Failed: %f', [dollars]);
Writeln(Format('%f', [dollars]));
dollars := dollars + oneCent;
end;
end.
本文标签: delphiConvert Currency amount to cents without going through floating pointStack Overflow
版权声明:本文标题:delphi - Convert Currency amount to cents without going through floating point - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736305120a1932477.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论