为什么在大多数编程语言中 0.1 + 0.2 不等于 0.3?

简介: 为什么在大多数编程语言中 0.1 + 0.2 不等于 0.3?

前言


在文章开始之前先看下面“诡异”的一幕。

a, b = 0.1, 0.2
print(a + b == 0.3)
print(a + b)
out:
False
0.30000000000000004
复制代码

0.1 + 0.2 == 0.3 结果竟然为 False ?不知道大家第一次见到这个场景作何感想,反正我是有点怀疑人生,为什么会产生这样的结果呢,下面详细看一下。


浮点数的限制


浮点数在计算机硬件中表示为一个以 2 为基数(二进制)的小数。我们先看看如果用十进制和二进制来表示0.125(10)。

十进制

0.125(10)

等于

1\times10^{-1} + 2\times10^{-2} + 5\times10^{-3} = \cfrac{1}{8}

>**二进制**<br> >0.001(2)<br> >$$ 0\times2^{-1} + 0\times2^{-2} + 1\times2^{-3} = \cfrac{1}{8}

这两个小数均表示 0.125(10),唯一真正的区别是第一个是以 10 为基数的小数表示法,第二个则是 2 为基数。


不幸的是,大多数的十进制小数都不能精确地表示为二进制小数,但有些浮点数也能够用二进制精确的表述,条件是位数有限且分母能表示成 2^n 的小数。如 0.5, 0.125。这将导致在大多数情况下,你输入的十进制浮点数都只能近似地以二进制浮点数形式储存在计算机中。


正如上文中的 0.1 ,我们手动计算一下它的二进制结果。

注:十进制整数转二进制方法:除2取余;十进制小数转二进制方法:乘2除整

计算过程:

0.1 * 2 = 0.2 # 0
0.2 * 2 = 0.4 # 0
0.4 * 2 = 0.8 # 0
0.8 * 2 = 1.6 # 1
0.6 * 2 = 1.2 # 1
0.2 * 2 = 0.4 # 0
0.4 * 2 = 0.8 # 0
.....
复制代码


从上面结果可以看出,0.1 的二进制为:

0.0001100110011001100110011001100110011001100110011...
复制代码

这是一个二进制无限循环小数,但计算机内存有限,我们不能储存所有的小数位数。那如何解决呢?

答案就是从末尾某个位置截断,直接取近似值,因此,在目前大部分编程语言(支持处理器浮点运算)中,浮点数都只能近似地使用二进制小数表示。


很多人使用 Python 的时候都不会意识到这个差异的存在,因为 Python 只会输出计算机中存储的二进制值的十进制近似值。但我们要牢记,即使输出的结果看起来好像就是 0.1 的精确值,实际储存的值只是最接近 0.1 的计算机可表示的二进制值。


解决方式


1.decimal

decimal 模块可以进行十进制数学计算,我们将浮点数转成字符串进行运算。

from decimal import Decimal
a, b = Decimal('0.1'), Decimal('0.2')
a + b == Decimal('0.3')
out:True
复制代码


2.numpy.float32

numpy 模块中的32为浮点型保存数据。

import numpy as np
temp = np.array([0.1, 0.2, 0.3], dtype=np.float32)
temp[0] + temp[1] == temp[2]
复制代码


当然体高精度的同时,性能可能会降低,在实际应用中这些近似值造成的细微偏差可能不会造成什么影响。如果碰到了留个心眼就好!

说了这么多,总结出一句话就是:浮点数转二进制时丢失了精度,计算完再转回十进制时和理论结果不同。不知道大家get到了吗?



相关文章
|
6月前
|
C++
在C++语言中比较两个数的大小的方法
在C++语言中比较两个数的大小的方法
1699 1
|
6月前
|
存储 C++
在C++语言中判断是否能被3整除
在C++语言中判断是否能被3整除
479 0
|
5月前
|
存储 Dart 编译器
Dart编程语言中的数值类型与运算
Dart编程语言中的数值类型与运算
125 0
|
Python
Python编程 数值类型 数学计算
Python编程 数值类型 数学计算
11398 0
|
测试技术 Python
Python第2章 数值类型与数学运算(下)
Python第2章 数值类型与数学运算
1257 0
|
算法 Python Windows
Python第2章 数值类型与数学运算(上)
第2章 数值类型与数学运算
243 0
|
程序员 C++ Python
程序员数学基础【三、取模运算(取余运算功能重叠部分)】(Python版本)
程序员数学基础【三、取模运算(取余运算功能重叠部分)】(Python版本)
255 0
程序员数学基础【三、取模运算(取余运算功能重叠部分)】(Python版本)
|
Python
用Python编程语言来实现阿姆斯特朗数的检查
用Python编程语言来实现阿姆斯特朗数的检查
221 0
用Python编程语言来实现阿姆斯特朗数的检查
|
Rust 算法 安全
【算法】5859. 差的绝对值为 K 的数对数目(java / c / c++ / python / go / rust)
给你一个整数数组 nums 和一个整数 k ,请你返回数对 (i, j) 的数目,满足 i < j 且 |nums[i] - nums[j]| == k 。 |x| 的值定义为: 如果 x >= 0 ,那么值为 x 。 如果 x < 0 ,那么值为 -x 。
|
程序员 Python
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(二)
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(二)
209 0
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(二)