实数 - 如何确定需要浮点数还是双精度浮点数?

10

给定一个实数,我们可以检查是否需要使用double数据类型来存储该数字,或者使用float已足够?

我知道精度因架构而异。是否有C/C++函数可确定正确的数据类型?


两者都可以存储从负无穷到正无穷的值。 - Pubby
1
是的,无论是浮点数还是双精度数都可能不足够! - Grijesh Chauhan
3
@Pubby:你一定在开玩笑... - Jakob S.
1
@Pubby:http://zh.wikipedia.org/wiki/可计算数 - user541686
1
“足够”是什么意思?你是指它是否在最小和最大浮点值范围内吗?还是指一个浮点数能否精确表示它? - David Brown
显示剩余9条评论
6个回答

4

背景请参见计算机科学家应该了解的浮点数算术知识

不幸的是,我认为没有任何自动化决策的方法。

通常,当人们使用浮点数而不是字符串表示数字时,意图是使用数字进行算术运算。即使所有输入都以给定的浮点类型具有可接受的精度,仍然必须考虑舍入误差和中间结果。

实际上,大多数计算将使用64位类型具有足够的精度,以获得可用的结果。许多计算将无法仅使用32位获得可用的结果。

在现代处理器中,总线和算术单元宽度足以为32位和64位浮点数提供类似的性能。使用32位的主要动机是在存储非常大的数组时节省空间。

这导致以下策略:

如果数组足够大,可以花费大量精力将其减半,那么需要分析和实验来确定32位类型是否提供足够好的结果,如果是,则使用它。否则,使用64位类型。


1
矢量计算(例如SSE)使用单精度与双精度相比,可以通过相同的ALU获得两倍的吞吐量,因此64位ALU普遍存在并不是一个好的论据。同样,在相同的时间内,无论总线宽度如何,您都可以将两倍数量的32位数字传输到数据总线中。使事物变小的动机是性能。无论如何,通常需要对精度进行某种分析,因为如果没有这样做,您可能会像在32位中一样被精度错误所困扰。 - Potatoswatter

3
我认为你的问题假定了一种在C/C++(或任何其他程序)中指定任何“实数”而不会丢失精度的方法。
假设您通过代码或用户输入来获得这个实数;检查浮点数或双精度浮点数是否足以存储它而不会丢失精度的方法是仅计算有效位数,并将其与浮点数和双精度浮点数的数据范围进行比较。
如果该数字表示为表达式(即1/7sqrt(2)),您还需要检测以下内容: 此外,还有一些数字,例如0.9,在理论上无法通过浮点数/双精度表示“准确”(至少在我们的二进制计算范例中不行)-请参见Jon Skeet在此问题上的出色回答。 最后,请参阅关于浮点数与双精度的其他讨论。

3
精度并不是非常依赖于平台。虽然允许平台存在差异,但float几乎普遍采用IEEE标准单精度浮点格式,而double则是双精度浮点格式

单精度分配了23位“尾数”或小数点后的二进制数字。由于小数点前的位始终为1,因此这相当于24位小数。除以log2(10)= 3.3,一个浮点数可以获得7.2个十进制数字的精度。

对于double进行相同的过程会产生15.9个数字,而long double会产生19.2个数字(适用于使用英特尔80位格式的系统)。

尾数之外的位用于指数。指数位数决定了允许的数字范围。单精度可达到约10±38,双精度可达到约10±308

至于您是否需要7、16或19个数字,或者是否适用于有限精度表示,这实际上超出了问题的范围。这取决于算法和应用程序。


对于 double,它不应该是 log10(2^53) = 15.95 位数字吗? - Raj
@Raj 即使它不占用存储空间,隐式前导的“1”也会被计算在内。 - Potatoswatter
52位尾数并带有一个隐含的前导1?所以总共53位。我是否漏掉了什么? - Raj

1
一个非常详细的帖子,可能会回答你的问题。
一个完整的系列,涉及浮点复杂性!

嗯,我读了关于浮点数复杂性的前十几个条目,它们最多是过度简化,最糟糕的情况下完全错误。例如,“FLT_MIN 不是最小的正浮点数(FLT_MIN 是最小的正常规浮点数)”是正确的,如果你的硬件支持 subnormals。大多数都支持,但并非全部。这就是为什么 std::numeric_limits 有一个名为 has_denorm 的布尔成员的原因。 - Pete Becker
那篇特定的文章确实说明它正在谈论IEEE 754标准,其中子规范是被定义的。如果您的硬件恰好不符合标准,那么您几乎不能责怪一篇关于标准的文章在涉及您的硬件方面出现错误。这些文章可能过于简化,但对于没有整个浮点业务知识的人来说,我觉得它处于正确的复杂性水平。 - jonathanasdf
我只看了第一页,但我没有看到它说是关于IEEE 754的。无论如何,C++不需要IEEE 754。大多数人在浮点运算中遇到的问题是他们对其的看法过于简单化;另一种过度简化并不能解决这个问题。 - Pete Becker
@PeteBecker 对于大多数程序员来说,假设他们的编程平台提供了IEEE 754浮点算术,并理解这意味着什么(其中一些影响列在http://www.altdevblogaday.com/2012/04/05/floating-point-complexities/上)将是一个巨大的进步。 - Pascal Cuoq
@PascalCuoq - 当然,如果明确说明所说的内容适用于IEEE 754实现,那就没问题。我对所讨论的文章的反对意见在于它提供了可爱的概括,但没有提供上下文。 - Pete Becker

0

你可以将它存储到一个float和一个double变量中,然后比较这两个变量。这应该会隐式地将float转换回double - 如果没有差异,那么float就足够了吗?

float f = value;
double d = value;
if ((double)f == d)
{
     // float is sufficient
}

如果你将 double 强制转换为 float,然后再转回 double,结果几乎(*)永远不会等于原始值,即使原始值可以表示为 float(达到其精度)。 - Victor K
2
@VictorK:你的意思是,如果原始值可以表示为浮点数,将其转换为浮点数然后再转换回双精度浮点数几乎永远不会产生原始值?如果双精度浮点数中的值可以被精确地表示为浮点数,则两个转换都会产生精确的值;没有任何变化。 - Eric Postpischil
@Eric Postpischil - 同意 :) 这是一种有点扭曲的讨论。只是想提供一个不实现这个解决方案的原因之一。 - SChepurin
@Eric Postpischil double类型有53位的有效数字,而float类型只有24位的有效数字。当你将double类型转换为float类型时,你会失去29位有效数字,即使这个数在单精度浮点数的最小/最大值范围内(我并没有说它可以被准确地表示;我想这是我用词不当的问题)。 - Victor K
1
@VictorK:这个答案中的代码旨在检测一个双精度浮点数是否可以被精确地表示为单精度浮点数。鉴于此,您所描述的行为并不是一种批评,而是支持代码的目的:无法被单精度浮点数精确表示的双精度浮点数会被往返转换所改变,而可以被单精度浮点数精确表示的双精度浮点数则不会被改变。这就是代码的意图。 - Eric Postpischil
显示剩余6条评论

0

你不能用浮点或双精度变量表示实数,只能表示有理数的一个子集。

当进行浮点运算时,你的CPU浮点单元会为你决定最佳近似值。

我可能错了,但我认为浮点(4字节)和双精度(8字节)浮点表示实际上是独立于计算机体系结构指定的。


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