We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
如果要深究 IEEE 754 精度为什么会丢失的原理,需要从原码、反码、补码说起。具体可以查看浮点数精度之谜这篇文章。
那么怎么可以避免这种情况呢?
网上不少文章里,提到了直接乘10的n次幂,完了再除以10的n次幂,但是这样也可能碰到问题:
35.41 * 100 = 3540.9999999999995
这里可以采取另一种方法:浮点数toString后indexOf('.'),记录一下小数位的长度,然后将小数点抹掉
toString
indexOf('.')
.
如果是加减乘除,就需要对每一项,都进行1、2步骤的转换。然后选取最长的小数位的项,最终返回的结果除以最长的小数位的长度,得到最终的值。
/*** method ** * add / subtract / multiply /divide * floatObj.add(0.1, 0.2) >> 0.3 * floatObj.multiply(19.9, 100) >> 1990 * */ var floatObj = function() { /* * 判断obj是否为一个整数 */ function isInteger(obj) { return Math.floor(obj) === obj } /* * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100 * @param floatNum {number} 小数 * @return {object} * {times:100, num: 314} times是倍数,num是转换后的整数 */ function toInteger(floatNum) { var ret = {times: 1, num: 0} if (isInteger(floatNum)) { ret.num = floatNum return ret } var strfi = floatNum + '' var dotPos = strfi.indexOf('.') var len = strfi.substr(dotPos+1).length var times = Math.pow(10, len) var intNum = Number(floatNum.toString().replace('.','')) ret.times = times ret.num = intNum return ret } /* * 核心方法,实现加减乘除运算,确保不丢失精度 * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除) * * @param a {number} 运算数1 * @param b {number} 运算数2 * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide) * */ function operation(a, b, op) { var o1 = toInteger(a) var o2 = toInteger(b) var n1 = o1.num var n2 = o2.num var t1 = o1.times var t2 = o2.times var max = t1 > t2 ? t1 : t2 var result = null switch (op) { case 'add': if (t1 === t2) { // 两个小数位数相同 result = n1 + n2 } else if (t1 > t2) { // o1 小数位 大于 o2 result = n1 + n2 * (t1 / t2) } else { // o1 小数位 小于 o2 result = n1 * (t2 / t1) + n2 } return result / max case 'subtract': if (t1 === t2) { result = n1 - n2 } else if (t1 > t2) { result = n1 - n2 * (t1 / t2) } else { result = n1 * (t2 / t1) - n2 } return result / max case 'multiply': result = (n1 * n2) / (t1 * t2) return result case 'divide': result = (n1 / n2) * (t2 / t1) return result } } // 加减乘除的四个接口 function add(a, b) { return operation(a, b, 'add') } function subtract(a, b) { return operation(a, b, 'subtract') } function multiply(a, b) { return operation(a, b, 'multiply') } function divide(a, b) { return operation(a, b, 'divide') } // exports return { add: add, subtract: subtract, multiply: multiply, divide: divide } }();
在来试一下刚才的问题:
35.41 * 100 = 3540.9999999999995 || floatObj.multiply(35.41, 100) // 3541
参考: JS中浮点数精度问题
The text was updated successfully, but these errors were encountered:
No branches or pull requests
如果要深究 IEEE 754 精度为什么会丢失的原理,需要从原码、反码、补码说起。具体可以查看浮点数精度之谜这篇文章。
那么怎么可以避免这种情况呢?
网上不少文章里,提到了直接乘10的n次幂,完了再除以10的n次幂,但是这样也可能碰到问题:
这里可以采取另一种方法:浮点数
toString
后indexOf('.')
,记录一下小数位的长度,然后将小数点抹掉.
给抹掉,并记录一下有多少位小数。如果是加减乘除,就需要对每一项,都进行1、2步骤的转换。然后选取最长的小数位的项,最终返回的结果除以最长的小数位的长度,得到最终的值。
在来试一下刚才的问题:
参考:
JS中浮点数精度问题
The text was updated successfully, but these errors were encountered: