将浮点数转换为双精度

15

float 转换为 double 有多昂贵?它是否像将 int 转换为 long 那样简单?

编辑:我假设平台上的 float 是 4 字节,double 是 8 字节。


6
你的性能分析器是否表明你的程序在将浮点数转换为双精度浮点数时变得很慢? - Michael Kristofik
请指定平台。这是基于 x86 架构的 Windows(Win32)还是基于 x64 架构的 Windows(Win64)?或者是 PPC,或者是一些嵌入式平台?如果不知道平台,则无法回答该问题。 - Suma
6个回答

11

平台考虑

这取决于用于浮点计算的平台。对于x87 FPU,转换是免费的,因为寄存器内容相同-您有时可能会付出的唯一代价是内存流量,但在许多情况下,甚至没有流量,因为您可以直接使用值而无需进行任何转换。就这方面而言,x87实际上是一种奇怪的生物-很难在它上面正确区分浮点数和双精度数,因为所使用的指令和寄存器相同,不同之处在于加载/存储指令和计算精度本身是使用状态位控制的。使用混合的浮点/双精度计算可能会导致意想不到的结果(并且由于这个原因,有编译器命令行选项来控制精确行为和优化策略)。

当您使用SSE(有时Visual Studio默认使用SSE)时,情况可能会有所不同,因为您可能需要在FPU寄存器中传输值或执行某些显式操作以执行转换。

内存节省性能

总之,回答您在其他地方的评论:如果您希望将浮点计算的结果存储到32b存储中,则结果速度将相同或更快,因为:

  • 如果您在x87上执行此操作,则转换是免费的-唯一的区别是fstp dword[]将用于代替fstp qword[]。
  • 如果启用了SSE,您甚至可能会看到一些性能提升,因为一些浮点计算可以使用SSE执行,只要计算的精度为float而不是默认的double即可。
  • 在所有情况下,内存流量都较低

6

在一些平台上(如PPC、x86),浮点数转换为双精度数可以免费进行(如果你的编译器/运行时采用“无论你告诉我使用什么类型,我都要将所有内容评估为long double”的评估模式)。

在使用SSE寄存器实际执行指定类型的浮点运算的x86环境中,float和double之间的转换与浮点加法或乘法一样昂贵(即,除非你需要进行大量此类操作,否则不太可能影响性能)。

在缺乏硬件浮点支持的嵌入式环境中,这些转换可能会比较昂贵。


1

我想象不出这会更加复杂。将int转换为long和将float转换为double之间的主要区别在于,int类型有两个组成部分(符号和值),而浮点数有三个组成部分(符号、尾数和指数)。

IEEE 754单精度使用32位编码,其中1位用于符号,8位用于指数,23位用于有效数字。但是,它使用了一个隐藏位,因此有效数字是24位(p = 24),即使只使用了23位进行编码。

-- David Goldberg, 计算机科学家应该了解的浮点运算知识

因此,将float转换为double将保持相同的符号位,将float的尾数的最后23/24位设置为double的尾数,并将float的指数的最后8位设置为double的指数。

这种行为甚至可能由IEEE 754保证...我没有检查过,所以不确定。


0

这个与你正在使用的C++实现有关。在C++中,默认的浮点类型是double。编译器应该为以下代码发出警告:

float a = 3.45;

因为将双精度值3.45赋给了浮点数。如果您需要特别使用浮点数,请在值后缀加上f

float a = 3.45f;

重点是,所有浮点数默认都是双精度类型。如果您不确定编译器的实现细节并且对浮点运算没有深入的理解,那么坚持使用这个默认值是安全的。避免强制转换。
此外,请参阅C++编程语言第4.5节。

我需要存储大量的浮点数值,不需要双精度,并希望将所需内存减半。 - Tony the Pony
1
@Jen:正如我所说,这不是语言问题,而是编译器与浮点运算实现的问题。你需要查阅你的编译器和硬件手册。 - Vijay Mathew
1
这完全没有回答问题。 - Justicle
@Justicle 没有一个标准答案!这是一个特定于平台的问题。 - Vijay Mathew

-1

或许这可以帮助:

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>

double _ftod(float fValue)
{
  char czDummy[30];
  printf(czDummy,"%9.5f",fValue);
  double dValue = strtod(czDummy,NULL);
  return dValue;
}


int main(int argc, char* argv[])
{
  float fValue(250.84f);
  double dValue = _ftod(fValue);//good conversion
  double dValue2 = fValue;//wrong conversion
  printf("%f\n",dValue);//250.840000
  printf("%f\n",dValue2);//250.839996
  getch();
  return 0;
}

至少向提问者解释一下你的代码片段为什么能回答他的问题,这样你的回答才会有些可接受。 - β.εηοιτ.βε

-1

将 int 转换为 long 可能会比这个稍微慢一些,因为所需的内存更大且操作更复杂。有关 内存对齐问题 的良好参考。


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