IT Share you

MATLAB에서 24.0000이 24.0000과 다른 이유는 무엇입니까?

shareyou 2020. 11. 10. 22:38
반응형

MATLAB에서 24.0000이 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

결과에서 두 점 ( vertex1vertex2)을 제거해야합니다. 아래 명령으로 수행해야합니다.

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

결과는 빈 행렬이어야합니다. 보시다시피 첫 번째 (또는 두 번째?) 쌍은 [33.0000 24.0000]제거되었지만 두 번째 쌍은 제거되지 않았습니다.

그런 다음이 두 가지 표현을 확인했습니다.

>> 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에서 사용되는 기본값)로 제한됩니다.

실제 대 표시 정밀도

이제 질문의 특정 예를 다루기 위해 ... 같은 방식으로 표시 되는 동안 이 경우에는 실제로 매우 작은 십진수로 차이가 있음이 밝혀졌습니다. MATLAB 은 기본적으로 4 개의 유효 자릿수 만 표시 하여 전체 디스플레이를 깔끔하고 깔끔하게 유지하므로 표시 되지 않습니다 . 24.000024.0000전체 정밀도를 보려면 format long명령을 실행하거나 숫자 16 진수 표현확인 해야합니다 .

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

초기화 된 값과 계산 된 값

부동 소수점 숫자로 표현할 수있는 값의 수가 한정되어 있기 때문에 계산 결과 두 표현 사이에 속하는 값이 나올 수 있습니다. 이 경우 결과는 그 중 하나로 반올림되어야합니다. 이로 인해 작은 기계 정밀도 오류가 발생 합니다. 이것은 또한 값을 직접 초기화하거나 일부 계산으로 초기화하면 약간 다른 결과를 얻을 수 있음을 의미합니다. 예를 들어, 값 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

부동 소수점 비교를 올바르게 처리하는 방법

Since floating-point values can differ by very small amounts, any comparisons should be done by checking that the values are within some range (i.e. tolerance) of one another, as opposed to exactly equal to each other. For example:

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

will display "Equal!".

You could then change your code to something like:

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

Floating-point representation

A good overview of floating-point numbers (and specifically the IEEE 754 standard for floating-point arithmetic) is What Every Computer Scientist Should Know About Floating-Point Arithmetic by David Goldberg.

A binary floating-point number is actually represented by three integers: a sign bit s, a significand (or coefficient/fraction) b, and an exponent e. For double-precision floating-point format, each number is represented by 64 bits laid out in memory as follows:

enter image description here

The real value can then be found with the following formula:

enter image description here

This format allows for number representations in the range 10^-308 to 10^308. For MATLAB you can get these limits from realmin and realmax:

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

Since there are a finite number of bits used to represent a floating-point number, there are only so many finite numbers that can be represented within the above given range. Computations will often result in a value that doesn't exactly match one of these finite representations, so the values must be rounded off. These machine-precision errors make themselves evident in different ways, as discussed in the above examples.

In order to better understand these round-off errors it's useful to look at the relative floating-point accuracy provided by the function eps, which quantifies the distance from a given number to the next largest floating-point representation:

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

Notice that the precision is relative to the size of a given number being represented; larger numbers will have larger distances between floating-point representations, and will thus have fewer digits of precision following the decimal point. This can be an important consideration with some calculations. Consider the following example:

>> 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

Note that when we shift the values of x from the range [0 1] to the range [10000 10001], compute a mean, then subtract the mean offset for comparison, we get a value that differs for the last 3 significant digits. This illustrates how an offset or scaling of data can change the accuracy of calculations performed on it, which is something that has to be accounted for with certain problems.


Look at this article: The Perils of Floating Point. Though its examples are in FORTRAN it has sense for virtually any modern programming language, including MATLAB. Your problem (and solution for it) is described in "Safe Comparisons" section.


type

format long g

This command will show the FULL value of the number. It's likely to be something like 24.00000021321 != 24.00000123124


Try writing

0.1 + 0.1 + 0.1 == 0.3.

Warning: You might be surprised about the result!


Maybe the two numbers are really 24.0 and 24.000000001 but you're not seeing all the decimal places.


Check out the Matlab EPS function.

Matlab uses floating point math up to 16 digits of precision (only 5 are displayed).

참고URL : https://stackoverflow.com/questions/686439/why-is-24-0000-not-equal-to-24-0000-in-matlab

반응형