Com*_* 10 17 c floating-point double gcc
我与谁在使用旧版本的GCC(3.2.3确切地说),但想要升级客户端和一个已经给出绊脚石升级到新版本的一个原因是工作型的大小不同float_t,其,果然是正确的:
在GCC 3.2.3上
sizeof(float_t) = 12
sizeof(float) = 4
sizeof(double_t) = 12
sizeof(double) = 8
Run Code Online (Sandbox Code Playgroud)
关于GCC 4.1.2
sizeof(float_t) = 4
sizeof(float) = 4
sizeof(double_t) = 8
sizeof(double) = 8
Run Code Online (Sandbox Code Playgroud)
但这种差异的原因是什么?为什么尺寸变得越来越小,时应该和不应该使用float_t或double_t?
use*_*019 12
float_t的原因是对于某些使用较大类型的处理器和编译器,例如float的long double可能更有效,因此float_t允许编译器使用较大的类型而不是float.
因此在使用float_t的OPs情况下,尺寸的变化是标准所允许的.如果原始代码想要使用较小的float大小,那么它应该使用float.
open-std doc有一些基本原理
例如,类型定义float_t和double_t(在<math.h>中定义)旨在允许有效地使用具有更高效,更宽格式的体系结构.附件
小智 9
"为什么"是某些编译器将在浮点寄存器中返回浮点值.这些寄存器只有一种尺寸.例如,在X86上,它是80位宽.无论该类型是否已声明为float,double,float_t或double_t,返回浮点值的函数的结果都将放入此寄存器中.如果返回值的大小和浮点寄存器的大小不同,那么在某些时候将需要一条指令向下舍入到所需的大小.
整数也需要相同类型的转换,但是对于后续的加法和减法,没有开销,因为有指令选择操作中涉及哪些字节.将整数转换为较小尺寸的规则指定最重要的位被抛弃,因此缩小尺寸的结果可以产生完全不同的结果(例如(短)(2147450880) - > -32768),但是某些原因似乎与编程社区一致.
在进行浮点缩小时,结果被指定为四舍五入到最接近的可表示数字.如果整数遵循相同的规则,那么上面的例子将截断(短)(2147450880) - > +32767.显然,需要更多的逻辑来执行仅仅截断高位的操作.对于浮点数,指数和有效位数在float,double和long double之间改变大小,因此更复杂.此外,还存在无穷大,NaN,标准化数字和需要考虑的重整化数字之间的转换问题.硬件可以在与整数加法相同的时间内实现这些转换,但如果转换需要在软件中实现,则可能需要20条指令,这会对性能产生显着影响.由于C编程模型确保无论浮点是以硬件还是软件实现,都会生成相同的结果,因此软件必须执行这些额外的指令以符合计算模型.float_t和double_t类型旨在公开最有效的返回值类型.
编译器定义FLT_EVAL_METHOD,它指定在中间计算中使用多少精度.对于整数,规则是使用所涉及的操作数的最高精度来进行中间计算.这将对应于FLT_EVAL_METHOD == 0.但是,原始K&R指定所有中间计算都以double结束,因此产生FLT_EVAL_METHOD == 1.但是,随着IEEE浮点标准的引入,它在某些平台上变得司空见惯,特别是Macintosh PowerPC和Windows X86以长双80位执行中间计算,从而产生FLT_EVAL_METHOD == 2.
回归测试将受FLT_EVAL_METHOD计算模型的影响.因此,您的回归代码应考虑到这一点.一种方法是测试FLT_EVAL_METHOD并为每个模型分配不同的分支.类似的方法是测试sizeof(float_t),并具有不同的分支.第三种方法是使用某种epsilon来检查结果是否足够接近.
不幸的是,有一些计算基于计算结果做出决定,导致真或假,这不能通过使用epsilon来解决.这发生在计算机图形中,例如,以确定点是在多边形内部还是外部,这确定是否应该填充特定像素.如果您的回归涉及其中之一,则不能使用epsilon方法,并且必须根据计算模型使用不同的分支.
解决模型之间的决策回归的另一种方法是将结果明确地转换为特定的期望精度.这大部分时间都适用于许多编译器,但有些编译器认为它们比你更聪明,并且拒绝进行转换.这发生在中间结果存储在寄存器中但在后续计算中使用的情况下.您可以在中间结果中尽可能多地抛弃精度,但编译器将不执行任何操作 - 除非您将中间结果声明为 volatile.然后,这会强制编译器缩小尺寸并将中间结果存储在内存中指定大小的变量中,然后在需要进行计算时检索它.IEEE浮点标准对于基本运算(+ - */)和平方根是精确的.我相信sin(),cos(),exp(),log()等被指定在最接近数字表示结果的2 ULP(最低有效位置的单位)内.长双(80位)格式被设计为允许计算那些其他超越函数与最接近的数字表示结果.
这包括很多在这个线程长大(和隐含的)的问题,但没有回答的时候这个问题,你应该使用则float_t和DOUBLE_T类型.显然,在与使用这些类型的API进行交互时,您需要这样做,尤其是在传递其中一种类型的地址时.
如果您主要关心的是性能,那么您可能需要考虑在计算和API中使用float_t和double_t类型.但最有可能的是,您获得的性能提升既不可测量也不明显.
但是,如果您担心不同编译器和不同机器之间的回归,您应该尽可能地避免使用这些类型,并使用自由放置以确保跨平台兼容性.
C99标准说:
类型
float_tdouble_t浮动类型至少与float和double一样宽,并且至少与float
double_t一样宽float_t.如果FLT_EVAL_METHOD等于0,float_t并且double_t是float和double,分别为; 如果FLT_EVAL_METHOD等于1,他们都是double; 如果FLT_EVAL_METHOD等于2,他们都是long double; 对于其他值FLT_EVAL_METHOD,它们在其他方面是实现定义的.178)
事实上,在以前版本的gcc中,它们被long double默认定义为.