時間、速度、距離などの物理エンティティを処理し、距離 = 時間 * 速度などの簡単な計算を実行しています。速度と距離は 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; }
ありがとう、ボリス。