long double

long double の構造
アーキテクチャ合計ビット幅 小数部のビット長10進法での仮数部の精度 指数部のビット長表現可能な値の範囲
IEEE754 double64 5316.0桁 1110^{-308} ... 10^{308}
IA3280 6419.3桁 1510^{-4932} ... 10^{4932}
SPARC128 11334.0桁 1510^{-4932} ... 10^{4932}
POWER128 >= 10631.9桁以上 1110^{-308} ... 10^{308}
IEEE754-2008 binary128128 11334.0 1510^{-4932} ... 10^{4932}
仮数部のビット長には、暗黙の省略の 1 (hidden one) を含む。

long double は(厳密には) 4 倍長のことではない。 SPARC, POWER では 4 倍長に相当する。


最も雑なプログラム
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;

int main()
{
    long double c;
    c = 1.0;

    cout << sizeof(c) << endl;

    cout << c << endl;
    cout << setprecision(40) << atan(c) << endl;
    return 0;
}
atan(1) = 0.7853981633974483096156608458198757210493
(小数点以下 40 桁、41桁目を四捨五入した値)

メモリでは、

ただし、仮数部には暗黙の1を整数部に明示している。 IEEE754 倍精度、SPARC long double では、この 1 は メモリ中に保存されない。

暗黙の1を明示した仮数部のビット表現は、

1.1001 0010 0001 1111 1011 0101 0100 0100 0100 0010 1101 0001 1000 0100 0110 1001 1000 1001
これを先頭から 4 ビットずつ区切ると
1100 1001 0000 1111 1101 1010 1010 0010 0010 0001 0110 1000 1100 0010 0011 0100 1100 0100 1...
となり、16進法に直すと
c90fdaa22168c234c4.
IA32 の 80ビット拡張精度数は暗黙の1もメモリ中に保存されることに注意。

結果
CPUOScompiler sizeofatan(1) の出力結果ビット
SPARC Solaris Sun WorkshopPro 9 160.7853981633974483096156608458198756993698 3f:fe:92:1f:b5:44:42:d1:84:69:89:8c:c5:17:01:b8
GCC 3.4.3 160.7853981633974482789994908671360462903976 3f:fe:92:1f:b5:44:42:d1:80:00:00:00:00:00:00:00
Opteron Solaris Sun WorkshopPro9 120.7853981633974483096282022398515465511082 35:c2:68:21:a2:da:0f:c9:fe:3f:d9:fe
GCC 3.4.3 120.7853981633974483096282022398515465511082 35:c2:68:21:a2:da:0f:c9:fe:3f:06:08
Xeon Linux GCC 3.4.0 120.78539816339744830963 35:c2:68:21:a2:da:0f:c9:fe:3f:ff:bf
FreeBSD GCC 3.4.2 120.7853981633974483096282022398515465511082 35:c2:68:21:a2:da:0f:c9:fe:3f:04:08
Athlon64 Linux GCC 3.4.2 160.7853981633974483096282022398515465511082 35:c2:68:21:a2:da:0f:c9:fe:3f:40:00:00:00:00:00
Itanium2 Linux GCC 2.96 160.7853981633974482789994908671360462903976 00:c0:68:21:a2:da:0f:c9:fe:3f:00:00:00:00:00:00
GCC 3.3 160.78539816339744830963 35:c2:68:21:a2:da:0f:c9:fe:3f:00:00:00:00:00:00
POWER5 AIX XLC V7.0 (with -qlongdouble) 16 0.7853981633974482800003f:e9:21:fb:54:44:2d:18:3f:df:ff:ff:e1:eb:5f:cf
GCC 3.4.3 8 0.785398163397448283f:e9:21:fb:54:44:2d:18
雑なプログラムでも、SPARC + WorkshopPro の組合せは 4 倍精度を返している。


正しい記述
宣言long double f;
定数リテラルの代入f = 0.1L;
f = 1e-1L;
組み込み関数atanl(f), sinl(f), etc.
出力cout << setprecision(32) << f << endl;
printf("%.32Lf\n", f);
サンプル
#ifdef __sun
#include <sunmath.h>
#endif

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
using namespace std;

int main()
{
    long double f;
    f = 0.1L;
    printf("%.40Lf\n", f);

    long double f2;
    f2 = atanl(1);
    
    printf("%.40Lf\n", f2);

    return 0;
}
結果
CPUOScompiler atan(1) の出力結果0.1 の出力
SPARCSolairsSun WorkshopPro 0.1000000000000000000000000000000000048148
POWERAIXXLC 7 0.0999999999999999999999999999999996918512

SunWorkshop Pro でのコンパイル

注意事項: atanl など、long double 対応の関数を使うには sunmath.h ヘッダをとりこむ。

% /opt/SUNWspro/bin/CC prog.cpp -lsunmath

SPARC アーキテクチャでの拡張倍精度の内部表現

アドレス小
0符号(1 bit):指数MSB(7 bits)
1指数LSB
2仮数MSB
・・・
仮数
・・・
15仮数LSB

アドレス大

IBM XLC でのコンパイル
% xlc++ -qlongdouble prog.cpp
% xlc++128 prog.cpp
など。どちらも同じ。

POWER アーキテクチャでの拡張倍精度の内部表現

アドレス小
00符号1(1 bit):指数1 MSB(7 bits)
01指数1 LSB(4 bits):仮数1 MSB(4bits)
02仮数1 MSB
・・・
07仮数1 LSB
08符号(1bit):指数2 MSB(7bits)
09指数2 LSB(4bits):仮数2 MSB(4 bits)
10仮数2 MSB
・・・
15仮数2 LSB

アドレス大
IBM の4倍精度数は、2つの倍精度数の和として表現される。 所謂 exact sum というやつ。

「IBM の 4倍精度は、ハードウエアで処理するので速い」と言われる。 但し「4 倍精度数を直接扱い得る回路」を内蔵しているわけではなく、 4倍精度数を 2 つの倍精度数に分割して表現し、そのそれぞれに対して 倍精度用の回路で処理していることを表現している。


GCC/IA32 で 128bit long double を使うときは
g++ -m128bit-long-double src.cpp
とする。
Fortran のリテラル文字 実数型
単精度1.0E0
倍精度1.0D0
四倍精度1.0Q0

整数型

リテラル定数に続けて、アンダースコアと「種別番号(INT_KIND)」を付する。
例:「1」の表現
サイズ範囲プログラム中での表現
8ビット整数-2^7 から 2^7-11_1
16ビット整数-2^15 から 2^15-11_2
32ビット整数-2^31 から 2^31-11_3
64ビット整数-2^63 から 2^63-11_4

fujiwara (at) acs.i.kyoto-u.ac.jp