将数字四舍五入到指定小数位数的基本方法是将数字乘以 10^DIGITS 将小数点 DIGITS 数字左移,执行四舍五入,然后除以相同的 10^DIGITS 以移动小数指向右边。
var value:Number = 45 * (1 - (1 / 3));
trace(value); // 30.000000000000004
trace(Math.ceil(value)); // 31
// Round the number to 13 decimal digits.
const POWER:Number = 1e13;
value = Math.round(value * POWER) / POWER;
trace(value); // 30
// Compute number's ceiling.
value = Math.ceil(value);
trace(value); // 30`
它适用于您的示例,但有一个很大的问题。如果您将值更改为450 * (1 - (1 / 3));
,您的原始问题将再次出现。现在要摆脱它,您必须四舍五入到 12 位十进制数字。基本上,双精度格式(数字)的有效位可以容纳大约 15 个有效数字。这意味着随着值增加十倍,小数点向左移动,并且您要删除的最后一个“4”位越来越接近小数点。所以代码变得更加复杂。
var value:Number = 450 * (1 - (1 / 3));
trace(value); // 30.000000000000004
trace(Math.ceil(value)); // 31
var exp:Number = Math.floor(Math.log(Math.abs(value)) * Math.LOG10E);
trace('exp=' + exp); // exp=2
const POWER:Number = Math.pow(10, 14 - exp);
value *= POWER;
trace(value); // 300000000000000.06
value = Math.round(value);
trace(value); // 300000000000000
value /= POWER;
trace(value); // 300
如您所见,无论值的大小如何,它现在都可以工作。首先,我通过取数字绝对值的以 10 为底的对数,然后将其向下舍入来找到数字的指数。如果计算a = value * Math.pow(10, exp);
,则值可以表示为 a * 10^b,其中 (1 ≤ |a| < 10),称为归一化科学记数法。但这不是我们在这里所做的。现在我们知道小数点左边有多少位,我们将小数点向右移动,但不要太远,以保持一个 0 和我们想要去掉的这个错误数字,在右边小数点。因此,乘以 10^(14-exp),四舍五入,然后除以相同的幂。