如何正确地将浮点数舍入为 epsilon 溢出

问题描述 投票:0回答:1

为了在不允许重复的数据结构(如二叉树、堆等)中对浮点数进行排序,我想将

float
舍入到一定程度的精度,如下所示:

float round_to_epsilon(x);

bool less_than(float x, float y) {
    return round_to_epsilon(x) < round_to_epsilon(y);
}

换句话说,我想将

float
量化为
std::numeric_limits<float>::epsilon
的倍数,即2-23

第一个想法:乘法和地板

乍一看,您似乎可以这样做:

float round_to_epsilon(float x) {
    // note: floor or ceil must be used to avoid bias around zero
    return std::floor(x / std::numeric_limits<float>::epsilon());
}

但是,这会将每个大于 2105 的数字变成正无穷大,这不是溢出正确的。

第二个想法:除法以放弃精度

另一种方法是乘以一个非常小的数字来故意导致下溢,并丢弃一些数字。然而,这使得非规范化的数字很可能出现,因此这种方法可能会出现严重的性能问题。

问题

如何舍入为 epsilon;或者换句话说,如何将数字降到 2-23 以下,而不导致不必要的上溢或下溢?

我的直觉是,也许我可以除以二的幂,然后再次相乘以获得避免非规范化的数字,但我不确定如何做到这一点,或者这是否是一个好方法。

c++ floating-point rounding
1个回答
0
投票

换句话说,我想将

float
量化为
std::numeric_limits<float>::epsilon

的倍数

我将按要求回答问题,而不讨论这是否是最适合所述用例的方法。您的第一个想法实际上是可行的,只要处理输入域的末端即可。

数量级足够大的数字自然会被量化为

eps
的整数倍。比
eps
小得多的数字将四舍五入为零。要在量化过程中舍入到最接近或偶数,可以使用
rint()
,前提是默认舍入模式设置为舍入到最近或偶数(通常是这样)。此警告是必要的,因为与 floor()
ceil()
trunc()
 不同,
rint()
 不使用固定舍入模式运行,而是使用当前有效的舍入模式。

float round_to_epsilon (float x) { float eps, cutoff, r; eps = std::numeric_limits<float>::epsilon(); cutoff = 0.5f * eps; if (x < cutoff) { r = copysignf (0.0f, x); } else if (x >= 2.0f) { r = x; } else { r = eps * rintf (x / eps); } return r; }
    
© www.soinside.com 2019 - 2024. All rights reserved.