[英]Is checking the location of the sign bit enough to determine endianness of IEEE-754 float with respect to integer endianness?
I recently wrote some code that uses memcpy
to unpack float
/ double
to unsigned integers of the appropriate width, and then uses some bit-shifting to separate the sign bit from the combined significand/exponent.我最近编写了一些代码,使用memcpy
将float
/ double
解包为适当宽度的无符号整数,然后使用一些位移将符号位与组合的有效数/指数分开。
Note: For my use case, I don't need to separate the latter two parts from eachother, but I do need them in the correct order ie:
{sign, (exponent, significand)}
, with the latter tuple packed as an unsigned int of sufficient width.注意:对于我的用例,我不需要将后两个部分彼此分开,但我确实需要它们以正确的顺序,即:{sign, (exponent, significand)}
,后一个元组打包为无符号int 足够的宽度。
My code is working fine, thoroughly tested and no trouble;我的代码运行良好,经过全面测试,没有问题; however I was a bit alarmed to discover that IEEE-754 doesn't specify the endianness of its binary interchange formats —which to my understanding, means there is a rare possibility that my bit-shifting may be incorrect in the rare occasions where float endianness ≠ integer endianness .然而,我有点惊恐地发现 IEEE-754 没有指定其二进制交换格式的字节顺序——据我了解,这意味着在浮动字节顺序的罕见情况下,我的位移可能不正确的可能性很小≠ integer 字节序。
Based on the answered question here , my assumption is that given that bit-shifting is independent of actual endianness in storage, I only need to worry about whether the endianness of my floats matches that of my ints.根据此处已回答的问题,我的假设是,鉴于位移与存储中的实际字节序无关,我只需要担心我的浮点数的字节序是否与我的整数相匹配。
I devised the following code loosely following that in the linked answer, but avoiding the use of type-punning through pointer casts, which seems like unspecified/undefined behaviour territory to me:我在链接的答案中松散地设计了以下代码,但避免通过指针强制转换使用类型双关语,这对我来说似乎是未指定/未定义的行为领域:
#include <cstdint>
#include <cstring>
// SAME means "same as integer endianness"
enum class FloatEndian { UNKNOWN, SAME, OPPOSITE, };
FloatEndian endianness() {
float check = -0.0f; // in IEEE-754, this should be all-zero significand and exponent with sign=1
std::uint32_t view;
std::memcpy(&view, &check, sizeof(check));
switch (view) {
case 0x80000000: // sign bit is in most significant byte
return FloatEndian::SAME;
case 0x00000080: // sign bit is in least significant byte
return FloatEndian::OPPOSITE;
default: // can't detect endianness of float
return FloatEndian::UNKNOWN;
}
}
If I ensure that my floats are indeed IEEE-754 with std::numeric_limits<T>::is_iec559
, is my approach a robust and portable way of making sure I get the floats "the right way round" when I chop them up?如果我确保我的浮点数确实是 IEEE-754 和std::numeric_limits<T>::is_iec559
,那么我的方法是否是一种可靠且可移植的方法来确保我在切碎它们时“以正确的方式”获得浮点数?
Is checking the location of the sign bit enough to determine endianness of IEEE-754 float with respect to integer endianness?检查符号位的位置是否足以确定 IEEE-754 浮点数相对于 integer 字节序的字节序?
As I read it, given the C++ spec and the C spec that it tends to also rely on, checking the sign bit is technically insufficient to determine endian relationship between float/uint32_t
.当我读到它时,鉴于 C++ 规范和 C 规范,它往往也依赖,检查符号位在技术上不足以确定float/uint32_t
之间的字节序关系。 It is likely practically sufficient as endians other than big/little are rare as well as differences between float/uint32_t
endian.这实际上可能已经足够了,因为除了 big/little 之外的字节序很少,而且float/uint32_t
字节序之间的差异也很少。
I would suggest a different constant than -0.0f
, maybe -0x1.ca8642p-113f
which has the pattern 0x87654321 and would be a more thorough endian test.我会建议一个与 -0.0f 不同的常数,也许是-0.0f
-0x1.ca8642p-113f
,它的模式为 0x87654321 并且将是一个更彻底的字节序测试。 Quite unclear why OP wants to use a one's-bit-sparse -0.0f
to discern 3 possible results.很不清楚为什么 OP 想要使用一个位稀疏-0.0f
来辨别 3 个可能的结果。
As mentioned by others, in C++, the test should be a compile time one, so thoroughness is not a run-time cost over the simplicity of only testing a sign bit.正如其他人所提到的,在 C++ 中,测试应该是编译时的,因此与仅测试符号位的简单性相比,彻底性不是运行时成本。
Relying on is_iec559
is true may unnecessarily limits portability as for that to be true, many non-finite compliance rules are needed.依赖is_iec559
为 true 可能会不必要地限制可移植性,因为要做到这一点,需要许多非有限的合规性规则。 ref . 参考。 Does your code really need quiet and signaling NANs?你的代码真的需要安静和发信号的 NAN 吗?
See also If is_iec559
is true, does that mean that I can extract exponent and mantissa in a well defined way?另请参阅如果is_iec559
为真,这是否意味着我可以以明确定义的方式提取指数和尾数? . .
I hope OP also tests that the sizeof(float) == sizeof(uint32_t)
else memcpy(&view, &check, sizeof(check))
is bad code.我希望 OP 还测试sizeof(float) == sizeof(uint32_t)
else memcpy(&view, &check, sizeof(check))
是错误的代码。
is my approach a robust and portable way of making sure I get the floats "the right way round" when I chop them up?我的方法是一种可靠且便携的方法,可以确保在我切碎它们时“以正确的方式”获得花车吗?
Code is not as robust and portable as it could be.代码不像它应该的那样健壮和可移植。
"when I chop them up" --> that code is not shown, so unanswerable. “当我把它们切碎时”->该代码未显示,因此无法回答。 I am suspect of the endianness()
goal that is used to support "uses memcpy to unpack float/double to unsigned integers of the appropriate width, and then uses some bit-shifting to separate the sign bit from the combined significand/exponent."我怀疑用于支持“使用 memcpy 将浮点/双精度解包为适当宽度的无符号整数,然后使用一些位移将符号位与组合有效数/指数分开”的endianness()
目标。 It is that code that deserves review.正是该代码值得审查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.