문제

매트릭스에 저장된 중복 지점을 삭제 해야하는 프로그램을 작성하고 있습니다. 문제는 해당 점이 행렬에 있는지 확인할 때 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

두 점 (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

결과는 빈 행렬이어야합니다. 보시다시피, 첫 번째 (또는 두 번째?) 쌍의 [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에 사용 된 기본값).

실제 대 표시 정밀도

이제 질문의 특정 예를 다루려면 ... 동안 24.0000 그리고 24.0000 ~이다 표시 같은 방식으로,이 경우 실제로는 매우 작은 10 진수로 실제로 다르다는 것이 밝혀졌습니다. 당신은 Matlab이기 때문에 그것을 보지 못합니다 기본적으로 4 자리 만 표시됩니다, 전체 디스플레이를 깔끔하고 깔끔하게 유지합니다. 완전한 정밀도를보고 싶다면 format long 명령 또는보기 a 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

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

부동 소수점 값은 매우 적은 양으로 다를 수 있으므로 값이 서로 정확히 동일한 범위 (즉, 공차) 내에 있는지 확인하여 비교를 수행해야합니다. 예를 들어:

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 부동 소수점 산술 표준) 이다 모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 것 David Goldberg.

이진 부동 소수점 번호는 실제로 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

부동 소수점 수를 나타내는 데 사용되는 유한 한 비트가 있으므로 위의 주어진 범위 내에서 표현할 수있는 유한 숫자는 너무 많습니다. 계산은 종종 이러한 유한 표현 중 하나와 정확히 일치하지 않는 값을 초래하므로 값을 반올림해야합니다. 이것들 기계-정당화 오류 위의 예에서 논의 된 바와 같이 다른 방식으로 분명하게 만듭니다.

이러한 라운드 오프 오류를 더 잘 이해하려면 함수가 제공하는 상대 부동 소수점 정확도를 살펴 보는 것이 유용합니다. 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

이 명령은 숫자의 전체 값을 보여줍니다. 24.00000021321과 같은 것 같습니다! = 24.00000123124

글쓰기를 시도하십시오

0.1 + 0.1 + 0.1 == 0.3.

경고 : 결과에 놀랄 수도 있습니다!

아마도 두 숫자는 실제로 24.0과 24.000000001 일지 모르지만 소수점 이외의 장소를 보는 것은 아닙니다.

확인하십시오 MATLAB EPS 기능.

Matlab은 16 자리 숫자의 정밀도 (5 개만 표시됨)의 부동 소수점 수학을 사용합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top