如果 std::numeric_limits<float>::is_iec559 为真,这是否意味着我可以以明确定义的方式提取指数和尾数?
If std::numeric_limits<float>::is_iec559 is true, does that mean that I can extract exponent and mantissa in a well defined way?
我已经构建了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
我确保float
满足
IEC 559 (IEEE 754( 标准的要求。
我的问题是:这是否意味着我正在做的位操作是明确定义的并且可以做我想做的?如果没有,有没有办法解决它?
我测试了一些随机值,它似乎是正确的,至少在使用 msvc 编译的 Windows 10 和 wandbox 上。但是请注意,(故意(我不是在处理次正常、NaN
和inf
的边缘情况。
如果有人想知道我为什么要这样做:在基准测试中,我发现这个版本的frexp
比 Windows 15 上的std::frexp
快 10 倍。我还没有测试过其他平台。但我想确保这不仅仅是巧合,而且将来可能会刹车。
编辑:
正如评论中提到的,恩迪亚内斯可能是一个问题。有人知道吗?
"这是否意味着我正在执行的位操作已明确定义......">
TL;DR;,根据"明确定义"的严格定义:否。
您的假设可能是正确的,但定义不明确,因为无法保证位宽或float
的实现。从§ 3.9.1:
有三种浮点类型:浮点型、双精度型和长型双精度型。双精度型至少提供与浮点数一样多的精度,而长型双精度型提供的精度至少与双精度一样多。浮点型的值集是双精度类型的值集的子集;双精度类型的值集是长双精度类型的值集的子集。浮点类型的值表示形式是实现定义的。
is_iec559
条款仅符合以下条件:
且仅当类型符合 IEC 559 标准时为 True
如果一个文字精灵给你写了一个糟糕的编译器,并做了float
=binary16,double
=binary32,long double
=binary64,并且对所有类型都is_iec559
正确,它仍然会遵守标准。
这是否意味着我可以用明确定义的方式提取指数和尾数?
TL;DR;,由C++标准的有限保证:否。
假设您使用float32_t
并且is_iec559
为真,并且从所有规则中逻辑推断出它只能是二进制32,没有陷阱表示,并且您正确地认为memcpy
是相同宽度的算术类型之间的转换的良好定义,并且不会破坏严格的混叠。即使有所有这些假设,行为也可能被很好地定义,但只是可能且不能保证你可以通过这种方式提取尾数。
IEEE 754 标准和 2 的补码涉及位字符串编码,memcpy
的行为使用字节描述。虽然假设uint32_t
和float32_t
的位字符串将以相同的方式编码(例如相同的字节序(是合理的,但在标准中无法保证这一点。如果位字符串的存储方式不同,并且您移动并屏蔽复制的整数表示以获得尾数,则答案将不正确,尽管memcpy
行为已明确定义。
正如评论中提到的,恩迪亚内斯可能是一个问题。有人知道吗?
至少有一些体系结构对浮点寄存器和整数寄存器使用了不同的字节序。同样的链接说,除了小型嵌入式处理器,这不是一个问题。我完全信任维基百科的所有主题,并拒绝做任何进一步的研究。
- 如何重新定义MPI_FLOAT,MPI_DOUBLE以 typedef 的方式
- 具有调整对齐方式的类型定义
- C++结构模板变量快捷方式定义不起作用
- 请描述一下在 c++ 中在此类中定义构造函数的方式?
- 如果 std::numeric_limits<float>::is_iec559 为真,这是否意味着我可以以明确定义的方式提取指数和尾数?
- 为什么以这种方式在C 中定义模板函数
- 如何以编程方式自定义Windows Media Player
- 有没有人有书面证据来保证函数中参数的定义方式与普通变量声明相同?
- 快捷方式在C 中编写自定义编译命令时
- 以面向对象的方式解析自定义数据包
- 为什么 cppreference 将type_traits xxx_v快捷方式定义为内联 constexpr,而不仅仅是
- 将值传递给自定义QtWidget的最佳方式
- 拥有 std::map 的最佳方式,我可以在其中定义如果没有键时返回的内容
- C++命名空间std的定义方式/位置(文档/标准链接)
- 类定义中定义的成员函数的编译方式是否与C++中其他位置定义的成员函数不同
- 自定义快捷方式上的上下文菜单
- 如何在自定义信号处理程序中以编程方式获取sigterm的默认行为
- C++结构来定义数据的排列和访问方式
- c++类定义.属性作为指针?这是正确的方式
- 为什么派生类中复制/移动函数"normal"实现的行为会有所不同,具体取决于它们的定义方式?