什么是x86-64的长双?

时间:2022-07-23 02:55:57

Someone told me that:

有人告诉我:

Under x86-64, FP arithmetic is done with SSE, and therefore long double is 64 bits.

在x86-64下,FP算法用SSE完成,因此long double是64位。

But in the x86-64 ABI it says that:

但是在x86-64 ABI中它说:

    C type  | sizeof | alignment | AMD64 Architecture
long double |   16   |    16     | 80-bit extended (IEEE-754)

See: amd64-abi.pdf

and gcc says sizeof(long double) is 16 and gives FLT_DBL = 1.79769e+308 and FLT_LDBL = 1.18973e+4932

和gcc说sizeof(long double)是16并给出FLT_DBL = 1.79769e + 308和FLT_LDBL = 1.18973e + 4932

So I'm confused, how is long double 64 bit? I thought it is an 80-bit representation.

所以我很困惑,怎么是长双64位?我认为这是一个80位的表示。

3 个解决方案

#1


7  

Under x86-64, FP arithmetic is done with SSE, and therefore long double is 64 bits.

在x86-64下,FP算法用SSE完成,因此long double是64位。

That's what usually happens under x86-64 (where the presence of SSE instructions is guaranteed), but the program is still free to use x87, to which the compiler can resort when you use a long double.

这通常发生在x86-64(保证存在SSE指令)的情况下,但程序仍然可以*使用x87,编译器在使用long double时可以使用x87。

You can have confirmation of this by compiling a program like this with g++ on Linux:

您可以通过在Linux上使用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;
}

In the assembly output, I find mulsd xmm1, xmm0 for the double product and mulss xmm0, xmm2 for the float product (both SSE instructions), but fmulp st(1), st (x87 instruction) for the long double product.

在汇编输出中,我找到mulsd xmm1,xmm0为double产品,mulss为xmm0,xmm2为浮动产品(均为SSE指令),但fmulp st(1),st(x87指令)为long double产品。

So, it's confirmed, the compiler uses SSE when it can, but still allows 80-bit precision computations via the old x87 instruction set.

因此,经过验证,编译器尽可能使用SSE,但仍允许通过旧的x87指令集进行80位精度计算。


Notice that this is compiler-specific - some compilers (e.g. VC++) always ignored 80-bit precision types and just treated long double as a synonym of double.

请注意,这是特定于编译器的 - 某些编译器(例如VC ++)始终忽略80位精度类型,并将long double视为double的同义词。

On the other hand, since the x86-64 System V ABI (adopted on Linux) mandates that long double is 80 bit, the only way for a compiler to perform computations using all the available precision of the type is to use the x87 instructions.

另一方面,由于x86-64 System V ABI(在Linux上采用)要求long double为80 bit,因此编译器使用该类型的所有可用精度执行计算的唯一方法是使用x87指令。

#2


5  

The AMD ABI cannot actually compel what the C long double type is, because it does not have the jurisdiction/authority to do so. Each C implementation can make its own specification of what the types are, subject to the C standard (if the C implementation is conforming to the standard), and each C implementation can choose whether or not to conform to the AMD ABI.

AMD ABI实际上不能强制C long double类型是什么,因为它没有管辖/权限这样做。每个C实现都可以根据C标准(如果C实现符合标准)制定自己的类型规范,并且每个C实现可以选择是否符合AMD ABI。

This means you cannot simply ask “What is long double on x86-64?” You must ask what is long double in a specific C implementation. That means specifying a particular C compiler, version, and switches used to compile. (A compiler might have a switch for which one setting makes long double a 64-bit binary IEEE 754-floating-point object and another setting makes long double the 80-bit Intel floating-point object. Technically, each different combination of compiler, version, and switches is a distinct C implementation.)

这意味着你不能简单地问“什么是x86-64上的长双?”你必须问一下特定C实现中的长双精度。这意味着指定用于编译的特定C编译器,版本和开关。 (编译器可能有一个开关,其中一个设置使得长两倍的64位二进制IEEE 754浮点对象,另一个设置使得长两倍的80位英特尔浮点对象。从技术上讲,每个不同的编译器组合, version和switch是一个独特的C实现。)

A compiler that implements long double as a 64-bit binary IEEE-754 floating-point object simply passes them as what the AMD ABI calls double; it never passes them as what the ABI calls long double. In doing so, this aspect of the compiler would be compatible only with other software that treats long double similarly.

实现long double作为64位二进制IEEE-754浮点对象的编译器只是将它们传递给AMD ABI调用的两倍;它永远不会像ABI所说的那样传递它们。在这样做时,编译器的这个方面将仅与处理long double的其他软件兼容。

#3


0  

The SSE calculation is double precision and the intermediate representation is 64 bits.

SSE计算是双精度,中间表示是64位。

That's not long double, as you have pointed out. The 64 bit value is just written to the long double after calculation.

正如你所指出的那样,这不会太长。 64位值仅在计算后写入long double。

#1


7  

Under x86-64, FP arithmetic is done with SSE, and therefore long double is 64 bits.

在x86-64下,FP算法用SSE完成,因此long double是64位。

That's what usually happens under x86-64 (where the presence of SSE instructions is guaranteed), but the program is still free to use x87, to which the compiler can resort when you use a long double.

这通常发生在x86-64(保证存在SSE指令)的情况下,但程序仍然可以*使用x87,编译器在使用long double时可以使用x87。

You can have confirmation of this by compiling a program like this with g++ on Linux:

您可以通过在Linux上使用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;
}

In the assembly output, I find mulsd xmm1, xmm0 for the double product and mulss xmm0, xmm2 for the float product (both SSE instructions), but fmulp st(1), st (x87 instruction) for the long double product.

在汇编输出中,我找到mulsd xmm1,xmm0为double产品,mulss为xmm0,xmm2为浮动产品(均为SSE指令),但fmulp st(1),st(x87指令)为long double产品。

So, it's confirmed, the compiler uses SSE when it can, but still allows 80-bit precision computations via the old x87 instruction set.

因此,经过验证,编译器尽可能使用SSE,但仍允许通过旧的x87指令集进行80位精度计算。


Notice that this is compiler-specific - some compilers (e.g. VC++) always ignored 80-bit precision types and just treated long double as a synonym of double.

请注意,这是特定于编译器的 - 某些编译器(例如VC ++)始终忽略80位精度类型,并将long double视为double的同义词。

On the other hand, since the x86-64 System V ABI (adopted on Linux) mandates that long double is 80 bit, the only way for a compiler to perform computations using all the available precision of the type is to use the x87 instructions.

另一方面,由于x86-64 System V ABI(在Linux上采用)要求long double为80 bit,因此编译器使用该类型的所有可用精度执行计算的唯一方法是使用x87指令。

#2


5  

The AMD ABI cannot actually compel what the C long double type is, because it does not have the jurisdiction/authority to do so. Each C implementation can make its own specification of what the types are, subject to the C standard (if the C implementation is conforming to the standard), and each C implementation can choose whether or not to conform to the AMD ABI.

AMD ABI实际上不能强制C long double类型是什么,因为它没有管辖/权限这样做。每个C实现都可以根据C标准(如果C实现符合标准)制定自己的类型规范,并且每个C实现可以选择是否符合AMD ABI。

This means you cannot simply ask “What is long double on x86-64?” You must ask what is long double in a specific C implementation. That means specifying a particular C compiler, version, and switches used to compile. (A compiler might have a switch for which one setting makes long double a 64-bit binary IEEE 754-floating-point object and another setting makes long double the 80-bit Intel floating-point object. Technically, each different combination of compiler, version, and switches is a distinct C implementation.)

这意味着你不能简单地问“什么是x86-64上的长双?”你必须问一下特定C实现中的长双精度。这意味着指定用于编译的特定C编译器,版本和开关。 (编译器可能有一个开关,其中一个设置使得长两倍的64位二进制IEEE 754浮点对象,另一个设置使得长两倍的80位英特尔浮点对象。从技术上讲,每个不同的编译器组合, version和switch是一个独特的C实现。)

A compiler that implements long double as a 64-bit binary IEEE-754 floating-point object simply passes them as what the AMD ABI calls double; it never passes them as what the ABI calls long double. In doing so, this aspect of the compiler would be compatible only with other software that treats long double similarly.

实现long double作为64位二进制IEEE-754浮点对象的编译器只是将它们传递给AMD ABI调用的两倍;它永远不会像ABI所说的那样传递它们。在这样做时,编译器的这个方面将仅与处理long double的其他软件兼容。

#3


0  

The SSE calculation is double precision and the intermediate representation is 64 bits.

SSE计算是双精度,中间表示是64位。

That's not long double, as you have pointed out. The 64 bit value is just written to the long double after calculation.

正如你所指出的那样,这不会太长。 64位值仅在计算后写入long double。