단순하게 생각해보면 성능문제 아닐까? 보통 정수로 유리수 구현하면 절대 예상 못할 부분들에서 오버플로우 뻥뻥 터지면서 씹창날테니 분자고 분모고 정수 표현 범위가 무한해야 할텐데, 공간도 많이 처먹을테고 계산도 오래걸릴테고? 곱셈 알고리즘같은거 성능 좋은거 집어넣으려면 구현도 복잡할텐데.. 뭐 이렇게 생각함 나는
음 글게 꽤 재밌는 생각이네 근데 찾아보니
Python의 fractions 모듈을 사용하면 Fraction 자료형을 이용할 수 있습니다.
Ruby에서는 Rational 클래스를 통해 분수를 표현하고 연산할 수 있습니다.
Haskell: Haskell에는 Rational이라는 분수 자료형이 내장되어 있습니다. Common Lisp: Common Lisp에서는 분수를 자동으로 인식하고 연산합니다.
있더라고
머 어차피 구현이 없더라도 만들기는 쉬우니...
파이썬처럼 내장 라이브러리로 지원하는 경우도 있고 외부 라이브러리에서 그런 연산을 지원하는 경우도 있긴 할 거임
문제는 언젠가 그 분수에서 분자 / 분모를 '정확히' 계산한 값을 (정수든 실수든) 써야 할 때가 올 건데, 이 과정에선 결국 부동소수점을 사용하거나 정수로 내림하면서 정확도를 상당히 잃게 될 거 같음.
+ 윗댓 말처럼 분자 분모에 계속 곱해나가다 보면 오버플로 때문에 써먹지 못하게 되는 경우도 비일비재할 듯
윗댓들 바탕으로 내 생각을 정리해보면,
일단 정수를 이용한 유리수 집합과 연산(덧셈, 곱셈, 비교 등)의 정의는 이미 유리수체로 잘 정의되어있음
링크: https://namu.wiki/w/%EC%B2%B4(%EB%8C%80%EC%88%98%ED%95%99)#s-2.1
기본 자료형으로 없는 이유는 부동소수점 형식은 아예 하드웨어에서 지원하고 비트 표현 형식도 다르다보니 별도의 자료형으로 분리할 필요가 있었지만 유리수는 정수 튜플로 표현할 수 있기 때문에 언어 레벨의 지원이 좀 빈약할 수도 있겠다는 생각을 했음. 비슷한 상황으로 부동소수점의 튜플로 표현되는 복소수 타입도 C에서는 선택적 기능이고 기본 타입으로 지원하지 않는 언어가 많음
성능 문제를 따진다면 부동소수점 덧셈 한번 하는동안 정수 곱셈, 덧셈을 여러번 할 수 있는거 생각하면 나눗셈 말고는 연산의 성능에 대한 리스크는 거의 없을거라고 생각함. 실수타입이 덧셈 뺄셈보다 곱셈 나눗셈에 특화되어 있기도 하고 정수 나눗셈이 실수 나눗셈보다 느릴 수 있다는걸 본 거 같아. 게다가 벡터화 덕분에 정수 연산 두 번하는데 시간이 두배가 걸리지도 않고 이부분은 아예 intrinsic으로 감싸서 라이브러리화 해버리면 엄청 빠를거같긴 함
링크: https://stackoverflow.com/questions/55832817/why-float-division-is-faster-than-integer-division-in-c
+) 생각해보니까 나눗셈은 그냥 역수의 곱셈이잖아 이것도 개빠르겠네
정확도를 생각해본다면 사실 이부분은 float가 비비질 못하는게 float는 반올림된 값이지만 유리수는 수학적으로 원본과 동일한 참값을 가짐. 그리고 할 거 다 한 뒤에 마지막 출력/변환에서 한 번 반올림 되는 것과 매 연산마다 반올림이 일어나는걸 비교하면 전자가 훨씬 좋지
오버플로우 문제는 사실 다른 타입에도 존재하는 문제라서 유리수 타입만의 문제는 아니기도 하고 통분같은 경우에는 소인수 분해와 다르게 두 정수(분모 분자)의 최대 공약수를 구하는건 유클리드 호제법이라는 개쩌는 알고리즘이 있어서 그렇게 느리지는 않을거 같네
무리수 표현이 빡센건 말 그대로 무리수를 유리수로 표현하려 하니까 당연하다고 생각되고 그것보다는 유리수랑 실수끼리 연산하는게 추가 처리가 필요해서 힘들긴 하겠지
덧붙여 정확한 실수 표현을 위한 새로운 표준으로 decimal floating point라는게 도입됐다고 들었는데 이거는 나도 잘 몰?루
윗댓들 바탕으로 내 생각을 정리해보면,
일단 정수를 이용한 유리수 집합과 연산(덧셈, 곱셈, 비교 등)의 정의는 이미 유리수체로 잘 정의되어있음
링크: https://namu.wiki/w/%EC%B2%B4(%EB%8C%80%EC%88%98%ED%95%99)#s-2.1
기본 자료형으로 없는 이유는 부동소수점 형식은 아예 하드웨어에서 지원하고 비트 표현 형식도 다르다보니 별도의 자료형으로 분리할 필요가 있었지만 유리수는 정수 튜플로 표현할 수 있기 때문에 언어 레벨의 지원이 좀 빈약할 수도 있겠다는 생각을 했음. 비슷한 상황으로 부동소수점의 튜플로 표현되는 복소수 타입도 C에서는 선택적 기능이고 기본 타입으로 지원하지 않는 언어가 많음
성능 문제를 따진다면 부동소수점 덧셈 한번 하는동안 정수 곱셈, 덧셈을 여러번 할 수 있는거 생각하면 나눗셈 말고는 연산의 성능에 대한 리스크는 거의 없을거라고 생각함. 실수타입이 덧셈 뺄셈보다 곱셈 나눗셈에 특화되어 있기도 하고 정수 나눗셈이 실수 나눗셈보다 느릴 수 있다는걸 본 거 같아. 게다가 벡터화 덕분에 정수 연산 두 번하는데 시간이 두배가 걸리지도 않고 이부분은 아예 intrinsic으로 감싸서 라이브러리화 해버리면 엄청 빠를거같긴 함
링크: https://stackoverflow.com/questions/55832817/why-float-division-is-faster-than-integer-division-in-c
+) 생각해보니까 나눗셈은 그냥 역수의 곱셈이잖아 이것도 개빠르겠네
정확도를 생각해본다면 사실 이부분은 float가 비비질 못하는게 float는 반올림된 값이지만 유리수는 수학적으로 원본과 동일한 참값을 가짐. 그리고 할 거 다 한 뒤에 마지막 출력/변환에서 한 번 반올림 되는 것과 매 연산마다 반올림이 일어나는걸 비교하면 전자가 훨씬 좋지
오버플로우 문제는 사실 다른 타입에도 존재하는 문제라서 유리수 타입만의 문제는 아니기도 하고 통분같은 경우에는 소인수 분해와 다르게 두 정수(분모 분자)의 최대 공약수를 구하는건 유클리드 호제법이라는 개쩌는 알고리즘이 있어서 그렇게 느리지는 않을거 같네
무리수 표현이 빡센건 말 그대로 무리수를 유리수로 표현하려 하니까 당연하다고 생각되고 그것보다는 유리수랑 실수끼리 연산하는게 추가 처리가 필요해서 힘들긴 하겠지
덧붙여 정확한 실수 표현을 위한 새로운 표준으로 decimal floating point라는게 도입됐다고 들었는데 이거는 나도 잘 몰?루
이산수학으로 분수를 표현하는게 불가능에 가까워서...
예를들어 1/7 을 이산수학적으로 계산하려면 1을 7로 나누기로 시작해야 하는데
나눗셈 연산 알고리즘 역시 0과 1을 사용하여 나타나는 방식이라, 분수를 표현할려면 부동소수라는 개념으로 진행해야 함.
참고: https://ttl-blog.tistory.com/1014
그렇기 때문에 현용 컴퓨터 구조에서는 분수 표현이 굉장히 힘들어짐.
추상적으로 분수를 정의하여 다루는 언어들도 있지만, 컴퓨터 구조상 부동소수에 비해 연산 방식이 좀 특별할 가능성이 큼.
이산수학으로 분수를 표현하는게 불가능에 가까워서...
예를들어 1/7 을 이산수학적으로 계산하려면 1을 7로 나누기로 시작해야 하는데
나눗셈 연산 알고리즘 역시 0과 1을 사용하여 나타나는 방식이라, 분수를 표현할려면 부동소수라는 개념으로 진행해야 함.
참고: https://ttl-blog.tistory.com/1014
그렇기 때문에 현용 컴퓨터 구조에서는 분수 표현이 굉장히 힘들어짐.
추상적으로 분수를 정의하여 다루는 언어들도 있지만, 컴퓨터 구조상 부동소수에 비해 연산 방식이 좀 특별할 가능성이 큼.