当前位置: 首页 > 知识库问答 >
问题:

C中浮点数据类型的精度

陈和裕
2023-03-14

为什么浮点数据类型的精度不与其大小成正比增长?例如:

std::cout << sizeof(float) << "\n";  // this gives 4 on my machine "debian 64 bit" with "gcc 6.3.0"  
std::cout << std::numeric_limits<float>::digits10  << "\n"; // gives 6

std::cout << sizeof(double) << "\n";  // gives 8
std::cout << std::numeric_limits<double>::digits10 <<  "\n"; // gives 15

std::cout << sizeof(long double) <<  "\n";  // gives 16
std::cout << std::numeric_limits<long double>::digits10  << "\n"; // gives 18

正如您所看到的,Double的精度大约是浮动精度的两倍,这是有意义的,因为Double的大小是的两倍。浮点

但这与双精度和长双精度的情况不同,长双精度的大小是128位,是64位双精度的两倍,但其精度只多出三位!!

我不知道浮点数是如何实现的,但从理性的角度来看,仅为三位精度使用64位内存是否有意义?!

我四处搜索,但没有找到一个简单明了的答案。如果有人能解释为什么长双精度只比双精度高三位数,你能解释一下为什么这与双精度和浮点精度不同吗?

我还想知道如何在不定义自己的数据类型的情况下获得更好的精度,这显然会以性能为代价?

共有3个答案

向修谨
2023-03-14

你的问题中有许多错误的假设

首先,C中没有关于类型大小的要求。该标准仅要求每种类型的最小精度,并且。。。

... double类型提供的精度至少与float相同,long double类型提供的精度至少与double相同。float类型的值集是double类型的值集的子集;double类型的值集是长double类型的值集的子集。浮点类型的值表示由实现定义。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

大多数现代实现将浮点和双精度映射到IEEE-754单精度和双精度格式,因为对它们的硬件支持是主流。然而,长双精度并没有得到如此广泛的支持,因为很少有人需要比双精度更高的精度,而这些精度的硬件成本要高得多。因此,一些平台将其映射到IEEE-754双精度,即与双精度相同。如果底层硬件支持,其他一些人将其映射到80位IEEE 754扩展精度格式。否则,长双精度将由算术或IEEE-754四倍精度表示

此外,精度也不会与类型中的位数成线性比例。很容易看出,尽管只有两倍的存储空间,但双精度是浮点精度的两倍多,范围比浮点宽8倍,因为它的有效位为53位,而浮点中为24位,指数位为3位。类型也可以具有陷阱表示或填充位,因此不同的类型可能具有不同的范围,即使它们具有相同的大小并且属于同一类别(整数或浮点)

所以这里重要的是std::numeric\u极限

  • -malign-双-mno-alie-Double用于控制long Double
  • 的对齐方式
  • -m96bit-long-双-m128bit-long-双用于更改填充大小
  • -mlong-dule-64-mlong-dule-80-mlong-dule-128用于控制底层long Double实现

通过更改选项,您将获得以下长双精度的结果

  • -mlong-double-128:size=16,digits10=33,digits2=113
  • -m96位长双精度:大小=12,数字10=18,数字2=64
  • -mlong-double-64:size=8,digits10=15,digits2=53

如果禁用填充,则大小将为10,但由于未对齐,这将以性能为代价。查看编译器资源管理器上的更多演示

在PowerPC中,更改浮点格式时也可以看到相同的现象。使用-mabi=ibmlongdouble(双-双算术,这是默认值),您将得到(size,digits10,digits2)=(16,31,106),但使用-mabi=ieeelongdouble,元组将变为(16,33,113)

有关更多信息,您应该阅读https://en.wikipedia.org/wiki/Long_double

我还想知道如何在不定义自己的数据类型的情况下获得更好的精度

要搜索的关键字是任意精度的算术。在任意精度算术软件列表中可以找到各种库。您可以在标记bigint、biginger或任意精度中找到更多信息

薄烨
2023-03-14

除了浮点类型必须满足的一些最低级别外,C标准没有对浮点类型设定固定的要求。

很可能您使用的C实现针对的是英特尔处理器。除了常见的IEEE-754基本32位和64位二进制浮点格式外,Intel还有80位格式。您的C实现可能将其用于长double。

英特尔80位格式的有效位比64位双精度格式多11位。(实际上它使用64,其中双精度格式使用52,但其中一个保留为显式前导1。)11位以上意味着211=2048倍的有效位值,这大约是三位以上的十进制数字。

80位格式(即10个字节)优先与16个字节的倍数对齐,因此包括6个字节的填充,以使长双字节大小为16个字节的倍数。

孟英叡
2023-03-14

“精度”并不是浮点值的全部。这也是关于“幅度”(但不确定该术语是否正确!):表示的值可以变大(或变小)?

为此,请尝试打印每种类型的max_exponent

std::cout << "float: " << sizeof(float) << "\n";
std::cout << std::numeric_limits<float>::digits << "\n";
std::cout << std::numeric_limits<float>::max_exponent << "\n";

std::cout << "double: " << sizeof(double) << "\n";
std::cout << std::numeric_limits<double>::digits << "\n";
std::cout << std::numeric_limits<double>::max_exponent << "\n";

std::cout << "long double: " <<  sizeof(long double) << "\n";
std::cout << std::numeric_limits<long double>::digits << "\n";
std::cout << std::numeric_limits<long double>::max_exponent << "\n";

ideone上的输出:

float: 4
24
128
double: 8
53
1024
long double: 16
64
16384

因此,额外的位并不都用于表示更多的数字(精度),而是允许指数更大。使用IEE 754long Double中的措辞主要增加了指数范围而不是精度。

我上面的ideone示例显示的格式显示(可能)“x86扩展精度格式”,它为整数部分分配1位,为小数部分分配63位(总共64位),为指数分配15位(2^(15-1) = 16384, 1位用于指数的符号)。

注意,C标准只要求长双精度至少与双精度相同,因此长双精度可以是所示x86扩展精度格式(最有可能)的同义词,也可以是更好的格式(仅限PowerPC上的AFAIK GCC)。

我还想知道如何在不定义自己的数据类型的情况下获得更好的精度,这显然会以性能为代价?

您需要自己编写(当然是一种学习体验,最好不要为生产代码编写)或使用库,如GNU MPFR或Boost。多精度。

 类似资料:
  • 本文向大家介绍PHP浮点数据类型,包括了PHP浮点数据类型的使用技巧和注意事项,需要的朋友参考一下 定义和用法 在PHP中,float数据类型表示任何数字,并带有小数部分。小数部分可以包含小数点后的数字,或者可以使用e或E以科学计数法表示。例如,科学计数法中的100是10e2。 浮点数的大小取决于硬件/ OS平台,尽管通常会精确到小数点后14位。 语法 为了更好的可读性,整数文字可以使用“ _” 

  • 在处理浮点数时,我对C#中“精度”的实际含义有些怀疑。如果逻辑性不强,而且解释太长,我提前道歉。 我知道浮点数(例如)的精度为6到9位。假设我们有下一个代码: 我在控制台里得到了确切的数字。现在,让我们使用下一个代码: 打印了一个不同的数字:,即使这个数字有9位数,这也是极限。 这是我的第一个怀疑。精度取决于数字本身还是计算机的结构? 此外,数据以位的形式存储在计算机中,在中间,我记得将数字的小数

  • 我试图控制我在字符串中添加的位数,但我无法控制它,因为我正在打印字符串数组。 但是我最终得到了一个字符串数组,如下所示: 0.050000//3.000000//... 在将浮点数添加到字符串之前,有什么方法可以控制浮点数的精度吗? (所以我可以有一个结果字符串控制一个固定数量的数字) 0.05//3.00// ...

  • 问题内容: $a = ‘35’; $b = ‘-34.99’; echo ($a + $b); 结果为0.009999999999998 这是怎么回事?我想知道为什么我的程序不断报告奇怪的结果。 为什么PHP不返回预期的0.01? 问题答案: 因为浮点运算!=实数运算。对于一些浮子和,由不精确性引起的差异的说明是。这适用于使用浮点数的任何语言。 由于浮点数是具有有限精度的二进制数,因此存在有限数量

  • 本文向大家介绍Fortran 浮点数精度,包括了Fortran 浮点数精度的使用技巧和注意事项,需要的朋友参考一下 示例 类型的浮点数real不能有任何实数值。它们可以表示实数,最多可以包含一定数量的十进制数字。 FORTRAN 77保证了两种浮点类型,而最新的标准则至少保证了两种实数类型。实变量可以声明为 x这是默认类型的实数,并且y是比更大的十进制精度的实数x。在Fortran 2008中,十

  • 本文向大家介绍C ++中浮点数的精度(floor(),ceil(),trunc(),round()和setprecision()),包括了C ++中浮点数的精度(floor(),ceil(),trunc(),round()和setprecision())的使用技巧和注意事项,需要的朋友参考一下 浮点数的精度是浮点数可以保留小数点后的值的精度。 例如10/6 = 1.6666666…这些具有重复的小