17

私は現在、数値計算を行うC++プロジェクトに取り組んでいます。コードの大部分は単精度浮動小数点値を使用しており、それで完全に機能します。このため、コンパイラフラグを使用して、デフォルトの倍精度ではなく、基本的な浮動小数点リテラルを単精度にします。これにより式が読みやすくなり、どこかで「f」を忘れることを心配する必要がなくなります。ただし、倍精度計算によって提供される追加の精度が必要になることがあります。私の質問は、倍精度リテラルをそのような式にどのように組み込むことができるかということです。これまでに試したすべての方法で、最初に値を単精度変数に格納し、切り捨てられた値を倍精度値に変換します。私が欲しいものではありません。

私がこれまでに試したいくつかの方法を以下に示します。

#include <iostream>

int main()
{
  std::cout << sizeof(1.0E200) << std::endl;
  std::cout << 1.0E200 << std::endl;

  std::cout << sizeof(1.0E200L) << std::endl;
  std::cout << 1.0E200L << std::endl;

  std::cout << sizeof(double(1.0E200)) << std::endl;
  std::cout << double(1.0E200) << std::endl;

  std::cout << sizeof(static_cast<double>(1.0E200)) << std::endl;
  std::cout << static_cast<double>(1.0E200) << std::endl;

  return 0;
}

単精度定数を使用して実行すると、次の結果が得られます。

~/path$ g++ test.cpp -fsingle-precision-constant && ./a.out
test.cpp:6:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:7:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:12:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:13:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:15:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:16:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
4
inf
16
1e+200
8
inf
8
inf

最後の2つのケースで提供される8バイトは、1.0E200を保持するのに十分であると理解しています。これは、同じプログラムが-fsingle-precision-constantなしでコンパイルされる次の出力でサポートされる理論です。

~/path$ g++ test.cpp  && ./a.out
8
1e+200
16
1e+200
8
1e+200
8
1e+200

上記の例で提案されている考えられる回避策は、元々倍精度を使用するつもりだったすべての場所で4倍精度の浮動小数点リテラルを使用し、ライブラリなどで必要な場合はいつでも倍精度にキャストすることです。ただし、これは少し無駄に感じます。

他に何ができますか?

4

4 に答える 4

19

マークが言ったように、標準は、その後にfが続かない限り、それはダブルであると言っています。

標準の背後には正当な理由があり、便宜上コンパイラフラグを使用してそれを回避することは悪い習慣です。

したがって、正しいアプローチは次のようになります。

  1. コンパイラフラグを削除します
  2. 浮動小数点変数にdouble値を格納する際の精度の低下に関するすべての警告を修正します(すべてのfサフィックスを追加します)
  3. doubleが必要な場合は、fサフィックスを省略してください。

それはおそらくあなたが探していた答えではありませんが、コードベースの寿命を気にする場合に使用すべきアプローチです。

于 2012-08-30T20:57:26.303 に答える
11

2.13.3 / 1を読むと、次のように表示されます。

接尾辞で明示的に指定されていない限り、浮動リテラルのタイプはdoubleです。接尾辞fとFはfloatを指定し、接尾辞lとLはlongdoubleを指定します。

doubleつまり、デフォルトをに変更した場合、リテラル浮動小数点定数に指定する接尾辞はありませんfloat。残念ながら、この場合、両方の長所を活用することはできません。

于 2012-08-30T20:49:40.163 に答える
8

GCC4.7またはClang3.1を購入できる場合は、ユーザー定義のリテラルを使用してください。

double operator "" _d(long double v) { return v; }

使用法:

std::cout << sizeof(1.0E200_d) << std::endl;
std::cout << 1.0E200_d << std::endl;

結果:

8
1e+200
于 2012-08-30T21:07:16.093 に答える
5

独自のサフィックスを定義することはできませんが、おそらく次のようなマクロです。

#define D(x) (double(x##L))

あなたのために働くだろう。コンパイラはdouble定数を出力するだけでよく-O2、私のシステムではそう見えます。

于 2012-08-30T21:06:51.817 に答える