> For the complete documentation index, see [llms.txt](https://blog.sinoastro.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.sinoastro.org/why_0.1_plus_0.2_not_equal_to_0.3.md).

# Why 0.1 + 0.2 != 0.3

讀書百遍而義自見 - 晉・陳壽《三國志・魏志・王肅傳》

## Problem

When you enter 0.1 + 0.2 in Python or JavaScript console, the result is not 0.3. How could this happen?

```
# Python
>>> 0.1+0.2
0.30000000000000004
>>> 0.1+0.2==0.3
False

# JavaScript
> 0.1+0.2
0.30000000000000004
> 0.1+0.2===0.3
false
```

It's quite an old question and there're already many answers in [stackoverflow](https://stackoverflow.com/questions/588004/is-floating-point-math-broken). But I still want to explain it a bit, because I want to (a) get a better understanding of this question, (b) explain this question using my own words.

## Solution

Computers do math in binary, let's convert 0.1 from decimal to binary manually with below method. But usually I just go to [Wolfram Alpha](https://www.wolframalpha.com/input?i=0.1+to+binary) and type "0.1 to binary".

```
0.1 x 2 = 0.2 ... 0
0.2 x 2 = 0.4 ... 0
0.4 x 2 = 0.8 ... 0
0.8 x 2 = 1.6 ... 1
0.6 x 2 = 1.2 ... 1
0.2 x 2 = 0.4 ... 0
...
```

So `0.1` in binary can be represented as $$(0.00011001100110011...)\_2$$, using a scientific notation it's $$(1.1001100110011...)*2\times2^{-4}$$. Similarly $$(0.2)*{10}=(1.1001100110011...)\_2\times2^{-3}$$.

After adding 2 numbers in binary, based on how many digits you keep, you will get results like below.

$$
\begin{align\*} &(1.0011001100110011001100110011001100110011001100110100)*2 \times 2^{-2} \ &=(0.30000000000000004441)*{10} \end{align\*}
$$

That's exactly the same output(except for the rounding) as it is from console!

To conclude, human uses decimal while computer uses binary for arithmetic. Decimal numbers are converted to binary for calculation and then converted back to decimal afterwards. There are **precision lost** during the conversions, so we see the odd output.

## Going Further

### Representing Floating Point Numbers

But it's not yet how it is represented in computer, e.g. [IEEE 754 double-precision binary floating-point format](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) AKA float64, requires numbers to be formatted as below.

![IEEE 754 Double Floating Point Format](https://upload.wikimedia.org/wikipedia/commons/a/a9/IEEE_754_Double_Floating_Point_Format.svg)

Described in formula it's $$(-1)^{sign}(1.b\_{51}b\_{50}...b\_0)\_2\times2^{e-1023}$$.

For `0.1`, `sign` equals to 0 and `e` equals to 1019. So it's $$(-1)^0(1.1001100110011001100110011001100110011001100110011010)\_2 \times 2^{1019-1023}$$.

Written in float64 format and that's how `0.1` is represented in memory:

![0.1 in float64 format, rounded](https://3281271027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkGO6-8FmjChzmb88LQ%2Fuploads%2Fgit-blob-99e5f7a70c7344880d3a25ebf5d982cd35b1d66b%2F0.1.svg?alt=media)

Note that it depends on which number representation standard used by each language. e.g. Python and JavaScript represent floating point numbers using double precision defined by the IEEE 754 standard, but for C, it offers a wide variety of arithmetic types, double precision is not required by the standards. And platform also matters, e.g. float64 will work for a 8-bit machine.

#### Largest and Smallest Numbers

Referenced from [JavaScript: The Definitive Guide, 7th Edition](https://learning.oreilly.com/library/view/javascript-the-definitive/9781491952016/)

> JavaScript represents numbers using the 64-bit floating-point format defined by the IEEE 754 standard, which means it can represent numbers as large as $$\pm1.7976931348623157 × 10^{308}$$ and as small as $$\pm5 × 10^{−324}$$.

When I first read this, I asked myself, how are these largest and smallest numbers calculated? Luckily with the handy online conversion tools I got the answer.

**Largest representable number:** $$+1.7976931348623157\times10^{308}$$ -> [0x7FEFFFFFFFFFFFFF](https://www.binaryconvert.com/result_double.html?hexadecimal=7FEFFFFFFFFFFFFF)

**Smallest number without losing precision:** $$+2.2250738585072014\times10^{-308}$$ -> [0x0010000000000000](https://www.binaryconvert.com/result_double.html?hexadecimal=0010000000000000)

**Smallest representable number:** $$+5\times10^{−324}$$ -> [0x0000000000000001](https://www.binaryconvert.com/result_double.html?hexadecimal=0000000000000001)

### Representing Integers

This part is largely referenced from an article from [Ruan YiFeng's Blog](http://www.ruanyifeng.com/blog/2009/08/twos_complement.html).

A negative number is represented by [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement), a non-negative number is represented by its ordinary binary representation.

#### What is Two's Complement

1 hour clockwise equals 11 hours anti clockwise.

> The two's complement of an $$N$$-bit number is defined as its complement with respect to $$2^N$$; the sum of a number and its two's complement is $$2^N$$.

It's called "**two's**" because it's based on 2, more accurately $$2^N$$**'s complement**. Similarly there are 10's complement(decimal), 12's complement(clock).

Below is an example, assuming numbers are 8-bit.

$$
\begin{align\*} +8 &= 0000,1000 \ -8 &= 1,0000,0000-0000,1000 \ &= 1111,1000 \end{align\*}
$$

$$1,0000,0000$$ can be written as $$1111,1111+0000,0001$$

```
　１１１１１１１１
－００００１０００
－－－－－－－－－ NOT operation
　１１１１０１１１
＋０００００００１
－－－－－－－－－ plus 1
　１１１１１０００
```

#### Why Using Two's Complement

Two's-complement integer representations eliminate the need for separate addition and subtraction units. It simplifies the design of CPU, because it can use one type of circuit for both addition and subtraction.

It also conveys the idea of **unification** in software engineering.

## See Also

* [Computer Systems: A Programmer's Perspective, 3/E](https://csapp.cs.cmu.edu/) -> Chapter 2 - Representing and Manipulating Information
* [Understanding Floating Point Number Representation](https://www.cprogramming.com/tutorial/floating_point/understanding_floating_point_representation.html)
* [Comp 411 - Computer Organization](http://www.csbio.unc.edu/mcmillan/index.py?run=Courses.Comp411F18)
* [MathTex format](https://katex.org/)

\
\
壬寅年谷雨後一日於Düsseldorf
