1

2 つの値を補間してパーセンタイルを推定する式があります。

windowMin + (currentPercentile - lastPercentile) * (windowMax - windowMin) / (percentile - lastPercentile)

これにより、非常に優れた現実世界の結果が得られました。ただし、単体テストでは、常に重大な丸め誤差が発生するため、正しく機能していると断言するのに苦労しています。

3 つのテスト ケースで、40パーセンタイル、 50パーセンタイル、および 60パーセンタイルを取得しようとした結果、の計算が行われました。

1 + (0.4 - 0.3333333333333333) * (2 - 1) / (0.6666666666666666 - 0.3333333333333333)
1 + (0.5 - 0.3333333333333333) * (2 - 1) / (0.6666666666666666 - 0.3333333333333333)
1 + (0.6 - 0.3333333333333333) * (2 - 1) / (0.6666666666666666 - 0.3333333333333333)

これにより、次の結果が得られます。

{
  "0.4": 1.2000000000000002,
  "0.5": 1.5,
  "0.6": 1.8
}

1.2これは、40パーセンタイルを探しているという私の主張に反します。

すべてのケースで精度を向上させるためにこの式を再構築する方法はありますか? そうでない場合、chai アサーションでこの問題を回避する簡単な方法はありますか?

4

4 に答える 4

1

これらの丸め誤差は、浮動小数点演算の特性です。

考えられる解決策の 1 つ.toPrecision()は、結果を返す前に計算に適用することです。

var result = windowMin + (currentPercentile - lastPercentile) * (windowMax - windowMin) / (percentile - lastPercentile);
return result.toPrecision(6);  // returns six significant figures

またはおそらくtoFixed()

return result.toFixed(2); // returns two decimal places.
于 2013-09-22T04:49:26.690 に答える
0

以下の Pharo smalltalk 式で示されているように、1.2000000000000002 が、送信した正確な補間に最も近い倍精度浮動小数点値である場合があります (asTrueFraction は、浮動小数点値がまったく同じ値を持つ Fraction に変換されることを意味します)。

(1 + ((0.4 asTrueFraction - 0.3333333333333333 asTrueFraction) * (2 - 1) / (0.6666666666666666 asTrueFraction - 0.3333333333333333 asTrueFraction))) asFloat
-> 1.2000000000000002.

正確な算術演算で補間を評価する場合でも、asTrueFraction を asMinimalDecimalFraction に置き換えることでそれを行うことができます (これにより、同じ Float に丸められる最小桁数の 10 進数が得られます)。

0.4 asTrueFraction -> (3602879701896397/9007199254740992).
0.4 asMinimalDecimalFraction -> (2/5).
0.3333333333333333 asMinimalDecimalFraction -> (3333333333333333/10000000000000000).
0.6666666666666666 asMinimalDecimalFraction -> (3333333333333333/5000000000000000).

次に、同じ結果が再び得られます。分解方法を確認してください。

(1 + ((0.4 asMinimalDecimalFraction - 0.3333333333333333 asMinimalDecimalFraction) * (2 - 1) / (0.6666666666666666 asMinimalDecimalFraction - 0.3333333333333333 asMinimalDecimalFraction))) 
 -> (4000000000000000/3333333333333333).

(4000000000000000/3333333333333333) asFloat ->  1.2000000000000002.

つまり、浮動小数点の結果が必要な場合は、1.2000000000000002 が最適な値です。

補間式が書かれているとおりに常に正確であるとは言いません。丸め誤差が累積する可能性がありますが、入力データに対して適切な処理を実行しています。

式ではなくテストを変更し、明示的な精度要件を挿入します。

于 2013-09-23T10:32:51.227 に答える
0

この問題を解決するには、次の 2 つの方法があります。

  1. 結果に有限数しかない場合は、数値をわずかな精度に丸めることができます

  2. 分割はあなたを混乱させます。等式の両側を除算器に掛けると、結果に無限分数がなくなります:)

于 2013-09-22T04:48:25.210 に答える