Сократить число до двух знаков после запятой без округления

Предположим, что у меня значение 15.7784514, я хочу отобразить его 15.77 без округления.

var num = parseFloat(15.7784514);
document.write(num.toFixed(1)+"<br />");
document.write(num.toFixed(2)+"<br />");
document.write(num.toFixed(3)+"<br />");
document.write(num.toFixed(10));

Результаты -

15.8
15.78
15.778
15.7784514000 

Как отобразить 15.77?

Ответ 1

Преобразуйте число в строку, сопоставьте номер со вторым десятичным знаком:

function calc(theform) {
    var num = theform.original.value, rounded = theform.rounded
    var with2Decimals = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0]
    rounded.value = with2Decimals
}
<form onsubmit="return calc(this)">
Original number: <input name="original" type="text" onkeyup="calc(form)" onchange="calc(form)" />
<br />"Rounded" number: <input name="rounded" type="text" placeholder="readonly" readonly>
</form>

Ответ 2

Обновление 5 ноября 2016 г.

Новый ответ, всегда точный

function toFixed(num, fixed) {
    var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?');
    return num.toString().match(re)[0];
}

Поскольку математика с плавающей запятой в javascript всегда будет иметь краевые случаи, предыдущее решение будет точным в большинстве случаев, что недостаточно. Есть несколько решений для этого типа num.toPrecision, BigDecimal.js и accounting.js. Тем не менее, я считаю, что просто синтаксический анализ строки будет самым простым и всегда точным.

Основываясь на обновлении хорошо написанного регулярного выражения из принятого ответа от @Gumbo, эта новая функция toFixed будет работать так, как ожидалось.


Старый ответ, не всегда точный.

Сбросьте свою собственную функцию toFixed:

function toFixed(num, fixed) {
    fixed = fixed || 0;
    fixed = Math.pow(10, fixed);
    return Math.floor(num * fixed) / fixed;
}

Ответ 3

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

num = num.toString(); //If it not already a String
num = num.slice(0, (num.indexOf("."))+3); //With 3 exposing the hundredths place
Number(num); //If you need it back as a Number

Это даст вам "15.77" с num = 15.7784514;

Ответ 4

Октябрь 2017 года

Общее решение - усечь (без округления) число до n-й десятичной цифры и преобразовать его в строку с ровно n десятичными цифрами для любого n≥0.

function toFixedTrunc(x, n) {
  const v = (typeof x === 'string' ? x : x.toString()).split('.');
  if (n <= 0) return v[0];
  let f = v[1] || '';
  if (f.length > n) return '${v[0]}.${f.substr(0,n)}';
  while (f.length < n) f += '0';
  return '${v[0]}.${f}'
}

где x может быть числом (которое преобразуется в строку) или строкой.

Вот несколько тестов для n = 2 (включая тест, запрошенный OP):

0           => 0.00
0.01        => 0.01
0.5839      => 0.58
0.999       => 0.99
1.01        => 1.01
2           => 2.00
2.551       => 2.55
2.99999     => 2.99
4.27        => 4.27
15.7784514  => 15.77
123.5999    => 123.59
0.000000199 => 1.99 *

* Как уже упоминалось в примечании, из-за неявного преобразования javascript в экспоненциальное для "1.99e-7" И для некоторых других значений n:

15.001097   => 15.0010 (n=4)
0.000003298 => 0.0000032 (n=7)
0.000003298257899 => 0.000003298257 (n=12)

Ответ 5

parseInt быстрее, чем Math.floor

function floorFigure(figure, decimals){
    if (!decimals) decimals = 2;
    var d = Math.pow(10,decimals);
    return (parseInt(figure*d)/d).toFixed(decimals);
};

floorFigure(123.5999)    =>   "123.59"
floorFigure(123.5999, 3) =>   "123.599"

Ответ 6

num = 19.66752
f = num.toFixed(3).slice(0,-1)
alert(f)

Это вернет 19.66

Ответ 7

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

мое решение преобразует вашу десятичную строку в строку, извлекает символы и затем возвращает все это как число.

function Dec2(num) {
  num = String(num);
  if(num.indexOf('.') !== -1) {
    var numarr = num.split(".");
    if (numarr.length == 1) {
      return Number(num);
    }
    else {
      return Number(numarr[0]+"."+numarr[1].charAt(0)+numarr[1].charAt(1));
    }
  }
  else {
    return Number(num);
  }  
}

Dec2(99); // 99
Dec2(99.9999999); // 99.99
Dec2(99.35154); // 99.35
Dec2(99.8); // 99.8
Dec2(10265.985475); // 10265.98

Ответ 8

Моя версия для положительных чисел:

function toFixed_norounding(n,p)
{
    var result = n.toFixed(p);
    return result <= n ? result: (result - Math.pow(0.1,p)).toFixed(p);
}

Быстро, красиво, очевидно. (версия для положительных чисел)

Ответ 9

Просто сделайте это

number = parseInt(number * 100)/100;

Ответ 10

Вы можете получить значение до N десятичных знаков точности (используйте больше для лучшего эффекта), затем отбросьте последние нежелательные символы его строкового значения:

var num = parseFloat(15.7784514);
var str = num.toFixed(20);
str = str.substring(0, str.length-7);
// str = 15.77

Ответ 11

Эти решения действительно работают, но для меня кажутся излишне сложными. Я лично хотел бы использовать оператор модуля для получения оставшейся части операции деления и удалить это. Предполагая, что num = 15.7784514:

num-=num%.01;

Это эквивалентно произнесению num = num - (num%.01).

Ответ 12

Следующий код работает очень хорошо для меня:

num.toString().match(/.\*\\..{0,2}|.\*/)[0];

Ответ 13

Вот вы. Ответ, который показывает еще один способ решения проблемы:

// For the sake of simplicity, here is a complete function:
function truncate(numToBeTruncated, numOfDecimals) {
    var theNumber = numToBeTruncated.toString();
    var pointIndex = theNumber.indexOf('.');
    return +(theNumber.slice(0, pointIndex > -1 ? ++numOfDecimals + pointIndex : undefined));
}

Обратите внимание на использование символа + перед окончательным выражением. То есть, чтобы преобразовать нашу усеченную, нарезанную строку обратно в тип номера.

Надеюсь, что это поможет!

Ответ 14

Я исправил использование следующих простых way-

var num = 15.7784514;
Math.floor(num*100)/100;

Результатом будет 15,77

Ответ 15

усекать без нулей

function toTrunc(value,n){  
    return Math.floor(value*Math.pow(10,n))/(Math.pow(10,n));
}

или же

function toTrunc(value,n){
    x=(value.toString()+".0").split(".");
    return parseFloat(x[0]+"."+x[1].substr(0,n));
}

тестовое задание:

toTrunc(17.4532,2)  //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1)   //1.4
toTrunc(.4,2)       //0.4

усекать с нулями

function toTruncFixed(value,n){
    return toTrunc(value,n).toFixed(n);
}

тестовое задание:

toTrunc(17.4532,2)  //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1)   //1.4
toTrunc(.4,2)       //0.40

Ответ 16

Простой способ сделать это следующий, но необходимо убедиться, что значение параметра приведено в виде строки.

function truncate(amountAsString, decimals = 2){
  var dotIndex = amountAsString.indexOf('.');
  var toTruncate = dotIndex !== -1  && ( amountAsString.length > dotIndex + decimals + 1);
  var approach = Math.pow(10, decimals);
  var amountToTruncate = toTruncate ? amountAsString.slice(0, dotIndex + decimals +1) : amountAsString;  
  return toTruncate
    ?  Math.floor(parseFloat(amountToTruncate) * approach ) / approach
    :  parseFloat(amountAsString);

}

console.log(truncate("7.99999")); //OUTPUT ==> 7.99
console.log(truncate("7.99999", 3)); //OUTPUT ==> 7.999
console.log(truncate("12.799999999999999")); //OUTPUT ==> 7.99

Ответ 17

Просто усечь цифры:

function truncDigits(inputNumber, digits) {
  const fact = 10 ** digits;
  return Math.floor(inputNumber * fact) / fact;
}

Ответ 18

Я использовал (num-0.05).toFixed(1), чтобы получить второй десятичный знак.

Ответ 19

Еще одно однострочное решение:

number = Math.trunc(number*100)/100

Я использовал 100, потому что вы хотите усечь вторую цифру, но более гибким решением будет:

number = Math.trunc(number*Math.pow(10, digits))/Math.pow(10, digits)

где цифры - это количество десятичных цифр.

Ответ 20

Это сработало для меня. Надеюсь, он также исправит ваши проблемы.

function toFixedNumber(number) {
    const spitedValues = String(number.toLocaleString()).split('.');
    let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
    decimalValue = decimalValue.concat('00').substr(0,2);

    return '$'+spitedValues[0] + '.' + decimalValue;
}

// 5.56789      ---->  $5.56
// 0.342        ---->  $0.34
// -10.3484534  ---->  $-10.34 
// 600          ---->  $600.00

function convertNumber(){
  var result = toFixedNumber(document.getElementById("valueText").value);
  document.getElementById("resultText").value = result;
}


function toFixedNumber(number) {
        const spitedValues = String(number.toLocaleString()).split('.');
        let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
        decimalValue = decimalValue.concat('00').substr(0,2);

        return '$'+spitedValues[0] + '.' + decimalValue;
}
<div>
  <input type="text" id="valueText" placeholder="Input value here..">
  <br>
  <button onclick="convertNumber()" >Convert</button>
  <br><hr>
  <input type="text" id="resultText" placeholder="result" readonly="true">
</div>

Ответ 21

Создайте собственную функцию toFixed: для положительных значений Math.floor работает нормально.

function toFixed(num, fixed) {
    fixed = fixed || 0;
    fixed = Math.pow(10, fixed);
    return Math.floor(num * fixed) / fixed;
}

Для отрицательных значений Math.floor округляется значение. Таким образом, вы можете использовать Math.ceil.

Пример,

Math.ceil(-15.778665 * 10000) / 10000 = -15.7786
Math.floor(-15.778665 * 10000) / 10000 = -15.7787 // wrong.

Ответ 22

Второе решение Gumbo с регулярным выражением работает, но медленное из-за регулярного выражения. Первое решение Gumbo выходит из строя в определенных ситуациях из-за неточности чисел с плавающей запятой. См. JSFiddle для демонстрации и теста. Второе решение занимает около 1636 наносекунд за звонок в моей текущей системе, процессор Intel Core i5-2500 на частоте 3,30 ГГц.

Решение, которое я написал, включает добавление небольшой компенсации, чтобы позаботиться о неточности с плавающей запятой. Это в основном мгновенно, т.е. Порядка наносекунд. Я запустил 2 наносекунды за звонок, но таймеры JavaScript не очень точные или гранулированные. Вот JS Fiddle и код.

function toFixedWithoutRounding (value, precision)
{
    var factorError = Math.pow(10, 14);
    var factorTruncate = Math.pow(10, 14 - precision);
    var factorDecimal = Math.pow(10, precision);
    return Math.floor(Math.floor(value * factorError + 1) / factorTruncate) / factorDecimal;
}

var values = [1.1299999999, 1.13, 1.139999999, 1.14, 1.14000000001, 1.13 * 100];

for (var i = 0; i < values.length; i++)
{
    var value = values[i];
    console.log(value + " --> " + toFixedWithoutRounding(value, 2));
}

for (var i = 0; i < values.length; i++)
{
    var value = values[i];
    console.log(value + " --> " + toFixedWithoutRounding(value, 4));
}

console.log("type of result is " + typeof toFixedWithoutRounding(1.13 * 100 / 100, 2));

// Benchmark
var value = 1.13 * 100;
var startTime = new Date();
var numRun = 1000000;
var nanosecondsPerMilliseconds = 1000000;

for (var run = 0; run < numRun; run++)
    toFixedWithoutRounding(value, 2);

var endTime = new Date();
var timeDiffNs = nanosecondsPerMilliseconds * (endTime - startTime);
var timePerCallNs = timeDiffNs / numRun;
console.log("Time per call (nanoseconds): " + timePerCallNs);

Ответ 23

Уже есть подходящий ответ с регулярным выражением и арифметическим расчетом, вы также можете попробовать это

function myFunction() {
    var str = 12.234556; 
    str = str.toString().split('.');
    var res = str[1].slice(0, 2);
    document.getElementById("demo").innerHTML = str[0]+'.'+res;
}

// output: 12.23

Ответ 24

На основе ответа Дэвида D:

function NumberFormat(num,n) {
  var num = (arguments[0] != null) ? arguments[0] : 0;
  var n = (arguments[1] != null) ? arguments[1] : 2;
  if(num > 0){
    num = String(num);
    if(num.indexOf('.') !== -1) {
      var numarr = num.split(".");
      if (numarr.length > 1) {
        if(n > 0){
          var temp = numarr[0] + ".";
          for(var i = 0; i < n; i++){
            if(i < numarr[1].length){
              temp += numarr[1].charAt(i);
            }
          }
          num = Number(temp);
        }
      }
    }
  }
  return Number(num);
}

console.log('NumberFormat(123.85,2)',NumberFormat(123.85,2));
console.log('NumberFormat(123.851,2)',NumberFormat(123.851,2));
console.log('NumberFormat(0.85,2)',NumberFormat(0.85,2));
console.log('NumberFormat(0.851,2)',NumberFormat(0.851,2));
console.log('NumberFormat(0.85156,2)',NumberFormat(0.85156,2));
console.log('NumberFormat(0.85156,4)',NumberFormat(0.85156,4));
console.log('NumberFormat(0.85156,8)',NumberFormat(0.85156,8));
console.log('NumberFormat(".85156",2)',NumberFormat(".85156",2));
console.log('NumberFormat("0.85156",2)',NumberFormat("0.85156",2));
console.log('NumberFormat("1005.85156",2)',NumberFormat("1005.85156",2));
console.log('NumberFormat("0",2)',NumberFormat("0",2));
console.log('NumberFormat("",2)',NumberFormat("",2));
console.log('NumberFormat(85156,8)',NumberFormat(85156,8));
console.log('NumberFormat("85156",2)',NumberFormat("85156",2));
console.log('NumberFormat("85156.",2)',NumberFormat("85156.",2));

// NumberFormat(123.85,2) 123.85
// NumberFormat(123.851,2) 123.85
// NumberFormat(0.85,2) 0.85
// NumberFormat(0.851,2) 0.85
// NumberFormat(0.85156,2) 0.85
// NumberFormat(0.85156,4) 0.8515
// NumberFormat(0.85156,8) 0.85156
// NumberFormat(".85156",2) 0.85
// NumberFormat("0.85156",2) 0.85
// NumberFormat("1005.85156",2) 1005.85
// NumberFormat("0",2) 0
// NumberFormat("",2) 0
// NumberFormat(85156,8) 85156
// NumberFormat("85156",2) 85156
// NumberFormat("85156.",2) 85156

Ответ 25

Более надежно получить две плавающие точки без округления.

Справочный ответ

var number = 10.5859;
var fixed2FloatPoints = parseInt(number * 100) / 100;
console.log(fixed2FloatPoints);

Ответ 26

Вот что это такое со строкой

export function withoutRange(number) {
  const str = String(number);
  const dotPosition = str.indexOf('.');
  if (dotPosition > 0) {
    const length = str.substring().length;
    const end = length > 3 ? 3 : length;
    return str.substring(0, dotPosition + end);
  }
  return str;
}

Ответ 27

Все эти ответы кажутся немного сложными. Я бы просто вычел 0.5 из вашего числа и использовал бы toFixed().

Ответ 28

Наиболее эффективное решение (для 2-х дробных цифр) - вычесть 0,005 перед вызовом toFixed()

function toFixed2( num ) { return (num-0.005).toFixed(2) }

Отрицательные числа тоже будут округлены (от нуля). ОП ничего не сказал об отрицательных числах.

Ответ 29

Я знаю, что уже есть несколько рабочих примеров, но я думаю, что стоит предложить мой эквивалент String.toFixed, некоторые могут найти его полезным.

Это моя альтернатива toFixed, которая не округляет числа, просто усекает ее или добавляет нули в соответствии с заданной точностью. Для очень длинных чисел используется встроенное округление JS, когда точность слишком велика. Функция работает для всех проблемных чисел, которые я нашел в стеке.

function toFixedFixed(value, precision = 0) {
    let stringValue = isNaN(+value) ? '0' : String(+value);

    if (stringValue.indexOf('e') > -1 || stringValue === 'Infinity' || stringValue === '-Infinity') {
        throw new Error('To large number to be processed');
    }

    let [ beforePoint, afterPoint ] = stringValue.indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];

    // Force automatic rounding for some long real numbers that ends with 99X, by converting it to string, cutting off last digit, then adding extra nines and casting it on number again
    // e.g. 2.0199999999999996: +('2.019999999999999' + '9999') will give 2.02
    if (stringValue.length >= 17 && afterPoint.length > 2 && +afterPoint.substr(afterPoint.length - 3) > 995) {
        stringValue = String(+(stringValue.substr(0, afterPoint.length - 1) + '9'.repeat(stringValue.split('.').shift().length + 4)));
        [ beforePoint, afterPoint ] = String(stringValue).indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];
    }

    if (precision === 0) {
        return beforePoint;
    } else if (afterPoint.length > precision) {
        return '${beforePoint}.${afterPoint.substr(0, precision)}';
    } else {
        return '${beforePoint}.${afterPoint}${'0'.repeat(precision - afterPoint.length)}';
    }
}

Имейте в виду, что точность не может быть обработана должным образом для чисел длиной 18 и более, например, 64-битный Chrome будет округлять его или добавлять "e+"/"e-", чтобы длина номера оставалась равной 18.

Если вы хотите выполнить операции с действительными числами, то безопаснее Math.sqrt(10, precision) умножить их на Math.sqrt(10, precision), затем выполнить вычисления, а затем вычислить результат на значение множителя.

Пример:

0.06 + 0.01 - это 0.06999999999999999, и каждая функция форматирования, которая не 0.06999999999999999, 0.06999999999999999 ее до 0.06 для точности 2.

Но если вы выполните ту же операцию с множителем и делителем: (0.06 * 100 + 0.01 * 100)/100, вы получите 0.07.

Вот почему так важно использовать такой множитель/делитель при работе с реальными числами в JavaScript, особенно когда вы рассчитываете деньги...

Ответ 30

Мое решение в машинописи (может быть легко перенесено на JS):

/**
 * Returns the price with correct precision as a string
 *
 * @param   price The price in decimal to be formatted.
 * @param   decimalPlaces The number of decimal places to use
 * @return  string The price in Decimal formatting.
 */
type toDecimal = (price: number, decimalPlaces?: number) => string;
const toDecimalOdds: toDecimal = (
  price: number,
  decimalPlaces: number = 2,
): string => {
  const priceString: string = price.toString();
  const pointIndex: number = priceString.indexOf('.');

  // Return the integer part if decimalPlaces is 0
  if (decimalPlaces === 0) {
    return priceString.substr(0, pointIndex);
  }

  // Return value with 0s appended after decimal if the price is an integer
  if (pointIndex === -1) {
    const padZeroString: string = '0'.repeat(decimalPlaces);

    return '${priceString}.${padZeroString}';
  }

  // If numbers after decimal are less than decimalPlaces, append with 0s
  const padZeroLen: number = priceString.length - pointIndex - 1;
  if (padZeroLen > 0 && padZeroLen < decimalPlaces) {
    const padZeroString: string = '0'.repeat(padZeroLen);

    return '${priceString}${padZeroString}';
  }

  return priceString.substr(0, pointIndex + decimalPlaces + 1);
};

Тестовые случаи:

  expect(filters.toDecimalOdds(3.14159)).toBe('3.14');
  expect(filters.toDecimalOdds(3.14159, 2)).toBe('3.14');
  expect(filters.toDecimalOdds(3.14159, 0)).toBe('3');
  expect(filters.toDecimalOdds(3.14159, 10)).toBe('3.1415900000');
  expect(filters.toDecimalOdds(8.2)).toBe('8.20');

Какие-нибудь улучшения?