Hendrik Boom wrote:
> I've always been doubtful about the use of floating point by gnucash.
The problem with floating point types is that they only provide an approximation to
what you want.
To go into painful detail, here's what I understand about floating point types.
The first bit past the decimal point represents 2^-1, or 1/2. The next position is
2^-2, or 1/4. And so on, for as many bits form the mantissa. The exponent just says
how far the decimal point has been moved (in base 2). The mantissa is normalised so
that it is just a fraction, being in the range -1..1.
Now, let us consider the problem of representing 0.1 (decimal) in binary
fractions.Remember that 10 (decimal) can be written as 1 * 8 + 0 * 4 + 1 * 2 + 0 *
1, which we write in binary as 1010. Binary fractions use negative powers of 2 to
do a similar thing:
1/2 = 0.5 > 0.1, so we have 0 * 2^-1.
1/4 = 0.25 > 0.1, so we have 0 * 2^-2.
1/8 = 0.125 > 0.1, so we have 0 * 2^-3.
0 * 1/2 + 0 * 1/4 + 0 * 1/8 + 1 * 1/16 = 0.0625, so we have 0.375 left over.
0 * 1/2 + 0 * 1/4 + 0 * 1/8 + 1 * 1/16 + 1 * 1/32 = 0.09375, so we have 0.00625
left over.
1/64 = 0.015625 > 0.00625, so we have 0 * 2^-6.
1/128 = 0.0078125 > 0.00625, so we have 0 * 2^-7.
1/256 = 0.00390625 <= 0.00625, so
0 * 1/2 + 0 * 1/4 + 0 * 1/8 + 1 * 1/16 + 1 * 1/32 + 0 * 1/64 + 0 * 1/128 + 1 *
1/256 = 0.09375, so we have 0.00234375 left over.
You continue with this approximating process until you run out of bits, or you have
completely converted the number. I think you will see that the remainder is getting
smaller, but it's unlikely to be matched exactly by one of the factors at our
disposal. We may approximate to as many bits as we want, but it's just that: an
approximation.
This type of number is fine in a physics calculation, where you know that the
precision of the answer will be related to the precision of the input, and you
don't mind much if the last few digits are not exactly correct. (More to the point,
you know how many are corect, and you only quote the significant figures in your
results.) However, in a financial application, we need to reliably track every last
cent (or penny, or yen, or whatever). Thus, I feel that the double type is
eminently unsuitable.
What's the solution to this problem?
I will first mention a historical solution - this probably bears little relevance
to what we should do, but anyway...
I seem to remember that the 6502 microprocessor, which was used in the C64, had a
BCD flag. When it was enabled, it entered a special mode, where all math operations
assumed that each byte held 2 decimal digits, being allowed to range from 0 to 9.
If you added 09 and 01, you got 10 (as expected), but in terms of the raw binary,
that would be 00001001 + 00000001 = 00010000. It was inefficient on space, but
prevented rounding errors that we have seen may occur in floating point. I believe
that this mode was used by a spreadsheet.
Alternately, integers have no rounding error. However, they are susceptible to
overflow. Their range is
unsigned: 0..4,294,967,295 (2^32-1)
signed: -2,147,483,648...2,147,483,647 (2^31-1)
long long (or int64) would give us
unsigned: 0 ... 18,446,744,073,709,551,615
signed: -9,223,372,036,854,775,808 ... 9,223,372,036,854,775,807
One would think this might be enough to record the net worth of the world economy,
but perhaps someone else could comment on that. If this is insufficient, then the
multiple precision package mentioned earlier should be employed, but only if it has
an integer mode. (Aside: If we were using C++, we could substitute a portable
user-defined type for 64-bit integers on platforms which don't have builtin
compiler support, and we would not have to change any other code... It could even
be binary compatible with the int64 type.)
If we are going to change the fundamental type, what impact will this have on the
reports, and the parts of the GUI written in scheme?
Whatever we do, we should alert the user if overflow ever does occur, but it would
be nicer if it never did. (The C++ bit is nice here because overflow checking can
be incorporated into the number class.)
However, I realise that you guys like C and want to keep it that way.
Ben.
--
Gnucash Developer's List
To unsubscribe send empty email to: [EMAIL PROTECTED]