Observing the error in practice
Let's imagine the following scenario, I want to enroll in the gym and I decided to pay quarterly, I have R$600.90 in cash available and the gym's monthly fee is R$200.30, theoretically if you make this account you have enough money available, but when we try to replicate that logic to code it doesn't:
Now to prove my point, let's look at the same example in Python:
Well, well, who would say not?
The problem: floating point and rounding
To try to avoid confusion, as the concept of floating point is not very easy to understand, let's try to superficially explain the concept, but if you want to dig deep and understand at the root, I recommend reading this article in english .
To understand what a floating point is, you first need to understand that there are many types of numbers and ways to represent them that we will go through. We call 1 an integer – it's an integer with no fractional values.
½ is what the famous fraction is. This implies that the integer 1 is being divided into 2. This concept of fractions is very important when deriving floating points.
0.5 is known as a decimal number. However, a very important distinction needs to be made – 0.5 is just the decimal (base 10) representation of the fraction ½. This is how ½ is represented when written as a base 10 number – for this article, we can call this dot notation. We call 0.5 a finite representation because the numbers in the fraction representation are finite – there are no more numbers after 5 in 0.5. An infinite representation would be, a periodic tithe, for example 0.3333 … when representing ⅓.
There is another way to represent numbers other than whole numbers, fractions or decimal notations. You've probably seen this before, it's the scientific notations, something like this: 6,022 x 10²³ and this is the IEEE 754 format adopted. This format has a 64-bit limitation, so when the number's storage limit is reached, you will need to round the last digit up or down.
There are some proposed solutions, some more restrictive indicate that the best way is to multiply to whole numbers before doing the math:
const myMoney = 600.90 * 100;
const Monthly Fee = 200.30 * 100;
const totalOfMonthlys =PriceOfMonthly *3;
// Outputs: true
// Outputs: 60090
And other solutions use string-based transformation and calculation, which can be useful but comes at the cost of performance.
But then, do all languages have this problem?
Understand that other languages, such as C#, Java, Phyton and many others, also use IEEE-754, so don't think you can get away with this problem by simply changing the language.
The difference is that other languages often have other types of number storage that you can use that avoid these problems. For example, C# has a native decimal type that must be used for tasks such as monetary calculations.