Я хотел бы округлить максимум 2 десятичных знака, но только при необходимости.
Входные данные:
10
1.7777777
9.1
Вывод:
10
1.78
9.1
Как я могу сделать это в JavaScript
?
Используйте Math.round(num * 100) / 100
Если значение представляет собой текстовый тип:
parseFloat("123.456").toFixed(2);
Если значение представляет собой число:
var numb = 123.23454;
numb = numb.toFixed(2);
Существует недостаток, что значения, такие как 1,5, будут давать "1,50" в качестве вывода. Исправление, предложенное @minitech:
var numb = 1.5;
numb = +numb.toFixed(2);
// Note the plus sign that drops any "extra" zeroes at the end.
// It changes the result (which is a string) into a number again (think "0 + foo"),
// which means that it uses only as many digits as necessary.
Кажется, что Math.round
- лучшее решение. Но это не так! В некоторых случаях он будет НЕ округлен правильно:
Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!
В некоторых случаях toFixed() также будет НЕ округлять (проверено в Chrome v.55.0.2883.87)!
Примеры:
parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.
parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.
// However, it will return correct result if you round 1.5551.
parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.
1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.
// However, it will return correct result if you round 1.35551.
1.35551.toFixed(2); // Returns 1.36 as expected.
Я думаю, это потому, что 1.555 на самом деле что-то вроде float 1.55499994 за кулисами.
Решение 1 - использовать script с требуемым алгоритмом округления, например:
function roundNumber(num, scale) {
if(!("" + num).includes("e")) {
return +(Math.round(num + "e+" + scale) + "e-" + scale);
} else {
var arr = ("" + num).split("e");
var sig = ""
if(+arr[1] + scale > 0) {
sig = "+";
}
return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
}
}
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
Решение 2 состоит в том, чтобы избежать вычислений переднего конца и вытащить округленные значения с серверного сервера.
parseFloat(number.toFixed(decimalPlaces));
@PerLundberg
Вы можете использовать
function roundToTwo(num) {
return +(Math.round(num + "e+2") + "e-2");
}
Я нашел это на MDN. Их способ избегает проблемы с 1.005, о которой упоминалось.
roundToTwo(1.005)
1.01
roundToTwo(10)
10
roundToTwo(1.7777777)
1.78
roundToTwo(9.1)
9.1
roundToTwo(1234.5678)
1234.57
+(val)
- эквивалент приведения Number(val)
. Конкатенация «e-2» с числом привела к появлению строки, которую необходимо преобразовать обратно в число.
Ответ MarkG правильный. Здесь общее расширение для любого числа десятичных знаков.
Number.prototype.round = function(places) {
return +(Math.round(this + "e+" + places) + "e-" + places);
}
Использование:
var n = 1.7777;
n.round(2); // 1.78
Unit test:
it.only('should round floats to 2 places', function() {
var cases = [
{ n: 10, e: 10, p:2 },
{ n: 1.7777, e: 1.78, p:2 },
{ n: 1.005, e: 1.01, p:2 },
{ n: 1.005, e: 1, p:0 },
{ n: 1.77777, e: 1.8, p:1 }
]
cases.forEach(function(testCase) {
var r = testCase.n.round(testCase.p);
assert.equal(r, testCase.e, 'didn\'t get right number');
});
})
function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
Можно использовать .toFixed(NumberOfDecimalPlaces)
.
var str = 10.234.toFixed(2); // => '10.23'
var number = Number(str); // => 10.23
Этот вопрос сложный.
Предположим, что у нас есть функция roundTo2DP(num)
, которая принимает float как аргумент и возвращает значение, округленное до 2 десятичных знаков. Что должно оценивать каждое из этих выражений?
roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
"Очевидный" ответ заключается в том, что первый пример должен округляться до 0,01 (потому что он ближе к 0,01, чем к 0,02), в то время как другие два должны округляться до 0,02 (поскольку 0.0150000000000000001 ближе к 0,02, чем к 0,01, а потому, что 0,015 является точно на полпути между ними, и есть математическое соглашение о том, что такие числа округляются).
Ловушка, о которой вы, возможно, догадались, заключается в том, что roundTo2DP
не может быть реализована, чтобы дать эти очевидные ответы, потому что все три числа, переданные ей, имеют одинаковое число. Бинарные числа с плавающей запятой IEEE 754 (тип, используемый JavaScript) не могут точно представлять большинство нецелочисленных чисел, поэтому все три числовых литерала выше округляются до близкого действительного числа с плавающей запятой. Это число, как это бывает, точно соответствует
0,01499999999999999944488848768742172978818416595458984375
что ближе к 0,01, чем к 0,02.
Вы можете видеть, что все три номера одинаковы на вашей консоли браузера, оболочке Node или другом интерпретаторе JavaScript. Просто сравните их:
> 0.014999999999999999 === 0.0150000000000000001
true
Итак, когда я пишу m = 0.0150000000000000001
, точное значение m
, которое я заканчиваю, ближе к 0.01
, чем к 0.02
. И все же, если я преобразую m
в String...
> var m = 0.0150000000000000001;
> console.log(String(m));
0.015
> var m = 0.014999999999999999;
> console.log(String(m));
0.015
... Я получаю 0,015, который должен округляться до 0,02, и это заметно не 56-значное число, которое я ранее говорил, что все эти числа были в точности равны. Итак, что такое темная магия?
Ответ можно найти в спецификации ECMAScript, в разделе 7.1.12.1: ToString применяется к типу Number. Здесь устанавливаются правила преобразования некоторого числа m в строку. Ключевой частью является точка 5, в которой генерируется целое число s, цифры которого будут использоваться в строковом представлении m:
пусть n, k и s - целые числа, такие, что k ≥ 1, 10 k -1 ≤ s < 10 k числовое значение для s × 10 n - k равно m, и k как можно меньше. Заметим, что k - это число цифр в десятичном представлении s, что s не делится на 10 и что наименее значимая цифра s не обязательно однозначно определяется этими критериями.
Ключевой частью здесь является требование, чтобы "k было как можно меньше". Это требование является требованием, чтобы, учитывая число m
, значение String(m)
должно иметь наименьшее возможное количество цифр, в то же время удовлетворяя требованию, что Number(String(m)) === m
. Поскольку мы уже знаем, что 0.015 === 0.0150000000000000001
, теперь ясно, почему String(0.0150000000000000001) === '0.015'
должно быть истинным.
Конечно, ни одно из этих обсуждений прямо не ответило на то, что должен вернуться roundTo2DP(m)
. Если точное значение m
равно 0,0149999999999999999944488848768742172978818416595458984375, но его строковое представление "0,015", тогда какой правильный ответ - математически, практически, философски или что-то еще - когда мы округлим его до двух знаков после запятой?
На этот вопрос нет единого правильного ответа. Это зависит от вашего варианта использования. Вероятно, вы хотите уважать представление String и кругом вверх, когда:
С другой стороны, вы, вероятно, хотите уважать двоичное значение с плавающей запятой и округлять вниз, когда ваше значение происходит из непрерывного масштаба - например, если это считывание с датчика.
Эти два подхода требуют разного кода. Чтобы уважать строковое представление числа, мы можем (с довольно небольшим количеством разумно тонкого кода) реализовать наше собственное округление, которое действует непосредственно на строковое представление, по цифре, используя тот же алгоритм, который вы использовали бы в школе, когда вы учили, как округлить числа. Ниже приведен пример, в котором соблюдается требование OP о представлении числа до двух знаков после запятой "только при необходимости" путем удаления конечных нулей после десятичной точки; вы, конечно, можете настроить его на точные нужды.
/**
* Converts num to a decimal string (if it isn't one already) and then rounds it
* to at most dp decimal places.
*
* For explanation of why you'd want to perform rounding operations on a String
* rather than a Number, see http://stackoverflow.com/a/38676273/1709587
*
* @param {(number|string)} num
* @param {number} dp
* @return {string}
*/
function roundStringNumberWithoutTrailingZeroes (num, dp) {
if (arguments.length != 2) throw new Error("2 arguments required");
num = String(num);
if (num.indexOf('e+') != -1) {
// Can't round numbers this large because their string representation
// contains an exponent, like 9.99e+37
throw new Error("num too large");
}
if (num.indexOf('.') == -1) {
// Nothing to do
return num;
}
var parts = num.split('.'),
beforePoint = parts[0],
afterPoint = parts[1],
shouldRoundUp = afterPoint[dp] >= 5,
finalNumber;
afterPoint = afterPoint.slice(0, dp);
if (!shouldRoundUp) {
finalNumber = beforePoint + '.' + afterPoint;
} else if (/^9+$/.test(afterPoint)) {
// If we need to round up a number like 1.9999, increment the integer
// before the decimal point and discard the fractional part.
finalNumber = Number(beforePoint)+1;
} else {
// Starting from the last digit, increment digits until we find one
// that is not 9, then stop
var i = dp-1;
while (true) {
if (afterPoint[i] == '9') {
afterPoint = afterPoint.substr(0, i) +
'0' +
afterPoint.substr(i+1);
i--;
} else {
afterPoint = afterPoint.substr(0, i) +
(Number(afterPoint[i]) + 1) +
afterPoint.substr(i+1);
break;
}
}
finalNumber = beforePoint + '.' + afterPoint;
}
// Remove trailing zeroes from fractional part before returning
return finalNumber.replace(/0+$/, '')
}
Пример использования:
> roundStringNumberWithoutTrailingZeroes(1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes(10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes(0.015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes('0.015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'
Вышеупомянутая функция, вероятно, вы хотите использовать, чтобы пользователи никогда не видели числа, которые они ввели, закругленные неправильно.
(В качестве альтернативы вы также можете попробовать библиотеку round10, которая обеспечивает аналогичную работу с совершенно другой реализацией).
Но что, если у вас есть второй вид Number - значение, взятое из непрерывного масштаба, где нет оснований думать, что приближенные десятичные представления с меньшим количеством знаков после запятой более точны, чем те, у кого больше? В этом случае мы не хотим уважать представление String, потому что это представление (как поясняется в спецификации) уже имеет округлую форму; мы не хотим ошибаться, говоря "0.014999999... 375 раундов до 0,015, которые округляются до 0,02, поэтому 0,014999999... 375 раундов до 0,02".
Здесь мы можем просто использовать встроенный метод toFixed
. Обратите внимание, что, вызывая Number()
в String, возвращаемом toFixed
, мы получаем Number, представление String которого не имеет конечных нулей (благодаря тому, как JavaScript вычисляет строковое представление числа, обсуждавшегося ранее в этом ответе).
/**
* Takes a float and rounds it to at most dp decimal places. For example
*
* roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
*
* returns 1.234
*
* Note that since this treats the value passed to it as a floating point
* number, it will have counterintuitive results in some cases. For instance,
*
* roundFloatNumberWithoutTrailingZeroes(0.015, 2)
*
* gives 0.01 where 0.02 might be expected. For an explanation of why, see
* http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
* roundStringNumberWithoutTrailingZeroes function there instead.
*
* @param {number} num
* @param {number} dp
* @return {number}
*/
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
var numToFixedDp = Number(num).toFixed(dp);
return Number(numToFixedDp);
}
/**
* Takes a float and rounds it to at most dp decimal places. For example
*
* roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
*
* returns 1.234
*
* Note that since this treats the value passed to it as a floating point
* number, it will have counterintuitive results in some cases. For instance,
*
* roundFloatNumberWithoutTrailingZeroes(0.015, 2)
*
* gives 0.01 where 0.02 might be expected. For an explanation of why, see
* http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
* roundStringNumberWithoutTrailingZeroes function there instead.
*
* @param {number} num
* @param {number} dp
* @return {number}
*/
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
var numToFixedDp = Number(num).toFixed(dp);
return Number(numToFixedDp);
}
roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)
. Ожидаемый результат (как в echo round(362.42499999999995, 2)
PHP echo round(362.42499999999995, 2)
): 362.43
. Фактический результат: 362.42
round
PHP дает 362,43. Это кажется интуитивно неправильным, поскольку 362.42499999999995 меньше 362,425 (в математике и в коде - 362.42499999999995 < 362.425
верно как для JS, так и для PHP). Ответ PHP также не минимизирует расстояние между исходным и округленным числами с плавающей запятой, поскольку 362.43 - 362.42499999999995 > 362.42499999999995 - 362.42
. Согласно php.net/manual/en/function.round.php , round
PHP соответствует стандарту C99; Я должен рискнуть в страну Си, чтобы понять, что происходит.
Точный метод округления. Источник: Mozilla
(function(){
/**
* Decimal adjustment of a number.
*
* @param {String} type The type of adjustment.
* @param {Number} value The number.
* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
* @returns {Number} The adjusted value.
*/
function decimalAdjust(type, value, exp) {
// If the exp is undefined or zero...
if (typeof exp === 'undefined' || +exp === 0) {
return Math[type](value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
return NaN;
}
// Shift
value = value.toString().split('e');
value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
}
// Decimal round
if (!Math.round10) {
Math.round10 = function(value, exp) {
return decimalAdjust('round', value, exp);
};
}
// Decimal floor
if (!Math.floor10) {
Math.floor10 = function(value, exp) {
return decimalAdjust('floor', value, exp);
};
}
// Decimal ceil
if (!Math.ceil10) {
Math.ceil10 = function(value, exp) {
return decimalAdjust('ceil', value, exp);
};
}
})();
Примеры:
// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50
Math.round10(3544.5249, -2)
возвращает 3544,52 вместо 3544,53
Ни один из найденных здесь ответов не является правильным.. @stinkycheeseman попросил округлить, вы все округлили число.
Чтобы округлить, используйте это:
Math.ceil(num * 100)/100;
Рассмотрим .toFixed()
и .toPrecision()
:
Вы должны использовать:
Math.round( num * 100 + Number.EPSILON ) / 100
Кажется, никто не знает о Number.EPSILON
.
Также стоит отметить, что это не странность JavaScript, как некоторые люди заявили.
Это просто способ чисел с плавающей запятой работает на компьютере. Как и 99% языков программирования, JavaScript не имеет домашних чисел с плавающей запятой; для этого он использует CPU/FPU. Компьютер использует двоичный код, а в двоичном выражении нет чисел, таких как 0.1
, а просто двоичное приближение для этого. Зачем? По той же причине, что и 1/3 не может быть записано в десятичной форме: ее значение равно 0.33333333... с бесконечностью трех.
Вот и Number.EPSILON
. Это число является разницей между 1 и следующим числом, существующим в числах с плавающей запятой двойной точности. Это: Нет числа от 1
до 1 + Number.EPSILON
.
РЕДАКТИРОВАТЬ:
Как указано в комментариях, давайте проясним одно: добавление Number.EPSILON
имеет значение только тогда, когда значение round равно результатом арифметической операции, так как оно может усвоить некоторую ошибку Number.EPSILON
плавающей запятой.
Это не полезно, когда значение исходит от прямого источника (например: буква, вход пользователя или датчик).
Вот простой способ сделать это:
Math.round(value * 100) / 100
Возможно, вы захотите сделать еще одну функцию, чтобы сделать это для вас:
function roundToTwo(value) {
return(Math.round(value * 100) / 100);
}
Затем вы просто передадите значение.
Вы можете увеличить его до округления до любого произвольного числа десятичных знаков, добавив второй параметр.
function myRound(value, places) {
var multiplier = Math.pow(10, places);
return (Math.round(value * multiplier) / multiplier);
}
+(10).toFixed(2); // = 10
+(10.12345).toFixed(2); // = 10.12
(10).toFixed(2); // = 10.00
(10.12345).toFixed(2); // = 10.12
+(0.015).toFixed(2) == 0.01
.
2017
Просто используйте собственный код .toFixed()
number = 1.2345;
number.toFixed(2) // "1.23"
Если вам нужно быть строгим и добавлять цифры, то при необходимости он может replace
number = 1; // "1"
number.toFixed(5).replace(/\.?0*$/g,'');
Для меня Math.round() не дал правильного ответа. Я обнаружил, что toFixed (2) работает лучше. Ниже приведены примеры обоих:
console.log(Math.round(43000 / 80000) * 100); // wrong answer
console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer
Попробуйте это облегченное решение:
function round(x, digits){
return parseFloat(x.toFixed(digits))
}
round(1.222, 2) ;
// 1.22
round(1.222, 10) ;
// 1.222
return Number(x.toFixed(digits))
?
Есть несколько способов сделать это. Для таких людей, как я, вариант Lodash
function round(number, precision) {
var pair = (number + 'e').split('e')
var value = Math.round(pair[0] + 'e' + (+pair[1] + precision))
pair = (value + 'e').split('e')
return +(pair[0] + 'e' + (+pair[1] - precision))
}
Применение:
round(0.015, 2) // 0.02
round(1.005, 2) // 1.01
Если ваш проект использует jQuery или lodash, вы также можете найти правильный метод round
в библиотеках.
Я удалил вариант n.toFixed(2)
, потому что это неверно. Спасибо @avalanche1
Number.toFixed()
вернет строку, но с символом плюс перед ней, интерпретатор JS преобразует строку в число. Это синтаксис сахара.
MarkG и Lavamantis предложили гораздо лучшее решение, чем тот, который был принят. Стыдно, что они не получают больше бонусов!
Вот функция, которую я использую для решения задач с десятичными знаками с плавающей запятой также на основе MDN. Он еще более общий (но менее краткий), чем решение Lavamantis:
function round(value, exp) {
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
Используйте его с помощью:
round(10.8034, 2); // Returns 10.8
round(1.275, 2); // Returns 1.28
round(1.27499, 2); // Returns 1.27
round(1.2345678e+2, 2); // Returns 123.46
По сравнению с решением Lavamantis мы можем сделать...
round(1234.5678, -2); // Returns 1200
round("123.45"); // Returns 123
Если вы используете библиотеку lodash, вы можете использовать круглый метод lodash, как показано ниже.
_.round(number, precision)
Например:
_.round(1.7777777, 2) = 1.78
var roundUpto = function(number, upto){
return Number(number.toFixed(upto));
}
roundUpto(0.1464676, 2);
toFixed(2)
здесь 2 - количество цифр, до которых мы хотим округлить это число.
Это может помочь вам:
var result = (Math.round(input*100)/100);
для получения дополнительной информации, вы можете посмотреть эту ссылку
Используйте что-то вроде этого "parseFloat (parseFloat (значение).toFixed(2))"
parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78
parseFloat(parseFloat("10").toFixed(2))-->10
parseFloat(parseFloat("9.1").toFixed(2))-->9.1
Самый простой способ:
+num.toFixed(2)
Он преобразует его в строку, а затем обратно в целое число/float.
В общем, округление выполняется путем масштабирования: round(num/p) * p
Использование экспоненциальной нотации позволяет правильно округлить число +ve. Тем не менее, этот метод не позволяет правильно обработать края -ve.
function round(num, precision = 2) {
var scaled = Math.round(num + "e" + precision);
return Number(scaled + "e" + -precision);
}
// testing some edge cases
console.log( round(1.005, 2) ); // 1.01 correct
console.log( round(2.175, 2) ); // 2.18 correct
console.log( round(5.015, 2) ); // 5.02 correct
console.log( round(-1.005, 2) ); // -1 wrong
console.log( round(-2.175, 2) ); // -2.17 wrong
console.log( round(-5.015, 2) ); // -5.01 wrong
Здесь также есть одна функция, которую я написал для правильного арифметического округления. Вы можете проверить это самостоятельно.
/**
* MidpointRounding away from zero ('arithmetic' rounding)
* Uses a half-epsilon for correction. (This offsets IEEE-754
* half-to-even rounding that was applied at the edge cases).
*/
function RoundCorrect(num, precision = 2) {
// half epsilon to correct edge cases.
var c = 0.5 * Number.EPSILON * num;
// var p = Math.pow(10, precision); //slow
var p = 1; while (precision--> 0) p *= 10;
if (num < 0)
p *= -1;
return Math.round((num + c) * p) / p;
}
// testing some edge cases
console.log(RoundCorrect(1.005, 2)); // 1.01 correct
console.log(RoundCorrect(2.175, 2)); // 2.18 correct
console.log(RoundCorrect(5.015, 2)); // 5.02 correct
console.log(RoundCorrect(-1.005, 2)); // -1.01 correct
console.log(RoundCorrect(-2.175, 2)); // -2.18 correct
console.log(RoundCorrect(-5.015, 2)); // -5.02 correct
Вот прототип метода:
Number.prototype.round = function(places){
places = Math.pow(10, places);
return Math.round(this * places)/places;
}
var yournum = 10.55555;
yournum = yournum.round(2);
Это может сработать для вас,
Math.round(num * 100)/100;
чтобы узнать разницу между toFixed и round. Вы можете посмотреть Math.round(num) vs num.toFixed(0) и несоответствия браузера.
Если вы уже используете библиотеку d3, у них есть мощная библиотека форматирования чисел: https://github.com/mbostock/d3/wiki/Formatting
Округление конкретно здесь: https://github.com/mbostock/d3/wiki/Formatting#d3_round
В вашем случае ответ:
> d3.round(1.777777, 2)
1.78
> d3.round(1.7, 2)
1.7
> d3.round(1, 2)
1
num * Math.pow(n)
вместо num * 100
(но это определенно аккуратный однострочный ;-)
Чтобы не иметь дело со многими 0, используйте этот вариант:
Math.round(num * 1e2) / 1e2
Поскольку ES6 имеет "правильный" способ (без переопределения статики и создания обходных решений), чтобы сделать это, используя toPrecision
var x = 1.49999999999;
console.log(x.toPrecision(4));
console.log(x.toPrecision(3));
console.log(x.toPrecision(2));
var y = Math.PI;
console.log(y.toPrecision(6));
console.log(y.toPrecision(5));
console.log(y.toPrecision(4));
var z = 222.987654
console.log(z.toPrecision(6));
console.log(z.toPrecision(5));
console.log(z.toPrecision(4));
(1.005).toPrecision(3)
прежнему возвращает 1.00
вместо 1.01
самом деле.
toPrecision
возвращает строку, которая изменяет желаемый тип вывода.
Более простой способ ES6 - это
const round = (x, n) =>
parseFloat(Math.round(x * Math.pow(10, n)) / Math.pow(10, n)).toFixed(n);
Этот шаблон также возвращает заданную точность.
например:
round(44.7826456, 4) // yields 44.7826
round(78.12, 4) // yields 78.1200
Один из способов достижения такого округления только при необходимости - использовать Number.prototype.toLocaleString():
myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false})
Это обеспечит точно результат, который вы ожидаете, но как строки. Вы можете преобразовать их обратно в номера, если это не тот тип данных, который вы ожидаете.
toLocaleString
.
Это самое простое, более элегантное решение (и я лучший в мире;):
function roundToX(num, X) {
return +(Math.round(num + "e+"+X) + "e-"+X);
}
//roundToX(66.66666666,2) => 66.67
//roundToX(10,2) => 10
//roundToX(10.904,2) => 10.9
E
Я добавлю еще один подход к этому.
number = 16.6666666;
console.log(parseFloat(number.toFixed(2)));
"16.67"
number = 16.6;
console.log(parseFloat(number.toFixed(2)));
"16.6"
number = 16;
console.log(parseFloat(number.toFixed(2)));
"16"
.toFixed(2)
возвращает строку с точностью до 2 десятичных точек, которые могут быть или не быть завершающими нулями. Выполнение parseFloat()
устраняет эти конечные нули.
Используйте эту функцию Number(x).toFixed(2);
Number
раз, если вы не хотите, чтобы оно возвращалось в виде строки: Number(Number(x).toFixed(2));
Number
не требуется, x.toFixed(2)
работает.
Простое решение будет использовать функцию lodash ceil, если вы хотите округлить...
https://lodash.com/docs/4.17.10#ceil
_.round(6.001,2)
дает 6
_.ceil(6.001, 2);
дает 6,01
_.ceil(37.4929,2);
дает 37,5
_.round(37.4929,2);
дает 37,49
Это помогло (TypeScript):
round(decimal: number, decimalPoints: number): number{
let roundedValue = Math.round(decimal * Math.pow(10, decimalPoints)) / Math.pow(10, decimalPoints);
console.log('Rounded ${decimal} to ${roundedValue}');
return roundedValue;
}
// Sample output:
Rounded 18.339840000000436 to 18.34
Rounded 52.48283999999984 to 52.48
Rounded 57.24612000000036 to 57.25
Rounded 23.068320000000142 to 23.07
Rounded 7.792980000000398 to 7.79
Rounded 31.54157999999981 to 31.54
Rounded 36.79686000000004 to 36.8
Rounded 34.723080000000124 to 34.72
Rounded 8.4375 to 8.44
Rounded 15.666960000000074 to 15.67
Rounded 29.531279999999924 to 29.53
Rounded 8.277420000000006 to 8.28
Я знаю, что есть много ответов, но большинство из них имеют побочный эффект в некоторых конкретных случаях.
Самое простое и кратчайшее решение без каких-либо побочных эффектов:
Number((2.3456789).toFixed(2)) // 2.35
Он округляется правильно и возвращает число вместо строки
console.log(Number((2.345).toFixed(2))) // 2.35
console.log(Number((2.344).toFixed(2))) // 2.34
console.log(Number((2).toFixed(2))) // 2
console.log(Number((-2).toFixed(2))) // -2
console.log(Number((-2.345).toFixed(2))) // -2.35
console.log(Number((2.345678).toFixed(3))) // 2.346
Попробуйте использовать плагин jQuery .:
var number = 19.8000000007;
var res = 1 * $.number(number, 2);
Я строил простой tipCalculator, и здесь было много ответов, которые, похоже, слишком усложняют проблему. Поэтому я нашел подведение итогов этого вопроса как лучший способ по-настоящему ответить на этот вопрос
если вы хотите создать округленное десятичное число, сначала вы вызываете toFixed(# of decimal places you want to keep)
а затем обертываете это в Number()
поэтому конечный результат:
let amountDue = 286.44;
tip = Number((amountDue * 0.2).toFixed(2));
console.log(tip) // 57.29 instead of 57.288
toFixed
просто toFixed
значение и возвращает строку. Number(1.005).toFixed(2) => "1.00"
Number(10).toFixed(2) => "10.00"
Для округления в десятичных положениях pos
(включая десятичные знаки) do Math.round(num * Math.pow(10,pos)) / Math.pow(10,pos)
var console = {
log: function(s) {
document.getElementById("console").innerHTML += s + "<br/>"
}
}
var roundDecimals=function(num,pos) {
return (Math.round(num * Math.pow(10,pos)) / Math.pow(10,pos) );
}
//https://en.wikipedia.org/wiki/Pi
var pi=3.14159265358979323846264338327950288419716939937510;
for(var i=2;i<15;i++) console.log("pi="+roundDecimals(pi,i));
for(var i=15;i>=0;--i) console.log("pi="+roundDecimals(pi,i));
<div id="console" />
Вот кратчайший и полный ответ:
function round(num, decimals) {
var n = Math.pow(10, decimals);
return Math.round( (n * num).toFixed(decimals) ) / n;
};
Это также касается примера 1.005, который вернет 1.01.
Вы также можете переопределить функцию Math.round для правильного округления и добавить параметр для десятичных знаков и использовать его так: Math.round(Number, Decimals). Имейте в виду, что это переопределяет встроенный компонент Math.round и дает ему другое свойство, тогда оно оригинальное.
var round = Math.round;
Math.round = function (value, decimals) {
decimals = decimals || 0;
return Number(round(value + 'e' + decimals) + 'e-' + decimals);
}
Тогда вы можете просто использовать его следующим образом:
Math.round(1.005, 2);
Я написал для себя следующий набор функций. Возможно, это тоже поможет.
function float_exponent(number) {
exponent = 1;
while (number < 1.0) {
exponent += 1
number *= 10
}
return exponent;
}
function format_float(number, extra_precision) {
precision = float_exponent(number) + (extra_precision || 0)
return number.toFixed(precision).split(/\.?0+$/)[0]
}
Использование:
format_float(1.01); // 1
format_float(1.06); // 1.1
format_float(0.126); // 0.13
format_float(0.000189); // 0.00019
Для вас:
format_float(10, 1); // 10
format_float(9.1, 1); // 9.1
format_float(1.77777, 1); // 1.78
Вот функция, которую я придумал, чтобы "округлить". Я использовал двойной Math.round, чтобы компенсировать неточное умножение JavaScript, поэтому 1.005 будет правильно округлено как 1.01.
function myRound(number, decimalplaces){
if(decimalplaces > 0){
var multiply1 = Math.pow(10,(decimalplaces + 4));
var divide1 = Math.pow(10, decimalplaces);
return Math.round(Math.round(number * multiply1)/10000 )/divide1;
}
if(decimalplaces < 0){
var divide2 = Math.pow(10, Math.abs(decimalplaces));
var multiply2 = Math.pow(10, Math.abs(decimalplaces));
return Math.round(Math.round(number / divide2) * multiply2);
}
return Math.round(number);
}
Из существующих ответов я нашел другое решение, которое, кажется, отлично работает, что также работает с отправкой в строку и исключает завершающие нули.
function roundToDecimal(string, decimals) {
return parseFloat(parseFloat(string).toFixed(decimals));
}
Он не принимает во внимание, если вы отправляете какого-то быка.. например, "апа". Или это, вероятно, вызовет ошибку, которая, как мне кажется, является правильным способом, никогда не удастся скрыть ошибки, которые должны быть исправлены (вызывающей функцией).
Основываясь на выбранном ответе и поднятом комментарии на тот же вопрос:
Math.round((num + 0.00001) * 100) / 100
Это работает для обоих этих примеров:
Math.round((1.005 + 0.00001) * 100) / 100
Math.round((1.0049 + 0.00001) * 100) / 100
Это сработало очень хорошо для меня, когда я хотел всегда округлять до определенного десятичного числа. Ключевым моментом здесь является то, что мы всегда будем округлять с помощью функции Math.ceil.
Вы можете условно выбрать потолок или пол при необходимости.
/**
* Possibility to lose precision at large numbers
* @param number
* @returns Number number
*/
var roundUpToNearestHundredth = function(number) {
// Ensure that we use high precision Number
number = Number(number);
// Save the original number so when we extract the Hundredth decimal place we don't bit switch or lose precision
var numberSave = Number(number.toFixed(0));
// Remove the "integer" values off the top of the number
number = number - numberSave;
// Get the Hundredth decimal places
number *= 100;
// Ceil the decimals. Therefore .15000001 will equal .151, etc.
number = Math.ceil(number);
// Put the decimals back into their correct spot
number /= 100;
// Add the "integer" back onto the number
return number + numberSave;
};
console.log(roundUpToNearestHundredth(6132423.1200000000001))
В среде узлов я просто использую модуль roundTo:
const roundTo = require('round-to');
...
roundTo(123.4567, 2);
// 123.46
Начиная с примера, предложенного над precisionRound, который я нашел на MDN (это событие для 1.005 returs 1, а не 1.01), я пишу пользовательскую точность Round, которая управляет номером случайной точности и для 1.005 возвращает 1.01.
Это функция:
function precisionRound(number, precision)
{
if(precision < 0)
{
var factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
}
else
return +(Math.round(number + "e+"+precision) + "e-"+precision);
}
console.log(precisionRound(1234.5678, 1)); // output: 1234.6
console.log(precisionRound(1234.5678, -1)); // output: 1230
console.log(precisionRound(1.005, 2)); // output: 1.01
console.log(precisionRound(1.0005, 2)); // output: 1
console.log(precisionRound(1.0005, 3)); // output: 1.001
console.log(precisionRound(1.0005, 4)); // output: 1.0005
Для TypeScript:
public static precisionRound(number: number, precision: number)
{
if (precision < 0)
{
let factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
}
else
return +(Math.round(Number(number + "e+" + precision)) +
"e-" + precision);
}
Общий ответ для всех браузеров и исправлений:
function round(num, places) {
if(!places){
return Math.round(num);
}
var val = Math.pow(10, places);
return Math.round(num * val) / val;
}
round(num, 2);
Только для записи метод масштабирования теоретически может вернуть Infinity, если число и цифры, которые вы хотите округлить, достаточно велики. В JavaScript, который не должен быть проблемой, поскольку максимальное число равно 1.7976931348623157e + 308, но если вы работаете с действительно большими числами или множеством десятичных знаков, вы можете попробовать эту функцию вместо:
Number.prototype.roundTo = function(digits)
{
var str = this.toString();
var split = this.toString().split('e');
var scientific = split.length > 1;
var index;
if (scientific)
{
str = split[0];
var decimal = str.split('.');
if (decimal.length < 2)
return this;
index = decimal[0].length + 1 + digits;
}
else
index = Math.floor(this).toString().length + 1 + digits;
if (str.length <= index)
return this;
var digit = str[index + 1];
var num = Number.parseFloat(str.substring(0, index));
if (digit >= 5)
{
var extra = Math.pow(10, -digits);
return this < 0 ? num - extra : num + extra;
}
if (scientific)
num += "e" + split[1];
return num;
}
Я просто хотел поделиться своим подходом, основываясь на ранее упомянутых ответах:
Создайте функцию, которая округляет любое заданное числовое значение до заданного количества десятичных знаков:
function roundWDecimals(n, decimals) {
if (!isNaN(parseFloat(n)) && isFinite(n)) {
if (typeof(decimals) == typeof(undefined)) {
decimals = 0;
}
var decimalPower = Math.pow(10, decimals);
return Math.round(parseFloat(n) * decimalPower) / decimalPower;
}
return NaN;
}
И представим новый "круглый" метод для прототипа чисел:
Object.defineProperty(Number.prototype, 'round', {
enumerable: false,
value: function(decimals) {
return roundWDecimals(this, decimals);
}
});
И вы можете проверить его:
function roundWDecimals(n, decimals) {
if (!isNaN(parseFloat(n)) && isFinite(n)) {
if (typeof(decimals) == typeof(undefined)) {
decimals = 0;
}
var decimalPower = Math.pow(10, decimals);
return Math.round(parseFloat(n) * decimalPower) / decimalPower;
}
return NaN;
}
Object.defineProperty(Number.prototype, 'round', {
enumerable: false,
value: function(decimals) {
return roundWDecimals(this, decimals);
}
});
var roundables = [
{num: 10, decimals: 2},
{num: 1.7777777, decimals: 2},
{num: 9.1, decimals: 2},
{num: 55.55, decimals: 1},
{num: 55.549, decimals: 1},
{num: 55, decimals: 0},
{num: 54.9, decimals: 0},
{num: -55.55, decimals: 1},
{num: -55.551, decimals: 1},
{num: -55, decimals: 0},
{num: 1.005, decimals: 2},
{num: 1.005, decimals: 2},
{num: 19.8000000007, decimals: 2},
],
table = '<table border="1"><tr><th>Num</th><th>Decimals</th><th>Result</th></tr>';
$.each(roundables, function() {
table +=
'<tr>'+
'<td>'+this.num+'</td>'+
'<td>'+this.decimals+'</td>'+
'<td>'+this.num.round(this.decimals)+'</td>'+
'</tr>'
;
});
table += '</table>';
$('.results').append(table);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="results"></div>
Этот ответ скорее о скорости.
var precalculatedPrecisions = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10];
function round(num, _prec) {
_precision = precalculatedPrecisions[_prec]
return Math.round(num * _precision + 1e-14) / _precision ;
}
jsPerf об этом.
Проблему округления можно избежать, используя числа, представленные в экспоненциальной нотации.
public static roundFinancial(amount: number, decimals: number) {
return Number(Math.round(Number('${amount}e${decimals}')) + 'e-${decimals}');
}
VM82:1 Uncaught SyntaxError: Unexpected identifier
Используя решение Брайана Устаса:
function roundDecimal(value, precision) {
var multiplier = Math.pow(10, precision);
return Math.round(value * multiplier) / multiplier;
}
number=(parseInt((number +0.005)*100))/100;
добавьте 0.005, если вы хотите нормальный раунд (2 десятичных знака)
8.123 +0.005=> 8.128*100=>812/100=>8.12
8.126 +0.005=> 8.131*100=>813/100=>8.13
function round(value, decimals) {
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}
раунд (1.005, 2);//return 1.01
раунд (1.004, 2);//возвращаем 1 вместо 1.00
Ответ идет по этой ссылке: http://www.jacklmoore.com/notes/rounding-in-javascript/
Попробуйте выполнить эту функцию в typescript (Angular 2). Протестировано в комплексных десятичных знаках.
/**
* @param num numeric to round off
* @param decToRound desired decimal digit to round
*/
roundNumberDec(num, decToRound) {
if ([undefined, null, ''].indexOf(num) >= 0) {
return null;
}
if (isNaN(num)) { return null; }
// check if decimal
if (num.toString().indexOf('.') > -1) {
const deci = num.toString().split('.')[1];
if (deci.length <= decToRound) { return Number(num); }
let isUp = false; let newDecimal = 0;
let digi;
for (let i = deci.length - 1; i > decToRound - 1; i--) {
digi = Number(Number(deci.charAt(i)) + (isUp ? 1 : 0));
isUp = digi >= 5;
}
const frontDigi = num.toString().substr(0, num.toString().indexOf('.'));
const dec2dig = '0.' + deci.toString().substr(0, decToRound);
if (isUp) {
const rounder = Math.pow(10, decToRound);
newDecimal = Math.round((Number(dec2dig) + (1 / rounder)) * rounder) / rounder;
} else {
newDecimal = Number(dec2dig);
}
return Number(Number(frontDigi) + Number(newDecimal));
} else {
return Number(num);
}
}
Пожалуйста, используйте функцию ниже, если вы не хотите округлять.
function ConvertToDecimal(num) {
num = num.toString(); // If it not already a String
num = num.slice(0, (num.indexOf(".")) + 3); // With 3 exposing the hundredths place
alert('M : ' + Number(num)); // If you need it back as a Number
}
Это помогло мне в Node.js за считанные секунды:
npm install math
Math.round(v*100)/100
. github.com/josdejong/mathjs/blob/master/lib/function/arithmetic/...
Я попробовал свой собственный код, попробуйте
function AmountDispalyFormat(value) {
value = value.toFixed(3);
var amount = value.toString().split('.');
var result = 0;
if (amount.length > 1) {
var secondValue = parseInt(amount[1].toString().slice(0, 2));
if (amount[1].toString().length > 2) {
if (parseInt(amount[1].toString().slice(2, 3)) > 4) {
secondValue++;
if (secondValue == 100) {
amount[0] = parseInt(amount[0]) + 1;
secondValue = 0;
}
}
}
if (secondValue.toString().length == 1) {
secondValue = "0" + secondValue;
}
result = parseFloat(amount[0] + "." + secondValue);
} else {
result = parseFloat(amount);
}
return result;
}
let numbers = 5.1356;
const countingDecimals = (numbers) => {
let decimal = numbers.toString().split(".").length;
return decimal;
}
if (countingDecimals(numbers) === 0) {
let localNumbers = numbers;
localNumbers = Math.Floor(localNumbers);
console.log(localNumbers);
} else if (countingDecimals(numbers) === 1) {
let localNumbers = numbers;
localNumbers = Math.round(localNumbers * 10) / 10
console.log(localNumbers);
} else {
let localNumbers = numbers;
localNumbers = Math.round(localNumbers * 100) / 100;
console.log(localNumbers); }
Я все еще не думаю, что кто-нибудь дал ему ответ на то, как только округлить, если необходимо. Самый простой способ, который я вижу для этого, - проверить, есть ли даже десятичное число в числе:
var num = 3.21;
if ( (num+"").indexOf('.') >= 0 ) { //at least assert to string first...
// whatever code you decide to use to round
}
indexOf
- это прежде всего не метод для чисел.
Number.EPSILON
. ИспользуйтеMath.round( num * 100 + Number.EPSILON ) / 100
.