有人告诉我:
在x86-64下,FP算法使用SSE完成,因此long double是64位。
但是在x86-64 ABI中它说:
C type | sizeof | alignment | AMD64 Architecture
long double | 16 | 16 | 80-bit extended (IEEE-754)
请参阅:amd64-abi.pdf
和gcc说sizeof(long double)
是16,并且FLT_DBL
= 1.79769e+308
和FLT_LDBL = 1.18973e+4932
所以我很困惑,long double
64位怎么样?我认为这是一个80位的表示。
答案 0 :(得分:8)
在x86-64下,FP算法使用SSE完成,因此long double是64位。
这就是x86-64下的通常发生的(保证SSE指令的存在),但程序仍然可以自由使用x87,当你使用{时,编译器可以使用x87 {1}}。
您可以通过在Linux上使用long double
编译这样的程序来确认这一点:
g++
在汇编输出中,我找到了#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
std::srand(std::time(NULL));
float f1=rand(), f2=rand();
double d1=rand(), d2=rand();
long double l1=rand(), l2=rand();
std::cout<<f1*f2<<" "<<d1*d2<<" "<<l1*l2<<std::endl;
return 0;
}
产品的mulsd xmm1, xmm0
和double
产品的mulss xmm0, xmm2
(两个SSE说明),但float
( x87指令)代表fmulp st(1), st
产品。
所以,已经证实,编译器尽可能使用SSE,但仍允许通过旧的x87指令集进行80位精度计算。
请注意,这是特定于编译器的 - 某些编译器(例如VC ++)始终忽略80位精度类型,只是将long double
视为long double
的同义词。
另一方面,由于x86-64 System V ABI(在Linux上采用)要求double
为80位,因此编译器使用该类型的所有可用精度执行计算的唯一方法是使用x87说明。
答案 1 :(得分:4)
AMD ABI实际上无法强制C long double
类型是什么,因为它没有管辖权/权限。每个C实现都可以根据C标准制定自己的类型规范(如果C实现符合标准),并且每个C实现可以选择是否符合AMD ABI。
这意味着您不能简单地询问“x86-64上的long double
是什么?”您必须询问特定C实现中的long double
是什么。这意味着指定用于编译的特定C编译器,版本和开关。 (编译器可能有一个开关,其中一个设置使long double
成为64位二进制IEEE 754浮点对象,另一个设置使long double
成为80位英特尔浮点对象。技术上,编译器,版本和开关的每个不同组合都是一个独特的C实现。)
将long double
实现为64位二进制IEEE-754浮点对象的编译器只是将它们传递给AMD ABI调用double
;它永远不会像ABI所称的那样传递它们long double
。在这样做时,编译器的这个方面只能与同样处理long double
的其他软件兼容。
答案 2 :(得分:0)
SSE计算是双精度,中间表示是64位。
正如你所指出的,那不是long double
。 64位值仅在计算后写入long double。