Decimal toFixed javascript [дубликат]

Мы обнаружили, что решение Дэвида Б работает лучше всего. Но мы адаптировали его к более общему решению:

list.GroupBy(item => item.SomeProperty) 
   .Select(group => new List<T>(group)) 
   .ToArray();
63
задан Rudi Visser 2 March 2013 в 00:01
поделиться

23 ответа

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);
}
38
ответ дан kirilloid 21 August 2018 в 11:08
поделиться
  • 1
    Да, прототипы не работают надежно кросс-браузер. Вместо того, чтобы определять эту (ограниченную цель) функцию через систему типов, таким образом, чтобы она не работала надежно, почему бы просто не поместить ее в библиотеку. – Thomas W 14 June 2012 в 02:47
  • 2
    Это не работает как исключение. Попробуйте номер 17.56 и цифры = 2. Это должно быть 17.56, но эта функция вернет 17.55. – shendz 12 February 2013 в 22:29
  • 3
    Два несоответствия с этой функцией: эта функция возвращает строку, поэтому 1.11.toFixedDown(1) + 22 заканчивается как 1.122 вместо 23.1. Также 0.toFixedDown(1) должен произвести 0, но вместо этого он создает -0.1. – Nick Knowlson 12 March 2014 в 00:41
  • 4
    Обратите внимание, что эта функция удаляет отрицательный знак. Пример: (-10.2131).toFixedDown(2) // ==> 10.21. – usandfriends 15 July 2014 в 17:20
  • 5
    Кроме того, (1e-7).toFixedDown(0) // ==> 1e-7. Это для 1e-(>=7) (например: 1e-8, 1e-9, ...). – usandfriends 15 July 2014 в 17:38

Результирующий тип остается числом ...

/* 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);
1
ответ дан Bob Lyon 21 August 2018 в 11:08
поделиться

Рассмотрим , используя двойную тильду: ~~ .

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

function truncator(numToTruncate, intDecimalPlaces) {    
    var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
    return ~~(numToTruncate * numPower)/numPower;
}

Я пытаюсь сопротивляться завершению вызова ~~ в parens;

alert(truncator(5.1231231, 1)); // is 5.1

alert(truncator(-5.73, 1)); // is -5.7

alert(truncator(-5.73, 0)); // is -5

JSFiddle link .

EDIT: Оглядываясь назад, я непреднамеренно также обрабатывал случаи, чтобы округлить слева от десятичного числа.

alert(truncator(4343.123, -2)); // gives 4300.

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

48
ответ дан Community 21 August 2018 в 11:08
поделиться
  • 1
    Почему неожиданно? Изменение направления округления, когда вы опускаетесь ниже 0, вызывает всевозможные арифметические артефакты и amp; дерьмовая математика. Например, в два раза больше чисел будет округлено до 0, как и любое другое целое число. Для графики, учета и amp; много других применений, вы получите дрянные результаты. По правде говоря, было бы труднее сказать, что ваше предложение good для того, чтобы сказать, что это not . – Thomas W 14 June 2012 в 02:54
  • 2
    Это хорошо для того, что он говорит - когда вы хотите усекать десятичные числа, а не округлять. – Nick Knowlson 14 June 2012 в 16:32
  • 3
    Не собираюсь работать с 17.56, потому что браузер дает 17.56 * 100 = 1755.9999999999998 не 1756 – shendz 12 February 2013 в 22:30
  • 4
    Хорошая точка шендз. Я обновил свой ответ с помощью решения, которое устраняет всю ошибку с плавающей запятой для тех, кто в ней нуждается. – Nick Knowlson 1 March 2013 в 23:50
  • 5
    Это не будет работать для чисел, которые меньше 1, если вы не хотите децимал - усечь Десятичные числа (.12345, 0) приводит к NaN, если вы не добавите чек: if(isNAN(result) result = 0; Зависит от поведения, которое вы хотите. – Jeremy Witmer 22 April 2013 в 23:18
  • 6
    Это лучший ответ. Если вы продлеваете прототип Math с этим и проверяете NaN-s перед выполнением, это будет просто отлично. – Barth Zalewski 3 December 2014 в 16:59

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

0
ответ дан Cristian Sima 21 August 2018 в 11:08
поделиться

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

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

  return ((number * shift) | 0) / shift;
};
9
ответ дан Daniel X Moore 21 August 2018 в 11:08
поделиться
  • 1
    Хороший звонок. Использование побитового оператора коэрцирует значение в int, а or ing с помощью 0 означает «просто сохранить то, что у меня уже есть». Делает то, что делает мой ответ ~~, но с одной побитовой операцией. Хотя это имеет то же ограничение, что и написано: Мы не можем переходить 2 ^ 31 . – ruffin 12 June 2015 в 19:37
  • 2
    Это хорошо работает для моего решения. – crh225 16 March 2017 в 23:06
Number.prototype.truncate = function(places) {
  var shift = Math.pow(10, places);

  return Math.trunc(this * shift) / shift;
};
0
ответ дан Dercni 21 August 2018 в 11:08
поделиться
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
23
ответ дан Dogbert 21 August 2018 в 11:08
поделиться
  • 1
    Это работает хорошо, но даст результаты, которые, вероятно, нежелательны, если он (или кто-то другой, смотрящий на этот ответ позже) должен иметь дело с отрицательными числами. См. stackoverflow.com/a/9232092/224354 – Nick Knowlson 10 February 2012 в 19:31
  • 2
    Почему нежелательно? Изменение направления округления, когда вы опускаетесь ниже 0, вызывает всевозможные арифметические артефакты. – Thomas W 14 June 2012 в 02:50
  • 3
    Существует разница между округлением и усечением. Усечение - это явно поведение, которое ищет этот вопрос. Если я назову truncate(-3.14) и получу -4 назад, я бы определенно назвал это нежелательным. – Nick Knowlson 13 August 2013 в 22:34
  • 4
    Я согласен с Томасом. Разница в перспективе может заключаться в том, что вы обычно усекаетесь для отображения или для вычисления. С вычислительной точки зрения это позволяет избежать «арифметических артефактов», – John Robertson 9 June 2015 в 17:25
  • 5
    var a = 65.1 var truncated = Math.floor(a * 100) / 100; // = 65.09 Следовательно, это не правильное решение – Sanyam Jain 28 December 2017 в 09:44
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
0
ответ дан Flavio 21 August 2018 в 11:08
поделиться

Ответ от @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: недостаточно репо, чтобы прокомментировать это решение.

0
ответ дан Jaiwardhan Terminal Swarnakar 21 August 2018 в 11:08
поделиться

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

~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
4
ответ дан John Strickler 21 August 2018 в 11:08
поделиться

Я нашел проблему: учитывая следующую ситуацию: 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

Это фиксированная функция Ника Ноулсона

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/

1
ответ дан juanpscotto 21 August 2018 в 11:08
поделиться

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

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

1
ответ дан Julio Cesar Cervantes Martinez 21 August 2018 в 11:08
поделиться
  • 1
    Через два года после этого было опубликовано, но наткнулся на это, когда я пытался найти лучший способ использовать Math.trunc, regex и т. Д. Мне действительно нравится это решение. Мертвый просто, но отлично работает (для моего варианта использования в любом случае). – giles123 19 July 2018 в 08:43
  • 2
    Однако не забывайте учитывать n = 0. – giles123 19 July 2018 в 09:31

Lodash имеет несколько методов полезности Math, которые могут round , floor и 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));

Ссылка к исходному коду

0
ответ дан Matthias Dailey 21 August 2018 в 11:08
поделиться
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
1
ответ дан Max Zlotskiy 21 August 2018 в 11:08
поделиться

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

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
ответ дан MeestorHok 21 August 2018 в 11:08
поделиться

Здесь я беру тему:

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
ответ дан opensas 21 August 2018 в 11:08
поделиться

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

(f - 0.005).toFixed(2)
20
ответ дан RichardTheKiwi 21 August 2018 в 11:08
поделиться
  • 1
    +1 Отлично. Это простое решение. – Sampath 18 April 2013 в 15:39
  • 2
    Заголовки: поскольку это не работает для очень маленьких чисел, чисел с более чем тремя десятичными знаками или отрицательных чисел. Попробуйте .0045, 5.4678 и -5.467. – Nick Knowlson 23 October 2013 в 22:47
  • 3
    Это будет работать до тех пор, пока вы выберете значение, которое вы вычитаете, с длиной, которую вы хотите иметь. все, что вы передаете toFixed (), должно быть числом 0 после десятичного. – dmarra 2 April 2018 в 19:34

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

           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;
            }
1
ответ дан RohannG 21 August 2018 в 11:08
поделиться

Тот, который является признаком в качестве решения, является лучшим решением, которое я нашел до сегодняшнего дня, но имеет серьезную проблему с 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);
}
1
ответ дан Sebastián Rojas 21 August 2018 в 11:08
поделиться

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

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

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])
0
ответ дан Sergio Campamá 21 August 2018 в 11:08
поделиться

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

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

var f = parseFloat(value);
return (Math.floor(f * t)) / t;
0
ответ дан Steve 21 August 2018 в 11:08
поделиться

@ Ответ Соберта может быть улучшен с помощью 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
4
ответ дан zurfyx 21 August 2018 в 11:08
поделиться
50
ответ дан Community 1 November 2018 в 05:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: