Currency is your friend
currency type is the standard Delphi type to be used when
storing and handling monetary values. It will avoid any rounding problems, with
4 decimals precision. It is able to safely store numbers in the range
-922337203685477.5808 .. 922337203685477.5807. Should be enough for your pocket
As stated by the official Delphi documentation:
Currency is a fixed-point data type that minimizes rounding errors in monetary calculations. On the Win32 platform, it is stored as a scaled 64-bit integer with the four least significant digits implicitly representing decimal places. When mixed with other real types in assignments and expressions, Currency values are automatically divided or multiplied by 10000.
In fact, this type matches the corresponding
.Net implementation of
currency, and the one used by
most database providers (when it comes to money, a dedicated type is worth the
cost in a "rich man's world"). It is still implemented the same in the
Win64 platform (since XE 2). The
representation of the
currency type (i.e.
as accessible via
PInt64(aCurrencyValue)^) is a safe and fast
In our framework, we tried to avoid any unnecessary conversion to float
values when dealing with
currency values. Some dedicated functions
have been implemented for fast and secure access to
published properties via RTTI, especially when converting values to or from
JSON text. Using the
Int64 binary representation can be not only
faster, but also safer: you will avoid any rounding problem which may be
introduced by the conversion to a float type. Rounding issues are a nightmare
to track - it sounds safe to have a framework handling natively a
currency type from the ground up.
Faster and safer way of comparing two
currency values is
certainly to map the variables to their internal
representation, as such:
function CompCurrency(var A,B: currency): Int64; var A64: Int64 absolute A; B64: Int64 absolute B; begin result := A64-B64; end;
This will avoid any rounding error during comparison (working with *10000 integer values), and will be faster than the default implementation, which uses the FPU (or SSE2 under x64 architecture) instructions.
there are some functions using the
Int64 binary representation
(accessible either as
PInt64(aCurrencyVar)^ or the
They will by-pass the FPU/SSE2 use, and are therefore both fast and safe at the same time:
function Curr64ToString(Value: Int64): string;
function StrToCurr64(P: PUTF8Char): Int64;
function Curr64ToStr(Value: Int64): RawUTF8;
function Curr64ToPChar(Value: Int64; Dest: PUTF8Char):
function StrCurr64(P: PAnsiChar; const Value: Int64):
Using those functions can be much faster for textual conversion
than using the standard
FloatToText() implementation. They are
validated with provided regression tests.
Of course, in normal code, it is certainly not worth using the
Int64 binary representation of
currency, but rely on
the default compiler/RTL implementation. In all cases, having optimized
functions was a need for both speed and accuracy of our ORM data processing,
and also for external database handling.
Comments and feedback are welcome on our forum.