假设我有一个值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?
我的解决方案在typescript(可以很容易地移植到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');
任何改善吗?
2016年11月5日更新
新的答案,总是准确的
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函数将始终按预期工作。
老答案,并不总是准确的。
固定功能:
function toFixed(num, fixed) {
fixed = fixed || 0;
fixed = Math.pow(10, fixed);
return Math.floor(num * fixed) / fixed;
}
我知道已经有一些工作示例,但我认为值得提出我的String。对于固定等价物,有些人可能会发现它很有用。
这是我的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乘以它会更安全。先根号(10,精度),进行计算,然后按乘数的值潜水结果。
例子:
0.06 + 0.01等于0.0699999999999999999,每个格式化函数
这不是四舍五入会截断为0.06以达到精度2。
但如果你用乘数和除法器(0.06 * 100 + 0.01 * 100)/ 100执行同样的操作,你会得到0.07。
这就是为什么在javascript中处理实数时使用乘数/除法是如此重要,特别是当你计算金钱时…