|
3 | 3 | | Contents | |
4 | 4 | | :--- | |
5 | 5 | | [How `Numbers` Work and Behave in JS](#how-numbers-work-and-behave-in-js) | |
| 6 | +| [Floating Point (Im)Precision](#floating-point-imprecision) | |
6 | 7 |
|
7 | 8 | ## How [`Numbers`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) Work and Behave in JS |
8 | 9 |
|
@@ -37,3 +38,51 @@ console.log(Number.MAX_VALUE); // 1.7976931348623157e+308 |
37 | 38 | It's worth noting that when performing operations that exceed the representable range or precision, JavaScript doesn't throw an error. Instead, it provides an imprecise result. For example, if you subtract an integer from the smallest representable number, the result may be imprecise due to exceeding the bit range available for numbers. JavaScript will truncate the bits and convert the result back to a decimal number, which may lead to unexpected outcomes. The conversion between the binary system (used internally by JavaScript) and the decimal system (used for output) can be perplexing, but understanding the limitations and potential inaccuracies is essential. |
38 | 39 |
|
39 | 40 | While working with such large numbers or numbers with numerous decimal places is infrequent in everyday programming, it's crucial to be aware of these limitations to avoid unexpected behaviors. |
| 41 | + |
| 42 | +## Floating Point (Im)Precision |
| 43 | + |
| 44 | +In JavaScript, floating-point imprecision refers to the inherent limitations of representing real numbers with floating-point numbers. JavaScript uses the IEEE 754 standard to represent floating-point numbers, which uses a fixed number of bits to represent a decimal number. While this representation is very efficient and suitable for most cases, it comes with some limitations. |
| 45 | + |
| 46 | +One significant limitation is that certain decimal numbers cannot be precisely represented in binary format. As a result, when performing arithmetic operations or comparisons with floating-point numbers in JavaScript, you may encounter unexpected imprecisions, especially when dealing with decimal numbers that have repeating fractions or cannot be represented exactly in binary. |
| 47 | + |
| 48 | +So, in simple terms, floating-point imprecision in JavaScript is a result of the fundamental differences between the binary system used internally by JavaScript and the decimal system in which programmers work. When performing calculations involving decimal numbers with fractions (e.g., 0.1, 0.2, 0.4), the binary representation may lead to slight inaccuracies due to the limitations of representing certain decimal numbers in binary format. |
| 49 | + |
| 50 | +The issue arises because certain fractions, which have repeating fractions in the decimal system, cannot be precisely represented in the binary system. For example, 0.2 in the decimal system is equivalent to 1/5, and 0.4 is equivalent to 2/5. In the binary system, there are certain fractions, like 1/5, for which there is no finite representation (just as there is no perfect representation for 1/3 in the decimal system). |
| 51 | + |
| 52 | +When JavaScript converts these decimal numbers to the binary system for calculations, it may lead to imprecise results. For example, when adding 0.2 and 0.4, the expected result would be 0.6, but due to the binary representation, JavaScript gives a slightly imprecise result (e.g., 0.6000000000000001). As a result, direct equality comparisons between floating-point numbers can lead to unexpected outcomes: |
| 53 | + |
| 54 | +```javascript |
| 55 | +console.log(0.2 + 0.4 === 0.6); // Output: false |
| 56 | +``` |
| 57 | + |
| 58 | +To mitigate this issue, developers can use techniques like using an epsilon value for approximate comparisons. It is recommended to avoid direct equality comparisons between floating-point numbers. Instead, you can use a small tolerance or epsilon value to check if two numbers are approximately equal |
| 59 | + |
| 60 | +```javascript |
| 61 | +function areAlmostEqual(num1, num2, epsilon = 0.0001) { |
| 62 | + return Math.abs(num1 - num2) < epsilon; |
| 63 | +} |
| 64 | + |
| 65 | +console.log(areAlmostEqual(0.1 + 0.2, 0.3)); // Output: true |
| 66 | + |
| 67 | +``` |
| 68 | + |
| 69 | +Or rounding methods like [`toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) to control the number of decimal places displayed to the user. |
| 70 | + |
| 71 | +```javascript |
| 72 | +// Demonstrating Imprecision |
| 73 | +console.log(0.2.toFixed(20)) |
| 74 | +// Output - '0.20000000000000001110' |
| 75 | + |
| 76 | +console.log(0.2.toFixed(2)) |
| 77 | +// Output - '0.20' |
| 78 | +``` |
| 79 | + |
| 80 | +Alternatively, when absolute precision is required, developers may work with integers by multiplying decimal numbers by a fixed factor (e.g., multiplying by 100 to work with cents) to avoid floating-point imprecision. |
| 81 | + |
| 82 | +Readings: |
| 83 | + |
| 84 | +- [Floating-point arithmetic](https://en.wikipedia.org/wiki/Floating-point_arithmetic) |
| 85 | + |
| 86 | +- [2ality – JavaScript and more](https://2ality.com/2012/04/number-encoding.html) |
| 87 | + |
| 88 | +- [Dealing with float precision in Javascript](https://stackoverflow.com/questions/11695618/dealing-with-float-precision-in-javascript) |
0 commit comments