用适当的替换覆盖 toFixed() 以修复浮点错误 javascript

Overwrite toFixed() with appropriate replacement to fix floating point error javascript

这是我尝试修复 JavaScript toFixed() 函数...

非常感谢任何输入、想法和对可能错误的更正!

这是我的尝试 -> 下面的演示(查看控制台日志)

Number.prototype.toFixed = function(fractionDigits) {
    var digits = parseInt(fractionDigits) || 0;
    var num = Number(this);
    if( isNaN(num) ) {
        return 'NaN';
    }
    
    var sign = num < 0 ? -1 : 1;
    if (sign < 0) { num = -num; }
    digits = Math.pow(10, digits);
    num *= digits;
    num = Math.round( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );
    var finalNumber = sign * num / digits;

    // add 0 after last decimal number (not 0) for as many as requested (fractionDigits)
    // in else case, check if requested digits exceed actual, then add 0 (avoid 10.1 for toFixed(2))

    if(fractionDigits > 0 && finalNumber.toString().indexOf('.') == -1){
        // check that .00 is present
        finalNumber = finalNumber.toString() + '.' + '0'.repeat(fractionDigits);
    } else if(fractionDigits > finalNumber.toString().split('.')[1]?.length){
        finalNumber = finalNumber.toString() + '0'.repeat((fractionDigits - finalNumber.toString().split('.')[1]?.length));
    }
    
    return finalNumber.toString(); // tofixed returns as string always, do the same
}

console.log('(35.355).toFixed(2)', (35.355).toFixed(2));
console.log('(35.1).toFixed(2)', (35.1).toFixed(2));
console.log('(35).toFixed(2)', (35).toFixed(2));

Number.prototype.toFixed = function(fractionDigits) {
//function toFixed(numberInput, fractionDigits){
    var digits = parseInt(fractionDigits) || 0;
    var num = Number(this);
    if( isNaN(num) ) {
        return 'NaN';
    }
    
    var sign = num < 0 ? -1 : 1;
    if (sign < 0) { num = -num; }
    digits = Math.pow(10, digits);
    num *= digits;
    num = Math.round( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );
    var finalNumber = sign * num / digits;

    // add 0 after last decimal number (not 0) for as many as requested (fractionDigits)

    if(fractionDigits > 0 && finalNumber.toString().indexOf('.') == -1){
        // check that .00 is present
        finalNumber = finalNumber.toString() + '.' + '0'.repeat(fractionDigits);
    } else if(fractionDigits > finalNumber.toString().split('.')[1]?.length){
        finalNumber = finalNumber.toString() + '0'.repeat((fractionDigits - finalNumber.toString().split('.')[1]?.length));
    }
    
    return finalNumber.toString(); // tofixed returns as string always, do the same
}

console.log('post-fix | (35.355).toFixed(2)', (35.355).toFixed(2));
console.log('post-fix | (35.1).toFixed(2)', (35.1).toFixed(2));
console.log('post-fix | (35).toFixed(2)', (35).toFixed(2));

这里尝试将其解析为整数,而不是舍入数字 num = Math.round( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );

Math.round 将根据大于或小于 0.5 的阶乘部分对值进行四舍五入。正如您在此处所期望的那样,parseInt 将简单地获取整数部分而不进行舍入。

console.log('(35.355).toFixed(2)', (35.355).toFixed(2));
console.log('(35.1).toFixed(2)', (35.1).toFixed(2));
console.log('(35).toFixed(2)', (35).toFixed(2));

Number.prototype.toFixed = function(fractionDigits) {
//function toFixed(numberInput, fractionDigits){
    debugger;
    var digits = parseInt(fractionDigits) || 0;
    var num = Number(this);
    if( isNaN(num) ) {
        return 'NaN';
    }
    
    var sign = num < 0 ? -1 : 1;
    if (sign < 0) { num = -num; }
    digits = Math.pow(10, digits);
    num *= digits;
    num = parseInt( Math.round(num * Math.pow(10,12)) / Math.pow(10,12) );
    var finalNumber = sign * num / digits;

    // add 0 after last decimal number (not 0) for as many as requested (fractionDigits)

    if(fractionDigits > 0 && finalNumber.toString().indexOf('.') == -1){
        // check that .00 is present
        finalNumber = finalNumber.toString() + '.' + '0'.repeat(fractionDigits);
    } else if(fractionDigits > finalNumber.toString().split('.')[1]?.length){
        finalNumber = finalNumber.toString() + '0'.repeat((fractionDigits - finalNumber.toString().split('.')[1]?.length));
    }
    
    return finalNumber.toString(); // tofixed returns as string always, do the same
}

console.log('post-fix | (35.355).toFixed(2)', (35.355).toFixed(2));
console.log('post-fix | (35.1).toFixed(2)', (35.1).toFixed(2));
console.log('post-fix | (35).toFixed(2)', (35).toFixed(2));

如果是我,我可能会有这样的字符串操作方法:

Number.prototype.toFixed = function(fractionDigits) {
  var number = String(this);
  var digits = fractionDigits || 0, length;
  
  if(digits < 0 && digits > 100) 
    throw 'RangeError: toFixed() digits argument must be between 0 and 100';

  var decimal = number.match(/(?<=\.)(\d*)/g);
  var factor = Math.pow(10, digits);
  if (decimal && decimal[0].length >= digits) 
    return String(Math.round(Number(number + '1') * factor) / factor);
  else {
    var length = digits - (decimal ? decimal[0].length : 0);
    var delimiter = number.includes('.') || !length ? '' : '.';
    return String(number) + delimiter + '0'.repeat(length);
  }
}

function test() {
  console.log((-35.555).toFixed(2))
  console.log((-35.35).toFixed(2))
  console.log((-35.9).toFixed(2))
  console.log((-35).toFixed(2))
}

注:

  • 我认为您不会在 toFixed 中遇到字符串,因为它不会被它触发,所以您不需要 isNaN 检查。
  • 当参数小于 0 或大于 100 时预先捕获。这应该像原来的那样抛出错误。

输出: