哪些操作可以使浮点数离开 [0, 1] 范围?
What operations can make floats leave a [0, 1] range?
我经常使用范围为 [0, 1] 的 float
或 double
类型。我知道浮点运算是不精确的,所以我通常会限制我的值,以保证它们在这个范围内 before/after 操作。
在某些情况下,我依赖于浮点数,甚至不是轻微的负值,而是恰好 <= 1
,因此这是必要的。
例如,在这些功能中是否有必要:
// x and y are guaranteed to be in [0, 1]
float avg(float x, float y) {
// the average of [0, 1] values should always be in [0, 1]
return std::clamp<float>((x + y) / 2, 0, 1);
}
float mul(float x, float y) {
// the product of [0, 1] values should always be in [0, 1]
return std::clamp<float>(x * y, 0, 1);
}
float pow(float x, unsigned y) {
// raising an [0, 1] value to any unsigned power should also result in an [0, 1] value
return std::clamp<float>(std::pow(x, y), 0, 1);
}
算术运算什么时候可以让浮点数离开[0, 1]范围,是否有一致的规则?
如果可以,请将此答案限制为 IEEE754。
0
、1
和 2
都可以精确表示为 float
。算术运算符需要 return 可能的最佳浮点值。由于 x
和 y
都不大于 1,因此它们的总和不能大于 2,否则总和会存在更好的 float
。换句话说,小于1
的两个float
之和不能大于2
.
同样适用于产品。
第三个需要夹具,因为不能保证 std::pow(x, y)
return 是最好的 float
。
角题
float pow(float x, unsigned y) {
// raising an [0, 1] value to any unsigned power should also result in an [0, 1] value
return std::clamp<float>(std::pow(x, y), 0, 1);
}
使用 std::pow(±0, 0)
可能会导致超出 [0..1] 范围(或导致域错误),因为该结果未由 std::pow()
指定,也未经过数学解析:Zero to the power of zero .
如果遵循 IEEE,结果为 1,但不需要符合要求的库。
如果不遵循 IEEE 和 std::pow(0,0)
return 的 NAN,我预计 std::clamp(NAN,0,1)
也会 return NAN 并破坏系统。
候选替代代码
return (y==0) ? 1 : x;
请注意函数的结果可能是 -0.0,但该值仍在 [0...1] 范围内。
我认为 mul()
、avg()
没有关于 -0.0 的问题,以更高的精度和变体舍入模式进行中间计算。
我经常使用范围为 [0, 1] 的 float
或 double
类型。我知道浮点运算是不精确的,所以我通常会限制我的值,以保证它们在这个范围内 before/after 操作。
在某些情况下,我依赖于浮点数,甚至不是轻微的负值,而是恰好 <= 1
,因此这是必要的。
例如,在这些功能中是否有必要:
// x and y are guaranteed to be in [0, 1]
float avg(float x, float y) {
// the average of [0, 1] values should always be in [0, 1]
return std::clamp<float>((x + y) / 2, 0, 1);
}
float mul(float x, float y) {
// the product of [0, 1] values should always be in [0, 1]
return std::clamp<float>(x * y, 0, 1);
}
float pow(float x, unsigned y) {
// raising an [0, 1] value to any unsigned power should also result in an [0, 1] value
return std::clamp<float>(std::pow(x, y), 0, 1);
}
算术运算什么时候可以让浮点数离开[0, 1]范围,是否有一致的规则?
如果可以,请将此答案限制为 IEEE754。
0
、1
和 2
都可以精确表示为 float
。算术运算符需要 return 可能的最佳浮点值。由于 x
和 y
都不大于 1,因此它们的总和不能大于 2,否则总和会存在更好的 float
。换句话说,小于1
的两个float
之和不能大于2
.
同样适用于产品。
第三个需要夹具,因为不能保证 std::pow(x, y)
return 是最好的 float
。
角题
float pow(float x, unsigned y) {
// raising an [0, 1] value to any unsigned power should also result in an [0, 1] value
return std::clamp<float>(std::pow(x, y), 0, 1);
}
使用 std::pow(±0, 0)
可能会导致超出 [0..1] 范围(或导致域错误),因为该结果未由 std::pow()
指定,也未经过数学解析:Zero to the power of zero .
如果遵循 IEEE,结果为 1,但不需要符合要求的库。
如果不遵循 IEEE 和 std::pow(0,0)
return 的 NAN,我预计 std::clamp(NAN,0,1)
也会 return NAN 并破坏系统。
候选替代代码
return (y==0) ? 1 : x;
请注意函数的结果可能是 -0.0,但该值仍在 [0...1] 范围内。
我认为 mul()
、avg()
没有关于 -0.0 的问题,以更高的精度和变体舍入模式进行中间计算。