Floating Point Rounding problem in Programming World

Ramsunthar Sivasankar
May 15 · 5 min read
Photo by Volkan Olmez on Unsplash

Before starting anything, Look at the following java program,

What do you think of this code, will it end when i hits 0 ?. lets look at the output,

10.0                                                                                                                    9.9                                                                                                                     9.799999                                                                                                                9.699999                                                                                                                9.599998                                                                                                                9.499998                                                                                                                9.399998                                                                                                                9.299997                                                                                                                9.199997                                                                                                                9.099997                                                                                                                8.999996                                                                                                                8.899996                                                                                                                8.799995                                                                                                                8.699995                                                                                                                8.599995                                                                                                                8.499994                                                                                                                8.399994                                                                                                                8.2999935                                                                                                               8.199993                                                                                                                8.099993                                                                                                                7.999993                                                                                                                7.899993                                                                                                                7.799993                                                                                                                7.699993                                                                                                                7.599993                                                                                                                7.4999933                                                                                                               7.3999934                                                                                                               7.2999935                                                                                                               7.1999936                                                                                                               7.0999937                                                                                                               6.999994                                                                                                                6.899994                                                                                                                6.799994                                                                                                                6.699994                                                                                                                6.599994                                                                                                                6.4999943                                                                                                               6.3999944                                                                                                               6.2999945                                                                                                               6.1999946                                                                                                               6.0999947                                                                                                               5.9999948                                                                                                               5.899995                                                                                                                5.799995                                                                                                                5.699995                                                                                                                5.599995                                                                                                                5.499995                                                                                                                5.3999953                                                                                                               5.2999954                                                                                                               5.1999955                                                                                                               5.0999956                                                                                                               4.9999957                                                                                                               4.899996                                                                                                                4.799996                                                                                                                4.699996                                                                                                                4.599996                                                                                                                4.499996                                                                                                                4.3999963                                                                                                               4.2999964                                                                                                               4.1999965                                                                                                               4.0999966                                                                                                               3.9999967                                                                                                               3.8999968                                                                                                               3.7999969                                                                                                               3.699997                                                                                                                3.599997                                                                                                                3.4999971                                                                                                               3.3999972                                                                                                               3.2999973                                                                                                               3.1999974                                                                                                               3.0999975                                                                                                               2.9999976                                                                                                               2.8999977                                                                                                               2.7999978                                                                                                               2.699998                                                                                                                2.599998                                                                                                                2.499998                                                                                                                2.3999982                                                                                                               2.2999983                                                                                                               2.1999984                                                                                                               2.0999985                                                                                                               1.9999985                                                                                                               1.8999984                                                                                                               1.7999984                                                                                                               1.6999984                                                                                                               1.5999984                                                                                                               1.4999983                                                                                                               1.3999983                                                                                                               1.2999983                                                                                                               1.1999983                                                                                                               1.0999982                                                                                                               0.9999982                                                                                                               0.8999982                                                                                                               0.79999816                                                                                                              0.69999814                                                                                                              0.5999981                                                                                                               0.49999812                                                                                                              0.39999813                                                                                                              0.29999813                                                                                                              0.19999814                                                                                                              0.09999814                                                                                                              -1.861155E-6                                                                                                            -0.100001864                                                                                                            -0.20000187                                                                                                             -0.30000186                                                                                                             -0.40000185                                                                                                             -0.50000185                                                                                                             -0.6000019                                                                                                              -0.7000019                                                                                                              -0.8000019                                                                                                              -0.90000194                                                                                                             -1.0000019                                                                                                              -1.1000019
.
.
.
.

This should go like 10.0,9.9,9.8,…. right ?. So then what happened?. This run without stopping. I have just copied the few lines of output to show here. Its because of the IEEE 754 floating point representation.

In computer there is a technical standard called IEEE 754 and that used to represent the floating-points numbers. And it has three main components as follows,

Sign — This consist only single bit of the binary notation and if its 1 the value is negative and 0 for positive.

Exponent — While representing the exponent, it should include both positive and the negative value. And can be represented in 2⁸ number of bits.
The range is -128 to 127 (this 127 is called as Exponent Bias) which means, if the power of 2 in Scientific notation value is positive then it must be added with the as Exponent Bias and takes in the exponent.

Mantissa — Mantissa is the binary representation of the scientific notation for base 2 number. In here only the value comes after the decimal point of scientific notation will be taken out.

components of IEEE

Lets look into an example,

I am going to convert 9.1 into to binary, for that we have convert 9 into binary and that gives the value 1001. now lets convert 0.1 and this is where things get interesting. It needs to be multiplied by 2 until two times become 1.0 So lets see how it goes, (This suppose to repeat until you find a pattern in the series).

converting 0.1 into binary

As I’ve showed in the above figure, it is never going to end. So the shaded part is going to repeat as a set. so lets write the binary format,

for 0.1 👇

0001100110011001100…………

for 9 👇

1001

So for 9.1 👇

1001.0001100110011001100…………

So this is how it looks like in scientific notation,

1.0010001100110011001100…… x 2³

Now Lets show it in the IEEE representation. Based on the theory, if the power is positive it should be added with the Exponent Bias (127). In our case it is 3 and it is positive as well. Then if we add 3+127 which is 130. Now lets convert that to binary to get the Exponent part.

10000010

Now lets look at the Mantissa, it only takes 23 bit so the binary value of 9.1 is 1.0010001100110011001100…… x 2³ and the Mantissa will be 00100011001100110011001

Now lets write the the value, since 9.1 is positive number so the sign bit is zero

0 | 10000010 | 00100011001100110011001

So, the representation according to IEEE standard is 01000001000100011001100110011001. But what computer does is, if the 24th bit is 1, it will add 1 to the 23rd bit (if 0 it doesn’t matter) and store.

So the answer would be 01000001000100011001100110011010 (Because in our case the 24th bit is 1 so it was added to the 23rd bit). Even if you check this with calculator you will get this answer.

Now lets se what will be the answer when we convert this value back to decimal,

Binary to Decimal conversion

So this is the floating point rounding problem. There are multiple solution for this problem, one is using an appropriate data type. In Java(Since I am a Java developer 😏) we can use BigDecimal and lets talk about it.

BigDecimal in Java

The BigDecimal class is a arbitrary-precision signed decimal numbers and provides operations for arithmetic, scale manipulation, rounding, comparison, hashing, and format conversion. this consist of 2 parts,

  • Unscaled value — an arbitrary precision integer.
  • Scale — a 32-bit integer representing the number of digits to the right of the decimal point.

We use BigDecimal for high-precision arithmetic. We also use it for calculations requiring control over scale and rounding off behavior. And it also has excellent accuracy when dealing with both big and tiny floating-point values. To initialize BigDecimal, it has numerous constructors. To build a BigDecimal object, an integer, string, or double value can be passed as the argument.

BigDecimal(int val)
BigDecimal(String val)
BigDecimal(double val)
BigDecimal(BigInteger val)
and more

It has lot of methods that we can use such as,

add(BigDecimal augend)
divide(BigDecimal divisor)
compareTo(BigDecimal val)
and more

Now lets solve the problem with BigDecimal,

In here I have imported math library because it has the BigDecimal class. So when I run this I got the output as follows,

10
9.9
9.8
9.7
9.6
9.5
9.4
9.3
9.2
9.1
9.0
8.9
8.8
8.7
8.6
8.5
8.4
8.3
8.2
8.1
8.0
7.9
7.8
7.7
7.6
7.5
7.4
7.3
7.2
7.1
7.0
6.9
6.8
6.7
6.6
6.5
6.4
6.3
6.2
6.1
6.0
5.9
5.8
5.7
5.6
5.5
5.4
5.3
5.2
5.1
5.0
4.9
4.8
4.7
4.6
4.5
4.4
4.3
4.2
4.1
4.0
3.9
3.8
3.7
3.6
3.5
3.4
3.3
3.2
3.1
3.0
2.9
2.8
2.7
2.6
2.5
2.4
2.3
2.2
2.1
2.0
1.9
1.8
1.7
1.6
1.5
1.4
1.3
1.2
1.1
1.0
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1

Ta-da 🥳. We got the answer.

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.

Ramsunthar Sivasankar

Written by

Associate Software Engineer at Virtusa

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.