Fixed point decimals for accounting

It’s not that the accounting rules are funky, so much as small errors in computing, are a problem. Basically, the numbers are always two decimal places, and work like integers.

Treating money as integer multiples of $0.01 can be exact if you only use +, -, and integer multiplication, but not if you allow division (splitting a dinner bill three ways) or multiplication by non-unit ratios (converting between currencies).

There must be standard practices for such cases in accounting. I’d think they’d be worked out as carefully as IEEE floating-point standards! I know nothing about it, but I have noticed that the IRS rounds to the nearest dollar.

5 Likes

That’s a good argument to implement a custom type: That way you can prevent division by either leaving it unimplemented or implementing it to immediatly raise an exception

Realize that decimal floating point is basically just as exact as decimal fixed point, with a much greater dynamic range.

Any elementary operation (+,*,/,-) whose result can be exactly represented in decimal is computed exactly, until you exceed the available number of significand digits. And when you do exceed the precision, the roundoff errors are typically much more gradual and benign than in fixed point (where overflow is catastrophic).

There is a pernicious myth that floating-point arithmetic always involves “random errors,” as if 1.0+1.0 only approximately gives 2.0.

2 Likes

So, rounding to two decimals should remove any error.

Rounding generally increases error, almost by definition.

1 Like

Decimals.jl says

Unlike another Julia package called DecFP , which aims at implementing the IEEE 754-2008 standard introducing 32, 64, and 64-bit precisions (decimal32, decimal64 and decimal128, respectively), this package allows arbitrary precision. Note, however, that in comparision with DecFP , which is is essentially a wrapper for a specialized Intel® Decimal Floating-Point Math Library, the present package is more computationally demanding. If more computational efficiency is demanded, functions from libmpdec library can be called directly.

Note that “arbitrary” precision is not the same as “infinite” precision. For example, 1/3 will never be represented exactly in decimal floating point regardless of the precision.

2 Likes

If you work with 100x the dollar value (ie. work with pennies) in normal binary floating point and round to the nearest integer you’ll probably do just fine unless maybe you’re working with transactions between the Federal Reserve and the US Treasury or something (ie. trillions of dollars)

Unless you’re talking about a situation like where the answer is person A should pay person B 33.33333333333333 dollars but because there is no 1/3 dollar they pay exactly $33.33 and then rounding to the nearest penny gives the correct answer to the question “what actually occurred?”

3 Likes

Exactly, and forget the floor stuff, I’m not sure what I was thinking there, normal rounding is always used.

I think rounding to two digits will work. Is there a way to always display two digits?

It’s my understanding that rounding to the nearest penny generally only occurs for the final transaction (e.g. when money exchanges hands, a bank deposit is made, etcetera), not necessarily on every intermediate financial calculation.

Also, in accounting situations you might have a fiduciary requirement to exactly represent decimal quantities, hence decimal fixed or floating point are often recommended over binary floating point. (Even if the precision of the binary floating point is such that $0.01 errors are unlikely to ever appear in the final rounded result no matter how many intermediate calculations were performed, you don’t want to be the a position of having to prove this by numerical analysis in a court.)

1 Like

yeah, I think that’s right. There are probably all sorts of legal issues as you mention later as well. Decimal floating point would be a good choice.

Of course, what’s really needed here is a numeric type that tracks the total roundoff error and automatically deposits the “leftover money” into the programmer’s bank account.

5 Likes

I don’t think it would end up in court, and rounding should allow the tests to work. (I can see if I have trouble). The only thing is that it only shows 1 or 2 decimal places, do it looks wrong.

Isn’t that the plot of Superman 3? Just make sure to not put a decimal in the wrong spot!

printing with 2 decimal places is no big deal, assuming your value is in pennies:

julia> p = 3316.0
3316.0

julia> @printf "You have \$%.2f" p/100
You have $33.16

Is that using a package? What if I add to a dataframe instead of printing?

Yeah a built-in / standard library package Printf · The Julia Language

using Printf

If you’re trying to create an “accounting number” based on using floating point in pennies… then you’ll want to create your own struct subtype of number

struct AccountBalance <: Number
    bal::Float64
end

Then you’ll want to create a constructor that automatically takes the balance, multiplies it by 100 and rounds it… create some + and - functions and such, and a printing function that uses @printf to do the right thing.

julia> function print(x::AccountBalance)
       @printf "\$%.2f" x.bal/100.0
       end
print (generic function with 33 methods)

julia> print(foo)
$13.80

Pluto doesn’t allow that @printf macro. It doesn’t allow a lot of macros, I think that’s something being worked on