8

非常に高性能なアプリでは、CPU が long 演算を double よりも大幅に高速に計算できることがわかりました。ただし、私たちのシステムでは、小数点以下 9 桁を超える精度は必要ないと判断されました。したがって、すべての浮動小数点演算に long を使用し、9 ポイントの精度を理解しました。

ただし、システムの特定の部分では、double を使用した方が読みやすいため、より便利です。そのため、小数点以下 9 桁を想定した long 値を double に変換する必要があります。

long を単純に 10 で割って 9 乗するか、1 を 10 で割って 9 乗すると、double で不正確な表現が得られることがわかります。

それを解決するために、 を使用しMath.Round(value,9)て正確な値を提供します。

ただし、Math.Round()パフォーマンスが恐ろしく遅いです。

したがって、現時点では、仮数と指数を double のバイナリ形式に直接変換することを考えています。この方法では、丸めの必要がなくなるからです。

double のビットを調べて仮数と指数を取得する方法をオンラインで学習しましたが、それを逆にして仮数と指数を取得し、ビットを使用して double を作成する方法を理解するのは混乱します。

助言がありますか?

[Test]
public unsafe void ChangeBitsInDouble()
{
    var original = 1.0D;
    long bits;
    double* dptr = &original;
    //bits = *(long*) dptr;
    bits = BitConverter.DoubleToInt64Bits(original);
    var negative = (bits < 0);
    var exponent = (int) ((bits >> 52) & 0x7ffL);
    var mantissa = bits & 0xfffffffffffffL;
    if( exponent == 0)
    {
        exponent++;
    }
    else
    {
        mantissa = mantissa | (1L << 52);
    }
    exponent -= 1075;

    if( mantissa == 0)
    {
        return;
    }

    while ((mantissa & 1) == 0)
    {
        mantissa >>= 1;
        exponent++;
    }

    Console.WriteLine("Mantissa " + mantissa + ", exponent " + exponent);

}
4

2 に答える 2

1

10^9 の倍率を使用するべきではなく、代わりに 2^30 を使用する必要があります。

于 2012-01-19T13:43:39.743 に答える
0

他の回答で既に認識しているように、double は浮動小数点 10 進数ではなく浮動小数点 2 進数で機能するため、最初のアプローチは機能しません。

また、必要な最大範囲が明確ではないため、意図的に単純化された式で機能するかどうかも明確ではなく、丸めが避けられなくなります。

これを迅速かつ正確に実行するという問題は、よく研究されており、多くの場合、CPU 命令によってサポートされています。組み込みの変換を打ち負かす唯一のチャンスは、次のいずれかです。

  1. あなたは、それについて書かれているいくつかの深刻な論文に値する数学的ブレークスルーを達成しました.
  2. 独自の例では発生しない十分なケースを除外しますが、一般的にビルトインの方が優れていますが、独自の使用に最適化されています。

使用する値の範囲が非常に限定されていない限り、倍精度 IEEE 754 と長整数の間の変換でショートカットが発生する可能性はますます小さくなります。

IEEE 754 がカバーするほとんどのケース、またはそれらのかなりの部分をカバーする必要がある場合は、処理が遅くなります。

私はあなたが持っているものにとどまることをお勧めしdoubleますdecimal. decimalfrom をlong簡単に作成できます:

private static decimal DivideByBillion (long l)
{
  if(l >= 0)
   return new decimal((int)(l & 0xFFFFFFFF), (int)(uint)(l >> 32), 0, false, 9);
  l = -l;
  return new decimal((int)(l & 0xFFFFFFFF), (int)(uint)(l >> 32), 0, true, 9);
}

さて、decimal算術で使用するのはマグニチュードよりも遅くなりますdouble(正確には、最初の質問であなたと同様のアプローチを実装していますが、指数と仮数が異なります)。ただし、文字列に表示またはレンダリングするための値を取得するための便利な方法が必要な場合は、への変換を手動でハッキングする方が への変換をdecimal手動でハッキングするよりも利点があるdoubleため、検討する価値があります。

于 2012-01-19T15:27:49.983 に答える