3

C または C++ を使用して、ループ内のすべての表現可能な 32 ビット浮動小数点数の範囲をインクリメントしたいと考えています。これは、32 ビット整数で表されるすべての個別の値をインクリメントする方法と同様です。

次のようなもの: for(float f = FLOAT_MIN; f < MAX; f = Next_Float(f)) {...}

標準数学ライブラリの「nexttoward」または「nextafter」関数を使用して、そのタスクを達成できると思います。http://www.cplusplus.com/reference/cmath/nextafter/を参照してください。

現在、double または long double を使用して「nexttoward」または「nextafter」関数をテストし、Ubuntu 13.04 で g++ 4.7 を使用してコンパイルしても、問題は発生しません。テストコードを参照してください:

#include <math.h>   
#include <iostream>
#include <iomanip>

int main ()
{
    double f = 0.1;
    for(int i = 0; i < 5; ++i)
    {
    //Marginally increment f in the upper direction.
    f = nexttoward(f,999.999);
    std::cout << std::setprecision(70) << f << std::endl;
    std::cout << nexttoward(f,999.999) << std::endl;
    }
  return 0;
}

プログラムの浮動小数点出力値は、予想どおり着実に増加します。

ubuntu@ubuntu:~$ g++ -o temp ~/temp.cpp

ubuntu@ubuntu:~$ ./temp

0.10000000000000001942890293094023945741355419158935546875 0.100000000000000033306690738754696212708950042724609375 0.100000000000000033306690738754696212708950042724609375 0.10000000000000004718447854656915296800434589385986328125 0.10000000000000004718447854656915296800434589385986328125 0.1000000000000000610622663543836097232997417449951171875 0.1000000000000000610622663543836097232997417449951171875 0.10000000000000007494005416219806647859513759613037109375 0.10000000000000007494005416219806647859513759613037109375 0.100000000000000088817841970012523233890533447265625

ubuntu@ubuntu:~$

しかし、double の代わりに float を使用しようとすると、「nexttoward」および「nextafter」関数が失敗します。関数は 32 ビット float よりも高い精度の値を返すように見え、戻り値を 32 ビット float に割り当てると、 float は、次に高い値に上がるのではなく、元の値を保持します。サンプル コードと出力を参照してください。

#include <math.h>    
#include <iostream>
#include <iomanip>

int main ()
{
    float f = 0.1f;
    for(int i = 0; i < 10; ++i)
    {
    //Marginally increment f in the upper direction.
    f = nexttoward(f,999.999f);
    std::cout << std::setprecision(70) << f << std::endl;
    std::cout << nexttoward(f,999.999f) << std::endl;
    }
  return 0;
}

「nexttoward」からの 2 番目の出力値の精度が高く、f が同じ値を維持していることに注意してください。

ubuntu@ubuntu:~$ g++ -o temp ~/temp.cpp

ubuntu@ubuntu:~$ ./temp

0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625 0.100000001490116119384765625 0.10000000149011613326255343281445675529539585113525390625

すべての 64 ビット倍精度値ではなく、すべての 32 ビット浮動小数点値をインクリメントしたい - すべての倍精度値をインクリメントする時間が長すぎる。

この問題を解決し、32 ビット浮動小数点変数の範囲を反復処理するための効率的で便利で移植可能な方法を実現するにはどうすればよいですか?

4

1 に答える 1

7

nextafterおよびnexttoward関数は type の引数を取り、 typeのdouble結果を返しますdouble

についてfloatは、対応するnextafterfおよびnexttowardf関数を使用します。

これは、 で宣言されているほとんどすべての数学関数の一般規則です<math.h>。たとえば、次の 3 つの平方根関数があります。

  • sqrtf(の場合float)
  • sqrt(の場合double)
  • sqrtl(の場合long double)

(floatおよびlong doubleバージョンは C99 によって追加されたものであり、すべての実装でサポートされているわけではありません。)

型に間違った関数を使用しても、コンパイラは文句を言いません。引数を予期される型に静かに変換し、その処理に応じて結果を変換します。

これは C の場合です。 を使用する場合、C++ はタイプおよび#include <cmath>の数学関数のオーバーロードされたバージョン (fまたはlサフィックスなし) を追加します。したがって、コードを C++ としてコンパイルすると、これらの関数は期待どおりに動作するはずです。( と の間には違いがあるかもしれません。いずれにせよ、C++ には後者を使用する必要があります。)floatlong double<math.h><cmath>

あなたの質問は、この分野で大きな違いがある C と C++ の両方にタグ付けされています。

(C99 は、<tgmath.h>C++ のオーバーロードされた関数と同様に動作する型固有のマクロを提供するヘッダーも追加します。)

于 2013-11-10T02:37:50.287 に答える