用适当的替换覆盖 toFixed() 以修复浮点错误 javascript
Overwrite toFixed() with appropriate replacement to fix floating point error javascript
这是我尝试修复 JavaScript toFixed() 函数...
非常感谢任何输入、想法和对可能错误的更正!
- 修复浮点数不准确(示例 (35.355).toFixed(2) = 35.36,不是 35.35)
- 没有大的附加库
- 综合函数(人类可读)
- 模拟到 Fixed / 即输出完全相同(尽管对浮点 inac. 或 course 进行了校正)
这是我的尝试 -> 下面的演示(查看控制台日志)
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 时预先捕获。这应该像原来的那样抛出错误。
输出:
这是我尝试修复 JavaScript toFixed() 函数...
非常感谢任何输入、想法和对可能错误的更正!
- 修复浮点数不准确(示例 (35.355).toFixed(2) = 35.36,不是 35.35)
- 没有大的附加库
- 综合函数(人类可读)
- 模拟到 Fixed / 即输出完全相同(尽管对浮点 inac. 或 course 进行了校正)
这是我的尝试 -> 下面的演示(查看控制台日志)
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 时预先捕获。这应该像原来的那样抛出错误。