MATLAB では 24.0000 が 24.0000 と等しくないのはなぜですか?
-
22-08-2019 - |
質問
行列に格納されている重複した点を削除する必要があるプログラムを作成しています。問題は、これらの点が行列内にあるかどうかを確認する際、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
解決
あなたが抱えている問題は次のようなものに関連しています 浮動小数点数 コンピュータ上で表現されます。浮動小数点表現のより詳細な説明は、私の回答の終わりの方に記載されています (「浮動小数点表現」セクション)。の TL;DR バージョン:コンピューターのメモリ量は有限であるため、数値は有限の精度でしか表現できません。したがって、浮動小数点数の精度は、小数点以下の特定の桁数 (有効桁数は約 16 桁) に制限されます。 倍精度値, 、MATLAB で使用されるデフォルト)。
実際の対表示精度
ここで、質問内の具体的な例について説明します... その間 24.0000
そして 24.0000
は 表示される 同様に、この場合、実際には非常に小さな小数点で異なることがわかります。MATLAB なので表示されません デフォルトでは有効数字 4 桁のみが表示されます, 、ディスプレイ全体をすっきりと整頓した状態に保ちます。 完全な精度を確認したい場合は、次のいずれかを発行する必要があります。 format long
コマンドまたは表示 16進数表現 数のうち:
>> pi
ans =
3.1416
>> format long
>> pi
ans =
3.141592653589793
>> num2hex(pi)
ans =
400921fb54442d18
初期化された値と計算値
浮動小数点数で表現できる値の数は有限であるため、計算の結果、これら 2 つの表現の間に入る値が得られる可能性があります。このような場合、結果はどちらか一方に四捨五入する必要があります。これは小さなことを紹介します 機械精度の誤差. 。これは、値を直接または何らかの計算によって初期化すると、わずかに異なる結果が得られる可能性があることも意味します。たとえば、値は 0.1
がありません ちょうど 浮動小数点表現 (すなわち、わずかに丸められます)、丸め誤差が累積する方法により、次のような直観に反する結果が得られます。
>> 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 標準) は すべてのコンピュータ科学者が浮動小数点演算について知っておくべきこと デビッド・ゴールドバーグ著。
2 進浮動小数点数は、実際には 3 つの整数で表されます。サインビット s
, 、仮数(または係数/分数) b
, 、および指数 e
. 倍精度浮動小数点形式の場合, 、各数値は次のようにメモリ内に配置された 64 ビットで表されます。
実際の値は次の式で求められます。
この形式では、10^-308 から 10^308 の範囲の数値表現が可能です。MATLAB の場合、これらの制限は次から取得できます。 realmin
そして realmax
:
>> realmin
ans =
2.225073858507201e-308
>> realmax
ans =
1.797693134862316e+308
浮動小数点数を表すために使用されるビットの数は有限であるため、上記の範囲内で表現できる有限数は限られています。計算の結果、これらの有限表現のいずれとも正確に一致しない値が得られることが多いため、値は四捨五入する必要があります。これら 機械精度の誤差 上記の例で説明したように、さまざまな方法でそれ自体を明らかにします。
これらの丸め誤差をよりよく理解するには、関数によって提供される相対的な浮動小数点精度を確認すると役立ちます。 eps
, 、指定された数値から次に大きい浮動小数点表現までの距離を定量化します。
>> eps(1)
ans =
2.220446049250313e-16
>> eps(1000)
ans =
1.136868377216160e-13
精度が 相対的 表現される特定の数値のサイズに応じて。数値が大きいほど、浮動小数点表現間の距離が大きくなるため、小数点以下の精度の桁数が少なくなります。これは、計算によっては重要な考慮事項となる場合があります。次の例を考えてみましょう。
>> 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 桁が異なる値が得られます。これは、データのオフセットやスケーリングによって、そのデータに対して実行される計算の精度がどのように変化するかを示しており、特定の問題ではこれを考慮する必要があります。
他のヒント
この記事を見てください。その例はFORTRANであるが、それは、MATLABを含むほとんどすべての近代的なプログラミング言語のための感覚を持っています。あなたの問題(およびそれのためのソリューション)は、「安全の比較」セクションに記載されてます。
タイプ
format long g
このコマンドは、番号のFULL値が表示されます。それは24.00000021321のようなものになりそうです!= 24.00000123124
タグ書いてみ
0.1 + 0.1 + 0.1 == 0.3。
警告:あなたは結果について驚くかもしれません。
たぶん、2つの数字が本当に24.0 24.000000001ですが、あなたはすべての小数点以下を見ていない。
MatlabのEPS機能をチェックします。
MATLABは、精度の16桁(5のみが表示されている)までの浮動小数点演算を使用します。