JavaScript中的舍入模式



这是一个非常小众的问题,但我正在JS中实现区间算术,我希望有正确的舍入。因此,我需要能够将两个数字相加,并使其向无穷大取整,-无穷大,零等。据我所知,JS总是向零取整,这种行为是不可变的,不像在带有fesetround的C/C++中那样。

我该怎么绕过这个?如果这意味着正确的四舍五入,我愿意对绩效产生重大影响;该功能可能可以切换以平衡速度和正确性。也许这样做的一种方法是以某种方式使函数roundUp和roundDown向上/向下舍入到下一个浮点值。

作为如何实现roundUp/roundDown的示例:


const floatStore = new Float64Array(1)
const intView = new Uint32Array(floatStore.buffer)
function roundUp(x) {
if (x === Infinity)
return Infinity
if (x === -Infinity)
return -Infinity
if (isNaN(x))
return NaN

floatStore[0] = x
let leastSignificantGroup = ++intView[0]
if (leastSignificantGroup === 0)
intView[1]++
return floatStore[0]
}
(5.1).toPrecision(100) // -> 5.0999999999999996447...
roundUp(5.1).toPrecision(100) // -> 5.100000000000000532...

对于任何想要快速获得连续浮点值的人来说,这是有效的:

const MAGIC_ROUND_C = 1.1113332476497816e-16 // just above machine epsilon / 2
const POSITIVE_NORMAL_MIN = 2.2250738585072014e-308
const POSITIVE_DENORMAL_MIN = Number.MIN_VALUE
function roundUp (x) {
if (x >= -POSITIVE_NORMAL_MIN && x < POSITIVE_NORMAL_MIN) {
// denormal numbers
return x + POSITIVE_DENORMAL_MIN
} else if (x === -Infinity) {
// special case
return -Number.MAX_VALUE
}
return x + Math.abs(x) * MAGIC_ROUND_C
}
function roundDown (x) {
if (x > -POSITIVE_NORMAL_MIN && x <= POSITIVE_NORMAL_MIN) {
return x - POSITIVE_DENORMAL_MIN
} else if (x === Infinity) {
return Number.MAX_VALUE
}
return x - Math.abs(x) * MAGIC_ROUND_C
}

唯一奇怪的是,它将+0-0视为相同的,因此将它们向上取整会得到最小的非正规化,向下取整也是一样的。

最新更新