| 이전 주제 보기 :: 다음 주제 보기 |
| 글쓴이 |
메시지 |
구자민
가입: 2007년 9월 21일 올린 글: 14
|
올려짐: 2007년9월27일 1:17 주제: 부동 소수점 연산 처리에 관해서 |
|
|
homework 2의 5번 문제를 풀고 있는데, 이론 상의 결과랑 실제 결과가 계속 다르게 나왔습니다.
| 코드: | * 숙제에서 요구하는 정확한 integral 함수가 아닙니다. 테스트를 위해 수정하였음
val dx=0.1
fun integral(a,b) = if (a<b) then if (a+dx<b) then integral(a+dx,b) else (b-a) else 0.0
integral(1.0,10.0) |
을 하면 당연히 | 코드: | ...반복 실행...
if (9.9<10.0) then if (9.9+0.1<10.0) else (10.0-9.9) |
이므로 0.1이 출력되어야 하는데 1.7763568394e-014이 출력됩니다.
이에 관련해서 여러가지 입력을 해보다가,
| 코드: | | if (4.6+0.1=4.7) then true else false |
라고 입력하면 false라고 출력되는 것도 발견했습니다. 소수점 첫째 자리가 6이나 7인 숫자로 비슷한 연산을 하면 false라고 출력됩니다. 아마 부동소수점 연산에서 특정한 숫자에 무한소에 가까운 숫자 α가 더 붙는 것 같습니다.
그렇게 생각하면, 첫 번째 코드의 결과가 의도와 다르게 나오는 것은 이렇게 생각할 수 있습니다.
| 코드: | 의도한 결과 : ...9.7, 9.8, 9.9 까지 증가하여 최종 a의 값이 9.9이므로 10.0-9.9=0.1 출력
실제 결과 : ...9.7-α, 9.8-α, 9.9-α, 10.0-α 까지 증가한다. 즉, 실제 9.9보다 작은 입력인 9.9-α가 들어가면서 if (a+dx<b) 에서 else가 아니라 then으로 들어가고, 한 번 더 실행되어 10.0-α까지 실행되면서 b-a는 α값이 출력된다. |
(수정)
아래 글을 보고 C에서도 마찬가지 작업을 수행하니 같은 결과가 나오네요. 그러면, 첫번째 코드와 같은 의도로 프로그램을 작성하고자 하면 어떻게 해야할까요?
구자민 가 2007년9월27일 10:41에 수정함, 총 2 번 수정됨 |
|
| 위로 |
|
 |
강지헌 손님
|
올려짐: 2007년9월27일 9:40 주제: |
|
|
일반적으로 실수 연산은 어느 정도 오류를 수반하는 것으로 알고 있습니다. 특히 등호나 부등호에서 더 심한걸로 알고 있구요.
그렇기 때문에 실수 연산을 할때는 계산이 틀릴수도 있다는 것을 염두해 두어야 할 것입니다. |
|
| 위로 |
|
 |
구자민
가입: 2007년 9월 21일 올린 글: 14
|
올려짐: 2007년9월27일 10:22 주제: |
|
|
위 글을 보고 C에서도 마찬가지 연산을 하니까 같은 오류가 발생하네요. 원래 double을 처리하는 구조상 2진법으로 처리하는 수와 10진법으로 생각하는 수가 오차가 있을거라고 생각은 했지만 이런 간단한 상황에서도 발생할 줄은 몰랐네요..
그러면 위 코드와 같은 상황, 즉 좀 더 정확한 정밀도가 필요한 경우는 어떻게 해야할까요? 그냥 '조심해서' 만드는 수 밖에 없나요?
일단 제 생각은 | 코드: | | if (a+dx<b) => if ((abs(b-(a+dx))<0.00001) | 정도로 정밀도에 제약을 두거나, 다른 자료형(고정 소수점 등)을 새로 정의하여 오차를 줄이도록 만드는 게 좋겠다고 생각됩니다. 다른 좋은 방법은 없을까요? |
|
| 위로 |
|
 |
신해수 손님
|
올려짐: 2007년9월28일 4:01 주제: |
|
|
모든 실수의 등호 비교는 마지막에 적으신대로 abs(a-b) < epsilon (epsilon = 적당히 작은수)로 하는 것이 정석입니다. 정말 정확한 실수 연산을 하려면 exact float calculation 루틴을 새로 작성하는 것이 맞고요. (예: 윈도 계산기)
하지만 이 경우 마지막에 오차때문에 한번더 Integral을 더 계산해준다고 하더라도, 그 값이 1e-14 정도의 작은 값이기때문에 전체 값에 큰 영향이 없을 것 같습니다. 게다가 dx를 곱해주면 그 영향은 더욱 작아지게 됩니다.
그리고 어차피 0.1 단위로 적분하는데 제대로 된 값이 나오긴 힘듭니다. 계산하는 방법에 따라 천차만별일테고. 채점시에도 이런 부분이 고려되어 어느 정도의 오차는 허용할 것이라 믿습니다. |
|
| 위로 |
|
 |
구자민
가입: 2007년 9월 21일 올린 글: 14
|
올려짐: 2007년9월28일 10:05 주제: |
|
|
보통은 오차 값이 1e-14 정도이므로 계산 상에 큰 차이가 나지 않지만, 제가 짠 두 개의 integral 식을 비교해 보면(abs를 사용하지 않은) 부동소수점 비교에 의해서 적분식의 실행횟수가 1번 차이가 날 수 있기 때문에 실제로는 오차가 꽤 생기더군요. 이론적으로는 동일한 식이라도, homework2의 식으로 비교하면 10 정도 차이가 나는 것을 확인했습니다. 앞으로는 주의해서 식을 짜야겠네요.
여담이지만, 9/25일 자로 엑셀 2007의 부동소수점 연산에 오류가 있다는 글이 올라왔습니다. http://blogs.msdn.com/excel/archive/2007/09/25/calculation-issue-update.aspx 에 자세한 내용이 있습니다. 간단히 얘기하면 엑셀 2007에서 =850*77.1 을 입력하면 원래 65535가 나와야 하는데 100000이 출력된다는 내용입니다. (이진수 출력같네요..)
MS의 대표적인 제품에서도 이런 에러가 발생하는 걸 보니 부동소수점 연산이 어렵긴 어려운가 봅니다.^^ |
|
| 위로 |
|
 |
|