Ожидаемый результат:Javascript toFixed
(1.175).toFixed(2) = 1.18 and
(5.175).toFixed(2) = 5.18
Но в JS показа:
(1.175).toFixed(2) = 1.18 but
*(5.175).toFixed(2) = 5.17*
Как исправить эту проблему?
Ожидаемый результат:Javascript toFixed
(1.175).toFixed(2) = 1.18 and
(5.175).toFixed(2) = 5.18
Но в JS показа:
(1.175).toFixed(2) = 1.18 but
*(5.175).toFixed(2) = 5.17*
Как исправить эту проблему?
Вы всегда можете попробовать использовать круглые, вместо toFixed.
Math.round(5.175*100)/100
Можно даже попробовать положить его в какой-то метод прототипа, если вы хотите.
Создано jsBin, в котором используется простой прототип для номера.
Number.prototype.toFixed = function(decimals) {
return Math.round(this * Math.pow(10, decimals))/(Math.pow(10, decimals));
};
Мне нравится это решение, за исключением того, что вы побеждаете цель функции, которая заключается в том, чтобы обеспечить определенное количество цифр после знаков после запятой. Ваша функция не удалась с цифрами 1, 1.0, 1.00000 и т. Д. Вы можете решить эту проблему, просто добавив «toFixed()» в оператор return, например: «return (Math.round (this * Math.pow (10, десятичные знаки)))/(Math.pow (10, десятичные числа))). ToFixed (decimals); " – stldoug
Мне нравится ваш комментарий, так как я имел дело с той же проблемой, когда я использовал это решение. Проблема с вашим подходом заключается в том, что вы не можете использовать функцию, которую вы переопределяете в определении этой функции. Он переходит в рекурсивную землю лалы. Мое решение здесь https://jsfiddle.net/yxjd78sj/ фиксирует старое определение функции .toFixed() и использует его как .oldToFixed(). Дайте мне знать, что вы думаете! – 3abqari
Это не ошибка. Это связано с тем, что цифры не сохраняются в десятичной форме, но в IEEE754 (так 5.175
не точно).
Если вы хотите, чтобы округлить в определенном направлении (вверх) и вы постоянно имеют номера этой точности, вы можете использовать этот трюк:
(5.175 + 0.00001).toFixed(2)
Это потому, что номера хранятся как IEEE754.
Я бы рекомендовал вам использовать класс Math (круглые, напольные или потолочные методы, в зависимости от ваших потребностей).
Я только что создал класс MathHelper, который может легко решить вашу проблему:
var MathHelper = (function() {
this.round = function (number, numberOfDecimals) {
var aux = Math.pow(10, numberOfDecimals);
return Math.round(number * aux)/aux;
};
this.floor = function (number, numberOfDecimals) {
var aux = Math.pow(10, numberOfDecimals);
return Math.floor(number * aux)/aux;
};
this.ceil = function (number, numberOfDecimals) {
var aux = Math.pow(10, numberOfDecimals);
return Math.ceil(number * aux)/aux;
};
return {
round: round,
floor: floor,
ceil: ceil
}
})();
Использование:
MathHelper.round(5.175, 2)
На самом деле я думаю, что это является ошибка в реализации Number.prototype.toFixed
. Алгоритм, приведенный в ECMA-262 20.1.3.3 10-a говорит, чтобы округлить в качестве тай-брейкера. Как отмечали другие, вероятно, не существует ничьей связи из-за неточности с плавающей запятой в реализации. Но это не делает это правильно.
По крайней мере, такое поведение согласовано между FF, Chrome, Opera, Safari. (Не пробовали другие.)
FWIW, вы действительно можете реализовать свою собственную версию toFixed
за спецификацию в JS, и это ведет себя так, как вы ожидали. См. http://jsfiddle.net/joenudell/7qahrb6d/.
Kippie ваше решение имеет проблемы один из них
39133.005.toFixed(2) => 39133
var Calc = function() {
var self = this;
this.float2Array = function(num) {
var floatString = num.toString(),
exp = floatString.indexOf(".") - (floatString.length - 1),
mant = floatString.replace(".", "").split("").map(function (i) { return parseInt(i); });
return { exp: exp, mant: mant };
};
this.round2 = function (num, dec, sep) {
var decimal = !!dec ? dec : 2,
separator = !!sep ? sep : '',
r = parseFloat(num),
exp10 = Math.pow(10, decimal);
r = Math.round(r * exp10)/exp10;
var rr = Number(r).toFixed(decimal).toString().split('.');
var b = rr[0].replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, "\$1" + separator);
r = (rr[1] ? b + '.' + rr[1] : b);
return r;
};
this.toFixed10 = function (f, num) {
var prepareInt = self.float2Array(f),
naturalInt = prepareInt.mant,
places = Math.abs(prepareInt.exp),
result = prepareInt.mant.slice(),
resultFixedLenth;
// if number non fractional or has zero fractional part
if (f.isInt()) {
return f.toFixed(num);
}
// if the number of decimal places equals to required rounding
if (places === num) {
return Number(f).toString();
}
//if number has trailing zero (when casting to string type float 1.0050 => "1.005" => 005 <0050)
if (places < num) {
return Number(f).round2(num);
}
for (var e = naturalInt.length - (places > num ? (places - num) : 0), s = 0; e >= s; e--) {
if (naturalInt.hasOwnProperty(e)) {
if (naturalInt[e] > 4 && naturalInt[e - 1] < 9) {
result[e] = 0;
result[e - 1] = naturalInt[e - 1] + 1;
break;
} else if (naturalInt[e] > 4 && naturalInt[e - 1] === 9) {
result[e] = 0;
result[e - 1] = 0;
result[e - 2] = naturalInt[e - 2] < 9 ? naturalInt[e - 2] + 1 : 0;
} else if (e === 0 && naturalInt[e] === 9 && naturalInt[e + 1] === 9) {
result[e] = 0;
result.unshift(1);
} else {
break;
}
}
}
if (places - num > 0) {
resultFixedLenth = result.slice(0, -(places - num));
} else {
for (var i = 0, l = num - places; i < l; i++) {
result.push(0);
}
resultFixedLenth = result;
}
return (parseInt(resultFixedLenth.join(""))/Math.pow(10, num)).round2(num);
};
this.polyfill = function() {
if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var T, A, k;
if (this == null) { throw new TypeError(' this is null or not defined'); }
var O = Object(this), len = O.length >>> 0;
if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); }
if (arguments.length > 1) { T = thisArg; }
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
A[k] = mappedValue;
}
k++;
}
return A;
};
}
};
this.init = function() {
self.polyfill();
Number.prototype.toFixed10 = function (decimal) {
return calc.toFixed10(this, decimal);
}
Number.prototype.round2 = function (decimal) {
return calc.round2(this, decimal);
}
Number.prototype.isInt = function() {
return (Math.round(this) == this);
}
}
}, calc = new Calc(); calc.init();
это работает хорошо)
obj = {
round(val) {
const delta = 0.00001
let num = val
if (num - Math.floor(num) === 0.5) {
num += delta
}
return Math.round(num + delta)
},
fixed(val, count = 0) {
const power = Math.pow(10, count)
let res = this.round(val * power)/power
let arr = `${res}`.split('.')
let addZero = ''
for (let i = 0; i < count; i++) {
addZero += '0'
}
if (count > 0) {
arr[1] = ((arr[1] || '') + addZero).substr(0, count)
}
return arr.join('.')
}
}
obj.fixed(5.175, 2)
// "5,18"
Почему это проблема? –
Я не знаю, разрешила ли эта проблема ваша проблема: http://stackoverflow.com/questions/10808671/javascript-how-to-prevent-tofixed-from-rounding-off-decimal-numbers –
Каков ожидаемый результат (5.175). ToFixed (2) –