Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That is not the correct way. The correct way is to use fxed-decimal math, and pay careful attention to rounding.

No floats. Not even once.



No floats. Not even once.

Do you mean no decimal floating point numbers or did you misread my comment as advocating binary floating point numbers plus careful rounding?

Fixed point decimal numbers are of course also okay, it just changes what you have to pay attention to. And often fixed point decimal numbers are in some sense secretly floating point decimal numbers, they just do not automatically adjust the decimal point [1] but require doing so explicitly.

And this may of course be useful because you will run into an overflow and not accidentally lose precision when numbers become large. On the other hand you may lose precision if numbers become small and you only have a fixed precision.

[1] I am not sure what the important factor is for calling a number type fixed point or floating point. Is it the ability to move the decimal point around or is it doing so automatically?


Ah, sounds like a terminology issue. Sorry if this get pedantic, but I wanted a solid response for anyone who stumbles on this thread down the road.

Fixed-point is a way of doing math, as well as a data representation. Think of it as keeping a very large integer, plus another int that represents where the decimal place should go. Hell, you can even think of it as a string of numbers and an optional '.', removing the issue of overflow as well.

When you do fixed-point math, you have to be explicit about rounding and precision changes, or set a default way to handle those situations. When two numbers are added, do we inherit the precision of the more or less precise number? What about division, where we run into necessarily repeating decimals?

Floating point math, on the other hand, uses a mantissa and necessarily loses precision. As a floating point number is an approximation from 0 to infinity using a fixed number of bits (often 32, 64, 128), there are a ton of amounts that it can't exactly represent. But that's not an acceptable situation in finance- we don't need infinity, but we do need countability within a range with some minimum step size.

An example- let's say we're adding amounts of bitcoin in Python

  > 1000.1234 + 1000.1234
  20000.2468
  > 10000.1234 * 3
  30000.3702
Looks good, but now we have a whale, a high frequency trader, or some HackerOne bounty hunter with API access

  > 10000.1234 * 50
  500006.17000000004
That calculation, at face value, just created .00000000004 bitcoin out of thin air. That's less than a satoshi, but if you keep going with a strategy like this on an automated platform, you can turn it into real money.

Instead, you want to use fixed-point.

  > from decimal import Decimal
  > Decimal('1000.1234') * Decimal('50')
  Decimal('50006.1700')
Note in this case the precision was expanded to the most precise in multiplication, and no money was created out of thin air.

You can also set precision explicitly (`Decimal('1000.1234').quantize('0.00000001')`), handle rounding per operation or across calculations, etc.


Why though? What are your arguments for fixed point over decimal floating point. If you ensure a sufficiently large mantissa it will be more resilient in procedures like calculating a small percentage of a small value.


This is a fairly settled issue in finance AFAIK, but to the arguments.

When doing math in finance, we need to be explicit about the precision we use, because we're counting finite things. Things like significant figures and rounding matter, and can't be ignored by imagining we have an "infinite precision" that throws away information, as floating point math does.

Using fixed-point decimal math as default helps mitigate this class of mistakes in this domain. It's similar to using a memory safe language outside embedded programming- if there's no value in the other option, and it's a source of bugs, eliminate it.

NB: Using fixed-point decimal math is similar to the advice to use integers, though it's a bit more flexible (eg keeping amounts in "BTC" with a fixed 8 decimal places instead of "satoshis").




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: