我已经构建了一个自定义版本frexp https://en.cppreference.com/w/cpp/numeric/math/frexp:
auto frexp(float f) noexcept
{
static_assert(std::numeric_limits<float>::is_iec559);
constexpr uint32_t ExpMask = 0xff;
constexpr int32_t ExpOffset = 126;
constexpr int MantBits = 23;
uint32_t u;
std::memcpy(&u, &f, sizeof(float)); // well defined bit transformation from float to int
int exp = ((u >> MantBits) & ExpMask) - ExpOffset; // extract the 8 bits of the exponent (it has an offset of 126)
// divide by 2^exp (leaving mantissa intact while placing "0" into the exponent)
u &= ~(ExpMask << MantBits); // zero out the exponent bits
u |= ExpOffset << MantBits; // place 126 into exponent bits (representing 0)
std::memcpy(&f, &u, sizeof(float)); // copy back to f
return std::make_pair(exp, f);
}
通过检查is_iec559 https://en.cppreference.com/w/cpp/types/numeric_limits/is_iec559我确定float
满足
IEC 559 (IEEE 754) 标准的要求。
我的问题是:这是否意味着我正在执行的位操作定义良好并且可以执行我想要的操作?如果没有,有办法解决吗?
我测试了它的一些随机值,它似乎是正确的,至少在使用 msvc 编译的 Windows 10 上wandbox https://wandbox.org/permlink/VdKLHXtSaqB6B4KR。但请注意,(故意)我没有处理次正规的边缘情况,NaN
, and inf
.
如果有人想知道我为什么这样做:在基准测试中我发现这个版本frexp
速度高达 15 倍std::frexp
在 Windows 10 上。我还没有测试过其他平台。但我想确保这不仅仅是巧合,而且将来可能会停止。
Edit:
正如评论中提到的,字节顺序可能是一个问题。有人知道吗?