GCC对四精度浮点型的支持
C语言标准中只提供了float型和double 型两种浮点类型。但是有些情况下,我们需要比double 型更大数据范围或更多的有效位数,为此,GCC 为我们提供了__float128型浮点类型。这种扩展类型可以表示的数据范围非常大,大约为-10e4932到10e4932,可以表示的最接近0的数大约为3.36*e-4932,可以表示的10进制有效位大约为33位。比起double 类型,无论是数据范围还是精度都有了一个极大的提升。当然,由于现在日常使用的计算机的CPU的浮点处理器不能直接对__float128进行运算,所以即使是两个简单的__float128型变量相加运算都要耗费CPU的相当多条指令来完成。因此程序中使用__float128 型后运算速度会降低很多。
除了对__float128数据类型的支持之外,GCC还提供一个GCC Quad-PrecisionMath Library(简称为quadmath),里面提供了基本数学函数库中相应函数的__float128型的版本。
下面简单的讲讲如何在程序中使用__float128数据和quadmath库。
首先,__float128 型和各种相关的函数声明在了 quadmath.h 中。因此,如果要在C程序中使用__float128 型浮点数就要包含这个头文件。相应的处理函数打包在了 libquadmath.o 中,为此,在最后链接(link)阶段要包括这个库文件,也就是加入链接命令行参数 -lquadmath。
除了 __float128 型,还有 __complex128 型,它是complex 型向4精度浮点型的升级。
既然有了__float128类型,就要提供对这种类型的输入输出的支持。GCC扩展了C语言的标准,增加了以Q结尾的__float128类型的数值常量。比如下面的例子:
#include <stdio.h>#include <stdlib.h>#include <quadmath.h>int main(void){ __float128 r1; __float128 r2; __float128 r3; char buf[64]; char *pEnd = buf; r1 = strtoflt128 ("1.234567890123456789 9.876543210987654321e5", &pEnd); r2 = strtoflt128 (pEnd, NULL); quadmath_snprintf (buf, sizeof buf, "%+-#*.20Qf", 64, r1); puts(buf); quadmath_snprintf (buf, sizeof buf, "%+-#*.20Qe", 64, r2); puts(buf); r3 = hypotq (r1, r2); quadmath_snprintf (buf, sizeof buf, "%.30Qe", 64, r3); puts(buf); return 0;}输出的结果为:
+1.23456789012345678900
+9.87654321098765432100e+05
9.876543210995370370242956091483e+05
结果是否准确,我们可以用 maxima 来验算一下:
fpprec:35$
r1:bfloat(1.234567890123456789b0)$
r2:bfloat(9.876543210987654321b05)$
r3:sqrt(r1*r1+r2*r2);
(%o4) 9.8765432109953703702429560914832608b5
小数点后30位全都是正确的。说明quadmath 库的计算精度还是相当不错的,至少hypotq函数的精度相当高。
__float128型浮点不是C语言标准类型,因此这里的介绍只对GCC编译器成立。另外,我使用的gcc的版本信息如下:
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.6.1/lto-wrapper.exe
mingw32
../gcc-4.6.1/configure--enable-languages=c,c++,fortran,objc,obj-c++ --disable-sjlj-exceptions--with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry--enable-libstdcxx-debug --enable-version-specific-runtime-libs --build=mingw32--prefix=/mingw
win32
gcc 4.6.1 (GCC)
其他版本的GCC 运行的结果不一定与这里相同。
如果需要更高的计算精度,就要考虑一些专用的多精度数值计算库了,比如大名鼎鼎的GMP。