74

C++ FAQ lite 「[29.17] 浮動小数点比較が機能しないのはなぜですか?」は、次の等価テストを推奨しています。

#include <cmath>  /* for std::abs(double) */

inline bool isEqual(double x, double y)
{
  const double epsilon = /* some small number such as 1e-5 */;
  return std::abs(x - y) <= epsilon * std::abs(x);
  // see Knuth section 4.2.2 pages 217-218
}
  1. これは、ゼロに等しい数は と だけであることを意味するというのは正しい+0です-0か?
  2. ゼロをテストするとき、または次のようなテストを行うときにも、この関数を使用する必要があります|x| < epsilonか?

アップデート

Daniel Daranas が指摘したように、関数はおそらく呼び出されたほうがよいでしょうisNearlyEqual(これは私が気にかけているケースです)。

誰かが「浮動小数点数の比較」を指摘しました。これをもっと目立つように共有したいと思います。

4

9 に答える 9

13

+0.0とのみに関心がある場合は、 from-0.0を使用できます。例えば:fpclassify<cmath>

if( FP_ZERO == fpclassify(x) ) do_something;

于 2016-01-07T14:07:12.110 に答える
6

次のような値のstd::nextafter固定factorで使用できます。epsilon

bool isNearlyEqual(double a, double b)
{
  int factor = /* a fixed factor of epsilon */;

  double min_a = a - (a - std::nextafter(a, std::numeric_limits<double>::lowest())) * factor;
  double max_a = a + (std::nextafter(a, std::numeric_limits<double>::max()) - a) * factor;

  return min_a <= b && max_a >= b;
}
于 2016-02-07T11:06:33.400 に答える
1

@Exceptiononが指摘したように、この関数は比較している値に対して「相対的」です。メジャーは xのEpsilon * abs(x)値に基づいてスケーリングされるためepsilon、x または y の値の範囲に関係なく、 と同じくらい正確に比較結果が得られます。

zero( y) を別の非常に小さな値 ( x)、たとえば 1e-8 と比較している場合abs(x-y) = 1e-8でも、 よりもはるかに大きくなりepsilon *abs(x) = 1e-13ます。したがって、 double 型で表現できない非常に小さな数値を扱っている場合を除き、この関数は仕事をし、 and に対してのみ 0 と一致+0します-0

この関数は、ゼロ比較に完全に有効であるようです。使用する予定がある場合は、フロートが関係するすべての場所で使用することをお勧めします。また、ゼロなどの特別なケースを持たないようにして、コードに統一性を持たせるようにしてください。

ps: これはきちんとした関数です。ご指摘ありがとうございます。

于 2013-11-07T15:39:00.907 に答える
1

次の例を検討してください。

bool isEqual = (23.42f == 23.42);

とはisEqual? 10 人中 9 人が「もちろんです」true答え、10 人中 9 人が間違っています: https://rextester.com/RVL15906

これは、浮動小数点数が正確な数値表現ではないためです。

2 進数であるため、10 進数として正確に表現できるすべての数値を正確に表現することさえできません。たとえば、0.1は 10 進数として正確に表すことができますが (正確に の 10 分の 1 です)、 2 進数として周期的1であるため、浮動小数点を使用して表すことはできません。浮動小数点用です 10 進数用です (これは10 進数です)0.00011001100110011...0.11/30.33333...

その結果、 のような計算は になります0.3 + 0.60.89999999999999991、これは ではありませんが0.9、それに近いです。したがって、計算の結果が に非常に近いにもかかわらず、 に0.1 + 0.2 - 0.3 == 0.0ならない可能性があるため、テストは失敗する可能性があります。00

==は正確検定であり、不正確な数値に対して正確検定を実行しても、通常はあまり意味がありません。多くの浮動小数点計算には丸め誤差が含まれているため、通常、比較では小さな誤差も許容する必要があります。これが、投稿したテスト コードの目的です。「 A は B と等しいか」をテストする代わりに、「 Aは B に非常に近いか」をテストします。非常に近いことが、浮動小数点計算から期待できる最良の結果であることがよくあるためです。

于 2020-06-09T15:22:02.803 に答える
0

そのコードは次のとおりです。

std::abs((x - y)/x) <= epsilon

絶対差が

于 2013-11-07T14:19:52.273 に答える