# Float Precision

# Date: 2019/April/15


# 60 seconds

# 問題: 0.1 + 0.2 != 0.3 ?

由於計算機底層使用0與1來代表數字的緣故, 你看見的0.1跟0.2並不是真正的0.1+0.2.
讓電腦實際上去跑一次就知道了:

$a = 0.1 + 0.2;
$b = 0.3;

var_dump(number_format($a, 20, '.', ' '));
var_dump(number_format($b, 20, '.', ' '));
var_dump($a == $b);
1
2
3
4
5
6

實際輸出:

string(22) "0.30000000000000004441"
string(22) "0.29999999999999998890"
bool(false)
1
2
3

# 解決方案

THE FLOATING-POINT GUIDE在php cheat sheet (opens new window)提到了可以使用 bcadd()來做運算,
也可以使用 number_format() 來印出資料.



# 60 minutes

# 為什麼?

THE FLOATING-POINT GUIDE - Binary Fractions (opens new window)有一個非常精美的表格,
解釋了表面上看到的數字, 實際上在電腦裡是怎麼儲存的:

Binary Fractions - How they work

能用二進制表示的不是問題, 可是小數通常都不會是只靠二進制就能解決的.

Binary Fractions - Problems

如圖所示, 可以看到從十進位轉換成二進位時的誤差有多嚴重.

作者提到有三種方式可以解決這種問題:

  1. Limited-Precision Decimal

以PHP來說, 有善心人士寫成的ext-decimal (opens new window), 可以嘗試使用看看.

  1. Arbitrary-Precision Decimal

在PHP裡面就有BCMath與GMP兩種選擇了. 詳細的比較可以參考這則StackOverflow (opens new window).

  1. Symbolic calculations

使用符號來表示數據, 而不是算出數字. 一樣有善心人士提供了套件 (opens new window)使用,
而且還是composer, 最低需求只需要PHP 7!



# References


# 其他參考資料

PHP Manual (2019). Floating point numbers (opens new window).

PHP Manual (2019). BC Math Functions (opens new window).

PHP Manual (2019). number_format — Format a number with grouped thousands (opens new window).

Borgwardt, M. (a.k.a. brazzy) (2010). Basic Answers (opens new window). THE FLOATING-POINT GUIDE.

Last Updated: 2022/7/7 上午8:34:36