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。




  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
11076 浮点数的分数表达 时间限制:1000MS 内存限制:65535K 提交次数:0 通过次数:0 题型: 编程题 语言: 无限制 Description 在计算机中,用float或double来存储小数有时不能得到精确值,若要精确表达一个浮点数的计算结果, 最好用分数来表示小数,有限小数或无限循环小数都可以转化为分数,无限循环小数的循环节用括号标记出来。如: 0.9 = 9/10 0.(3) = 0.3(3) = 0.3(33) = 1/3 当然一个小数可以用好几种分数形式来表示,我们只感兴趣最简的分数形式(即分母最小),如: 0.3(33) = 1/3 = 3/9 因为任何一个数都可以转化为一个整数和一个纯小数之和,整数部分较为简单无需做额外处理,只要将纯小数部分转化为分数形式,整数部分的分数部分就很简单了。 现在给定一个正的纯小数(这个纯小数为有限小数或无限循环小数),请你以最简分数形式来返回这个纯小数。 Input 给定一个纯小数,若是无限循环小数,用括号标记循环节,输入小数表达不超过100个字符。Output 输出:化为最简分数形式,分子在前,分母在后,中间空格连接。 Sample Input 0.3(33) Sample Output 1 3 Hint 此题题目规定:输入小数表达不超过100个字符。 如此长的数,本意要大家用高精度数的运算来求解. 但后台测试数据没有做如此之长,放松一些吧,用64位整数也是允许通过的! 此题采用字符串接收输入,大家在接受数据的时候,不要用(c=getchar())!='\n'诸如此类一个字符一个字符接受, 然后判断是否是回车符号来接受输入,这样的方式在你本机运行不会有问题,但OJ系统中会有错误,无法输出结果, 因为测试平台行末并非'\n'字符。这里接受数据用scanf的%s,或cin等,会自动判别回车字符的,不要在你程序里去专门判别或吸收回车字符。 char a[105]; scanf("%s",a); 或cin >> a; 解题思路: 考虑输入的是纯小数,先暂时不考虑分子和分母有公因子的情况。 (1) 假设有限小数:X=0.a1a2…an,式中的a1,a2,…,an都是0~9的数字。 X=0.a1a2…an=a1a2…an/10^n (2) 假设无限循环小数:X=0.a1a2…an(b1b2…bm),式中的a1,a2,…,an, b1,b2,…,bm都是0~9的数字,括号为循环节。 第一步,先将X化为只有循环部分的纯小数。 X=0.a1a2…an(b1b2…bm) (10^n)*X=a1a2…an+0.(b1b2…bm) X=(a1a2…an+0.(b1b2…bm))/(10^n) 上式中,a1a2…an是整数部分,容易解决。重点考虑小数部分0.(b1b2…bm)如何化为分数形式,再加上整数部分即可。 第二步,考虑Y=0.(b1b2…bm),将Y化为分数, (10^m)*Y=b1b2…bm+0.(b1b2…bm) ((10^m)-1)*Y=b1b2…bm Y=b1b2…bm/((10^m)-1) 将第二步的Y带入第一步的X,可得: X=(a1a2…an+Y)/(10^n)=((a1a2…an)*((10^m)-1)+(b1b2…bm))/((10^m)-1)*(10^n) 此时,可以将任何一个有限小数或无限循环小数,化为分数表示。 但此时的分子分母未必是最简化的,对分子分母再进行约分, 删去公共的因子,A/B=(A/GCD(A,B))/(B/GCD(A,B)),化为简单形式。 思路如上,但实现上,所有分子分母的变量,以及求最大公约数,都须用64位整数。 编译环境不同,对64位整数的定义和输入输出略有不同: 1)gnu gcc/g++ 中long long类型,或unsigned long long, 输入输出用cin和cout直接输出,用scanf和printf也可以的。 long long a; cin >> a; cout << a; 也可以使用 scanf("%lld",&a); 或scanf("%I64d",&a); printf("%lld",a); 或printf("%I64d",a); 2)vc中用__int64类型,或unsigned __int64 scanf("%I64d",&a); printf("%I64d",a); vc下,64整数不要用cin和cout来输入输出,据说vc下64位整数兼容不好,会出错,我未测试过大家可测试一下如下程序会出错否。 __int64 a; cin >> a; cout << a;
11076 浮点数的分数表达 时间限制:1000MS 内存限制:1000K 提交次数:0 通过次数:0 题型: 编程题 语言: 无限制 Description 在计算机中,用float或double来存储小数有时不能得到精确值,若要精确表达一个浮点数的计算结果, 最好用分数来表示小数,有限小数或无限循环小数都可以转化为分数,无限循环小数的循环节用括号标记出来。如: 0.9 = 9/10 0.(3) = 0.3(3) = 0.3(33) = 1/3 当然一个小数可以用好几种分数形式来表示,我们只感兴趣最简的分数形式(即分母最小),如: 0.3(33) = 1/3 = 3/9 因为任何一个数都可以转化为一个整数和一个纯小数之和,整数部分较为简单无需做额外处理,只要将纯小数部分转化为分数形式,整数部分的分数部分就很简单了。 现在给定一个正的纯小数(这个纯小数为有限小数或无限循环小数),请你以最简分数形式来返回这个纯小数。 输入格式 给定一个纯小数,若是无限循环小数,用括号标记循环节,输入小数表达不超过100个字符。 输出格式 输出:化为最简分数形式,分子在前,分母在后,中间空格连接。 输入样例 0.3(33) 输出样例 1 3 提示 此题涉及如下几个问题: 一、字符串输入的问题 此题采用字符串接收输入,大家在接受数据的时候,不要用(c=getchar())!='\n'诸如此类一个字符一个字符接受, 然后判断是否是回车符号来结束输入,这样的方式在你本机运行不会有问题,但OJ系统中会有错误,无法输出结果, 因为OJ的测试平台行末并非'\n'字符。这里接受数据用scanf的%s,或cin等,会自动判别结束字符的,你就不要在你程序里专门去判别或吸收回车字符。 char a[105]; scanf("%s",a); 或cin >> a; 二、高精度或64位整数表示的问题 此题题目规定:输入小数表达不超过100个字符。 如此长的数,本意要大家用高精度数的运算来求解. 但后台测试数据没有做如此之长,放松一些吧,用64位整数也是允许通过的! 实现上,所有分子分母的变量,以及求最大公约数,都须用64位整数。 编译环境不同,对64位整数的定义和输入输出略有不同: 1)gnu gcc/g++ 中long long类型,或unsigned long long, 输入输出用cin和cout直接输出,用scanf和printf也可以的。 long long a; cin >> a; cout << a; 也可以使用:(注意一下,本OJ系统的gcc/g++不支持64位整数以"%I64d"形式输出, 但标准gnu gcc支持如下的,在codeblocks上可以无误运行) scanf("%I64d",&a); printf("%I64d",a); 2)vc中用__int64类型,或unsigned __int64 scanf("%I64d",&a); printf("%I64d",a); vc下,64整数不要用cin和cout来输入输出,据说vc下64位整数兼容不好,会出错!大家可测试一下如下程序在vc下是否会出错? __int64 a; cin >> a; cout << a; 三、本题的解题思路 考虑输入的是纯小数,先暂时不考虑分子和分母有公因子的情况。 (1) 假设有限小数:X = 0.a1a2…an,式中的a1,a2,…,an都是0~9的数字。 X = 0.a1a2…an = a1a2…an/10^n (2) 假设无限循环小数:X = 0.a1a2…an(b1b2…bm),式中的a1,a2,…,an, b1,b2,…,bm都是0~9的数字,括号为循环节。 第一步,先将X化为只有循环部分的纯小数。 X = 0.a1a2…an(b1b2…bm) (10^n)*X = a1a2…an + 0.(b1b2…bm) X = (a1a2…an + 0.(b1b2…bm)) / (10^n) 上式中,a1a2…an是整数部分,容易解决。重点考虑小数部分0.(b1b2…bm)如何化为分数形式,再加上整数部分即可。 第二步,考虑Y = 0.(b1b2…bm),将Y化为分数, (10^m)*Y = b1b2…bm + 0.(b1b2…bm) ((10^m)-1)*Y = b1b2…bm Y = b1b2…bm / ((10^m)-1) 将第二步的Y带入第一步的X,可得: X = (a1a2…an+Y)/(10^n) = ((a1a2…an)*((10^m)-1) + (b1b2…bm)) / ((10^m)-1)*(10^n) 此时,可以将任何一个有限小数或无限循环小数,化为分数表示,分数的分子和分母如上分析的公式。 但此时的分子分母未必是最简化的,对分子分母再进行约分, 删去公共的因子,A/B = (A/GCD(A,B))/(B/GCD(A,B)),化为简单形式。 作者 zhengchan --------------------------------------------------------------------------------
### 回答1: 在使用printf函数输出浮点数时,需要在格式控制字符串中使用%f标识符。例如: ```printf("%f", 3.14);``` 这将会输出3.140000。 如果需要指定小数位数,可以在%f之后加上精度值,例如: ```printf("%.2f", 3.14);``` 这将会输出3.14。 ### 回答2: 要使printf函数支持浮点数的输出,有以下几个关键步骤: 1. 使用正确的格式说明符:%f 格式说明符是一种特殊的标记,告诉printf函数将要输出的变量是浮点数。在需要输出浮点数的地方,替换为"%f"。 2. 将浮点数作为参数传递给printf函数 在调用printf函数时,将需要输出的浮点数作为参数传递给该函数。确保浮点数变量是正确定义的,并且已被赋予适当的值。 3. 确保编译器支持浮点数 有些较早的编译器可能不支持浮点数的输出。如果无法使用printf输出浮点数,可能需要查看编译器的文档或更新到较新版本。 以下是一个示例代码,展示如何在C语言中使用printf函数输出浮点数: ``` #include <stdio.h> int main() { float num = 3.14; printf("The value of num is: %f\n", num); return 0; } ``` 上述代码中,定义了一个浮点数变量num,其值为3.14。通过在printf函数中使用"%f"格式说明符,将num作为参数传递给printf函数,从而在输出中显示浮点数的值。 这样,就可以使用printf函数输出浮点数了。注意,浮点数的输出可能受浮点数精度和格式控制的影响,可以使用其他的格式说明符和修饰符来调整打印输出的样式和精度。 ### 回答3: 要使printf支持浮点数,需要进行以下几个步骤: 1. 使用正确的格式说明符:%f来输出浮点数。这样,printf函数将会将浮点数作为参数输入,并按照指定的格式进行输出。 2. 确保所传递的浮点数参数具有正确的数据类型。在C语言中,浮点数数据类型包括float和double。如果所传入的参数的数据类型与格式说明符不匹配,可能会导致输出错误。 3. 在编译时,使用正确的编译选项。在使用gcc编译器时,可以添加"-lm"选项,以确保能够正确链接和使用数学库函数。 4. 声明正确的头文件。在程序中包含stdio.h头文件,以便正确使用printf函数。 以下是一个简单的示例程序,展示了如何使printf函数支持输出浮点数: ```c #include <stdio.h> int main() { double num = 3.14159; printf("The value of pi is: %f\n", num); return 0; } ``` 在上述示例中,我们将浮点数3.14159存储在变量num中,并使用"%f"格式说明符将其输出到屏幕上。运行程序后,屏幕将会显示出"The value of pi is: 3.141590"。 通过正确使用格式说明符和浮点数数据类型,并确保正确声明头文件和编译选项,我们可以使printf支持输出浮点数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值