This is why you shouldn’t use floats in financial system

Oleg Stadnichenko
3 min readJun 8, 2021

Just imagine if you are using a calculator and trying to add two numbers 0.3 and 0.4, but the result is 0.6999999. I suppose you’ll throw such a calculator. In the world of computer software you could easily receive such results using float numbers. I’ll explain to you why it is so, and what should be used instead. For simplicity I’m going to explain this using Java types, but the same is true for most of the languages with some differences.

Photo by Clayton Robbins

We’ll go through different types of data, and check how they store values.

Bit

The first one is a bit. Understanding the bit is quite straightforward. It can use two different values 0 or 1, sometimes we could say it is off or bit is on.

Byte

Byte consists of 8 bits. Which gives us values ranging from 00000000b to 11111111b, the b — means binary. The highest bit is on the left, like on decimal numbers. Having 8 bits gives us 2⁸ different combinations, and therefore we could store number from 0 to 255. If you want to read more about converting from binary to decimal and backward please read wiki.

For the signed number we could use the highest bit of byte for a sign. If it’s set on then the number is negative, but it’s not just the sign, negative number are stored by decrementing from zero, i.e. -1 is stored as 2⁸-1, which gives us range from -128 to 127 in decimal.

Short, Integer and Long

Short, integer and long are numbers with 2, 4 and 8 bytes respectively. Which gives us ranges from -2¹⁵ to 2¹⁵-1, from -2³¹ to 2³¹-1 and from -2⁶³ to 2⁶³-1 respectively.

Float

Float is quite interesting; it needs to store values with floating points. It takes 4 bytes of data and consists of three parts: sign, exponent and mantissa. Sign is the first highest bit. Exponent takes 8 bits, and the rest 23 bits for the mantissa. The end number looks like this:

where s — sign, m — mantissa, e — exponent.

Mantissa is the value from 0.5 including to 1 excluding represented in binary way. Binary fractions work like decimal fractions: 0.1101 represents 1/2 + 1/4 + 1/16 = 13/16 = 0.8125.Not every decimal number can be represented as a binary fraction. For example 1/10 = 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + … In this case, the number 0.1 is approximated by the closest 23 bit binary fraction 0.00011001100110011001. Since the mantissa always begins with a 1, there is no need to explicitly store this hidden bit.

This way is giving us a range for float numbers from ±1.40129846432481707e-45 to ±3.40282346638528860e+38.

Because of binary storing we couldn’t store any decimal value in the float number, only the approximate number in general. And therefore adding approximate numbers gives us more error in the result and converting to decimal number could give us unexpected results.

BigInteger

For that reason BigInteger was introduced in the java 1.1 version. It stores numbers in decimal representations, but with limitations. You should provide precision of the number, and that is what we want to use in the financial system. And 0.3 and 0.4 would be precisely that numbers in BigInteger and sum will be expected to result in a decimal system.

I hope you found this article helpful. And you’re not going to use the float number to store financial numbers, but only specified types like BigInteger. The same is true for databases.

--

--

Oleg Stadnichenko

🚀 Technical Leader 📚 Like to share my knowledge 🎤 Public Speaker 🏠💻 Live and work in London https://github.com/oleg-sta