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类型的数值常量。比如下面的例子:


__float128 a = 1.23456789012345Q;

还提供了两个函数以支持__float128类型与字符串间的转换:

__float128 strtoflt128 (const char *s, char **sp)
int quadmath_snprintf (char *str, size_t size, const char *format, ...)

strtoflt128 函数是 strtod 函数的__float128类型版本,参数类型与strtod 函数完全一样,只不过返回值是__float128类型。

quadmath_snprintf 函数是snprintf的__float128类型版本。通过在传统的解析字符串中增加了字符Q来表示__float128类型,比如“%f”表示的读取一个浮点数,“%Qf”则是读取一个__float128类型的数据。除了“%Qf”之外,还可以用“%QF”、“%Qe”、“%QE”、“%Qg”、“%QG”。

Quadmath 库中包含的数学函数如下,基本上就是对应的double 类型的函数的函数名后加了后缀q。因此,每个函数的含义就不一一解释了。

__float128 acosq (__float128)
 __float128 acoshq (__float128)
 __float128 asinq (__float128)
 __float128 asinhq (__float128)
 __float128 atanq (__float128)
 __float128 atanhq (__float128)
 __float128 atan2q (__float128, __float128)
 __float128 cbrtq (__float128)
 __float128 ceilq (__float128)
 __float128 copysignq (__float128, __float128)
 __float128 coshq (__float128)
 __float128 cosq (__float128)
 __float128 erfq (__float128)
 __float128 erfcq (__float128)
 __float128 expq (__float128)
 __float128 expm1q (__float128)
 __float128 fabsq (__float128)
 __float128 fdimq (__float128, __float128)
 int finiteq (__float128)
 __float128 floorq (__float128)
 __float128 fmaq (__float128, __float128, __float128)
 __float128 fmaxq (__float128, __float128)
 __float128 fminq (__float128, __float128)
 __float128 fmodq (__float128, __float128)
 __float128 frexpq (__float128, int *)
 __float128 hypotq (__float128, __float128)
 int isinfq (__float128)
 int ilogbq (__float128)
 int isnanq (__float128)
 __float128 j0q (__float128)
 __float128 j1q (__float128)
 __float128 jnq (int, __float128)
 __float128 ldexpq (__float128, int)
 __float128 lgammaq (__float128)
 long long int llrintq (__float128)
 long long int llroundq (__float128)
 __float128 logq (__float128)
 __float128 log10q (__float128)
 __float128 log2q (__float128)
 __float128 log1pq (__float128)
 long int lrintq (__float128)
 long int lroundq (__float128)
 __float128 modfq (__float128, __float128 *)
 __float128 nanq (const char *)
 __float128 nearbyintq (__float128)
 __float128 nextafterq (__float128, __float128)
 __float128 powq (__float128, __float128)
 __float128 remainderq (__float128, __float128)
 __float128 remquoq (__float128, __float128, int *)
 __float128 rintq (__float128)
 __float128 roundq (__float128)
 __float128 scalblnq (__float128, long int)
 __float128 scalbnq (__float128, int)
 int signbitq (__float128)
 void sincosq (__float128, __float128 *, __float128 *)
 __float128 sinhq (__float128)
 __float128 sinq (__float128)
 __float128 sqrtq (__float128)
 __float128 tanq (__float128)
 __float128 tanhq (__float128)
 __float128 tgammaq (__float128)
 __float128 truncq (__float128)
 __float128 y0q (__float128)
 __float128 y1q (__float128)
 __float128 ynq (int, __float128)


/* Prototypes for complex functions */
 __float128 cabsq (__complex128)
 __float128 cargq (__complex128)
 __float128 cimagq (__complex128)
 __float128 crealq (__complex128)
 __complex128 cacosq (__complex128)
 __complex128 cacoshq (__complex128)
 __complex128 casinq (__complex128)
 __complex128 casinhq (__complex128)
 __complex128 catanq (__complex128)
 __complex128 catanhq (__complex128)
 __complex128 ccosq (__complex128)
 __complex128 ccoshq (__complex128)
 __complex128 cexpq (__complex128)
 __complex128 cexpiq (__float128)
 __complex128 clogq (__complex128)
 __complex128 clog10q (__complex128)
 __complex128 conjq (__complex128)
 __complex128 cpowq (__complex128, __complex128)
 __complex128 cprojq (__complex128)
 __complex128 csinq (__complex128)
 __complex128 csinhq (__complex128)
 __complex128 csqrtq (__complex128)
 __complex128 ctanq (__complex128)
 __complex128 ctanhq (__complex128) 
下面举一个简单的例子:
#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。




你可能感兴趣的:(gcc,语言,float,library,fortran,wrapper)