Усечение (не округление) десятичных чисел в javascript

Я пытаюсь усечь десятичные числа до десятичных знаков. Что-то вроде этого:

5.467   -> 5.46  
985.943 -> 985.94

toFixed(2) делает почти правильную вещь, но это округляет ценность. Мне не нужно, чтобы значение округлялось. Надеюсь, это возможно в javascript.

Ответы

Ответ 1

обн

Итак, в конце концов, округлые ошибки всегда будут преследовать вас, как бы вы ни старались их компенсировать. Следовательно, проблему следует атаковать, представляя числа точно в десятичной нотации.

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);
}

Ответ 2

Догберт ответ хорош, но если ваш код может иметь дело с отрицательными числами, 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 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)),

РЕДАКТИРОВАТЬ: Шендз правильно указывает, что использование этого решения с 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. Вы можете найти другие библиотеки Javascript BigDecimal в этом SO вопросе: "Есть ли хорошая библиотека Javascript BigDecimal?" и вот хороший пост в блоге о математических библиотеках для Javascript

Ответ 3

var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46

Ответ 4

Вы можете исправить округление, вычитая 0,5 для toFixed, например.

(f - 0.005).toFixed(2)

Ответ 5

Попробуйте воспользоваться двойной тильдой: ~~.

Возьми в номер. Умножьте на значащие цифры после десятичной точки, чтобы можно было обрезать до нуля мест с помощью ~~. Разделите этот множитель обратно. Прибыль.

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.

Логика немного дурацкая, ищущая такое использование, и может выиграть от быстрого рефакторинга. Но это все еще работает. Лучше повезло, чем хорошо.

Ответ 6

Мне показалось, что я бы выбрал ответ, используя |, поскольку он прост и работает хорошо.

truncate = function(number, places) {
  var shift = Math.pow(10, places);

  return ((number * shift) | 0) / shift;
};

Ответ 7

Хорошее однострочное решение:

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

Ответ 8

Ответ @Dogbert может быть улучшен с помощью Math.trunc, который Math.trunc вместо округления.

Существует разница между округлением и усечением. Очевидно, что усечение - это поведение, которое ищет этот вопрос. Если я позвоню truncate (-3.14) и получу -4 обратно, я определенно назвал бы это нежелательным. - @NickKnowlson

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

Ответ 9

Обрезать с помощью побитовых операторов:

~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439

Ответ 10

Я нашел проблему: учитывая следующую ситуацию: 2.1 или 1.2 или -6.4

Что делать, если вы хотите всегда 3 десятичных знака или два или wharever, так что вам нужно закончить ведущие нули вправо

// 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

Это фиксированная функция Nick Knowlson

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/

Ответ 11

Я думаю, что эта функция может быть простым решением:

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));

Ответ 12

Тот, который является меткой в ​​качестве решения, является лучшим решением, которое я нашел до сегодняшнего дня, но имеет серьезную проблему с 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);
}

Ответ 13

Вот простая, но работающая функция для усечения числа до двух знаков после запятой.

           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;
            }

Ответ 14

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

Ответ 15

Получаемый тип остается числом...

/* 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);

Ответ 16

Ответ на @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 Number Round down

PS: недостаточно репо, чтобы прокомментировать это решение.

Ответ 17

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

Ответ 18

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));

Ссылка на исходный код

Ответ 19

Вот мой вопрос по теме:

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)

Ответ 20

просто указать на простое решение, которое сработало для меня

преобразуйте его в строку, а затем повторно...

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])

Ответ 21

Вот что я использую:

var t = 1;
for (var i = 0; i < decimalPrecision; i++)
    t = t * 10;

var f = parseFloat(value);
return (Math.floor(f * t)) / t;

Ответ 22

Вот код 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

Ответ 23

Number.prototype.truncate = function(places) {
  var shift = Math.pow(10, places);

  return Math.trunc(this * shift) / shift;
};

Ответ 24

Я написал ответ, используя более короткий метод. Вот что я придумала

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;
}