原来 0.1*0.2!=0.02

今天老大一本正经的跟我说要交给我一个重大任务。解决关于0.1*0.2的问题。

0.1*0.2不就等于0.02吗??!!一个小学生都知道的答案,但是程序告诉你0.1*0.2并不是0.02。

事实上,不仅仅是 JS,在其他采用 IEEE754 浮点数标准的语言中,0.1 * 0.2 都不会等于 0.02,0.1+0.2也不会等于0.3,就是这样。

如果以后有人问你0.1+0.2 等于多少,0.1*0.2等于多少可别被坑了,就是这么神奇。

更神奇的是,9007199254740992+1=9007199254740992

  

 

为什么0.1*0.2 不等于0.02呢 0.1+0.2不等于0.3呢,这并不是因为程序出bug 了,因为他在做浮点数学。电脑只能本地存储整数,所以他们需要一些表示十进制数的方法。 这种表示带有一定程度的不准确性。 这就是为什么0.1 + 0.2!= 0.3。

首先我们先来了解一下什么是IEEE标准754浮点数

这个我就不多说了,您请自己看,我说的也没它好。

IEEE Standard 754 Floating Point Numbers

Floating-point arithmetic

 

现在让我们来看关于 0.1,0.2,0.3,它的二进制表示

0.1D=   2^-3 * 0.11001100110011001100110011001100110011001100110011010
0.2D=   2^-2 * 0.11001100110011001100110011001100110011001100110011010
0.3D=   2^-1 * 0.10011001100110011001111001100110011001100110011001100

我是在ionic2 项目中通过npm install了double-bits 和 pad 

然后ts 文件里这样写

import { Component } from '@angular/core';
import * as db from 'double-bits';
import * as pad from 'pad';

@Component({
  selector: 'page-double-bits',
  templateUrl: 'double-bits.html',
})
export class DoubleBits {

  constructor() {
    console.log("0.1D=   " + this.base2Str(0.1));
    console.log("0.2D=   " + this.base2Str(0.2));
    console.log("0.3D=   " + this.base2Str(0.3));
  }

  base2Str(n) {
    var f = db.fraction(n)
    return (db.sign(n) ? "-" : "") +
      "2^" + (db.exponent(n) + 1) +
      " * 0." + pad(f[1].toString(2), 20, "0") +
      pad(f[0].toString(2), 32, "0")
  }
}

输出:

  0.1100110011001100110011001100110011001100110011001101B
+  1.1001100110011001100110011001100110011001100110011010B
= 10.0110011001100110011001100110011001100110011001100111B

将10.0110011001100110011001100110011001100110011001100111B转化成真值,结果为:0.30000000000000004

所以 0.1+0.2=0.30000000000000004 是这样来的了 。

那么如果我一定要 0.1+0.2=0.3呢

然后我找到了 这个 big.js. 一个小而快速的JavaScript库,用于任意精度的十进制算术。

安装

npm install big

导入项目 

import * as Big from 'big.js';
 
使用
this.tt ="0.1*0.2="+ new Big(0.1).times(0.2);
this.mm="0.1+0.2="+new Big(0.1).add(0.2);
 
页面显示结果:

ps:

double-bits  pad big-js

How numbers are encoded in JavaScript 

揭秘 0.1 + 0.2 != 0.3

 

此随笔乃本人学习工作记录,如有疑问欢迎在下面评论,转载请标明出处。

如果对您有帮助请动动鼠标右下方给我来个赞,您的支持是我最大的动力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
(1)顺序查找是一种从头到尾依次查找的算法,其平均查找长度ASL可以通过下面的公式计算: ASL = Σpi * (i+1) + Σqi * (n+1) 其中,pi表示第i个关键字的查找概率,qi表示第i个关键字的查找失败概率,n表示关键字的总数(这里n=5)。 根据题目中的信息,可以得到每个关键字的查找概率pi和查找失败概率qi,如下所示: | 关键字 | 查找成功概率 pi | 查找失败概率 qi | | ------ | --------------- | --------------- | | do | 0.2 | 0.8 | | for | 0.15 | 0.85 | | if | 0.1 | 0.9 | | repeat | 0.03 | 0.97 | | while | 0.01 | 0.99 | 将这些值代入公式,得到顺序查找的平均查找长度ASL为: ASL = 0.2*1 + 0.15*2 + 0.1*3 + 0.03*4 + 0.01*5 + 0.2*6 + 0.15*6 + 0.1*6 + 0.03*6 + 0.02*6 + 0.01*6 = 3.01 因此,顺序查找的平均查找长度为3.01。 (2)折半查找是一种基于比较目标值和中间值的大小来缩小查找范围的算法。在有序顺序表中,折半查找的平均查找长度ASL可以通过下面的公式计算: ASL = ∑(log2(i+1)) * pi + ∑(log2(n+1)) * qi 其中,pi和qi分别表示关键字的查找概率和查找失败概率,n表示关键字的总数。 将题目中的数据代入公式,得到折半查找的平均查找长度ASL为: ASL = (log2(1+1)*0.2 + log2(2+1)*0.15 + log2(3+1)*0.1 + log2(4+1)*0.03 + log2(5+1)*0.01) + (log2(5+1)*0.2 + log2(5+1)*0.15 + log2(5+1)*0.1 + log2(5+1)*0.03 + log2(5+1)*0.02 + log2(5+1)*0.01) = 1.779 因此,折半查找的平均查找长度为1.779。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值