C++声明跨平台独立的32位浮点数。

30

有没有办法在C++中声明32位浮点值-确保它始终是32位,而不管平台/编译器如何?

我可以像这样对整数进行操作:

#include <stdint.h>

uint32_t var;  //32 bit unsigned integer
uint64_t var1; //64 bit unsigned integer

有没有一种方法可以对浮点数做类似的操作?据我所知,

float var; //Usually is 32 bit, but NOT GUARANTEED to be 32 bit

实现方式因不同情况而异,不一定是32位的。(如果我错了请指出)。

我正在使用Qt,因此如果有使用它的解决方案,我会接受它——我找不到像quint16这样的浮点型(qreal根据平台改变大小)。


1
不行 - 有些平台可能会有小数浮点数。 - user2249683
4
在不支持32位二进制浮点数据类型的平台上,你打算如何处理这种数据类型? - David Heffernan
那么如果float不是32位,你希望发生什么呢?当然可以进行检查 if (sizeof(float) != 4 && CHAR_BITS == 8) PANIC("Not 32-bit float!!!"); - 但是如果没有32位的浮点数,我不确定你希望编译器做什么。 - Mats Petersson
2
那么,你是否正在编写可能在非常晦涩的硬件上运行的代码?我的意思是DSP和大型古老的主机?如果不是,那么我会建议忽略这个问题... [我有一种感觉,QT在主机上不会很好地工作,而DSP往往是非常专业化的]。 - Mats Petersson
1
毫无意义。即使您有两个都是32位的浮点数,当一个具有23位尾数,另一个具有25位尾数时,它们仍然不兼容。您需要指定所有宽度,而不仅仅是总宽度。 - MSalters
显示剩余2条评论
6个回答

17

你正在使用专为C++设计的Qt,因此我不确定为什么这个问题被标记为C。

据我所知,在支持Qt的所有平台上,类型float是32位IEEE格式。

如果有人决定将Qt移植到例如64位float的Cray向量机上,那么您将无法使用32位浮点类型(除非您自己在软件中实现它,但我不知道这有什么用)。

没有与<stdint.h>/<cstdint>相对应的<stdfloat.h>/<cstdfloat>。 C和C ++提供floatdoublelong double,并对它们施加最小要求,但不提供一种方式来请求任何特定大小的浮点类型。

你最好的选择可能是在main中添加类似以下内容的代码,或者在某个保证在程序启动期间调用的函数中添加:

assert(CHAR_BIT * sizeof (float) == 32);

如果你的代码会隐式依赖于 CHAR_BIT == 8,那么也许你需要考虑一下。

assert 很可能永远不会触发,如果真的触发了,那就表示你有更大的问题。

你可能需要重新考虑是否真的需要一个32位浮点类型。如果你的代码在一个拥有64位 float 的系统上运行,那会怎样影响你的需求呢?


谢谢!Qt只能在32位IEEE上运行吗?我标记为C,因为我使用qt但不限于它 - 任何确保浮点数为32位/提供保证为32位的浮点数据类型的解决方案都可以,包括C。我希望浮点数是32位的,因为我写32位代码时依赖于数据大小进行一些指针转换/算术运算。 - Ilya Kobelevskiy
@IlyaKobelevskiy:对我来说还不确定,而且它将继续保持不确定的可能性更小,但这是非常有可能的。考虑不编写任何关于 sizeof(float) 的假设代码。否则,如果没有32位浮点类型可用,就决定你想要做什么。除非你在软件中实现32位FP(这很可能过度),否则你将会运气不佳——assert 就是处理这种情况的方法。 - Keith Thompson
3
您也可以在编译时进行检查——C++定义了宏FLT_MINFLT_MAXFLT_MANT_DIG(需要包含头文件<cfloat>);或者在C++11代码中,您可以使用static_assert(numeric_limits<float>::max() <= ...)(或min等)(需要包含头文件<limits>)。 - peppe
1
那么如果有一个平台,float是32位,但格式不同于您想要的呢?很难确定您的要求。 - Keith Thompson
1
@IlyaKobelevskiy:一些低端的ARM只有64位IEEE硬件的double。32位FP可以在64位中相当高效地模拟,但你会遇到类似于x87 80位寄存器的问题。 - MSalters

10

没有这样大小的浮点类型,但您始终可以静态断言其大小为32位。甚至可能是一个全局字符数组:

#include <climits>

char static_assert_float32[1 - (2 * ((sizeof(float) * CHAR_BIT) != 32))];

如果声明一个负数大小的数组,且float不是32位,则此代码将无法通过编译。


1
或者更简单地说,static_assert(sizeof(float) == 4, "需要32位浮点数"). - Adam Burry
1
@Adam:不行,当CHAR_BIT==16时会失败。 - MSalters
2
@AdamBurry:是的,C++将byte定义为char的大小,而char不一定是八位(8 bits)。因此,根据定义,sizeof(char)==1。所有其他大小都相对于此定义。 - MSalters
@Adam Burry 那将排除sizeof(float) == 2 && CHAR_BIT == 16的情况。 - Mark B
6
显然有一个 static_assert(sizeof(float) * CHAR_BIT == 32, "require 32 bits floats",这使得32很明显,代码也具有可移植性。 - MSalters
显示剩余3条评论

4

大多数C和C++的实现将使用32位的float类型。如果您确实需要捕获任何不符合该情况的平台,您可以使用以下代码在程序早期抛出错误:

#include <limits.h>
if (sizeof(float) * CHAR_BIT != 32)
    // error code here

很遗憾,我不知道在编译时检测它的方法,我的早期答案是有缺陷的。


据我所知,sizeof()不能在预处理指令中使用。 - Martin R
@MartinR 为什么不行呢?反正这是编译时的事情 :p - user1551592
1
@user9000:因为预处理器在源代码被解析之前运行;sizeof关键字只是一个普通的标识符,没有特殊的意义。 - Keith Thompson
我的clang编译器报错:"错误:在预处理子表达式中,该标记不是有效的二元运算符。" - Martin R
std::conditional怎么办?使用float_type = typename std::conditional<sizeof(float) * CHAR_BIT == 32, float, float32>::type; 编辑:算了。我们正在定义float32,而不是使用它。 - bstamour
显示剩余2条评论

3

在支持IEEE-754标准的平台上,float类型是32位的。在不支持该标准的平台上,不同的宽度可能只是你面临问题中最小的一部分。总之,使用float类型并不需要担心。


2

Boolean静态成员常量std::numeric_limits<float>::is_iec559是真的,当且仅当float符合IEC 559/IEEE 754浮点标准。您需要#include头文件<limits>

请注意,这并不能告诉您float是否特定为32位IEEE浮点数,只是它是IEEE浮点数 - 一些没有32位浮点硬件的实现可能会选择float为64位IEEE浮点数。


0

一般来说,了解float的大小为32位可能是足够的,但并不适用于所有情况。

IEEE 758定义了众所周知的32位二进制浮点数binary32,它通常被实现。但是,IEEE 758还定义了一个32位的十进制浮点数decimal32,主要用于存储而非计算。还存在其他非IEEE 758的32位浮点数实现,尽管它们不如常见。

即使已知float是32位IEEE 758-2008 binary32,对于一个特定环境对其严格定义(NaN、次规范、舍入模式)的程度可能会有所不同。我怀疑这是32位浮点数实现变化微妙的最大原因。

因此,准确地了解所使用的浮点数模型的目标,很可能需要在编译时检测以确保跨平台的一致性,这可能是非常具有挑战性的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接