为什么C/C++中的浮点类型名称如此奇怪?

17

C++提供了三种浮点类型:float、double和long double。我很少在我的代码中使用浮点数,但当我使用时,总是会在看似无害的代码行上收到警告:

float PiForSquares = 4.0;

问题在于字面量4.0是一个双精度浮点数(double),而不是单精度浮点数(float) - 这很让人恼火。

对于整数类型,我们有short int、int和long int,这很直观。为什么C语言没有short float、float和long float呢?还有,“double”这个词从哪里来的呢?

编辑:看起来浮点类型的关系与整数类型类似。double至少要和float一样大,而long double至少要和double一样大。除此之外并没有其他的精确性/范围保证。


4.0不是字符串字面量,它是双精度字面量! - Jonathan Leffler
4
双精度浮点数(double)在长浮点数(long float)之前存在,当时双精度浮点数是长浮点数的同义词;但在C89标准中被移除了。 - Jonathan Leffler
3
我希望你能翻译成中文,我的意思是“双精度浮点数” :) - Johannes Schaub - litb
1
<float.h>中有很多保证,特别是像FLT_DIG这样的东西(我认为它保证能够表示5个小数位,即从0到99999的整数)。 - tc.
这个SO问题也许对于"single"和"double"这些名称也很有趣。 - zardosht
12个回答

36
术语 "单精度" 和 "双精度" 起源于 FORTRAN,并且在 C 语言发明时已经广泛使用。在20世纪70年代初期的机器上,单精度比双精度更有效率,像今天一样,使用的内存只有双精度的一半。因此,对于浮点数,它是一个合理的默认值。
在 IEEE 标准允许使用英特尔80287浮点芯片的时候,"long double"才被添加进来,该芯片使用80位浮点数,而不是经典的64位双精度浮点数。
问者关于保证的观点不正确;今天几乎所有语言都保证实现 IEEE 754 二进制浮点数的单精度(32位)和双精度(64位)。一些语言还提供了扩展精度(80位),在C中以"long double"的形式出现。IEEE 浮点标准由 William Kahan 领导,是好工程技术战胜急功近利的胜利:在当时的机器上,看起来代价高昂,但在今天的机器上,它非常便宜。IEEE浮点数的可移植性和可预测性每年必须要省下大量的开支。

1
OP在谈论C和C++,它们都不保证IEEE 754。 - Robert Gamble
4
C++中有一个标志用于查看是否实现了IEEE 754:numeric_limits<double>::is_iec559。 - Johannes Schaub - litb
4
同样地,C99有__STDC_IEC_559__宏,但这些仅测试实现是否声称使用IEEE。我反对的是“询问者对保证的观点是错误的”的声明,因为C / C ++并不保证IEEE浮点运算。 - Robert Gamble
1
我也怀疑“几乎所有(现代)语言都保证实现IEEE 754二进制浮点数”的说法。在我使用的所有语言中,我只能想到一种我知道能够保证这一点。 - Robert Gamble
我认为IEEE并没有“为80287芯片”甚至8087芯片“做出让步”。许多16位或32位处理器在没有FPU的情况下可以更有效地处理80位扩展精度值,而不是64位双精度值。添加三个64位值需要将前两个解包以分离尾数和指数,对齐值,执行加法,规范化结果,打包结果,解包结果和第三个值,对齐值,执行加法,规范化结果,并打包结果。使用80位中间类型... - supercat
显示剩余2条评论

25

也许你已经知道了,但你可以创建字面值浮点数/长双精度浮点数

 float f = 4.0f;
 long double f = 4.0l;

双精度浮点数是默认值,因为这是大多数人使用的。长双精度可能过于复杂或小数位数不够准确。双精度适用于几乎所有应用程序。

关于命名,当时只有32位浮点数(其实只有固定点数,但我跑题了)被广泛应用于现代架构中时,C语言可能是当时最流行的语言,并且给它取名为“float”。这个名字似乎很合理。

那时候可能有人想到了双精度,但是当时的CPU和浮点数处理器只有16位或32位,尚未真正实现它。一旦双精度在更多的架构中被使用,C语言可能会添加它。C需要一个两倍于float的东西的名称,因此我们得到了double。然后有人需要更高的精度,我们觉得他很疯狂,但我们还是加了进去。quadtuple(四元组?)这个名字太过头了,long double已经足够好了,而且没有引起太多的噪音。

混淆的部分是,好老的“int”似乎随着时间而改变。曾经,“int”表示16位整数。然而,float与IEEE std的32位IEEE浮点数相关联。因此,C将float定义为32位,并使double和long double指向更长的标准。


谢谢。但如果“float”是原始类型,为什么字面值是双精度?我认为IEEE的解释很好,但是不正确:IEEE-754于1985年发布... - Roddy
据我所知,“float”一词用于指代32位浮点数,而“double”一词用于指代64位双精度浮点数,这些术语可以追溯到60年代,在C语言出现之前。很可能是起源于IBM 360体系结构。 - Die in Sente
"非常糟糕的精度" - 告诉你的显卡制造商。所有GPU和基本上所有图形都是使用浮点数执行的。 - shoosh
C89浮点数可能是IEEE754格式,但不一定。 - MSalters
如果我的记忆没有出错的话(我想我是在90年代的K&R副本中读到的,但这可能完全错误),用于C和Unix原始开发的特定PDP-11子型号具有浮点单元,该单元只能在其寄存器中保存双精度值;从内存加载时,单精度值会自动扩展。因此,让C将单精度升级为双精度非常“自然”——文字量,未经原型化的参数升级以及通常的算术转换都反映了这种怪癖。 - zwol
显示剩余2条评论

5

字面量

问题在于字面量4.0是double类型而非float类型,这很让人恼火。

对于常量来说,整数和浮点数之间有一个重要的区别。确定使用哪种整数类型相对容易(选择足够小的类型来存储值,对于有符号/无符号还需要一些额外的复杂性),但对于浮点数却不是这么简单。许多值(包括像0.1这样的简单值)不能被浮点数完全表示,因此类型的选择不仅影响性能,还影响结果值。C语言设计者似乎更倾向于在这种情况下优先考虑健壮性而不是性能,因此他们决定默认的表示应该是更精确的那个。

历史

为什么C语言不只有short float、float和long float呢?"double"这个词从哪里来的?

术语“single precision”和“double precision”起源于FORTRAN,并且在C语言发明时已经广泛使用。


2

首先,这些名称并不是专门针对C++的,而是几乎适用于实现IEEE 754的任何浮点数据类型。

名称“double”指代“双精度”,而“float”通常被称为“单精度”。


不错的想法,但IEEE-754至少比C晚了十年... - Roddy

1
它们被称为单精度和双精度,因为它们与处理器的自然大小(术语不确定)有关。因此,32位处理器的单精度将为32位长,其双精度将是其两倍-64位长。他们只是决定在C中将单精度类型称为“float”。

1
你正在寻找“字长”这个术语。 - Jyaan

1

最常见的两种浮点数格式使用32位和64位,较长的一种是第一种大小的“双倍”,因此被称为“double”。


1

Double(双精度)之所以被称为双精度,是因为它比float(单精度)的“精度”高一倍。实际上,这意味着它使用了两倍于浮点值的空间——如果您的float是32位,则您的double将是64位。

双精度浮点数的名称有些不准确,因为双精度浮点数的尾数精度为52位,而单精度浮点数的尾数精度为23位(双精度为56位)。更多关于浮点数的信息请参见Floating Point - Wikipedia,其中包括底部链接到有关单精度和双精度浮点数的文章。

长双精度的名称可能只是遵循了整型类型中长整型与短整型相同的传统,只不过在这种情况下,它们反转了,因为'int'等价于'long int'。


1
在固定点表示法中,小数点后有固定数量的数字(十进制表示法中小数点的概括)。与此相对比的是浮点表示法,其中小数点可以在所表示数字的位数内移动或浮动。因此得名“浮点表示法”。这被缩写为“float”。
在K&R C中,“float”指的是具有32位二进制表示的浮点表示法,“double”指的是具有64位二进制表示的浮点表示法,即大小加倍,因此得名。然而,最初的K&R规范要求所有浮点运算都以双精度进行。
在最初的IEEE 754标准(IEEE 754-1985)中,浮点表示法和算术的黄金标准提供了单精度和双精度浮点数的二进制表示的定义。双精度数被恰当地命名为它们由两倍于单精度数的位数表示。
有关浮点表示法的详细信息,请阅读David Goldberg的article,《计算机科学家应该知道的浮点算术》。

0
因此,%f 用于浮点类型,而 %lf 用于长浮点数,它与双精度相同。

1
在 C 语言的 printf 函数中,%f 已经代表 double,而 %Lf 则代表 long double。不过对于 scanf 函数,你是正确的。 - Roland Illig

0

double是“双精度”的缩写。 我猜,long double是因为当处理器开始出现更高精度的浮点类型时,不想再添加另一个关键字。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接