

都知道0.1+0.2 = 0.30000000000000004,那要怎么让它等于0.3 - 初见雨夜
source link: https://www.cnblogs.com/rainy-night/p/16091646.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

都知道0.1+0.2 = 0.30000000000000004,那要怎么让它等于0.3
小学数学老师教过我们,0.1 + 0.2 = 0.3,但是为什么在我们在浏览器的控制台中输出却是0.30000000000000004?
除了加法有这个奇怪的现象,带小数点的减法和乘除计算也会得出意料之外的结果
console.log(0.3 - 0.1) // 0.19999999999999998
console.log(0.1 * 0.2) // 0.020000000000000004
console.log(0.3 / 0.1) // 2.9999999999999996
我们都知道计算机时是通过二进制来进行计算的,即 0 和 1
就拿 0.1 + 0.2 来说,0.1表示为0.0001100110011001...
,而0.2表示为0.0011001100110011...
而在二进制中 1 + 1 = 10,所以 0.1 + 0.2 = 0.0100110011001100...
转成10进制就近似表示为 0.30000000000000004
简单来说就是,浮点数转成二进制时丢失了精度,因此在二进制计算完再转回十进制时可能会和理论结果不同
对于浮点数的四则运算,许多编程语言都会有理论值和实际值不同的问题。例如Java中也会出现类似的问题,但是Java中可以使用java.math.BigDecimal类来避免这种情况
可是JS是弱类型的语言,作者Brendan Eich自述10天内开发出JS语言,一开始设计的时候就没有对浮点数计算有个处理的好方法
那么在日常开发的前端项目中我们可以怎么解决嘞?
使用toFixed()<不推荐>
可以控制小数点后几位,如果为空的话会用0补充,返回一个字符串
> 0.123.toFixed(2) // '0.12'
- 在不同浏览器中得出的值可能不相同,且部分数字得不到预计的结果,并不是执行严格的四舍五入
// 在chrome控制台中
> 1.014.toFixed(2) // '1.01'
> 1.215.toFixed(2) // '1.22'
> 1.105.toFixed(2) // '1.10'
> 1.115.toFixed(2) // '1.11'
乘以一个10的幂次方
把需要计算的数字乘以10的n次方,让数值都变为整数,计算完后再除以10的n次方,这样就不会出现浮点数精度丢失问题
> (0.1 * 10 + 0.2 *10) / 10 // 0.3
我们可以将它封装成一个函数
mathFloat = function (float, digit) {
const math = Math.pow(10, digit);
return parseInt(float * math, 10) / math;
}
mathFloat(0.1 + 0.2, 3) // 0.3
- JS中的存储都是通过8字节的double浮点类型表示的,因此它并不能准确记录所有数字,它存在一个数值范围
Number.MAX_SAFE_INTEGER为 9007199254740991,而Number.MIN_SAFE_INTEGER为 -9007199254740991,超出这个范围的话JS是无法表示的
虽然范围有限制,但是数值一般都够用
较为完整的实现
function mathPlus(arg1, arg2) {
let r1, r2, m;
try {
r1 = arg1.toString().split(".")[1].length; // 获取小数点后字符长度
} catch (error) {
r1 = 0; // 为整数状态,r1赋0
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (error) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2)); // 确保所有参数都为整数
return (arg1 * m + arg2 * m) / m;
}
> mathPlus(0.1, 0.2); // 0.3
> mathPlus(1, 2); // 3
function mathSubtract(arg1, arg2) {
let r1, r2, m;
try {
r1 = arg1.toString().split(".")[1].length;
} catch (error) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (error) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return ((arg1 * m - arg2 * m) / m);
}
> mathSubtract(0.3, 0.1); // 0.2
> mathSubtract(3, 1); // 2
function mathMultiply(arg1, arg2) {
let m = 0;
let s1 = arg1.toString();
let s2 = arg2.toString();
try {
m += s1.split('.')[1].length; // 小数相乘,小数点后个数相加
} catch (e) {}
try {
m += s2.split('.')[1].length;
} catch (e) {}
return (
(Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) /
Math.pow(10, m)
);
}
> mathMultiply(0.1, 0.2); // 0.02
> mathMultiply(1, 2); // 2
function mathDivide(arg1, arg2) {
let m1 = 0;
let m2 = 0;
let n1 = 0;
let n2 = 0;
try {
m1 = arg1.toString().split('.')[1].length;
} catch (e) {}
try {
m2 = arg2.toString().split('.')[1].length;
} catch (e) {}
n1 = Number(arg1.toString().replace('.', ''));
n2 = Number(arg2.toString().replace('.', ''));
/**
* 将除法转换成乘法
* n1 / n2 必为整数
* 乘以它们的小数点后个数差
*/
return mathMultiply(n1 / n2, Math.pow(10, m2 - m1));
}
// > 0.2 / 0.03 => 6.666666666666667
> mathDivide(0.2, 0.03); // 6.666666666666665
> mathDivide(0.3, 0.1); // 3
> mathDivide(3, 1); // 3
引入第三方库
站在前人的肩膀上,可以前进的更快。下面这些成熟的库封装了很多实用的函数,虽然部分函数可能永远不会用到
Math.js
介绍:功能强大,内置大量函数,体积较大
Github地址:https://github.com/josdejong/mathjs
star: 12.2k+
decimal.js
介绍:支持三角函数等,并支持非整数幂
Github地址:https://github.com/MikeMcl/decimal.js
star: 4.8k+
big.js
介绍:体积6k,提供了CDN
Github地址:https://github.com/MikeMcl/big.js
star: 3.9k+
number-precision
介绍:体积很小,只有1k左右
Github地址:https://github.com/nefe/number-precision
star: 3.4k+
Recommend
-
118
写在前面 今天在看《JavaScript高级程序设计》的时候,注意到书中特意提到了0.1+0.2=0.30000000000000004这样一个浮点数计算错误的问题,觉得很有意思。平时在工作中对于浮点数了解地并不多,正好最近小组同学也遇到了这个问题,准备来总结
-
15
@雨夜漫步大祭司:谈笑有博士,往来无二逼。
-
11
我第一次使用 Linux 服务器是漆黑的界面上只有一行白色字母,末尾还有一个孤独闪烁的光标。我小心翼翼地输入第一个命令 ls,然后重复输入了好几遍界面依旧是漆黑一片。这种感觉就像在漆黑的夜空,天上连一颗星星都没有。伸手不见五指,感觉孤独和...
-
6
雨夜!向赌博窝点进击!_哔哩哔哩_bilibili活动作品雨夜!向赌博窝点进击!79.9万播放 · 3943弹幕2021-07-04 07:18:20 全站排行榜最高第98名
-
3
说到防抖和节流相信大家都不陌生,这两个东西大家可能多多少少都有用到过,最少也有听过 古人云,温故而知新。虽然可能已经很熟悉防抖和节流了,但不妨再看一看巩固一下知识 什么?你说你不仅不会手写防抖和节流,也没有听过。那也没事,下文会详...
-
5
银河系漫游指南 一个白日梦想者的手札
-
19
V2EX › 信息安全 chrome 密码泄漏了, 才知道用 chrome 保存密码等于裸奔
-
5
雨夜惊魂剧情简介 2015年上映,由刘天荣执导,蓝心妍,王李丹妮,董玉峰等主演的《雨夜惊魂》在中国大陆上映。 故事讲述...
-
7
雨夜行车遇路障,“蔚小理”谁能“保命”?《有驾智能评测》首推雨夜AEB实测-品玩
-
1
无论是生活还是工作,我们都是按照自己的计划或者备忘录进行做事情的,比如你计划晚上看一场球赛,非常兴奋的等待着,但是因为今天太困了你没有看到,只能等待第二天才能看重播。那么有没有一种可能,设计个定时任务提前把球赛录制下来,等到第二天再去看呢?...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK