기타 지식

컴퓨터가 하지 못하는 계산

아래의 예는 어디까지나 생각없이 프로그래밍을 했을 때 발생하는 오류입니다.

당연히 제대로 만들면 할 수 있습니다.



0.1+0.1+0.1+0.1+... = 1?


0.1을 10번 더하면 1일까?

아니니까 글의 제목이 저렇겠지?

정말로 1일까.PNG


당근 빳다 1을 출력한다.


그런데 이게 정말 1인지 확인을 하기 위해서 뒤에 코드를 추가해보자.

이런.PNG


num을 출력했더니 1이라고 뜨지만, 정작 1과 같은지 체크를 하면 같지 않아서 "1 맞음"이 뜨지 않아.

심지어 num을 2^100번 거듭제곱을 해보니 num은 1이 아닌 무한대로 발산했지.

즉 num은 1보다 아주 조금 큰 숫자라는 뜻이야.

어째서 0.1을 10번 더했는데 1이 아니라 1보다 아주 조금 큰 숫자가 된 것일까?

(cpu에 따라서 1보다 아주 조금 작은 숫자가 되기도 한다.)

이것은 컴퓨터가 2진법으로 계산을 하기 때문에 일어나는 비극이야.


실제로 계산한 숫자의 값은 아래와 같아.

사실 이럼.PNG

진짜 1보다 조금 크네..



컴퓨터는 2진법으로 동작한다는 것은 대부분의 사람이 알 거야.

그러면 0.1을 2진법으로 나타내는 방법은?

학식만 되어도 가물가물... 할테니 중간과정을 생략하면

'0.00011001100...'(2) 이 되며, 0011이 반복되는 무한소수야.

무한소수를 유한소수로 나타내는 과정에서 어느정도의 오차가 생기기 때문에

0.1을 10번 더해서는 1이 되지 못하는 것이지.


정수는 그냥 진법교환을 하고 종이에 쓸 수 있는 만큼만 표기하면 된다.

그렇다면 길이가 정해져있지 않아서 어떻게 써야 할지 감이 오지 않는 소수는 어떻게 표현하는 것일까?

이것에 대한 표준은 IEEE 754에서 정의되어 있어.

https://ko.wikipedia.org/wiki/IEEE_754 : 부동소수점 정의만 적혀있음

https://en.wikipedia.org/wiki/IEEE_754 : 754내용이 적혀있음.


요약하면

float은 32비트이며, 1bit는 부호,8bit는 지수,23bit는 가수를 의미한다.

부호는 0일때 양수, 1일때 음수이다.

지수는 그 값에서 127을 더한다.

가수는 제일 처음의 1은 제외한 다른 값을 채운다.


따라서 위의 0.1을 2진수로 표현한 0.00011001100...(2)는

1.1001 1001 1001 1001 1001 1001 * 2^(-4)으로 표현을 해.


float에서 가수(소수부분)는 소수점 아래 23개 밖에 적지 못해.

그래서 저 진하게 쓴 1은 어떻게 되는 것일까?

그게 cpu마다 다를 수 있어서 어떤 cpu는 0이 되고, 어떤 cpu는 무한대가 되버려.

어차피 원래 숫자에서 엄청 작은 숫자라서 큰 상관은 없다고 생각했나봐.

(인텔은 대부분의 cpu가 저 경우 올린다고 배웠어.)


일단 내가 쓰는 cpu는 아래와 같이 된다.

1.1001 1001 1001 1001 1001 101 * 2^(-4)


당연히 이 숫자를 10번 더하면 1보다 아주 조큼 큰 숫자가 되겠지?


만약 버림을 하는 시피유라면

1.1001 1001 1001 1001 1001 100 * 2^(-4)

이라서 10번 더하면 1보다 아주 조금 작은 숫자가 되서 0이 되겠지


2진수의 비극으로 인해서 이러한 문제도 발생해


10 000 000 + (1+...10 000 000번) = 20 000 000?

큰수+작은수.PNG

어째서 천만이 더해진게 아니라 이상한 숫자밖에 더해지지 않았을까?


원리는 위의 0.1을 10번 더했을 때 1이 되지 않는 것과 같아.


23자리 문제지.



이처럼 32비트로 표현할 수 있는 40억가지 숫자안에 소수를 표현하려다보니 한계가 있어.

double도 방심할 수 없습니다.PNG

물론 어마어마하게 큰 64비트, 128비트에 넣어도 부동소수점의 한계상 저러한 문제가 생겨.

이 경우에는 안세봤지만, 00이 마지막 숫자라서 그 뒤에 와야 하는 숫자가 버림되었나봐.


결론.

컴퓨터는 소수계산, 큰수+작은 수에서 정확하게 엉뚱한 답을 낸다.

(그런 오류를 내게 프로그래밍이 가능하다.)

34개의 댓글

2018.05.26
실수값이 있는 변수를 조건문에 쓸때 == 를 쓰는 사람이 있으면 뒤통수 한대 후려줘라
0
@URA!!
ㄹㅇ
0
@URA!!
다 정밀성 문제 때문에 발생하는건데
개념만 알려주기 위한 거니까 넘어가자구
0
2018.05.26
부동소수점 모르는 애도 있음?
저건 당연한거 아님?
0
2018.05.26
@강간범
아~부동소수점 아시는구나~
0
2018.05.26
@강간범
부동소수점이 언제부터 보편적 수준의 상식이었냐
0
2018.05.26
@끼에엑
[삭제 되었습니다]
2018.05.26
@빠빠양
당장 컴개론만 펼쳐도 바로 나오는 내용이라지만
전공생 아니면 까놓고 누가 이딴 걸 알고 있냐.
0
2018.05.26
@
[삭제 되었습니다]
2018.05.26
@댕떼닥추
개드립 읽판에서 대체 뭔 소리하세요.
0
2018.05.26
@
[삭제 되었습니다]
0
2018.05.26
@댕떼닥추
아니 여기가 생활코딩 같은 사이트냐 뭐 그런 걸 이런 데서 따져 대체
그냥 읽판에 짤막하게 관심 있으면 읽을 만한 코딩글 올린 거 그 이상도 이하도 아닌데
0
@강간범
얘븅신인거 모르는 애도 있음?
당연한거 아님?
0
2018.05.26
@강간범
이게 그 지식의 저주인가 하는 그거냐 주로 공돌이가 걸린다는데
0
2018.05.28
@강간범
아아-이것은 '부동소수점'이라는 것이다. 전 인류가 태어나면서부터 당연히 알고있는 지식이지.
0
2018.05.31
@강간범
ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 좆병신 찐따새끼들 단체로 부들부들 거리노 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
0
2018.05.26
저거하면 단골 예제가
1234.56789를 출력하면
1234.567871이 나온다
0
2018.05.26
[삭제 되었습니다]
@이림
저런 경우는 그냥 더하기가 아니라 곱하기로 처리를 하면 아무 문제가 없어
0.1 * 10 = 1.0 (정확하게)
큰수+작은수에서 유효숫자 문제 때문에 제대로 나오지 않는 경우에는
작은수끼리 먼저 더한 뒤 큰숫자를 만드는 방법으로 우회하거나,
더 큰 자료형에서 계산하는 방식으로 회피해
위에 덧글 쓴 것처럼 부동소수점 데이터는 ==으로 비교하는게 아니라
변수에서 목표값을 뺀 결과의 절대값이 오차미만일 때 참으로 판단하거나 해
절대값(num-1) < 0.000001 같은 식으로 말이지

일반적인 계산환경에서는 저 문제를 겪을 일은 거의 없어
부동소수점 변수를 ==으로 비교하는 경우를 제외하고 말이지
0
2018.05.26
[삭제 되었습니다]
@댕떼닥추
c++의 특징이 아니라 <<해서 그런게 맞아
cout << 의 경우에는 알아서 적절한 자리수만큼 출력을 해
1.5를 넣으면 1.5라고 뜨고 1.01을 넣으면 1.01이라고
printf에서 %f라고 하면 값과 관계없이 6자리가 뜨는 것과는 달라
0
2018.05.27
수치해석
0
2018.05.27
신기하네 그럼 일반적인 컴퓨터로 천문학적인 계산을 한다던가 하면 큰 오차가 나올 수밖에 없음?
0
2018.05.27
@나눌수없는것
일반적인 컴퓨터로는 오차가 나는게 문제가 아니고 천문학적 계산을 할 수가 없음.
천문학적 숫자를 계산하기 위한 표현 규칙을 임의로 짜서 돌릴 수 있을 뿐이지.
그렇게 되면 그건 CPU랑 아무 상관 없는거라서 저런건 무시해도됨
0
2018.05.28
사악한 씨뿔뿔
0
2018.05.28
요새 인공지능 배우는데
학습하는 가중치가 소수점단위로 나오더라
근데 프린트찍어보면 생략해서 0으로 표시되도 0이아닌
0.0000000001917173
이런식으로나오길래 찾아본적있음
0
2018.05.28
[삭제 되었습니다]
@맏춤뻡빌런
위에 썼다시피
비교값-목표값의 절대값이 목표값*오차 보다 작은지 체크해야해
보통 사용하는 오차는 10의 -8승이야
Float의 유효숫자가 7자리거든
0
2018.05.29
@맏춤뻡빌런
보편적인 방법으론 epsilon number 로 비교함.
Math.abs(a-b) < Number.EPSILON
하면 거의 같다고 보는거지.
그리고 요즘 나오는 언어는 대부분 보정해줘서 == 로 비교해도 돌아가는것처럼 보이긴 함.
단지 위에서 말한 인공지능같이 작은 오차에도 민감한 계산을 할땐 중요하게 체크해야함.
0
2018.05.28
그러니까 전기로 작동하는거죠?(소곤소곤)
0
2018.05.30
신기하다
0
2018.06.01
2^100번 거듭제곱이아니라
100번 거듭제곱인것같다
0
@HIGH SIERRA
아님.
Ret = 1 초기화 후
Ret = Ret*obj
했을때가 100번임

2넣고 손으로 풀어봐라
2의 1승 2승 4승 8승 16승으로 넘어간다
0
2018.06.01
@아이워너비그린
오구러냉
0
무분별한 사용은 차단될 수 있습니다.
번호 제목 글쓴이 추천 수 날짜
12408 [역사] 지도로 보는 정사 삼국지 ver2 7 FishAndMaps 6 17 시간 전
12407 [기타 지식] 100년을 시간을 넘어서 유행한 칵테일, 사제락편 - 바텐더 개... 1 지나가는김개붕 0 21 시간 전
12406 [기타 지식] 오이...좋아하세요? 오이 칵테일 아이리쉬 메이드편 - 바텐더... 3 지나가는김개붕 2 2 일 전
12405 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 지구 1부 29 Mtrap 8 2 일 전
12404 [기타 지식] 칵테일의 근본, 올드 패션드편 - 바텐더 개붕이의 술 이야기 15 지나가는김개붕 13 2 일 전
12403 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 인류 2부 20 Mtrap 13 2 일 전
12402 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 인류 1부 13 Mtrap 19 2 일 전
12401 [역사] 군사첩보 실패의 교과서-욤 키푸르(完) 1 綠象 0 1 일 전
12400 [호러 괴담] [살인자 이야기] 미치도록 잡고 싶었다. 체포되기까지 28년이... 1 그그그그 6 3 일 전
12399 [역사] 아편 전쟁 실제 후기의 후기 3 carrera 11 4 일 전
12398 [과학] 경계선 지능이 700만 있다는 기사들에 대해 36 LinkedList 9 4 일 전
12397 [역사] 미지에의 동경을 그린 만화 8 식별불해 5 7 일 전
12396 [호러 괴담] [살인자 이야기] 두 아내 모두 욕조에서 술을 마시고 익사했... 그그그그 2 7 일 전
12395 [기타 지식] 서부 개척시대에 만들어진 칵테일, 카우보이 그리고 프레리 ... 3 지나가는김개붕 5 7 일 전
12394 [유머] 웃는 자에게 복이 오는 삶 10 한그르데아이사쯔 7 8 일 전
12393 [기타 지식] 모던 클래식의 현재를 제시한 칵테일편 - 바텐더 개붕이의 술... 4 지나가는김개붕 2 8 일 전
12392 [호러 괴담] [살인자 이야기] 공소시효만료 11개월을 앞두고 체포된 범인 그그그그 3 9 일 전
12391 [호러 괴담] [살인자 이야기] 범인으로 지목받자 딸에게 누명을 씌우려다... 그그그그 4 10 일 전
12390 [기타 지식] 브라질에서 이 칵테일을 다른 술로 만들면 불법이다, 카이피... 5 지나가는김개붕 1 10 일 전
12389 [기타 지식] 럼, 라임, 설탕 그리고 다이키리 편 - 바텐더 개붕이의 술 이... 2 지나가는김개붕 6 10 일 전