27

高精度の科学計算を行っています。さまざまな効果の最適な表現を探す中で、次に高い (または低い) 倍精度数を取得したい理由を考え続けています。基本的に、私がやりたいことは、double の内部表現の最下位ビットに 1 を追加することです。

問題は、IEEE 形式が完全に統一されていないことです。低レベルのコードを使用し、実際に最下位ビットに 1 を追加すると、結果の形式は次に利用可能な double ではない可能性があります。たとえば、PositiveInfinity や NaN などの特殊なケースの数値である可能性があります。私が理解しているとは言いませんが、「通常の」パターンとは異なる特定のビットパターンを持っているように見えるサブノーマル値もあります。

「イプシロン」値が利用可能ですが、その定義を理解したことがありません。double 値は等間隔ではないため、1 つの値を double に加算して次に高い値にすることはできません。

なぜIEEEが次の高い値または低い値を取得する関数を指定していないのか、私には本当にわかりません。それを必要としているのは私だけではありません。

次の値を取得する方法はありますか (小さな値を追加しようとするある種のループなしで)。

4

7 に答える 7

13

正確にそれを行うために利用できる関数がありますが、使用する言語によって異なります。2 つの例:

  • 適切な C99 数学ライブラリにアクセスできる場合は、nextafter(およびその float と long double バリアント、nextafterfおよびnextafterl) を使用できます。またはnexttowardファミリ (2 番目の引数として long double を取ります)。

  • Fortran を記述した場合、nearest組み込み関数が利用可能になります。

これらにあなたの言語から直接アクセスできない場合は、このような自由に利用できるものでそれらがどのように実装されているかを確認することもできます。

于 2009-08-09T17:17:28.777 に答える
9

ほとんどの言語には、次または前の単精度 (32 ビット) または倍精度 (64 ビット) の数値を取得するための組み込み関数またはライブラリ関数があります。

32 ビットおよび 64 ビットの浮動小数点演算を使用するユーザーにとって、基本的な構造を十分に理解しておくと、それらの危険を回避するのに非常に役立ちます。IEEE 標準は一様に適用されますが、多くの詳細は実装者に委ねられています。したがって、機械語表現のビット操作に基づくプラットフォーム ユニバーサル ソリューションには問題があり、エンディアンなどの問題に依存する可能性があります。ビット レベルでどのように機能するか、または機能する必要があるかについての詳細をすべて理解することは、知的能力を実証する可能性がありますが、各プラットフォームに合わせて調整され、サポートされているプラ​​ットフォーム全体でユニバーサル API を備えた組み込みまたはライブラリ ソリューションを使用することをお勧めします。

C# と C++ のソリューションに気付きました。Java の場合は次のとおりです。

Math.nextUp:

public static double nextUp(double d):

  • 正の無限大方向で d に隣接する浮動小数点値を返します。このメソッドは、意味的には nextAfter(d, Double.POSITIVE_INFINITY); と同等です。ただし、nextUp 実装は、同等の nextAfter 呼び出しよりも高速に実行される場合があります。

特殊なケース:

  • 引数が NaN の場合、結果は NaN になります。
  • 引数が正の無限大の場合、結果は正の無限大になります。
  • 引数がゼロの場合、結果は Double.MIN_VALUE です。

パラメーター:

  • d - 浮動小数点値の開始

戻り値:

  • 正の無限大に近い隣接する浮動小数点値。

public static float nextUp(float f):

  • 正の無限大方向で f に隣接する浮動小数点値を返します。このメソッドは、意味的には nextAfter(f, Float.POSITIVE_INFINITY); と同等です。ただし、nextUp 実装は、同等の nextAfter 呼び出しよりも高速に実行される場合があります。

特殊なケース:

  • 引数が NaN の場合、結果は NaN になります。
  • 引数が正の無限大の場合、結果は正の無限大になります。
  • 引数がゼロの場合、結果は Float.MIN_VALUE になります。

パラメーター:

  • f - 浮動小数点値の開始

戻り値:

  • 正の無限大に近い隣接する浮動小数点値。

次の 2 つは、使用するのが少し複雑です。ただし、ゼロに向かう方向、または正または負の無限に向かう方向は、より可能性が高く有用な用途のようです。もう 1 つの用途は、2 つの値の間に中間値が存在することを確認することです。ループとカウンターを使用して、2 つの値の間にいくつ存在するかを判断できます。また、nextUp メソッドとともに、for ループでのインクリメント/デクリメントにも役立つようです。

Math.nextAfter:

public static double nextAfter(二重開始、二重方向)

  • 2 番目の引数の方向で最初の引数に隣接する浮動小数点数を返します。両方の引数を比較して等しい場合、2 番目の引数が返されます。

特殊なケース:

  • いずれかの引数が NaN の場合、NaN が返されます。
  • 両方の引数が符号付きゼロの場合、方向は変更されずに返されます (引数が等しい場合に 2 番目の引数を返すという要件によって暗示されているように)。
  • start が ±Double.MIN_VALUE で、方向の値が結果のマグニチュードが小さくなるような値の場合、start と同じ符号のゼロが返されます。
  • start が無限大で、方向が結果のマグニチュードが小さくなるような値を持つ場合、start と同じ符号を持つ Double.MAX_VALUE が返されます。
  • start が ± Double.MAX_VALUE に等しく、結果がより大きな大きさを持つような値が direction にある場合、start と同じ符号の無限大が返されます。

パラメーター:

  • start - 浮動小数点値の開始
  • direction - 開始の隣接または開始のどちらを返す必要があるかを示す値

戻り値:

  • direction の方向で start に隣接する浮動小数点数。

public static float nextAfter(float 開始、二重方向)

  • 2 番目の引数の方向で最初の引数に隣接する浮動小数点数を返します。両方の引数を比較して等しい場合、2 番目の引数と同等の値が返されます。

特殊なケース:

  • いずれかの引数が NaN の場合、NaN が返されます。
  • 両方の引数が符号付きゼロの場合、方向と同等の値が返されます。
  • start が ±Float.MIN_VALUE で、方向の値が結果のマグニチュードが小さくなるような値の場合、start と同じ符号のゼロが返されます。
  • start が無限大で、方向の値が結果のマグニチュードが小さくなるような値の場合、start と同じ符号の Float.MAX_VALUE が返されます。
  • start が ± Float.MAX_VALUE に等しく、方向の値が結果のマグニチュードが大きくなるような値の場合、start と同じ符号の無限大が返されます。

パラメーター:

  • start - 浮動小数点値の開始
  • direction - 開始の隣接または開始のどちらを返す必要があるかを示す値

戻り値:

  • direction の方向で start に隣接する浮動小数点数。
于 2012-07-10T21:10:25.743 に答える
6

Thorsten S. が言うように、これはクラスで行うことができますが、彼のメソッドはメソッドが の内部バイト構造を返すBitConverterことを前提としていますが、そうではありません。そのメソッドによって返される整数は、実際には 0 とあなたの値の間の表現可能な double の数を返します。つまり、最小の正の double は 1 で表され、次に大きい double は 2 などです。負の数は 0d から始まり、0d から離れます。DoubleToInt64Bitsdoublelong.MinValue

したがって、次のようなことができます。

public static double NextDouble(double value) {

    // Get the long representation of value:
    var longRep = BitConverter.DoubleToInt64Bits(value);

    long nextLong;
    if (longRep >= 0) // number is positive, so increment to go "up"
        nextLong = longRep + 1L;
    else if (longRep == long.MinValue) // number is -0
        nextLong = 1L;
    else  // number is negative, so decrement to go "up"
        nextLong = longRep - 1L;

    return BitConverter.Int64BitsToDouble(nextLong);
}

これは and には対応していませんInfinityNaN,、気になる場合はチェックして好きなように処理できます。

于 2010-02-17T19:02:47.957 に答える
3

はい、方法はあります。C# の場合:

       public static double getInc (double d)
        {
                // Check for special values
                if (double.IsPositiveInfinity(d) || double.IsNegativeInfinity(d))
                    return d;
                if (double.IsNaN(d))
                    return d;

                // Translate the double into binary representation
                ulong bits = (ulong)BitConverter.DoubleToInt64Bits(d);
                // Mask out the mantissa bits
                bits &= 0xfff0000000000000L;
                // Reduce exponent by 52 bits, so subtract 52 from the mantissa.
                // First check if number is great enough.
                ulong testWithoutSign = bits & 0x7ff0000000000000L;
                if (testWithoutSign > 0x0350000000000000L)
                  bits -= 0x0350000000000000L;
                else
                  bits = 0x0000000000000001L;
                return BitConverter.Int64BitsToDouble((long)bits);
}

増加分は加算および減算できます。

于 2009-12-08T00:04:52.560 に答える
1

あなたの問題をフォローしているかどうかわかりません。確かに IEEE 規格完全に統一されていますか? たとえば、倍精度数に関するウィキペディアの記事からの抜粋を見てください。

3ff0 0000 0000 0000   = 1
3ff0 0000 0000 0001   = 1.0000000000000002, the next higher number > 1
3ff0 0000 0000 0002   = 1.0000000000000004

2 進数または 16 進数表現で最下位ビットをインクリメントするだけの何が問題なのですか?

特殊数 (無限大、NaN など) に関する限り、それらは明確に定義されており、それほど多くはありません。制限も同様に定義されます。

あなたは明らかにこれを調べたので、私はスティックの間違った端を持っていると思います. これで問題が解決しない場合は、達成したいことを明確にしていただけますか? ここでのあなたの目的は何ですか?

于 2009-08-07T17:37:24.770 に答える
1

イプシロン関数に関しては、バイナリ double が 10 進値の近似値からどれだけ離れているかを推定したものです。これは、非常に大きな正または負の 10 進数、または非常に小さな正または負の 10 進数の場合、それらの多くが double と同じ 2 進数表現にマップされるためです。非常に大きな、または非常に小さな 10 進数をいくつか試し、それらから double を作成してから、10 進数に変換します。同じ 10 進数が返されないことがわかりますが、代わりに double に最も近い値が返されます。

値が 1 または -1 に近い (double が表すことができる 10 進値の広大な範囲に近い) 場合、イプシロンはゼロまたは非常に非常に小さくなります。+ または - 無限大またはゼロに向かって徐々に向かう値の場合、イプシロンは成長し始めます。ゼロまたは無限大に非常に近い値では、これらの範囲の 10 進数値に使用できるバイナリ表現が非常にまばらであるため、イプシロンは非常に大きくなります。

于 2012-07-11T09:00:06.770 に答える