Follow

Repeat after me: Don't use floats for currency!

(it's 2022. Why are developers still making the same mistakes? Can't we learn from our elders?)

@mrb Ironically, that accepted answer isn't entirely right either.

Not all currencies have base10; not all have decimals. Some currencies have 3, 5 or even 8 decimals. Some currencies don't have decimals at all. Some only certain fractions (div/2 or div/5) etc.

that partially explains why the implementations often use the simple approach. The problem is far from trivial and many choose something that /seems/ to work and move on. (I've seen it in many ERP implementations )

@mrb for sure! things get hairy quickly when you add VAT to the mix...

@berkes

I've had this argument with fellow developers but in our case the use of postgresql numeric type with specified precision and automatic conversion to rubys BigDecimal it seems to work. But I can't shake the feeling we will find a way to fuck up.

@pidu In Ruby the float problems are always a mere `/` away, too.

(BigDecimal(1) / 3) * 3
=> 0.999999999999999999e0

One. Cannot. Just. Divide. Currencies. In reality: if you split €10 over 3 people, one of them will get an extra cent. Currencies are not mathematics.

In ruby I never use basic types for currencies. Instead, I implement a simple Currency type. (And please, avoid using Money gem, it comes with lots of features: complexity&performance, you almost certainly won't need)

@berkes

You're right of course. Although I did expect ruby to do better on 1 / 3 * 3 (yields 99). I miss programming in common lisp with it's full numeric tower.

Now your simple currency type has me intrigued, what does it actually do?

@pidu What it does depends on the domain-requirements.

I've built a complicated financial backend for a bill-sharing app. We there needed to support all international currency-weirdness, so used a (fork-of, slimmed down) Money gem. An entire library just to divide money properly.

But I've also built simple ecommercie that only ever deals with EUR. And where arithmatics was just to apply taxes, coupons etc. Something like gist.github.com/berkes/86637d4 is prolly enough in those cases.

@berkes

Thanks for strengthening my belief that whole cents calculations is the superior alternative. It's easy to take the basics for granted when you juggle big picture concerns.

I still find this ruby fascinating:

0.1 + 0.2 != 0.3

BigDecimal.new(0.1, 2) + 0.2 == 0.3

BigDecimal.new(0.1, 2) + 0.20001 != 0.3

I guess it just strengthens your case :)

Sign in to participate in the conversation
Bitcoin Mastodon

Bitcoin Maston Instance