将数字截断为两位小数而不进行舍入

时间:2010-11-15 17:31:18

标签: javascript

假设我的值为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?

38 个答案:

答案 0 :(得分:197)

将数字转换为字符串,将数字与第二个小数位匹配:

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>

toFixed方法在某些情况下与toString不同,因此要非常小心。

答案 1 :(得分:55)

2016年11月5日更新

新答案,始终准确

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

由于floating point math in javascript总是有边缘情况,以前的解决方案在大多数情况下都是准确的,这还不够好。 有一些解决方案,如num.toPrecisionBigDecimal.jsaccounting.js。 然而,我认为仅仅解析字符串将是最简单且始终准确的。

根据@Gumbo接受的答案更新写好的正则表达式,这个新的toFixed函数将始终按预期工作。


老答案,并不总是准确的。

滚动你自己的固定功能:

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

答案 2 :(得分:28)

我选择写这个,而不是用字符串手动删除余数,所以我不必处理数字带来的数学问题:

num = num.toString(); //If it's 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

这会给你&#34; 15.77&#34;与num = 15.7784514;

答案 3 :(得分:14)

2017年10月

将任意数字截断(不舍入)到第n个十进制数字并将其转换为精确n个十进制数字的字符串的一般解决方案,对于任何n≥0。

function toFixedTrunc(value, n) {
  const v = value.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}`
}

以下是n = 2的一些测试(包括OP请求的测试):

0           => 0.00
0.01        => 0.01
0.2372      => 0.23
0.5839      => 0.58
0.999       => 0.99
1           => 1.00
1.01        => 1.01
2           => 2.00
2.551       => 2.55
2.5         => 2.50
2.99999     => 2.99
4.27        => 4.27
15.7784514  => 15.77
123.5999    => 123.59

请注意,虽然上述始终,但纯数字方法不会。例如,考虑以下函数(或任何类似函数):

function toFixedTrunc(value, n) {
  const f = Math.pow(10, n);
  return (Math.trunc(value*f)/f).toFixed(n);
}

虽然在概念上是正确的,但是会因一些无理数而失败,例如: 4.27,由于数字在内部表示的方式。

答案 4 :(得分:13)

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"

答案 5 :(得分:6)

简单做到这一点

number = parseInt(number * 100)/100;

答案 6 :(得分:5)

这里的答案对我没有帮助,它一直在四舍五入或给我错误的小数。

我的解决方案将您的小数转换为字符串,提取字符然后将整个事物作为数字返回。

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

答案 7 :(得分:5)

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

这将返回19.66

答案 8 :(得分:5)

我的正数版本:

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

快速,漂亮,明显。 (正数版本)

答案 9 :(得分:4)

这些解决方案确实有效,但对我来说似乎不必要地复杂化。我个人喜欢使用模运算符来获得除法运算的剩余部分,并删除它。假设num = 15.7784514:

num-=num%.01;

这相当于说num = num - (num%.01)。

答案 10 :(得分:4)

以下代码对我非常有用:

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

答案 11 :(得分:3)

我使用以下简单方法修复 -

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

结果 15.77

答案 12 :(得分:2)

你在这里。答案显示了另一种解决问题的方法:

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

注意在最终表达式之前使用+。那就是将截断的切片字符串转换回数字类型。

希望它有所帮助!

答案 13 :(得分:2)

截断无零

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

答案 14 :(得分:2)

下一个简单的方法是这样做,但必须确保amount参数以字符串形式给出。

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

答案 15 :(得分:1)

如果您确实想将精度截断为2位数,则可以采用简单的逻辑:

function myFunction(number) {
  var roundedNumber = number.toFixed(2);
  if (roundedNumber > number)
  {
      roundedNumber = roundedNumber - 0.01;
  }
  return roundedNumber;
}

答案 16 :(得分:1)

我使用(num-0.05).toFixed(1)来获得第二个十进制小数。

答案 17 :(得分:1)

另一个单线解决方案:

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

我使用100因为你想截断到第二个数字,但更灵活的解决方案是:

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

其中digits是要保留的小数位数。

答案 18 :(得分:1)

function formatLimitDecimals(value, decimals) {
  value = value.toString().split('.')

  if (value.length === 2) {
    return Number([value[0], value[1].slice(0, decimals)].join('.'))
  } else {
    return Number(value[0]);
  }
}

console.log(formatLimitDecimals(4.156, 2)); // 4.15
console.log(formatLimitDecimals(4.156, 8)); // 4.156
console.log(formatLimitDecimals(4.156, 0)); // 4

答案 19 :(得分:1)

这对我来说很好。我希望它也能解决您的问题。

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>

答案 20 :(得分:1)

只需截断数字:

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

答案 21 :(得分:0)

2021 年 6 月更新

这将修复给定长度的任何数字而无需四舍五入

let FixWithoutRounding = (v, l) => {
      const intPart = Math.trunc(v).toString()
      const fractionPart = v.toString().slice(v.toString().indexOf('.') + 1)
      if (fractionPart.length > l) {
        return Number(intPart.concat('.', fractionPart.slice(0, l)))
      } else {
        const padded = intPart.concat('.', fractionPart.padEnd(l, '0'))
        return padded
      }
    }

console.log(FixWithoutRounding(123.123, 12))

答案 22 :(得分:0)

function toFixed(num, fixed) {
    fixed = fixed || 0;
    var front = Math.floor(num);
    var back = 0;
    for (var i = 1; i <= fixed; i++) {
        var value = Math.floor(num * Math.pow(10, i)) % 10;
        back += value / Math.pow(10, i);
    }
    return front + back;
}

答案 23 :(得分:0)

const toFixed = (value) => value.toString().slice(0,5);

答案 24 :(得分:0)

结合以前所有答案中的知识,

这是我想出的解决方案:

function toFixedWithoutRounding(num, fractionDigits) {
  if ((num > 0 && num < 0.000001) || (num < 0 && num > -0.000001)) {
    // HACK: below this js starts to turn numbers into exponential form like 1e-7.
    // This gives wrong results so we are just changing the original number to 0 here
    // as we don't need such small numbers anyway.
    num = 0;
  }
  const re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fractionDigits || -1) + '})?');
  return Number(num.toString().match(re)[0]).toFixed(fractionDigits);
}

答案 25 :(得分:0)

另一种解决方案,可以截断舍入

function round (number, decimals, truncate) {
    if (truncate) {
        number = number.toFixed(decimals + 1);
        return parseFloat(number.slice(0, -1));
    }

    var n = Math.pow(10.0, decimals);
    return Math.round(number * n) / n;
};

答案 26 :(得分:0)

我在打字稿中的解决方案(可以轻松移植到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');

有什么改进吗?

答案 27 :(得分:0)

我知道已经有几个工作示例,但是我认为值得提出我的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)会更安全,然后进行计算,然后乘以乘数即可得出结果。

示例:

  

0.06 + 0.010.06999999999999999,每个格式化功能   如果不是舍入,则会将其截断为0.06,精度为2

     

但是,如果您使用乘数和除法器执行相同的运算:(0.06 * 100 + 0.01 * 100) / 100,则会得到0.07

这就是为什么在使用javascript处理实数时,尤其是在计算货币时,使用这种乘数/除法器如此重要的原因。

答案 28 :(得分:0)

最有效的解决方案(对于2个小数位数)是在调用toFixed()之前减去0.005

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

负数也将四舍五入(远离零)。 OP没有透露任何有关负数的信息。

答案 29 :(得分:0)

所有这些答案似乎有点复杂。我只需从您的数字中减去0.5,然后使用toFixed()。

答案 30 :(得分:0)

这是字符串的作用

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

答案 31 :(得分:0)

获得两个没有舍入的浮点数更可靠。

Reference Answer

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

谢谢!

答案 32 :(得分:0)

滚动您自己的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.

答案 33 :(得分:0)

Gumbo的第二个解决方案,使用正则表达式,确实有效但由于正则表达式而变慢。由于浮点数不精确,Gumbo的第一个解决方案在某些情况下失败。有关演示和基准,请参阅JSFiddle。第二种解决方案在我当前的系统,即3.30 GHz的Intel Core i5-2500 CPU上,每次呼叫大约需要1636纳秒。

我写的解决方案涉及添加一个小补偿来处理浮点不精确。它基本上是瞬时的,即在纳秒级。我每次调用时钟为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);

答案 34 :(得分:0)

David D&#39> 回答:

为基础
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

答案 35 :(得分:0)

对于正则表达式和算术计算已有一些合适的答案,您也可以尝试这个

        string num = "1011100";

        char[] myChar = num.ToCharArray();

        bool blFirst = false;  //This will check if there is "1" on first element of the input
        bool blLast = false;  //This will check if there is "1" on last element of the input

        if (myChar[0] == '0') //If the condition is true we will remove this on the result
            blFirst = true;

        if (myChar[myChar.Length - 1] == '0')
            blLast = true;

        string[] intArr = num.Split('1').ToArray();

        List<string> intResult = new List<string>();

        //We will make sure that all results only contains '0' and not empty.
        intResult = intArr.Where(x => x.All(y => y == '0') && x != string.Empty).Select(x => x).ToList();

        if (blFirst == true)
            intResult.RemoveAt(0);

        if (blLast == true)
            intResult.RemoveAt(intResult.Count - 1);

        //After all conditions are met (Get only '0' numbers between 1), that's the time we get the maximum count
        intOutput = intResult.Select(x => x).Max(x => x.Length);

答案 36 :(得分:-1)

感谢 Martin Varmus

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

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

我做了一个简单的更新,我得到了适当的舍入。更新是在

行之后
return ((figure*d)/d).toFixed(decimals);

删除parseInt()函数

答案 37 :(得分:-1)

这是保存.toFixed([digits])功能的另一个变体,没有舍入浮点变量:

Number.prototype.toRealFixed = function(digits) {
    return Math.floor(this.valueOf() * Math.pow(10, digits)) / Math.pow(10, digits);
};

并致电:

var float_var = 0.02209062;
float_var.toRealFixed();