JavaScript - 如何防止 toFixed 四舍五入小数?

16

我对html、javascript和css非常陌生,所以请原谅如果我的问题听起来很傻。我的问题是如何防止toFixed()函数对小数进行四舍五入。

这是我的链接:http://jsfiddle.net/RWBaA/4/

我想做的是每当用户在文本框中键入时,检查输入是否为有效的十进制数。同时,我还想检查输入是否为有效的货币,这意味着它只能在小数点右侧添加两个数字。问题在于,当用户在小数点后输入第3个数字时,如果第3个数字大于等于5,则会将小数点后第2个数字四舍五入到最近的百分位。

测试输入:

  输入         输出
123456.781 -> 123456.78
123456.786 -> 123456.79

为什么我的代码在chrome中不允许箭头键?

请帮忙。如果您有更好的解决方案,请随意提出建议。先行致谢。


非常相关。在这种情况下,由于输入已经是一个字符串,所以不需要将其转换为浮点数,但有一些重复的答案。 - user202729
7个回答

21

那甚至更简单:

function truncateToDecimals(num, dec = 2) {
  const calcDec = Math.pow(10, dec);
  return Math.trunc(num * calcDec) / calcDec;
}
所以:
truncateToDecimals(123456.786) -> 123456.78

不总是有效。4492903605.9 会产生 4492903605.89。 - user1376112
这是因为您正在添加一个新的小数,因为dec参数的默认值为2。您可以传递dec = 1或修复函数以从传递的数字中获取默认小数位长度。 - David
这里可能有一个警告,如果小数位是零,函数将减少小数位(例如:2.20将变成2.2)。 但在我看来,这没问题,因为这就是JavaScript的工作方式,对吧?尊重它。 我的意思是,你可以返回toFixed(),但在那种情况下,返回的类型将是一个字符串,我认为这不公平。 如果你想这样做,在函数外面做,比如在UI界面上,保持数字逻辑的清晰。 这样你就可以防止未来出现错误和丑陋的瑕疵。 - David
truncateToDecimals(99999999999999.9999,2) returns 100000000000000 - FaizanHussainRabbani

11

将数字舍入(向下)到最接近的分:

val = Math.floor(100 * val) / 100;

编辑 有人指出这个方法对于1.13等数字是不适用的。我自己也应该知道!

这种方法失败的原因是,1.13的内部浮点表示略小于1.13 - 将其乘以100并不会产生113,而是112.99999999999998578915,然后将其舍入到1.12。

重新阅读问题后,似乎您只是想执行输入验证(请参见下文),在这种情况下,您应该使用常规表单验证技术,根本不应该使用.toFixed()。该函数用于呈现数字,而不是进行计算。

$('#txtAmount').on('keypress', function (e) {
    var k = String.fromCharCode(e.charCode);
    var v = this.value;
    var dp = v.indexOf('.');

    // reject illegal chars
    if ((k < '0' || k > '9') && k !== '.') return false;

    // reject any input that takes the length
    // two or more beyond the decimal point
    if (dp >= 0 && v.length > dp + 2) {
        return false;
    }

    // don't accept >1 decimal point, or as first char
    if (k === '.' && (dp >= 0 || v.length === 0)) {
        return false;
    }
});

/ 100.0; 这不是C/C++。 - qwertymk
非常感谢,它解决了我的问题...但等等...为什么我不能在Google Chrome中使用箭头键?在Firefox中它运行正常。 - TheOnlyIdiot
这并不总是有效的。请尝试:Math.floor(100 * 1.13) / 100; - Remi Despres-Smyth

7

你可以尝试这个方法,它不会对你的小数进行四舍五入。

/**
 * @param {any} input 
 * @param {number} decimals 
 */
var toFixed = function(input, decimals) {
  var arr = ("" + input).split(".");
  if (arr.length === 1) return input;
  var int = arr[0],
      max = arr[1].length,
      dec = arr[1].substr(0, decimals > max ? max : decimals);
  return decimals === 0 ? int : [int, "." , dec].join("");
}

1
toFixed(99999999999999.9999,4) returns 100000000000000 - FaizanHussainRabbani
这是一个JS问题。在JS中,浮点数只能处理最多64位。如果您执行console.log(99999999999999.9999),它也会打印出四舍五入的整数。实际上,如果您声明一个像这样的变量,它将成为四舍五入的整数。我建议您阅读这篇文章:https://www.avioconsulting.com/blog/overcoming-javascript-numeric-precision-issues - Santiago Hernández

6

此外,为了防止toFixed()将小数四舍五入并使您的数字保留两位小数,您可以使用以下代码:

val = (Math.floor(100 * val) / 100).toFixed(2);

1
不总是有效。4492903605.9 产生 4492903605.89。 - user1376112

1
如果您想避免四舍五入... 例如:1.669 => 1.67,548.466 => 548.47
函数结果如下:1.669 => 1.66,548.466 => 548.46
接下来的 JQuery 函数将会帮助您。已经测试并且正常工作。
<input name="a" type="text" id="a" size="7%" tabindex="2">




  $('#a').keyup(function(e){
        if($(this).val().indexOf('.')!=-1){ 
            if($(this).val()=="." && $(this).val().length==1){
                this.value = parseFloat(0).toFixed(1);
            }else if($(this).val().split(".")[1].length > 2){                
                if( isNaN( parseFloat( this.value ) ) ) 
                    return;
                  this.value = $(this).val().split(".")[0]+"."+$(this).val().split(".")[1].substring(0,2);
            }   
        }
   });

0

这已经经过测试,适用于所有情况。

function truncateTwoDecimals(num, dec = 2) {
  const totalDecimal = countDecimals(num);
  if (totalDecimal === 1) {
    dec = 1;
  }
  if (totalDecimal === 2) {
    return num;
  }
  const calcDec = Math.pow(10, dec);
  return Math.trunc(num * calcDec) / calcDec;
}
function countDecimals(value) {
  if(Math.floor(value) === value) return 0;
  return value.toString().split(".")[1].length || 0; 
}
const res = truncateTwoDecimals(1.13);
console.log(res);
console.log(truncateTwoDecimals(4492903605.9));


1
truncateTwoDecimals(99999999999999.9999,4) returns 100000000000000 - FaizanHussainRabbani

0
这可能听起来很愚蠢,但为什么不通过数学方法来防止舍入?
基本上,您正在将该值偏移半个精度点,这样舍入就会变成向下取整。
正常情况: 0到4等于0 5到9等于10
在减去半个精度点后: -4(变成了6)到-1(变成了9)等于0 0到4等于0
您需要减去0.5 / 10 ^ N 在这种情况下,对于2位小数,0.5 / 10 ^ 2 = 0.5 / 100 = 0.005, 对于4位小数,您需要减去0.00005。
但是,由于计算机和CPU中浮点数的工作方式,您需要确保具有足够的精度用于此。因此,我强烈建议您将精度降低到CPU无法搞乱它的程度。
num = 123456.786
Math.trunc(num) + (num-Math.trunc(num)-0.005).toFixed(2)

num = 123456.781
Math.trunc(num) + (num-Math.trunc(num)-0.005).toFixed(2)

num = 123456.789
Math.trunc(num) + (num-Math.trunc(num)-0.005).toFixed(2)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接