# Float Double 失去精度问题

## 结论先行

* 浮点数计算不精确并不是 bug，因为标准就是这样的。
* 原因简单来说是这样：2 进制的小数无法精确的表达 10 进制小数，计算机在计算 10 进制小数的过程中要先转换为 2 进制进行计算，这个过程中出现了误差。
* 解决方法：对于需要精确结果的场景，别直接使用浮点数进行计算。使用 Decimal 类型。

## 先看个例子

```swift
print(Double(6.6) + Double(1.3))
print(Float(6.6) + Float(1.3))
print(Decimal(6.6) + Decimal(1.3))

// 输出: 
// 7.8999999999999995
// 7.8999996
// 7.9
```

从上面的结果我们可以看到 `Double` 和 `Float` 类型计算 6.6 + 1.3 的时候 结果会和我们预期不一样。 至于为什么会导致这种问题，经过翻阅一些文章和资料，我在下面话题给出答案。

**为什么会导致这种情况么**

> 要解释这个问题，就得从 10 进制与 2 进制的转换说起。

十进制数字在二进制中表示，众所周知，计算机做运算是使用二级制的。所以其实咱们在程序中做 10 进制运算，都是要转换为 2 进制再进行计算的。

**10 进制整数转换为 2 进制的方法可能大家都知道：**

> 除以 2，商继续除以 2，得到 0 为止，将余数逆序排列 例如： 22 / 2 11 余 0 11 / 2 5 余 1 5 / 2 2 余 1 2 / 2 1 余 0 1 / 2 0 余 1 所以 22 的的二进制是 10110

**那 10 进制小数转换为 2 进制的方法呢：**

> 乘以 2，取整，小数部分继续乘以 2，取整，得到小数部分 0 为止，将整数顺序排列 0.8125 x 2 1.625 取 1 0.625 x 2 1.25 取 1 0.25 x 2 0.5 取 0 0.5 x 2 1.0 取 1 所以 0.8125 的二进制是 0.1101

**`那么问题就来了，比如你想计算10进制0.2的2进制:`**

> 0.2 x 2 0.4 0.4 x 2 0.8 0.8 x 2 1.6 0.6 x 2 1.2 0.2 x 2 0.4 ……

发现了吗？它乘不尽，是无限循环的……

而 swift 使用 64 位双精度浮点数存储数字，类似科学计数法，其中 1 位用来存储符号，11 位用来存储指数值，52 位用来存储尾数值（真正的数字），当计算的结果的二进制有效位数超过 52 位时，就会出现精度丢失的问题……

#### 怎么处理

Swift 中已经内置了 `Decimal` 类型，当计算金钱的时候建议使用 `Decimal` 来保证精度问题

```swift
print(Double(6.6) + Double(1.3))
print(Float(6.6) + Float(1.3))
print(Decimal(6.6) + Decimal(1.3))

// 7.8999999999999995
// 7.8999996
// 7.9
```

本文参考： <http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yongpenglovemimi123.gitbook.io/henry/ios/float-double-shi-qu-jing-du-wen-ti.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
