Я хотел бы округлить не более 2 десятичных знаков, но только при необходимости .
Входные данные:
10
1.7777777
9.1
Вывод:
10
1.78
9.1
Как я могу сделать это в JavaScript?
javascript
rounding
decimal-point
stinkycheeseman
источник
источник
Number.EPSILON
. ИспользованиеMath.round( num * 100 + Number.EPSILON ) / 100
.Number.EPSILON
здесь?Ответы:
использование
Math.round(num * 100) / 100
Изменить: чтобы гарантировать, что такие вещи, как 1.005 раунд правильно, мы используем
Math.round((num + Number.EPSILON) * 100) / 100
источник
Math.round((num + 0.00001) * 100) / 100
. ПопробуйтеMath.round((1.005 + 0.00001) * 100) / 100
иMath.round((1.0049 + 0.00001) * 100) / 100
Если значение является текстовым типом:
Если значение является числом:
Недостатком является то, что такие значения, как 1,5, дадут «1,50» в качестве выхода. Исправление, предложенное @minitech:
Похоже,
Math.round
это лучшее решение. Но это не так! В некоторых случаях оно НЕ будет округлено правильно:toFixed () также не будет правильно округляться в некоторых случаях (протестировано в Chrome v.55.0.2883.87)!
Примеры:
Я думаю, это потому, что 1.555 - это что-то вроде плавающего 1.55499994 за кулисами.
Решение 1 - использовать скрипт с необходимым алгоритмом округления, например:
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
ПРИМЕЧАНИЕ: это не универсальное решение для всех. Существует несколько разных алгоритмов округления, ваша реализация может быть разной, в зависимости от ваших требований. https://en.wikipedia.org/wiki/Rounding
Решение 2 состоит в том, чтобы избежать расчетов внешнего интерфейса и получить округленные значения с внутреннего сервера.
источник
parseFloat(number.toFixed(decimalPlaces));
@PerLundbergparseFloat("55.555").toFixed(2)
возвращается"55.55"
в консоли разработчика Chrome.Ты можешь использовать
Я нашел это на MDN . Их путь позволяет избежать проблемы с 1.005, о которой упоминалось .
источник
+(val)
является принуждением, эквивалентным использованиюNumber(val)
. Конкатенация «e-2» с числом привела к появлению строки, которую необходимо преобразовать обратно в число.roundToTwo(1.0049999999999999)
появляется значение 1,01 (неизбежно с тех пор1.0049999999999999 == 1.005
). Мне кажется, что число с плавающей запятой, которое вы получите, если вы наберетеnum = 1.005
«очевидно», должно округляться до 1,00, потому что точное значение num меньше 1,005. Конечно, мне также кажется, что строка «1.005» «очевидно» должна быть округлена до 1.01. Тот факт, что разные люди, кажется, имеют разные представления о том, каково на самом деле правильное поведение, является частью того, почему это сложно.1.0049999999999999
и1.005
, по определению, это одно и то же число. Это называется dedekind cut.1.00499 < 1.005
естьtrue
,1.0049999999999999 < 1.005
оценивает доfalse
.Ответ MarkG является правильным. Вот общее расширение для любого количества десятичных знаков.
Применение:
Модульный тест:
источник
function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
(-1.005).round(2) === -1
Вы должны использовать:
Кажется, никто не знает
Number.EPSILON
.Также стоит отметить, что это не странность JavaScript, как утверждают некоторые люди.
Это просто способ, которым числа с плавающей запятой работают в компьютере. Как и в 99% языков программирования, JavaScript не имеет самодельных чисел с плавающей точкой; для этого он использует CPU / FPU. Компьютер использует двоичный код, а в двоичном коде нет таких чисел, как
0.1
, а просто двоичное приближение для этого. Почему? По той же причине, что 1/3 нельзя записать в десятичном виде: его значение равно 0,33333333 ... с бесконечностью троек.Вот иди
Number.EPSILON
. Это число представляет собой разницу между 1 и следующим числом, существующим в числах с плавающей запятой двойной точности. Вот и все: между1
1 и + нет номераNumber.EPSILON
.РЕДАКТИРОВАТЬ:
Как просили в комментариях, давайте уточним одну вещь: добавление
Number.EPSILON
имеет значение только тогда, когда значение округления является результатом арифметической операции, поскольку оно может поглотить некоторую дельту ошибки с плавающей запятой.Это не полезно, когда значение исходит из прямого источника (например, литерал, пользовательский ввод или датчик).
РЕДАКТИРОВАТЬ (2019):
Как @maganap и некоторые люди указали, лучше добавить
Number.EPSILON
перед умножением:РЕДАКТИРОВАТЬ (декабрь 2019 года):
В последнее время я использую функцию, похожую на эту, для сравнения чисел с учетом epsilon:
Мой вариант использования - библиотека утверждений + проверки данных, которую я разрабатываю уже много лет.
Фактически, в коде, который я использую,
ESPILON_RATE = 1 + 4 * Number.EPSILON
иEPSILON_ZERO = 4 * Number.MIN_VALUE
(в четыре раза больше эпсилона), потому что я хочу, чтобы средство проверки равенства было достаточно свободным для накопления ошибки с плавающей запятой.Пока это выглядит идеально для меня. Надеюсь, это поможет.
источник
Math.round( (num + Number.EPSILON) * 100) / 100
. Я согласен также, что это правильный метод для правильного округления (хотя это не совсем то, что было задано в этом вопросе).0.004999999999999999
в результате только сложную ошибку с плавающей запятой, и математически правильный результат был, вероятно, 0,005. Если это чтение с датчика? Не так много.Math.round(1.5)
= 2, ноMath.round(-1.5)
= -1. Так что это совершенно соответствует. Здесь -1 больше -2, как -1000 больше -1000.01. Не путать с большими абсолютными числами.Можно использовать
.toFixed(NumberOfDecimalPlaces)
.источник
+(1.005).toFixed(2)
который возвращает1
вместо1.01
.Number(9).toFixed(2).replace(/0+$/, '')
=> "9".Этот вопрос сложный.
Предположим, у нас есть функция,
roundTo2DP(num)
которая принимает в качестве аргумента значение с плавающей точкой и возвращает значение, округленное до 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. Просто сравните их:
Поэтому, когда я пишу
m = 0.0150000000000000001
, точное значение,m
которое я получаю, ближе к тому,0.01
чем оно есть0.02
. И все же, если я преобразуюm
в строку ...... Я получаю 0,015, что должно округлить до 0,02, и что заметно не то число с 56 десятичными я ранее говорил, что все эти числа в точности равны. Так что же это за темная магия?
Ответ можно найти в спецификации ECMAScript, в разделе 7.1.12.1: ToString применяется к типу Number . Здесь изложены правила преобразования некоторого числа m в строку. Ключевой частью является точка 5, в которой генерируется целое число s , цифры которого будут использоваться в строковом представлении m :
Ключевой частью здесь является требование, чтобы « k было как можно меньше». То, к чему относится это требование, - это требование о том, что для заданного числа
m
значениеString(m)
должно иметь наименьшее возможное количество цифр, но при этом удовлетворять этому требованиюNumber(String(m)) === m
. Поскольку мы это уже знаем0.015 === 0.0150000000000000001
, теперь понятно, почему этоString(0.0150000000000000001) === '0.015'
должно быть правдой.Конечно, ни одно из этого обсуждения не дало прямого ответа на то, что
roundTo2DP(m)
должно вернуться. Еслиm
точное значение равно 0,01499999999999999944488848768742172978818416595458984375, но его строковое представление равно 0,015, то каков правильный ответ - математически, практически, философски или как угодно - когда мы округляем его до двух десятичных знаков?На этот вопрос нет однозначного правильного ответа. Это зависит от вашего варианта использования. Вы, вероятно, хотите уважать представление String и округлять вверх, когда:
С другой стороны, вы, вероятно, хотите соблюдать двоичное значение с плавающей запятой и округлять в меньшую сторону, когда ваше значение по непрерывной шкале - например, если это считывание с датчика.
Эти два подхода требуют различного кода. Чтобы уважать строковое представление числа, мы можем (с небольшим количеством довольно тонкого кода) реализовать наше собственное округление, которое действует непосредственно на строковое представление, цифра за цифрой, используя тот же алгоритм, который вы использовали в школе, когда вы научили округлять числа. Ниже приведен пример, в котором соблюдается требование ОП о представлении числа в 2 десятичных знака «только при необходимости» путем удаления конечных нулей после десятичной точки; вам, конечно, может понадобиться настроить его в соответствии с вашими потребностями.
Пример использования:
Вышеприведенная функция - это, вероятно, то, что вы хотите использовать, чтобы пользователи никогда не видели, что введенные ими числа неправильно округляются.
(В качестве альтернативы вы также можете попробовать библиотеку round10, которая предоставляет функцию с аналогичным поведением и имеет совершенно другую реализацию.)
Но что, если у вас есть второй тип числа - значение, взятое из непрерывной шкалы, где нет оснований думать, что приближенные десятичные представления с меньшим количеством десятичных знаков более точны, чем те, у которых больше? В этом случае мы не хотим уважать представление String, потому что это представление (как объяснено в спецификации) уже округлено; мы не хотим ошибаться, говоря: «0,014999999 ... 375 округляет до 0,015, что округляет до 0,02, поэтому 0,014999999 ... 375 округляет до 0,02».
Здесь мы можем просто использовать встроенный
toFixed
метод. Обратите внимание, что при вызовеNumber()
String, возвращаемого функциейtoFixed
, мы получаем число, чье представление String не имеет конечных нулей (благодаря тому, как JavaScript вычисляет строковое представление числа, обсуждаемое ранее в этом ответе).источник
roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)
. Ожидаемый результат (как в PHPecho round(362.42499999999995, 2)
)362.43
. Фактический результат:362.42
round
дает 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 , PHPround
соответствует стандарту C99; Я должен рискнуть в страну C, чтобы понять, что происходит.Рассмотрим
.toFixed()
и.toPrecision()
:http://www.javascriptkit.com/javatutors/formatnumber.shtml
источник
Точный метод округления. Источник: Мозилла
Примеры:
источник
Math.round10(3544.5249, -2)
возвращается 3544,52 вместо 3544,533544.5249
к двум десятичным разрядам3544.52
(ошибка = 0,0049). Если это так3544.53
, ошибка будет 0,0051. Вы выполняете последовательное округление, то есть Math.round10 (Math.round10 (3544.5249, -3), -2), которое дает большую ошибку округления и, следовательно, нежелательно.number += 0.00011
Math.round10( Math.round10(3544.5249, -3) , -2)
Ни один из найденных здесь ответов не является правильным . @stinkycheeseman попросил округлить , вы все округлили число.
Чтобы округлить, используйте это:
источник
Math.ceil(1.1 * 100)/100;
- он возвращает1.11
, потому что 1.1 * 100110.00000000000001
соответствует новым современным браузерам Firefox, Chrome, Safari и Opera ... IE по-прежнему думает1.1*100=1100
.Math.ceil(num.toFixed(4) * 100) / 100
Math.ceil((1.1).toFixed(4) * 100) / 100
также вернется1.11
в Firefox, проблема / ошибка современных браузеров связана с умножением, и люди должны знать об этом (например, в то время я работал над лотереей).Вот простой способ сделать это:
Вы можете пойти дальше и сделать отдельную функцию, чтобы сделать это для вас, хотя:
Тогда вы просто передадите значение.
Вы можете увеличить его до любого произвольного числа десятичных знаков, добавив второй параметр.
источник
источник
+(0.015).toFixed(2) == 0.01
.Для меня Math.round () не давал правильного ответа. Я нашел toFixed (2) работает лучше. Ниже приведены примеры обоих:
источник
1.005
.(1.005).toFixed(2)
все еще приводит к1.00
.Используйте эту функцию
Number(x).toFixed(2);
источник
Number
снова, если вы не хотите, чтобы оно возвращалось в виде строки:Number(Number(x).toFixed(2));
Number
Вызов не нужно,x.toFixed(2)
работает.(1).toFixed(2)
возвращается1.00
, но спрашивающий нужен1
в этом случае.1.005.toFixed(2)
дает,"1"
когда это должно быть"1.01"
.2017
Просто используйте нативный код
.toFixed()
Если вам нужно быть строгим и добавлять цифры только при необходимости, он может использовать
replace
источник
toFixed
предложено несколько ответов за несколько лет до вашего, но он не удовлетворяет условию «только при необходимости» в вопросе;(1).toFixed(2)
дает,"1.00"
где пожелал аскер"1"
.Попробуйте это облегченное решение:
источник
return Number(x.toFixed(digits))
?.toFixed()
в любом случае допускает только числа.round(1.005, 2)
увидеть результат1
вместо1.01
.round(0.995, 2) => 0.99
;round(1.006, 2) => 1.01
;round(1.005, 2) => 1
Есть несколько способов сделать это. Для таких, как я, вариант Лодаша
Применение:
Если ваш проект использует jQuery или lodash, вы также можете найти подходящий
round
метод в библиотеках.Обновление 1
Я удалил вариант
n.toFixed(2)
, потому что это не правильно. Спасибо @ avalanche1источник
Number.toFixed()
вернет строку, но с символом плюс перед ней, интерпретатор JS преобразует строку в число. Это синтаксис сахара.alert((+1234).toFixed(2))
показывает "1234.00".alert(+1234.toFixed(2))
кидаетSyntaxError: identifier starts immediately after numeric literal
. Я придерживаюсь 1-го варианта.362.42499999999995
. Ожидаемый результат (как в PHPecho round(362.42499999999995, 2)
)362.43
. Фактический результат:362.42
Если вы используете библиотеку lodash, вы можете использовать метод lodash round, как показано ниже.
Например:
источник
Начиная с ES6, существует «правильный» способ (без переопределения статики и создания обходных путей) сделать это с помощью toPrecision.
тогда вы можете просто
parseFloat
и нули «уйдут».Однако это не решает «проблему округления 1.005», поскольку это присуще тому, как обрабатываются дробные дроби .
Если вы открыты для библиотек, вы можете использовать bignumber.js
источник
(1.005).toPrecision(3)
все еще возвращается1.00
вместо1.01
фактически.toPrecision
возвращает строку, которая изменяет желаемый тип вывода..toPrecision
метода, это специфика чисел с плавающей точкой (какие числа в JS) - попробуйте1.005 - 0.005
, он вернется0.9999999999999999
.(1).toPrecision(3)
возвращает «1,00», но спрашивающий хотел иметь1
в этом случае.toPrecision
делает формат, а не последний, и не является ответом на вопрос ОП, хотя на первый взгляд может показаться уместным, он получает много ошибок. См. En.wikipedia.org/wiki/Significant_figures . Например,Number(123.4).toPrecision(2)
возвращается"1.2e+2"
иNumber(12.345).toPrecision(2)
возвращается"12"
. Я также согласен с тем, что @ adamduren возвращает строку, которая нежелательна (не большая проблема, но нежелательная).MarkG и Lavamantis предложили гораздо лучшее решение, чем то, которое было принято. Жаль, что они не получают больше голосов!
Вот функция, которую я использую для решения проблем десятичных чисел с плавающей запятой, также основанных на MDN . Это даже более универсально (но менее кратко), чем решение Lavamantis:
Используйте это с:
По сравнению с решением Lavamantis, мы можем сделать ...
источник
Это может помочь вам:
Для получения дополнительной информации, вы можете посмотреть по этой ссылке
Math.round (num) против num.toFixed (0) и несоответствия браузера
источник
Самый простой подход - использовать toFixed, а затем удалить конечные нули с помощью функции Number:
источник
15.00
? Числа в JS не хранят десятичные разряды, и любое отображение автоматически усекает лишние десятичные разряды (любые нули в конце).toFixed(2)
здесь 2 - число цифр, до которого мы хотим округлить это число.источник
Это может работать для вас,
знать разницу между фиксированным и круглым. Вы можете взглянуть на Math.round (num) против num.toFixed (0) и несоответствия браузера .
источник
Самый простой способ:
+num.toFixed(2)
Он преобразует его в строку, а затем обратно в целое число / число с плавающей точкой.
источник
toFixed()
на 3. Так и будет+num.toFixed(3)
. Это работает так, как должно, 1.005 округляется до 1.00, что равно 1Вот метод-прототип:
источник
Используйте что-то вроде этого "parseFloat (parseFloat (value) .toFixed (2))"
источник
Один из способов добиться такого округления только при необходимости - использовать Number.prototype.toLocaleString () :
Это обеспечит именно тот результат, который вы ожидаете, но в виде строк. Вы все еще можете преобразовать их обратно в числа, если это не тот тип данных, который вы ожидаете.
источник
toLocaleString
.После прохождения различных итераций всех возможных способов достижения по-настоящему точной точности округления десятичных чисел становится ясно, что наиболее точным и эффективным решением является использование Number.EPSILON. Это обеспечивает истинное математическое решение проблемы математической точности с плавающей запятой. Он может быть легко заполнен, как показано здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON для поддержки всех последних оставшихся пользователей IE (тогда, опять же, возможно, мы должен прекратить делать это).
Адаптировано из решения, представленного здесь: https://stackoverflow.com/a/48850944/6910392
Простое решение для снижения, которое обеспечивает точное округление, настил и потолок с десятичной дробью, с необязательной переменной точности без добавления всей библиотеки.
ОБНОВЛЕНИЕ: Как отметил Сергей в комментариях, существует ограничение на этот (или любой) метод, на который стоит обратить внимание. В случае чисел, таких как 0,014999999999999999, вы все равно будете испытывать неточности, которые являются результатом достижения абсолютного предела ограничений точности для хранения значений с плавающей запятой. Не существует математического или другого решения, которое можно было бы применить для учета этого, поскольку само значение немедленно оценивается как 0,015. Вы можете подтвердить это, просто вызвав это значение в консоли. Из-за этого ограничения было бы невозможно даже использовать манипуляции со строками для уменьшения этого значения, поскольку его строковое представление просто «0,015». Любое решение для учета этого должно быть применено логически в источнике данных, прежде чем принимать значение в сценарии,
источник
Это самое простое, более элегантное решение (а я лучший в мире;):
источник
E
нотацию.roundToX(362.42499999999995, 2)
. Ожидаемый результат (как в PHPecho round(362.42499999999995, 2)
)362.43
. Фактический результат:362.42