Long double 出力の精度が正しくありません。何が間違っているのでしょうか?
-
22-08-2019 - |
質問
私は持っています long double
const または not-const として設定している定数。の精度よりも長い (40 桁) long double
私のテスト ワークステーション (19 桁)
印刷すると、19 桁の精度ではなく 16 桁の精度で表示されます。
私がテストしているコードは次のとおりです。
#include <iostream>
#include <iomanip>
#include <limits>
#include <cstdio>
int main ()
{
const long double constLog2 = 0.6931471805599453094172321214581765680755;
long double log2 = 0.6931471805599453094172321214581765680755;
std::cout << std::numeric_limits<long double>::digits10 + 1 << std::endl;
std::cout << "const via cout: " << std::setprecision(19) << constLog2 << std::endl;
std::cout << "non-const via cout: " << std::setprecision(19) << log2 << std::endl;
std::fprintf(stdout, "const via printf: %.19Lf\n", constLog2);
std::fprintf(stdout, "non-const via printf: %.19Lf\n", log2);
return 0;
}
コンパイル:
$ g++ -Wall precisionTest.cpp
出力:
$ ./a.out
19
const via cout: 0.6931471805599452862
non-const via cout: 0.6931471805599452862
const via printf: 0.6931471805599452862
non-const via printf: 0.6931471805599452862
私は期待します 0.6931471805599453094
しかし、代わりに取得します 0.6931471805599452862
.
19 桁の精度が 16 桁に削減される理由はありますか?
私の環境は次のとおりです。
$ gcc --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5490)
gcc の他のバージョンでも同じ問題が発生しています。例:
$ gcc --version
g++ (GCC) 3.4.6 20060404 (Red Hat 3.4.6-10)
NTL または他のライブラリを調べることはできますが、何が原因でこれが発生するのか興味があります。洞察力をありがとう。
解決
私はこの出力を取得します:
19
const via cout: 0.6931471805599453094
non-const via cout: 0.6931471805599453094
const via printf: 0.6931471805599453094
non-const via printf: 0.6931471805599453094
しかし、私は長い二リテラルの代わりに、二重のリテラルを使用しています:
const long double constLog2 = 0.6931471805599453094172321214581765680755L;
long double log2 = 0.6931471805599453094172321214581765680755L;
他のヒント
ハードウェア プラットフォームとコンパイル オプションに関連して、興味深い問題がいくつかあります。
- https://www.amazon.com/exec/obidos/ASIN/0954161793/network Theory-20
- 3.17.3 Intel 386 および AMD x86-64 オプション (gcc-4.0.1) (developer.apple.com ドキュメントのアーカイブ)
- 3.17.12 Intel 386 および AMD x86-64 オプション (gcc-4.0.1) (gcc.gnu.org ドキュメント)
これらの `-m' オプションは、i386 および x86-64 ファミリのコンピュータ用に定義されています。
-m96bit-long-double
-m128bit-long-double
これらのスイッチは、long double 型のサイズを制御します。i386アプリケーション・バイナリ・インターフェース はサイズを96ビットと指定しているので -32ビットモードではm96bit-long-doubleがデフォルトである。モダン・アーキテクチャ (ペンティアムおよびそれ以降)は、長時間の使用を好む。 ダブルを8または16にアライメントする。 バイト境界。配列または構造体 ABIに適合していても、これはABIではない。 可能だ。つまり -m128bit-long-doubleは、long doubleを次のように16バイト境界に揃える。 でパディングしている。 追加の32ビットゼロ。
x86-64コンパイラーでは、 -m128bit-long-doubleがデフォルトの選択である。 doubleは16バイトにアラインされる。 バウンダリー
これらのオプションのいずれも、長いダブルで80ビットのX87標準を超えて追加の精度を可能にしないことに注意してください。
警告:デフォルトの ターゲットABIの 構造体や配列に長い ダブル変数は サイズと関数呼び出し 長い関数の規約 倍が修正される。それゆえ、彼らは とのバイナリ互換性はありません。 コンパイルされたコード内の配列や構造体 そのスイッチなしで。