var a = 0.05
a += 0.01
这时候 a 会等于 0.060000000000000000000005
var a = 0.05
a += 0.01
这时候 a 会等于 0.060000000000000000000005
|
1
二进制保存小数问题,基本上编程语言都有类似的问题
|
|
2
JS 是双精度浮点数,用的 IEEE754 ,因而浮点数数值计算本来就不可能精确
|
|
zoudmAug 1, 2016 via iPhone
3
因为浮点数是实数的近似表示。计算的时候就会产生误差。跟具体什么语言没有关系。
C 里面可以自己决定使用 32 位的 float 或 64 位的 double , python 默认都是 64 位的浮点数。 定义一个 double d = 0.1 ,再 printf("%.20lf", d),就可以知道浮点数是无法准确表示 0.1 的。 |
|
CodingPuppyAug 1, 2016 via Android
4
跟语言没关系
|
|
br00kAug 1, 2016 via iPhone
5
和语言没关系
|
|
InFaNgAug 1, 2016 via Android
6
js 日常背锅
|
|
laoyurAug 1, 2016
7
In [1]: a = 0.05
In [2]: b = 0.01 In [3]: a + b Out[3]: 0.060000000000000005 Python 表示这个锅有 js 帮背,真舒坦 |
|
exoticknightAug 1, 2016
8
心痛 js
|
|
SourceManAug 1, 2016 via iPhone
9
日常背锅
|
|
aristotllAug 1, 2016
10
Js 表示虽然我设计的差 但真不是我的锅啊
|
|
FrankFang128Aug 1, 2016
11
楼主找 block 么
|
|
billleeAug 1, 2016
12
自己计算机基础都没学好,还怪 js
|
|
iVanillaAug 1, 2016
13
我用 PHP 无法还原这个过程,不知什么原因。
<?php $a = 0.05; $a += 0.01; echo $a; ?> 输出: 0.06 |
|
YuJianrongAug 1, 2016
14
|
|
iVanillaAug 1, 2016
15
@YuJianrong 如果数值大一些, PHP 也可以出现类似现象,鸟哥在他的博客有解释: http://www.laruence.com/2013/03/26/2884.html
如果说这帖子是钓鱼的话,只能说钩直饵咸。 |
|
justjavacAug 1, 2016 via Android
17
|
|
18
不知道你有没有听说过一个网站:
http://0.30000000000000004.com/ |
|
iVanillaAug 1, 2016
20
@zhanglintc 看了你这个链接之后用 PHP 复现成功。
<?php ini_set('precision', 17); $a = 0.05; $a += 0.01; echo $a; ?> 官方的解释: http://php.net/manual/zh/ini.core.php#ini.precision 浮点数中显示有效数字的位数。 我看了下, PHP7 的默认值是 14. |
|
zhanglintcAug 1, 2016
21
@iVanilla PHP 不是很熟哦. 不过你一说我突然想起来, 当时 PHP 这段我把我看笑了. PHP 居然如此机智的避开了这个问题.
|
|
russjAug 1, 2016
22
心疼 js
|
|
ljcarsenalAug 1, 2016 via Android
24
不如认真读一下 csapp
|
|
25
0.01 和 0.05 都是二进制下的无限循环小数,没法用 64 bit 表示
所以只能作为双精度浮点数存在 0.01 表示为 0x3f847ae147ae147b, 也就是二进制的 1.0100011110101110000101000111101011100001010001111011 * 2^-7 0.05 表示为 0x3fa999999999999a, 也就是二进制的 1.1001100110011001100110011001100110011001100110011010 * 2^-5 用竖式加起来 1.111010111000010100011110101110000101000111101011100011 * 2^-5 注意这个结果已经比原来的小数长了两位(末尾的 11 ),现在要做四舍五入 0.06 是 1.1110101110000101000111101011100001010001111010111000 * 2^-5 而 0.060000000000000005 是 1.1110101110000101000111101011100001010001111010111001 * 2^-5 显然后者的误差更小。 最后吐槽一下楼主的态度: 实际答案明明是 0.060000000000000005 , 楼主原帖多了六个 0 ,复制粘贴都不会吗,一定要手打? (我一定是知乎玩多了...) |
|
kidenyAug 1, 2016
26
楼主这被打脸的不清啊。
|
|
iVanillaAug 1, 2016
27
@zhanglintc 我开始以为之前很多人在 bugs.php.ne 反馈了,然后官方把这个值改了,不过我去 https://secure.php.net/releases/ 下载了十多年前的 PHP4.3.11 和 PHP5.0.0 ,发现这个值都是 14 。
@11138 很奇怪为什么你那个例子在不改 precision 的情况下能复现。 |
|
hasbugAug 1, 2016
28
IEEE 754···
|
|
11138Aug 1, 2016
29
@iVanilla 设置 precision 影响显示的值的位数(整数部分和小数点部分),但是开始和结尾部分的 0 不算数。
<?php $num = 0.012345600000000000; ini_set("precision", "12"); echo $num; // 0.0123456 echo "\n"; ini_set("precision", "3"); echo $num; // 0.0123 echo "\n"; ini_set("precision", "5"); echo $num; // 0.012346 echo "\n"; ?> |
|
30
@iVanilla 顺便说一句,如果有人要开发一套类似于支付宝的系统(或者 V2EX 的货币系统),那货币的金额一定要是 “ 1 分钱” 的整数倍,而不是有 “ 0.01 元” 这样的数据。所有的数据都要用整型表示,显示的时候再加上小数点,否则时间长了算账的时候会疯掉的。
举个例子,消失的一元钱: >>> 9999999999999999.0 + 1 - 9999999999999999 0.0 |
|
maomaomao001Aug 1, 2016 via Android
31
@kideny 什么叫被大脸????
他不是在好好的问问题吗???? |
|
br00kAug 1, 2016
32
|
|
gilgameshAug 1, 2016
35
|
|
36
「你看似有穷的小数, 在计算机的二进制表示里却是无穷的」
---from http://www.laruence.com/2013/03/26/2884.html |
|
kzzhrAug 1, 2016 via Android
37
相当一部分语言算不好 0.1+0.2-0.3 我记得
|
|
jeffersonpigAug 2, 2016
38
LZ 大一?
|
|
FrankHBAug 2, 2016
39
@lovedebug 你数一下 0 的个数大概就不能指望是 IEEE-754 的双精度了,起码是扩展双精度。
@iVanilla PHP 还真有相关的 bug ,而且曾经造成了比较严重的后果,不过具体表现和系统相关: https://bugs.php.net/53632 |
|
onceyoungAug 2, 2016 via iPhone
41
这个跟语言什么关系?
|
|
winglight2016Aug 2, 2016
42
@y 我做的微信商城的确是这样设计的
|
|
intsilenceAug 2, 2016
44
JavaScript : 怪我咯?
|
|
miss61008596Aug 16, 2016
45
c#的 decimal 和 Java 的 BigDecimal 之所以没有出现精度差异,只是因为在其内部作了相应处理,把这种精度差异给屏蔽掉了,
javascript decimal.js big.js http://mikemcl.github.io/decimal.js/ http://mikemcl.github.io/big.js/ -勤于思,敏于行。 |