2

時間、速度、距離などの物理エンティティを処理し、距離 = 時間 * 速度などの簡単な計算を実行しています。速度と距離は 8 桁に丸められた double 値であり、時間値の場合は .NET TimeSpan使用されている。TimeSpan は最も近いミリ秒に丸められるため、丸めエラーが発生するため、すべての計算を最も近いミリ秒に丸めるカスタム丸めメソッドを作成する必要があります。例 (単純化のため、8 桁目への丸めは省略されています):

  static void Main(string[] args) {
     var dist = 1.123451;
     var speed = 1.123452;

     var timeA = TimeSpan.FromHours(dist / speed);
     var timeB = timeA + TimeSpan.FromMilliseconds(1);

     var distA = _round(timeA.TotalHours * speed);
     var distB = _round(timeB.TotalHours * speed);

     var timeA1 = TimeSpan.FromHours(distA / speed);
     var timeB1 = TimeSpan.FromHours(distB / speed);

     // a correct implementation should give both the following vars true
     var isDistributive = distA == dist;
     var isPrecise = (timeB1 - timeA1) == TimeSpan.FromMilliseconds(1);
  }

  public static double _round(double d) {
     // Q: what should be here?
  }
  • Math.Round(d, 6) の使用は分配的ですが、精度が失われます (最大 4 ミリ秒までの精度)
  • Math.Round(d, 7) の使用は 1 ミリ秒の精度ですが、分配的ではありません (上の distA は 1.1234511 != 1.123451 になります)。
  • 次の使用 (最も近いミリ秒に丸める) は正しいようですが、丸めコード自体が独自の倍精度エラーを導入します。

      public static double _round(double d) {
        var pre = 3600000.0;
        return Math.Round(d * pre) / pre;
      }
    

ありがとう、ボリス。

4

2 に答える 2

2

Jon Skeetも同様に .Net 時間計算に不満を持っており、 noda-timeというプロジェクトに取り組んでおり、この問題を解決できると信じています。このプロジェクトがあなたの役に立てるほど進んでいるかどうかはわかりませんが、チェックする価値はあります。

編集:(不必要に)車輪​​を再発明するのではなく、人々にライブラリを使用および改善してもらうことを期待して、恥知らずにJSの名前を呼び出します。

于 2010-07-26T23:19:46.753 に答える
0

double 型の代わりに decimal を使用してみてください。それらはより正確 (28 桁の精度) であり、カスタムの丸め関数を実装しなくてもニーズに合うはずです。

于 2010-07-26T17:56:54.153 に答える