我遇到了条件0.1 + 0.2 !== 0.3
的问题。我尝试了0.0001 + 0.0002
,这不等于0.03
。据我所知,我们可以使用toFixed
来解决这个问题。但有没有解决方案来动态解决这个问题?因为我们使用0.1 + 0.2
toFixed(2)
而0.0001 + 0.0002
使用toFixed(4)
。
答案 0 :(得分:2)
您可以扩展Math以包含用于进行数学运算的函数。下面需要两个浮点数,确定最大小数位数然后根据数学然后使用最大小数位数进行固定。
Math.addFloats = function (f1,f2){
//Helper function to find the number of decimal places
function findDec(dec){
var count = 0;
while(dec%1){
dec*=10;
count++;
}
return count;
}
//Determine the greatest number of decimal places
var dec1 = findDec(f1);
var dec2 = findDec(f2);
var fixed = dec1>dec2 ? dec1 : dec2;
//do the math then do a toFixed, could do a toPrecision also
var n = (f1+f2).toFixed(fixed);
return +n;
}
console.log( Math.addFloats(0.1,0.2) == 0.3 ); //evaluates to true
console.log( Math.addFloats(1/3,1/7) ); //prints 0.47619047619047616
console.log( 1/3 + 1/7 ); //prints 0.47619047619047616
没有对它进行全面测试,但做了一些初步测试表明它可以动态工作,可能会修改它来做其他数学运算,但可能需要在进行除数/倍数等时更改小数计数检查
注意:对于电子表示法,这似乎不能很好地计算小数位数,即2e-14
得到的结果如30,应该是14
编辑:将findDec函数更改为查找小数位的this answers version似乎更好地确定不同类型数字的正确小数位数
function findDec(f1){
function isInt(n){
return typeof n === 'number' &&
parseFloat(n) == parseInt(n, 10) && !isNaN(n);
}
var a = Math.abs(f1);
f1 = a, count = 1;
while(!isInt(f1) && isFinite(f1)){
f1 = a * Math.pow(10,count++);
}
return count-1;
}
答案 1 :(得分:0)
(a)如果你正在处理(比如说)美元,那么最好的解决方案是使用整数来做所有事情。 (这只适用于你从不处理一分钱的部分。)
(b)在任何语言中,将双打/浮点数视为“实际值的良好近似值”,绝不与==
进行比较。而是写一个帮手
double nearlyEqual(x,y,tolerance=0.00001) {
return abs(x-y) < tolerance*max(abs(x),abs(y)); }
(警告:未经测试的代码)。
答案 2 :(得分:0)
非常感谢@Patrick。我创建了一个新代码,根据您的代码添加多个浮点数。它是:
/**
* Find the number of decimal places
* @method findDec
* @param {Float|Number} dec
* @return {Number}
*/
var findDec = function (dec) {
var count = 0;
while (dec % 1) {
dec *= 10;
count++;
}
return count;
};
/**
* Find the greatest number of decimal places
* @method findFixed
* @param {Float|Number} dec
* @return {Number}
*/
var findFixed = function () {
var fixed = [];
for (var i = 0, arg; arg = arguments[i]; i++) {
fixed.push(findDec(arg));
}
return Math.max.apply(this, fixed)
};
/**
* Calculate total
* @method findFixed
* @param {Float|Number}
* @return {Float|Number}
*/
var calculate = function () {
var total = 0;
for (var i = 0, arg; arg = arguments[i]; i++) {
total += arg;
}
return total;
}
/**
* Add float number
* @method addNumber
* @param {Float|Number}
* @return {Float|Number}
*/
Math.addNumber = function() {
//Determine the greatest number of decimal places
var fixed = findFixed.apply(this, arguments);
var total = calculate.apply(this, arguments);
//do the math then do a toFixed, could do a toPrecision also
return +total.toFixed(fixed);
}
答案 3 :(得分:0)
使用带有这样的自定义的Number.prototype:
Number.prototype.lenDecimalPoint = function(val){
var decStr = val.toString().match(/\.\d*/);
if(decStr && decStr.length > 0) {
return decStr[0].replace().replace('.','').length;
} else {
return 0;
}
}
Number.prototype.getVal = function(val, stdDec10Val){
var dec10ValLog = Math.log10(stdDec10Val);
var thisValDecPoint = this.lenDecimalPoint(val);
var thisValStr = val.toString();
thisValStr = thisValStr.replace('/^0\./','');
thisValStr = thisValStr.replace('.','');
thisValStr += Math.pow(10 ,dec10ValLog - thisValDecPoint).toString().replace('1','');
return Number(thisValStr);
}
Number.prototype.getDec10Val = function(val1, val2){
var thisDecPoint = this.lenDecimalPoint(val1);
var newNumValDecPoint = this.lenDecimalPoint(val2);
var decPoint = thisDecPoint > newNumValDecPoint ? thisDecPoint : newNumValDecPoint;
return Math.pow(10,decPoint);
}
Number.prototype.add = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number(((thisIntVal) + (newIntVal))/dec10Val);
}
Number.prototype.sub = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number(((thisIntVal) - (newIntVal))/dec10Val);
}
Number.prototype.div = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number(((thisIntVal) / (newIntVal)));
}
Number.prototype.mul = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number((thisIntVal * newIntVal)/Math.pow(dec10Val,2));
}
用法:
(0.1).add(0.3)