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.
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
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)
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 https://gist.github.com/berkes/86637d49fec6e3173b0d31f5558bd21b is prolly enough in those cases.
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 :)
Bitcoin Maston Instance