Я пытаюсь усечь десятичные числа до десятичных знаков. Что-то вроде этого:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
делает примерно то, что нужно, но округляет значение. Мне не нужно округлять значение. Надеюсь, это возможно в javascript.
Я пытаюсь усечь десятичные числа до десятичных знаков. Что-то вроде этого:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
делает примерно то, что нужно, но округляет значение. Мне не нужно округлять значение. Надеюсь, это возможно в javascript.
Ответы:
UPD :
Итак, как выяснилось, ошибки округления всегда будут преследовать вас, как бы вы ни старались их компенсировать. Следовательно, проблему следует решать, представляя числа точно в десятичной системе счисления.
Number.prototype.toFixedDown = function(digits) { var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); }; [ 5.467.toFixedDown(2), 985.943.toFixedDown(2), 17.56.toFixedDown(2), (0).toFixedDown(1), 1.11.toFixedDown(1) + 22]; // [5.46, 985.94, 17.56, 0, 23.1]
Старое подверженное ошибкам решение, основанное на компиляции чужих:
Number.prototype.toFixedDown = function(digits) { var n = this - Math.pow(10, -digits)/2; n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56" return n.toFixed(digits); }
источник
1.11.toFixedDown(1) + 22
заканчивается как1.122
вместо23.1
. Также0.toFixedDown(1)
должен производить,0
но вместо этого производит-0.1
.(-10.2131).toFixedDown(2) // ==> 10.21
.(1e-7).toFixedDown(0) // ==> 1e-7
. Есть ли что1e-(>=7)
(например:1e-8
,1e-9
, ...).Ответ Догберта хорош, но если ваш код может иметь дело с отрицательными числами,
Math.floor
сам по себе может дать неожиданные результаты.Например
Math.floor(4.3) = 4
, ноMath.floor(-4.3) = -5
Вместо этого используйте вспомогательную функцию, подобную этой, чтобы получить согласованные результаты:
truncateDecimals = function (number) { return Math[number < 0 ? 'ceil' : 'floor'](number); }; // Applied to Dogbert's answer: var a = 5.467; var truncated = truncateDecimals(a * 100) / 100; // = 5.46
Вот более удобный вариант этой функции:
truncateDecimals = function (number, digits) { var multiplier = Math.pow(10, digits), adjustedNum = number * multiplier, truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum); return truncatedNum / multiplier; }; // Usage: var a = 5.467; var truncated = truncateDecimals(a, 2); // = 5.46 // Negative digits: var b = 4235.24; var truncated = truncateDecimals(b, -2); // = 4200
Если это нежелательное поведение, вставьте вызов
Math.abs
в первую строку:var multiplier = Math.pow(10, Math.abs(digits)),
РЕДАКТИРОВАТЬ: shendz правильно указывает, что использование этого решения
a = 17.56
будет неправильно производить17.55
. Чтобы узнать больше о том, почему это происходит, прочтите « Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой». . К сожалению, написать решение, устраняющее все источники ошибок с плавающей запятой, с javascript довольно сложно. На другом языке вы бы использовали целые числа или, возможно, десятичный тип, но с javascript ...Это решение должно быть на 100% точным, но оно будет и медленнее:
function truncateDecimals (num, digits) { var numS = num.toString(), decPos = numS.indexOf('.'), substrLength = decPos == -1 ? numS.length : 1 + decPos + digits, trimmedResult = numS.substr(0, substrLength), finalResult = isNaN(trimmedResult) ? 0 : trimmedResult; return parseFloat(finalResult); }
Для тех, кому нужна скорость, но при этом нужно избегать ошибок с плавающей запятой, попробуйте что-нибудь вроде BigDecimal.js . Вы можете найти другие библиотеки BigDecimal для javascript в этом вопросе SO: «Есть ли хорошая библиотека BigDecimal для Javascript?» и вот хороший пост в блоге о математических библиотеках для Javascript
источник
if(isNAN(result) result = 0;
Зависит от желаемого поведения.var a = 5.467; var truncated = Math.floor(a * 100) / 100; // = 5.46
источник
truncate(-3.14)
и получу-4
ответ, я бы определенно назвал это нежелательным.var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
Следовательно, это неправильное решениеВы можете исправить округление, вычтя 0,5 для toFixed, например
(f - 0.005).toFixed(2)
источник
Рассмотрим , воспользовавшись двойной тильдой:
~~
.Возьмите число. Умножьте на значащие цифры после запятой, чтобы можно было обрезать до нуля с помощью
~~
. Разделите множитель обратно. Прибыль.function truncator(numToTruncate, intDecimalPlaces) { var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better return ~~(numToTruncate * numPower)/numPower; }
Я пытаюсь сопротивляться заключению
~~
вызова в скобки; Я считаю, что порядок операций должен заставить это работать правильно.alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
Ссылка JSFiddle .
РЕДАКТИРОВАТЬ: Оглядываясь назад, я непреднамеренно также обрабатывал случаи, чтобы округлить левую часть десятичной дроби.
alert(truncator(4343.123, -2)); // gives 4300.
Логика выглядит немного странной для такого использования, и может быть полезно провести быстрый рефакторинг. Но все равно работает. Лучше повезет, чем хорошо.
источник
Math
прототип этим и проверите NaN перед выполнением, это будет просто идеально.truncator((10 * 2.9) / 100, 2)
вернуть 0,28 вместо 0,29 ... jsfiddle.net/25tgrzq1Хорошее однострочное решение:
function truncate (num, places) { return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places); }
Затем вызовите его с помощью:
truncate(3.5636232, 2); // returns 3.56 truncate(5.4332312, 3); // returns 5.433 truncate(25.463214, 4); // returns 25.4632
источник
Я подумал, что добавлю ответ,
|
так как это просто и хорошо работает.truncate = function(number, places) { var shift = Math.pow(10, places); return ((number * shift) | 0) / shift; };
источник
or
ing с 0 означает «просто сохраните то, что у меня уже есть». Делает то, что~~
делает мой ответ, но с помощью одной побитовой операции. Хотя он имеет то же ограничение, что и написано: мы не можем перейти больше 2 ^ 31 .truncate((10 * 2.9) / 100);
этот код возвращает 0,28 вместо 0,29 jsfiddle.net/9pf0732dОбрезать с помощью побитовых операторов:
~~0.5 === 0 ~~(-0.5) === 0 ~~14.32794823 === 14 ~~(-439.93) === -439
источник
Ответ @Dogbert можно улучшить с помощью
Math.trunc
, который усекает вместо округления.var a = 5.467; var truncated = Math.trunc(a * 100) / 100; // = 5.46
var a = -5.467; var truncated = Math.trunc(a * 100) / 100; // = -5.46
источник
Math.trunc
, а чем9.28 * 100
это ,927.9999
а не928
. Возможно, вы захотите прочитать The Perils of Floating PointЯ написал ответ более коротким методом. Вот что я придумал
function truncate(value, precision) { var step = Math.pow(10, precision || 0); var temp = Math.trunc(step * value); return temp / step; }
Метод можно использовать так
truncate(132456.25456789, 5)); // Output: 132456.25456 truncate(132456.25456789, 3)); // Output: 132456.254 truncate(132456.25456789, 1)); // Output: 132456.2 truncate(132456.25456789)); // Output: 132456
Или, если вам нужен более короткий синтаксис, пожалуйста
function truncate(v, p) { var s = Math.pow(10, p || 0); return Math.trunc(s * v) / s; }
источник
Number.prototype.trim = function(decimals) { var s = this.toString(); var d = s.split("."); d[1] = d[1].substring(0, decimals); return parseFloat(d.join(".")); } console.log((5.676).trim(2)); //logs 5.67
источник
Думаю, эта функция может быть простым решением:
function trunc(decimal,n=2){ let x = decimal + ''; // string return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf() } console.log(trunc(-241.31234,2)); console.log(trunc(241.312,5)); console.log(trunc(-241.233)); console.log(trunc(241.2,0)); console.log(trunc(241));
источник
Я обнаружил проблему: учитывая следующую ситуацию: 2,1 или 1,2 или -6,4
Что делать, если вы хотите всегда 3 десятичных знака или два или что угодно, поэтому вам нужно заполнить ведущие нули справа
// 3 decimals numbers 0.5 => 0.500 // 6 decimals 0.1 => 0.10000 // 4 decimales -2.1 => -2.1000 // truncate to 3 decimals 3.11568 => 3.115
Это фиксированная функция Ника Ноулсона.
function truncateDecimals (num, digits) { var numS = num.toString(); var decPos = numS.indexOf('.'); var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits; var trimmedResult = numS.substr(0, substrLength); var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult; // adds leading zeros to the right if (decPos != -1){ var s = trimmedResult+""; decPos = s.indexOf('.'); var decLength = s.length - decPos; while (decLength <= digits){ s = s + "0"; decPos = s.indexOf('.'); decLength = s.length - decPos; substrLength = decPos == -1 ? s.length : 1 + decPos + digits; }; finalResult = s; } return finalResult; };
https://jsfiddle.net/huttn155/7/
источник
x = 0.0000
тестtruncateDecimals (x, 2)
не пройден. возвращается0
. не так, как ожидалось0.00
function toFixed(number, digits) { var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)") var array = number.toString().match(reg_ex); return array ? parseFloat(array[1]) : number.valueOf() } var test = 10.123456789 var __fixed = toFixed(test, 6) console.log(__fixed) // => 10.123456
источник
Ответ @kirilloid кажется правильным, однако основной код необходимо обновить. Его решение не заботится об отрицательных числах (которые кто-то упомянул в разделе комментариев, но не был обновлен в основном коде).
Обновление до полного окончательного протестированного решения:
Number.prototype.toFixedDown = function(digits) { var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); };
Пример использования:
var x = 3.1415629; Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Fiddle: округление номера JS вниз
PS: Недостаточно репо, чтобы прокомментировать это решение.
источник
Вот простая, но работающая функция для усечения числа до двух знаков после запятой.
function truncateNumber(num) { var num1 = ""; var num2 = ""; var num1 = num.split('.')[0]; num2 = num.split('.')[1]; var decimalNum = num2.substring(0, 2); var strNum = num1 +"."+ decimalNum; var finalNum = parseFloat(strNum); return finalNum; }
источник
Получившийся тип остается числом ...
/* Return the truncation of n wrt base */ var trunc = function(n, base) { n = (n / base) | 0; return base * n; }; var t = trunc(5.467, 0.01);
источник
Lodash имеет несколько вспомогательных методов Math , которые могут круглый , пол , и CEIL числа до заданной десятичной точности. Это оставляет нули в конце.
Они используют интересный подход, используя показатель степени числа. По-видимому, это позволяет избежать проблем с округлением.
(Примечание:
func
естьMath.round
илиceil
илиfloor
в приведенном ниже коде)// Shift with exponential notation to avoid floating-point issues. var pair = (toString(number) + 'e').split('e'), value = func(pair[0] + 'e' + (+pair[1] + precision)); pair = (toString(value) + 'e').split('e'); return +(pair[0] + 'e' + (+pair[1] - precision));
Ссылка на исходный код
источник
Вот мой взгляд на эту тему:
convert.truncate = function(value, decimals) { decimals = (decimals === undefined ? 0 : decimals); return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10); };
Это просто немного более проработанная версия
(f - 0.005).toFixed(2)
источник
То, что помечено как решение, является лучшим решением, которое я находил до сегодняшнего дня, но имеет серьезную проблему с 0 (например, 0.toFixedDown (2) дает -0.01). Поэтому я предлагаю использовать это:
Number.prototype.toFixedDown = function(digits) { if(this == 0) { return 0; } var n = this - Math.pow(10, -digits)/2; n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56" return n.toFixed(digits); }
источник
Вот что я использую:
var t = 1; for (var i = 0; i < decimalPrecision; i++) t = t * 10; var f = parseFloat(value); return (Math.floor(f * t)) / t;
источник
const TO_FIXED_MAX = 100; function truncate(number, decimalsPrecison) { // make it a string with precision 1e-100 number = number.toFixed(TO_FIXED_MAX); // chop off uneccessary digits const dotIndex = number.indexOf('.'); number = number.substring(0, dotIndex + decimalsPrecison + 1); // back to a number data type (app specific) return Number.parseFloat(number); } // example truncate(0.00000001999, 8); 0.00000001
работает с:
источник
просто чтобы указать на простое решение, которое сработало для меня
преобразовать его в строку, а затем регулярное выражение ...
var number = 123.45678; var number_s = '' + number; var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0] var number_truncated = parseFloat(number_truncated_s)
Его можно сократить до
var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
источник
Вот код ES6, который делает то, что вы хотите
const truncateTo = (unRouned, nrOfDecimals = 2) => { const parts = String(unRouned).split("."); if (parts.length !== 2) { // without any decimal part return unRouned; } const newDecimals = parts[1].slice(0, nrOfDecimals), newString = `${parts[0]}.${newDecimals}`; return Number(newString); }; // your examples console.log(truncateTo(5.467)); // ---> 5.46 console.log(truncateTo(985.943)); // ---> 985.94 // other examples console.log(truncateTo(5)); // ---> 5 console.log(truncateTo(-5)); // ---> -5 console.log(truncateTo(-985.943)); // ---> -985.94
источник
Number.prototype.truncate = function(places) { var shift = Math.pow(10, places); return Math.trunc(this * shift) / shift; };
источник
Вы можете работать со струнами. Проверяет, есть ли '.' существует, а затем удаляет часть строки.
усечь (7,88, 1) -> 7,8
усечь (7,889, 2) -> 7,89
усечь (-7,88, 1) -> -7,88
function truncate(number, decimals) { const tmp = number + ''; if (tmp.indexOf('.') > -1) { return +tmp.substr(0 , tmp.indexOf('.') + decimals+1 ); } else { return +number } }
источник
Я немного сбит с толку, почему существует так много разных ответов на такой фундаментально простой вопрос; есть только два подхода, которые я видел, и которые мне показались достойными внимания. Я провел быстрый тест, чтобы увидеть разницу в скорости, используя https://jsbench.me/ .
Это решение, которое в настоящее время (26.09.2020) помечено как ответ:
function truncate(n, digits) { var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"), m = n.toString().match(re); return m ? parseFloat(m[1]) : n.valueOf(); }; [ truncate(5.467,2), truncate(985.943,2), truncate(17.56,2), truncate(0, 1), truncate(1.11, 1) + 22];
Однако здесь выполняются строковые и регулярные выражения, что обычно не очень эффективно, и есть функция Math.trunc, которая точно выполняет то, что хочет OP, только без десятичных знаков. Следовательно, вы можете легко использовать это плюс небольшую дополнительную арифметику, чтобы получить то же самое.
Вот еще одно решение, которое я нашел в этой теме, и я бы его использовал:
function truncate(n, digits) { var step = Math.pow(10, digits || 0); var temp = Math.trunc(step * n); return temp / step; } [ truncate(5.467,2), truncate(985.943,2), truncate(17.56,2), truncate(0, 1), truncate(1.11, 1) + 22];
Первый метод "на 99,92% медленнее", чем второй, поэтому второй определенно один я рекомендовал бы использовать.
Хорошо, вернемся к поиску других способов избежать работы ...
источник