-
Notifications
You must be signed in to change notification settings - Fork 836
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? #28
Comments
原因JavaScript 在数字相加时会将数字转成二进制再运算
无限循环在截断时丢失精度,导致 解决利用 toFix 方法来解决精度丢失的问题 function add(a, b) {
return parseFloat((a + b).toFixed(2))
}
console.log(add(0.1, 0.2) === 0.3) //true |
原因因为 JS 采用 IEEE 754 双精度版本(64位) 解决export const addNum = (num1: number, num2: number) => {
let sq1;
let sq2;
let m;
try {
sq1 = num1.toString().split('.')[1].length;
} catch (e) {
sq1 = 0;
}
try {
sq2 = num2.toString().split('.')[1].length;
} catch (e) {
sq2 = 0;
}
m = Math.pow(10, Math.max(sq1, sq2));
return (Math.round(num1 * m) + Math.round(num2 * m)) / m;
};
|
原因由于计算机中所有数据都是以二进制储存的,计算时需要把数据转换成二进制进行计算,再把结果转换成十进制。 解决ES6使用ES6提供的Number.EPSILON方法 function numbersequal(a,b){
return Math.abs(a-b)<Number.EPSILON;
}
var a=0.1+0.2;
var b=0.3;
console.log(numbersequal(a,b)); //true ES6之前把计算数字 提升 10 的N次方倍再除以 10 的N次方。N>1. (0.1*1000+0.2*1000)/1000===0.3 //true |
原因:js使用的 IEEE 754 双精度问题 解决: const toFixed = (a,b,ratio=2)=>parseFloat((a+b).toFixed(ratio))
toFixed(0.1,0.2) |
原因:计算机数值计算采用二进制,而 JS 采用 IEEE 754 双精度版本 (64),在 解决:
二进制运算 + 0.00011001100110011001100110011001100110011001100110011010
- 0.0011001100110011001100110011001100110011001100110011010 二进制转十进制
|
浮点数双精度的问题 ,大数相加 ,也是同样的道理 一、分割字符串 单个相加 再拼起来 |
原因: JS采用 IEEE 754 双精度版本 (64),并且只要采用 IEEE 754 语言的都有该问题 0.00011001100110011001100110011001100110011001100110011010 + 解决办法: ES6: 在es6中,Number有个新的属性EPSILON,在计算机科学技术里面,这个单词的意思为极小值 0.3 - (0.1 + 0.2 ) < Number.EPSILON // true |
Math.abs((0.1+0.2) - 0.3) < Number.EPSILON |
JS采用 IEEE 754 双精度版本 (64), 0.1 + 0.2 会被计算机转成二进制,转换过程中发生了截取,导致计算后的结果再转成 十进制时发生了精度丢失. 转换之后结果正好为:0.30000000000000004 解决方法: 原生: ES6: 在ES6 中,Number有个新的属性,
|
原因:JS 采用 IEEE 754 双精度版本(64位),计算机二进制存储值,循环的数字被裁剪了,就会出现精度丢失的问题 解决方法:
function add(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length;
const num2Digits = (num2.toString().split('.')[1] || '').length;
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum;
} |
计算机中的数字都是以二进制存储的,需要将数字先转为二进制,像0.1、0.2这样的数字在转换为二进制数的时候会出现无限循环。
|
原因在JS中使用Number类型表示数字(整数和浮点数),遵循 IEEE-754 标准,通过64位二进制值来表示一个数字。JS中的数值是十进制的,但是存储到计算机底层以及进行运算的时候,都是先转换为二进制,再进行运算,再转换成十进制。如果数字转换成二进制会存在循环,裁剪后运算会导致精度缺失。 解决方式1.将数字转成整数计算,再转换为小数 const queryDigits = function queryDigits(num) {
num += '';
let [, char = ''] = num.split('.');
return char.length;
};
const plus = function plus(num1, num2) {
num1 = +num1;
num2 = +num2;
if (isNaN(num1) || isNaN(num2)) throw new TypeError('num1/num2 must be an number!');
let num1Digits = queryDigits(num1),
num2Digits = queryDigits(num2),
baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum;
};
console.log(plus(0.1, 0.2)); |
原因在于64位双精度问题处理方式自己整理了下const mathFuns = {
// 加法
add(num1, num2) {
let r1, r2, m;
try { r1 = num1.toString().split('.')[1].length; } catch (e) { r1 = 0; }
try { r2 = num2.toString().split('.')[1].length; } catch (e) { r2 = 0; }
m = Math.pow(10, Math.max(r1, r2));
return (Math.round(num1 * m) + Math.round(num2 * m)) / m;
},
// 减法
sub(num1, num2) {
return mathFuns.add(num1, -num2);
},
// 乘法
mul(num1, num2) {
let m = 0;
const s1 = num1.toString(), s2 = num2.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);
},
// 除法
div(num1, num2) {
let t1 = 0, t2 = 0, r1, r2;
try { t1 += num1.toString().split('.')[1].length; } catch (e) {}
try { t2 += num2.toString().split('.')[1].length; } catch (e) {}
r1 = Number(num1.toString().replace('.', ''));
r2 = Number(num2.toString().replace('.', ''));
if (t1 > t2) r2 = r2 * Math.pow(10, t1 - t2);
if (t2 > t1) r1 = r1 * Math.pow(10, t2 - t1);
return r1 / r2;
},
}; |
原因:1)、JavaScript中数字的存储机制:采用的是IEEE754 双精度64位浮点数 双精度(64位)浮点数的结构:(s) * (2 ^ e) * ( m ) s: sign 符号位: 1bit e: exponent 指数位: 11bit m: mantissa 尾数位: 52bit 排列规则为:符号位S(1位,0为正数,1为负数) + 阶码E(8位) + 尾数M(52位) 2)、0.1和0.2都会先转成二进制再相加,相加之后再转成十进制 0.1转成二进制为 然后用IEEE754 双精度64位浮点数 0.2=> m = 1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 0.1 + 0.2 //(先变成相同的指数再相加) 0.1=> m = 0. 11 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 0.2=> m = 1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 0.1 + 0.2 =
最后转换成十进制为:0.30000000000000004 解决方法 |
1 similar comment
原因:1)、JavaScript中数字的存储机制:采用的是IEEE754 双精度64位浮点数 双精度(64位)浮点数的结构:(s) * (2 ^ e) * ( m ) s: sign 符号位: 1bit e: exponent 指数位: 11bit m: mantissa 尾数位: 52bit 排列规则为:符号位S(1位,0为正数,1为负数) + 阶码E(8位) + 尾数M(52位) 2)、0.1和0.2都会先转成二进制再相加,相加之后再转成十进制 0.1转成二进制为 然后用IEEE754 双精度64位浮点数 0.2=> m = 1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 0.1 + 0.2 //(先变成相同的指数再相加) 0.1=> m = 0. 11 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 0.2=> m = 1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 0.1 + 0.2 =
最后转换成十进制为:0.30000000000000004 解决方法 |
JS使用IEEE 754 双精度,采用二进制表示 |
keyword: IEEE754 、二进制、精度损失
|
原因:js在计算时会转换成二进制去运算,这换算过程出现了精度丢失 (0.1100+0.2100)/100 |
原因:js中小数运算会先将小数转成64位二进制数再进行运算,这样就会导致再转换的时候发生数据的截取导致精度的丢失,导致运算后的结果与预期不符。 解决: |
为什么
0.1 + 0.2 !== 0.3
,请描述原因并手写解决该问题的函数。去答题
新建了一个大厂真题每日打卡群,有意愿学习打卡的再进,请备注打卡。
The text was updated successfully, but these errors were encountered: