web-dev-qa-db-ja.com

24.0000がMATLABの24.0000と等しくないのはなぜですか?

マトリックスに保存されている重複したポイントを削除する必要があるプログラムを書いています。問題は、それらの点が行列内にあるかどうかをチェックする場合、MATLABはそれらが存在しても行列内でそれらを認識できないことです。

次のコードでは、intersections関数が交差点を取得します。

[points(:,1), points(:,2)] = intersections(...
    obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
    [vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);

結果:

>> points
points =
   12.0000   15.0000
   33.0000   24.0000
   33.0000   24.0000

>> vertex1
vertex1 =
    12
    15

>> vertex2    
vertex2 =
    33
    24

2点(vertex1およびvertex2)は結果から削除する必要があります。以下のコマンドで実行する必要があります。

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

その後、次のような予期しない結果が生じます。

>> points
points =
   33.0000   24.0000

結果は空の行列になります。ご覧のとおり、最初の(または2番目の?)ペアの[33.0000 24.0000]は削除されましたが、2つ目は削除されませんでした。

次に、次の2つの式を確認しました。

>> points(1) ~= vertex2(1)
ans =
     0
>> points(2) ~= vertex2(2)
ans =
     1   % <-- It means 24.0000 is not equal to 24.0000?

何が問題ですか?


さらに驚くべきことに、次のコマンドのみを含む新しいスクリプトを作成しました。

points = [12.0000   15.0000
          33.0000   24.0000
          33.0000   24.0000];

vertex1 = [12 ;  15];
vertex2 = [33 ;  24];

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

期待どおりの結果:

>> points
points =  
   Empty matrix: 0-by-2
66
Kamran Bigdely

あなたが抱えている問題は、コンピュータでの 浮動小数点数 の表現方法に関連しています。浮動小数点表現のより詳細な説明は、私の答えの終わり近くに表示されます(「浮動小数点表現」セクション)。 TL; DRバージョン:コンピューターのメモリ容量には限りがあるため、数値は有限の精度でのみ表すことができます。したがって、浮動小数点数の精度は、小数点以下の桁数に制限されます(MATLABで使用されるデフォルトの 倍精度値 の有効桁数は約16)。

実際の精度と表示された精度

次に、質問の具体的な例を取り上げます..._24.000024.0000が同じdisplayedの間にこのように、実際には、これらは実際には非常にわずかな10進数の違いがあることがわかります。 MATLAB デフォルトでは4桁の有効数字のみを表示する であるため、表示されません。全体の表示を整然と保ちます。完全な精度を表示する場合は、 format longコマンドを発行するか、数値の 16進表記 を表示する必要があります。

>> pi
ans =
    3.1416
>> format long
>> pi
ans =
   3.141592653589793
>> num2hex(pi)
ans =
400921fb54442d18

初期値と計算値

浮動小数点数で表すことができる値の数は有限であるため、計算でこれらの2つの表現の間にある値が得られる可能性があります。そのような場合、結果はそれらの1つに四捨五入する必要があります。これにより小さな マシン精度エラー が発生します。これは、値を直接または何らかの計算によって初期化すると、わずかに異なる結果が得られる可能性があることも意味します。たとえば、値0.1にはexact浮動小数点表現がない(つまり、丸められる)ため、直観に反する結果になります。丸め誤差が累積するため、次のような結果になります。

>> a=sum([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]);  % Sum 10 0.1s
>> b=1;                                               % Initialize to 1
>> a == b
ans =
  logical
   0                % They are unequal!
>> num2hex(a)       % Let's check their hex representation to confirm
ans =
3fefffffffffffff
>> num2hex(b)
ans =
3ff0000000000000

浮動小数点比較を正しく処理する方法

浮動小数点値はごくわずかに異なる可能性があるため、値が互いに正確に等しいのではなく、値が互いにある範囲(許容誤差)内にあることを確認することによって、比較を行う必要があります。例えば:

a = 24;
b = 24.000001;
tolerance = 0.001;
if abs(a-b) < tolerance, disp('Equal!'); end

「等しい!」と表示されます。

次に、コードを次のように変更します。

points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ...
                (abs(points(:,2)-vertex1(2)) > tolerance),:)

浮動小数点表現

浮動小数点数(および具体的には IEEE 754浮動小数点演算の標準 )の概要は です。すべてのコンピュータ科学者が浮動小数点について知っておくべきことArithmetic デビッド・ゴールドバーグ著。

2進浮動小数点数は、実際には3つの整数で表されます。符号ビットs、仮数(または係数/小数)b、および指数eです。 倍精度浮動小数点形式の場合 、各数値は次のようにメモリに配置された64ビットで表されます。

enter image description here

次に、実際の値は次の式で求められます。

enter image description here

この形式では、10 ^ -308〜10 ^ 308の範囲の数値表現が可能です。 MATLABの場合、これらの制限は realmin および realmax から取得できます。

>> realmin
ans =
    2.225073858507201e-308
>> realmax
ans =
    1.797693134862316e+308

浮動小数点数を表すために使用されるビット数には限りがあるため、上記の範囲内で表現できる有限数は非常に多くなります。計算の結果、これらの有限表現の1つと正確に一致しない値が生じることが多いため、値は四捨五入する必要があります。これらの machine-precision errors は、上記の例で説明したように、さまざまな方法で明らかになります。

これらの丸め誤差をよりよく理解するには、関数 eps によって提供される相対的な浮動小数点の精度を調べると便利です。これは、特定の数値から次の数値までの距離を定量化します。最大の浮動小数点表現:

>> eps(1)
ans =
     2.220446049250313e-16
>> eps(1000)
ans =
     1.136868377216160e-13

精度は、表現されている特定の数値のサイズに対してrelativeであることに注意してください。数値が大きいほど、浮動小数点表現間の距離が大きくなるため、小数点以下の桁数が少なくなります。これは、一部の計算では重要な考慮事項になる場合があります。次の例を考えてみます。

>> format long              % Display full precision
>> x = Rand(1, 10);         % Get 10 random values between 0 and 1
>> a = mean(x)              % Take the mean
a =
   0.587307428244141
>> b = mean(x+10000)-10000  % Take the mean at a different scale, then shift back
b =
   0.587307428244458

xの値を[0 1]の範囲から[10000 10001]の範囲にシフトし、平均を計算してから、平均のオフセットを差し引いて比較すると、異なる値が得られることに注意してください。下3桁の有効数字。これは、データのオフセットまたはスケーリングがそのデータで実行される計算の精度をどのように変更できるかを示しています。これは、特定の問題で説明する必要があるものです。

92
gnovice

この記事を見てください The Perils of Floating Point 。その例はFORTRANにありますが、MATLABを含むほとんどすべての最新のプログラミング言語に意味があります。問題(およびその解決策)は、「安全な比較」セクションで説明されています。

22
Rorick

タイプ

format long g

このコマンドは、数値の完全な値を表示します。 24.00000021321!= 24.00000123124のようになります。

13
KitsuneYMG

書いてみてください

0.1 + 0.1 + 0.1 == 0.3。

警告:結果に驚くかもしれません!

7

たぶん、2つの数値は実際には24.0と24.000000001ですが、小数点以下がすべて表示されているわけではありません。

2
Jimmy J

Matlab EPS function を確認してください。

Matlabは最大16桁の精度の浮動小数点演算を使用します(5のみが表示されます)。

1
jle