2016-10-11 6 views
1

내장 함수 'CEILING'을 사용하려고하지만 반올림 오류로 인해 때때로 원하는 것을 얻지 못합니다.반올림 오류의 영향을받지 않고 CEILING 사용

PROGRAM MAIN 

    IMPLICIT NONE 

    INTEGER, PARAMETER  ::  ppm_kind_double = KIND(1.0D0) 
    REAL(ppm_kind_double)  ::  before,after,dx 

    before = -0.112 
    dx = 0.008 
    after = CEILING(before/dx) 

    WRITE(*,*) before, dx, before/dx, after 

    END 

그리고 결과를 얻었다 : 샘플 코드는 매우 간단합니다 enter image description here

코드의 난 '이전'에주는 가치와 'DX는 그냥 데모입니다. 예를 들어/dx = -13.5 이전의 경우, CEILING을 사용하여 -13을 얻고 싶습니다. 그러나 제가 보여 주었던 그림을 보려면 실제로 -14를 얻고 싶습니다.

IF(ABS(NINT(before/dx) - before/dx) < 0.001) 

과 같은 몇 가지 인수를 사용해 보았습니다. 그러나 그것은 단순히 아름답 지 않습니다. 이 작업을 수행하는 더 좋은 방법이 있습니까?

업데이트 : 내가 ppm_kind_double의 상수 변수를 설정하면 문제가 발생하지 않는 것을 발견 놀랐습니다

. 그래서이 '반올림 오류'는 내가 사용하는 기계의 반올림 정확도에 대한 자릿수가 ppm_kind_double에 정의 된 것 이상일 때만 발생합니다. 실제로 클러스터의 프로그램 (이 데모 코드 아님)을 실행합니다.이 코드는 기계 정밀도에 대해 알지 못합니다. 문제를 일으키는 기계의 4 배 정밀도일까요? 반올림 오류가 어디에서 오는지 당신이 알고하지 않기 때문에이 조금 까다 롭습니다

before = -0.112_ppm_kind_double 
dx = 0.008_ppm_kind_double 

enter image description here

+0

너는 나에게 -14를 원하고 조금 벗어 던졌다. -0.112/0.008이 정확히 -14라는 것을 깨닫는 데는 시간이 걸렸지 만 반올림 오류 때문에 결과가 약간 더 많아지고 'CEILING'은이 작은 오류를 증폭시킵니다. – chw21

+0

@ chw21, 실제로 나는 당신의 이전 코멘트를보고 당신이 그것을 찾을 때까지 기다리고있었습니다. :) – Ruizhi

+2

주어진 정밀도가 여기에있는 문제의 일부인 경우 리터럴 상수가 단 정밀도 만 사용한다는 점에 유의해야합니다. '-0.112'는 아마도'-0.112_ppm_kind_double'이라고 써야합니다. 이 변경으로 인해 근본적인 문제는 해결되지 않습니다. – IanH

답변

0

:

나는 이중 정밀도 상수를 설정 한 후. dx0.008보다 조금 작 으면 before/dx 부분은 여전히 ​​같은 값으로 반올림 될 수 있지만 이제는 -13이 올바른 답이됩니다.

내가 말했던 것 중 가장 일반적인 방법은 바로 에 찔러 반대 방향으로 조금씩 밀어 넣는 것입니다. 이런 식으로 뭔가가 :

program sign_test 
    use iso_fortran_env 
    implicit none 
    real(kind=real64) :: a, b 
    integer(kind=int32) :: c 
    a = -0.112 
    b = 0.008 
    c = my_ceiling(a/b) 
    print*, a, b, c 
contains 
    function my_ceiling(v) 
     implicit none 
     real(kind=real64), intent(in) :: v 
     integer(kind=int32) :: my_ceiling 
     my_ceiling = ceiling(v - 1d-6, kind=int32) 
    end function my_ceiling 
end program sign_test 

이 값의 대부분에 영향을주지 않지만 의도 한 것보다 더에 의해 반올림 얻을 것이다 몇 가지 값은 이제이 있습니다.

+0

감사합니다 chw21, 초기 추측 합리적인 변화도 좋은 방법입니다. – Ruizhi

0

노트는 사용자의 실수가 지정된 정밀도로 "정확한"개념적 경우 당신은 이런 식으로 뭔가를 할 수 있습니다

after=nint(1000*before)/nint(1000*dx) 

당신은 당신이 모두를 위해 무엇을 기대할 말했다하지 않은 .. 이것이 당신의 예를 들어 작동 긍정적 인 가치 등등. 그래서 당신은 약간 그것을 할 필요가 있습니다.