Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[未知]如何判断 0.1 + 0.2 与 0.3 相等? #10

Open
mqyqingfeng opened this issue Mar 9, 2020 · 7 comments
Open

[未知]如何判断 0.1 + 0.2 与 0.3 相等? #10

mqyqingfeng opened this issue Mar 9, 2020 · 7 comments

Comments

@mqyqingfeng
Copy link
Owner

No description provided.

@WSQ233
Copy link

WSQ233 commented Mar 9, 2020

function DeviationValue(num1, num2) {
    return Math.abs(num1 - num2) < Number.EPSILON
}

因为JavaScript使用IEEE浮点类型双精度。转换为二进制在计算但是小数无限延伸,二进制截取53位导致精度丢失。
这就是0.1+0.2不为0.3的原因
Number.EPSILON的精度是2^-52,所以只要丢失精度小于Number.EPSILON基本可以确认相等。

@wind-liang
Copy link

主要涉及到 IEEE 754 标椎,分享一下之前自己对浮点数的思考。

常用的 C 语言、java 的浮点数类型均采用的这个规则,js 的话不分整数和浮点数,只有一种数字类型 Number,采用的也是这个规则。

https://zhuanlan.zhihu.com/p/75581822

@mqyqingfeng
Copy link
Owner Author

作为一道面试题,我觉得重要的是要讲出一点其他人一般不会答出来的深度。像这道题,可以从原理和解决方案两个地方作为答题点,最好在编一个案例。大致讲自己遇到过这个问题,于是很好奇深入研究了一下,发现是浮点数精度导致……原理怎样怎样……然后又看了业界的库的源码,然后怎样怎样解决。

关于原理,我专门写了一篇文章 mqyqingfeng/Blog#155 来解释,实际回答的时候,我觉得答出来

  1. 非是 ECMAScript 独有
  2. IEEE754 标准中 64 位的储存格式,比如 11 位存偏移值
  3. 其中涉及的三次精度丢失

就已经 OK 了。

再讲解决方案,这个可以直接搜索到,各种方案都了解一下,比较一下优劣,还可以参考业界的一些库的实现,比如 math.js,不过相关的我并没有看过,后面我会研究一下。

如果还有精力的话,可以从加法再拓展讲讲超出安全值的数字的计算问题。

所以我觉得一能回答出底层实现,二能回答出多种解决方案的优劣,三能拓展讲出 bignum 的问题,就是一个非常完美的回答了。

@Zhengqbbb
Copy link

/**

  • @problem: 问题的出现时因为小数精度丢失导致,那么我们可以使用四舍五入法,通过表达式的结果保留几位小数得到的字符串再转为浮点数
  • @description: 将数学表达式的结果 -> 保留几位小数的字符串 -> 转为为浮点数
  • @param {Number} x 数学表达式
  • @param {Number} j 保留几位小数 || 默认十位
    */
    function toFloatFixed(x, j = 10) {
    return parseFloat(x.toFixed(j));
    }

console.log(toFloatFixed(0.1 + 0.2) === 0.3);

@juice157
Copy link

juice157 commented Jun 4, 2020

/**

  • @problem: 问题的出现时因为小数精度丢失导致,那么我们可以使用四舍五入法,通过表达式的结果保留几位小数得到的字符串再转为浮点数
  • @description: 将数学表达式的结果 -> 保留几位小数的字符串 -> 转为为浮点数
  • @param {Number} x 数学表达式
  • @param {Number} j 保留几位小数 || 默认十位
    */
    function toFloatFixed(x, j = 10) {
    return parseFloat(x.toFixed(j));
    }

console.log(toFloatFixed(0.1 + 0.2) === 0.3);

比如我们在做一些电商项目,涉及到金额这样子的小数运算,用这个方法也是没问题的吧?

@haiyoucuv
Copy link

function floatAdd(a, b) {
    // 先找出小数点后位数最长的长度
    const aLen = a >> 0 === a ? 0 : a.toString().split(".")[1].length;
    const bLen = b >> 0 === b ? 0 : b.toString().split(".")[1].length;
    const L = aLen > bLen ? aLen : bLen;
    
    // 同时缩放到最小整数位后相加
    const S = Math.pow(10, L);
    const vt = a * S + b * S;
    
    // 返回结果再缩放回去
    return vt / S;
}

@GGGorgeous
Copy link

GGGorgeous commented Apr 5, 2023

const floatAddEqual = (a,b,c) => ((a+b-c) < Number.EPSILON);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants