Javascript toFixed Not Rounding
Я использую javascript для привязки к некоторым флажкам, а toFixed(2)
не округляется. Любые идеи, почему это не округление? Например, если число 859.385
, оно отображает только 859.38
вместо 859.39
.
Я также читал, что toFixed
может варьироваться по-разному в зависимости от того, какой браузер вы используете, кто-нибудь знает об этом, чтобы мои вычисления javascript соответствовали моим вычислениям php?
var standardprice = parseFloat($('#hsprice_'+this.id.split('_')[1]).val());
var price = parseFloat($('#hprice_'+this.id.split('_')[1]).val());
var discount = parseFloat($('#hdiscount_'+this.id.split('_')[1]).val());
var deposit = parseFloat($('#hdeposit_'+this.id.split('_')[1]).val());
var currSprice = parseFloat($('#hTotalSprice').val());
var currPrice = parseFloat($('#hTotalPrice').val());
var currDiscount = parseFloat($('#hTotalDiscount').val());
var currDeposit = parseFloat($('#hTotalDeposit').val());
currSprice += standardprice;
currPrice += price;
currDiscount += discount;
currDeposit += deposit;
$('#lblTotalSprice').text('$'+addCommas(currSprice.toFixed(2)));
$('#lblTotalPrice').text('$'+addCommas(currPrice.toFixed(2)));
$('#lblTotalDiscount').text('$'+addCommas(currDiscount.toFixed(2)));
$('#lblTotalDeposit').text('$'+addCommas(currDeposit.toFixed(2)));
$('#hTotalSprice').val(currSprice.toFixed(2));
$('#hTotalPrice').val(currPrice.toFixed(2));
$('#hTotalDiscount').val(currDiscount.toFixed(2));
$('#hTotalDeposit').val(currDeposit.toFixed(2));
Ответы
Ответ 1
Я еще не нашел номер, который toFixed10 делает неправильно. Кто-нибудь еще может?
Благодаря blg
и его ответу, который указал мне на метод Mozilla toFixed10().
Используя это, я придумал этот короткий вкладыш, который действительно охватывает все случаи, упомянутые здесь...
function toFixed( num, precision ) {
return (+(Math.round(+(num + 'e' + precision)) + 'e' + -precision)).toFixed(precision);
}
Ответ 2
В Chrome раунды toFixed()
:
859.385 ==> 859.38
859.386 ==> 859.39
Когда я смотрю спецификацию 5-го выпуска ECMAScript для .toFixed()
(раздел 15.7.4.5), я не вижу, чтобы он явно описывал округление, хотя он описывает что-то довольно тупо, что может быть тем, что Chrome реализовал.
Мне кажется, что если вы хотите контролировать его с явным округлением, то вы, вероятно, должны использовать обходное предложение:
var roundedNum = (Math.round( num * 100 ) / 100).toFixed(2);
Это гарантирует, что вы получите предсказуемое округление, как вы привыкли.
Рабочая демонстрация здесь: http://jsfiddle.net/jfriend00/kvpgE/
Ответ 3
Я сделал это для использования во всех финансовых данных как наилучшую функцию округления. Вы можете проверить его на всех проблемных номерах. Javascript допускает некоторую точность, поэтому я использовал его для округления почти каждого числа, как ожидалось.
function roundTo(n, digits) {
if (digits === undefined) {
digits = 0;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
return Math.round(n) / multiplicator;
}
Ответ 4
Еще одно хорошее число, которое можно попробовать вместе с 35.855 - 1.005
Я не думаю, что решение Robert Messerle обрабатывает 1.005
Пример округления десятичной дроби здесь https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round $ revision/1383484 # Decimal_rounding преобразует числа в экспоненциальную запись и, кажется, дает лучшие результаты.
Я создал скрипку здесь http://jsfiddle.net/cCX5y/2/, которая демонстрирует нативный пример Роберта Мессерла выше (называемый toFixedB
) и тот из документов Mozilla (называемый toFixed10
).
Я еще не нашел номер, который toFixed10 делает неправильно. Кто-нибудь еще может?
Ответ 5
function roundup(num,dec){
dec= dec || 0;
var s=String(num);
if(num%1)s= s.replace(/5$/, '6');
return Number((+s).toFixed(dec));
}
var n= 35.855
roundup(n,2)
/* возвращаемое значение: (Number)
35,86
*/
Ответ 6
Так как в функции toFixed функции javascripts число с плавающей запятой 5
не принадлежит верхней половине целого числа, данное число округляется в меньшую сторону, если у вас есть такие числа:
859.385.toFixed(2)//results in 859.38
на самом деле вы можете добавить конечные числа с плавающей точкой (кроме нуля), как здесь:
859.3851.toFixed(2)//results in 859.39
Поэтому разработчики, как правило, добавляют числа, такие как 0.00000000001
чтобы они были округлены соответствующим образом и чтобы случайно не изменить значение числа.
Поэтому я придумал функцию, которая добавляет такое число в зависимости от того, сколько цифр вы хотите, чтобы число с плавающей запятой фиксировалось:
// both parameters can be string or number
function toFixed(number, decimals) {
var x = Math.pow(10, Number(decimals) + 1);
return (Number(number) + (1 / x)).toFixed(decimals)
}
toFixed(859.385, 2) //results in 859.39
Ответ 7
Вы можете использовать Math.round()
для округления числа. Если вы хотите округлить до определенной десятичной точки, вы можете использовать небольшую математику:
var result=Math.round(original*100)/100
Ответ 8
Сегодня я столкнулся с этой проблемой и даже попробовал предложения в других ответах, я обнаружил, что я все еще не получил ожидаемого результата. Наконец, когда я использую AngularJS для моего текущего проекта, когда я сталкивался с этим, я решил проверить, действительно ли AngularJS решил такую же проблему до и в самом деле. Здесь решение, которое они используют, и оно отлично работает для меня:
function toFixed(number, fractionSize) {
return +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
}
Найдено здесь: Источник angularJS filters.js
Ответ 9
Если вы хотите получить число в качестве вывода, рассмотрите технику Math.round()
в других ответах.
Но если вы хотите получить строку в качестве вывода для представления человеку, то часто n.toLocaleString()
более полезен, чем n.toFixed()
.
Зачем? Потому что это также добавит запятые или точки к голове большого числа, которые люди используют для чтения. Например:
var n = 1859.385
n.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})
// Produces 1,859.39 in USA (locale en-US)
// Produces 1 859,39 in France (locale fr-FR)
// Produces 1.859,39 in Germany (locale de-DE)
В спецификации сказано, что при передаче undefined
в качестве первого аргумента будет использоваться собственный языковой стандарт пользователя (как указано в ОС). К сожалению, как показывает связанная документация, Mozilla использует локализацию en-US в этой ситуации, но в будущем она может соответствовать спецификации.
Ответ 10
Я наткнулся на это, задаваясь вопросом, почему Number.toFixed
вел себя странно. Я вижу, что нативная функция ненадежна, что несчастливо. Заглядывая ответы из любопытства, я вижу, что большинство из них не ведут себя правильно с номером 35.855
, как T.J. Кроудер любезно прокомментировал каждого.
Возможно, это ответит на ваш вопрос.
function toFixed(n,precision) {
var match=RegExp("(\\d+\\.\\d{1,"+precision+"})(\\d)?").exec(n);
if(match===null||match[2]===undefined) {
return n.toFixed(precision);
}
if(match[2]>=5) {
return (Number(match[1])+Math.pow(10,-precision)).toFixed(precision);
}
return match[1];
}
Регулярное выражение разбивает ваш номер на массив строк, например, в toFixed(35.855,2)
: ["35.855", "35.85", "5"]
. Если последнее число (после прецизионного отсечения) >=5
, добавьте Math.pow(10, -precision)
к обрезанному номеру. Это добавит .01
, если вы отрезаете на 2 десятичных знака, .002
на 3, так далее и т.д.
Я не знаю, является ли это надежным, поскольку он по-прежнему выполняет десятичную математику по поплавкам, что может быть непредсказуемым. Я могу сказать, что раунды 35.855
до 35.86
.
Ответ 11
это может помочь
tofix2Decimals=function(float){
if(parseInt(float)==float)return float.toFixed(2);
$decimals=/\.(\d+)/.exec(float)[1].length;
$decimals=$decimals>=2?$decimals+1:3;
float+=Math.pow(10,-$decimals);
return float.toFixed(2);
}
Ответ 12
Это происходит из-за представления плавающей точки JavaScript.
Попробуйте следующее:
Number.prototype.round = function(digits) {
digits = Math.floor(digits);
if (isNaN(digits) || digits === 0) {
return Math.round(this);
}
if (digits < 0 || digits > 16) {
throw 'RangeError: Number.round() digits argument must be between 0 and 16';
}
var multiplicator = Math.pow(10, digits);
return Math.round(this * multiplicator) / multiplicator;
}
Number.prototype.fixed = function(digits) {
digits = Math.floor(digits);
if (isNaN(digits) || digits === 0) {
return Math.round(this).toString();
}
var parts = this.round(digits).toString().split('.');
var fraction = parts.length === 1 ? '' : parts[1];
if (digits > fraction.length) {
fraction += new Array(digits - fraction.length + 1).join('0');
}
return parts[0] + '.' + fraction;
}
Использование:
var n = 859.385;
console.log(n.round(2)); // 859.39
console.log(n.fixed(2)); // 859.39
console.log(n.round(4)); // 859.385
console.log(n.fixed(4)); // 859.3850
Ответ 13
Joy twindle answer здесь должен быть лучшим ответом вместо множества взломов.
x = 1859.385;
x = x.toFixed(2);
alert(x);
дает неправильное округление, т.е. 1859,38 вместо 1859,39
x = 1859.385;
x = x.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
alert(x);
дает правильное округление 1 859,39
Единственная проблема заключается в том, что возвращаемый результат представляет собой строку с разделителем-запятой тысяч и поэтому не может использоваться для вычислений. Используя регулярное выражение, которое я получил от, чтобы удалить запятую, конечный результат
x = 1859.385;
x = x.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
x=x.replace(/\,/g,'');
alert(x);
теперь он возвращает 1859,39 и может быть использован для расчетов. Значение перед регулярным выражением, т.е. 1859,39, можно использовать для отображения html, в то время как неформатированное значение 1859,39 можно использовать для расчетов.
Ответ 14
Я знаю, что это старый вопрос, но почему бы не сделать что-то вроде этого:
let TruncatedValueInString = ThenNumberYouWantToTruncate.toFixed(decPlaces + 1).slice(0, -1);
Ответ 15
toFixed() работает правильно! Проблема в том, что 859.385 не имеет представления как float на компьютере. Сканируется как ближайшее возможное value = 859,384999999999991. И округление этого значения до 2 цифр составляет 859,38, а не 859,39.
Это является причиной того, что многие (особенно старые для торговли, например, COBOL) языки программирования поддерживают числа BCD (двоично-десятичные дроби), где каждая цифра кодируется сама по себе в 4 бита (как шестнадцатеричный код без использования AF).
Общее решение по ценам: - Рассчитайте в центах/копейках и напечатайте NUMBER/100.
Примечание для других решений (функции, представленные здесь): они могут помочь для некоторых чисел, но в основном не работают, например, для 859,38499999.
Ответ 16
MDM имеет надежную реализацию округления. Это более точно, что большинство, если не все ответы здесь.