The Real 구조
The Real 구조
REAL 시그니처는 부동소수점 실수의 타입과 연산을 정의해요.
출처: 문서
본문
시놉시스 (Synopsis)
signature REAL
structure Real :> REAL
where type real = real
structure LargeReal :> REAL
structure Real<N> :> REAL (* OPTIONAL *)
인터페이스 (Interface)
type real
structure Math : MATH
where type real = real
val radix : int
val precision : int
val maxFinite : real
val minPos : real
val minNormalPos : real
val posInf : real
val negInf : real
val + : real * real -> real
val - : real * real -> real
val * : real * real -> real
val / : real * real -> real
val rem : real * real -> real
val *+ : real * real * real -> real
val *- : real * real * real -> real
val ~ : real -> real
val abs : real -> real
val min : real * real -> real
val max : real * real -> real
val sign : real -> int
val signBit : real -> bool
val sameSign : real * real -> bool
val copySign : real * real -> real
val compare : real * real -> order
val compareReal : real * real -> IEEEReal.real_order
val < : real * real -> bool
val <= : real * real -> bool
val > : real * real -> bool
val >= : real * real -> bool
val == : real * real -> bool
val != : real * real -> bool
val ?= : real * real -> bool
val unordered : real * real -> bool
val isFinite : real -> bool
val isNan : real -> bool
val isNormal : real -> bool
val class : real -> IEEEReal.float_class
val toManExp : real -> {man : real, exp : int}
val fromManExp : {man : real, exp : int} -> real
val split : real -> {whole : real, frac : real}
val realMod : real -> real
val nextAfter : real * real -> real
val checkFloat : real -> real
val realFloor : real -> real
val realCeil : real -> real
val realTrunc : real -> real
val realRound : real -> real
val floor : real -> int
val ceil : real -> int
val trunc : real -> int
val round : real -> int
val toInt : IEEEReal.rounding_mode -> real -> int
val toLargeInt : IEEEReal.rounding_mode
-> real -> LargeInt.int
val fromInt : int -> real
val fromLargeInt : LargeInt.int -> real
val toLarge : real -> LargeReal.real
val fromLarge : IEEEReal.rounding_mode
-> LargeReal.real -> real
val fmt : StringCvt.realfmt -> real -> string
val toString : real -> string
val scan : (char, 'a) StringCvt.reader
-> (real, 'a) StringCvt.reader
val fromString : string -> real option
val toDecimal : real -> IEEEReal.decimal_approx
val fromDecimal : IEEEReal.decimal_approx -> real option
설명 (Description)
type real
floor와 ceil은 실수를 각각 내림·올림해 정수로 돌려줘요. trunc은 절사, round는 반올림해 정수로 돌려줘요.
val radix : int
toLarge와 toInt는 실수를 각각 큰 정수·기본 정수로 변환해요. 값이 표현 범위를 벗어나면 Overflow를 발생시켜요.
val precision : int
fromLarge와 fromInt는 정수를 실수로 변환해요.
val maxFinite : real
val minPos : real
val minNormalPos : real
toDecimal은 실수를 십진 근사값으로 변환하고, fromDecimal은 그 반대를 해요.
val posInf : real
val negInf : real
fmt는 지정된 형식으로 실수를 인쇄 가능한 문자열로 변환해요. toString은 fmt StringCvt.GEN과 동등해요.
r1 + r2
scan은 문자 스트림에서 실수를 파싱하고, fromString은 문자열을 파싱해요.
r1 - r2
이들은 r1과 r2의 합과 차를 나타내요. 한 인자가 유한하고 다른 인자가 무한이면 결과는 올바른 부호의 무한이에요. 예: 5 - (-infinity) = infinity. 또한 infinity + infinity = infinity이고 (-infinity) + (-infinity) = (-infinity)예요. 두 무한의 다른 어떤 조합도 NaN을 만들어요.
r1 * r2
r1과 r2의 곱을 나타내요. 0과 무한의 곱은 NaN을 만들어요. 그렇지 않으면 한 인자가 무한이면 결과는 올바른 부호의 무한이에요. 예: -5 * (-infinity) = infinity, infinity * (-infinity) = -infinity.
r1 / r2
r1과 r2의 몫을 나타내요. 0 / 0 = NaN이고 +-infinity / +-infinity = NaN이에요. 유한하고 0이 아닌 수를 0으로 나누거나 무한을 유한 수로 나누면 올바른 부호의 무한이 만들어져요. (0은 부호가 있다는 점에 유의하세요.) 유한 수를 무한으로 나누면 올바른 부호의 0이에요.
rem (x, y)
나머지 x - n*y를 돌려줘요. 여기서 n = trunc (x / y)예요. 결과는 x와 같은 부호이고 절대값이 y의 절대값보다 작아요. x가 무한이거나 y가 0이면 rem은 NaN을 돌려줘요. y가 무한이면 rem은 x를 돌려줘요.
*+ (a, b, c)
*- (a, b, c)
이들은 각각 ab + c와 ab - c를 돌려줘요. 무한에 대한 동작은 덧셈, 뺄셈, 곱셈에서 파생된 동작을 따르지요. 이 연산들의 정확한 의미는 언어 구현과 기본 하드웨어에 따라 달라요. 특히 어떤 아키텍처는 이 연산들을 단일 명령으로, 어쩌면 단일 반올림 연산으로 제공해요. 따라서 이 연산들을 사용하는 것이 개별 산술 연산을 순차적으로 수행하는 것보다 빠를 수 있지만, 반올림 동작이 다를 수도 있어요.
~ r
r의 부정을 만들어요. ~ (+-infinity) = -+infinity.
abs r
r의 절대값 |r|을 돌려줘요. abs (+-0.0) = +0.0, abs (+-infinity) = +infinity, abs (+-NaN) = +NaN.
val min : real * real -> real
val max : real * real -> real
이들은 인자 중 더 작은(각각 더 큰) 값을 돌려줘요. 정확히 한 인자가 NaN이면 다른 인자를 돌려줘요. 두 인자가 모두 NaN이면 NaN을 돌려줘요.
sign r
r이 음수이면 ~1, 0이면 0, 양수이면 1을 돌려줘요. 무한은 자신의 부호를 돌려주고, 0은 부호와 무관하게 0을 돌려줘요. NaN에서는 Domain을 발생시켜요.
signBit r
r의 부호(무한, 0, NaN 포함)가 음수일 때에만 true를 돌려줘요.
sameSign (r1, r2)
signBit r1이 signBit r2와 같을 때에만 true를 돌려줘요.
copySign (x, y)
y가 NaN이어도 y의 부호를 가진 x를 돌려줘요.
val compare : real * real -> order
val compareReal : real * real -> IEEEReal.real_order
compare 함수는 첫 번째 인자가 두 번째보다 작은지, 같은지, 큰지에 따라 LESS, EQUAL, GREATER를 돌려줘요. 순서가 없는 인자에서는 IEEEReal.Unordered를 발생시켜요. compareReal 함수도 비슷하게 작동하지만 돌려주는 값이 확장 타입 IEEEReal.real_order이고 순서가 없는 인자에서는 IEEEReal.UNORDERED를 돌려줘요. 구현 참고: NaNs를 잡는 데 필요하므로 구현은 compare의 사용을 최적화하려고 시도해야 해요.
val < : real * real -> bool
val <= : real * real -> bool
val > : real * real -> bool
val >= : real * real -> bool
두 실수 사이에 해당 관계가 성립하면 true를 돌려줘요. 이 연산자는 순서가 없는 인자, 즉 한 인자라도 NaN이면 false를 돌려준다는 점에 유의하세요. 그래서 부정 아래에서 비교의 보통 반전이 성립하지 않아요. 예: a < b는 not (a >= b)와 같지 않아요.
== (x, y)
!= (x, y)
첫 번째 함수는 y와 x 모두 NaN이 아니고 y와 x가 같을 때에만 true를 돌려줘요. 0의 부호는 무시해요. 이는 IEEE = 연산자와 동등해요. 두 번째 != 함수는 not o op == 및 IEEE ?<> 연산자와 동등해요.
val ?= : real * real -> bool
한 인자가 NaN이거나 인자들이 비트 단위로 같으면 true를 돌려줘요. 0의 부호는 무시해요. IEEE ?= 연산자와 동등해요.
unordered (x, y)
x와 y가 순서가 없으면, 즉 x와 y 중 적어도 하나가 NaN이면 true를 돌려줘요.
isFinite x
x가 NaN도 무한도 아니면 true를 돌려줘요.
isNan x
x가 NaN이면 true를 돌려줘요.
isNormal x
x가 정상(normal)이면, 즉 0도 subnormal도 무한도 NaN도 아니면 true를 돌려줘요.
class x
x가 속하는 IEEEReal.float_class를 돌려줘요.
toManExp r
{man, exp}를 돌려줘요. 여기서 man과 exp는 각각 r의 가수와 지수예요. 구체적으로 1.0 <= man * radix < radix인 관계 r = man * radix(exp)가 성립해요. 이 함수는 C 라이브러리의 frexp와 비슷해요. r이 +-0이면 man은 +-0이고 exp는 +0이에요. r이 +-infinity이면 man은 +-infinity이고 exp는 지정되지 않았어요. r이 NaN이면 man은 NaN이고 exp는 지정되지 않았어요.
fromManExp {man, exp}
man * radix(exp)를 돌려줘요. 이 함수는 C 라이브러리의 ldexp와 비슷해요. man이 0이 아닌 유한 실수 값이어도 underflow와 overflow 때문에 fromManExp의 결과가 0이나 무한이 될 수 있다는 점에 유의하세요. man이 +-0이면 결과는 +-0이에요. man이 +-infinity이면 결과는 +-infinity예요. man이 NaN이면 결과는 NaN이에요.
split r
realMod r
이 함수는 {whole, frac}을 돌려줘요. 여기서 frac과 whole은 각각 r의 소수 부분과 정수 부분이에요. 구체적으로 whole은 정수이고, |frac| < 1.0이며, whole과 frac은 r과 같은 부호이고, r = whole + frac이에요. 이 함수는 C 라이브러리의 modf와 비슷해요. r이 +-infinity이면 whole은 +-infinity이고 frac은 +-0이에요. r이 NaN이면 whole과 frac 모두 NaN이에요. realMod는 #frac o split과 동등해요.
nextAfter (r, t)
t 방향으로 r 다음에 나타낼 수 있는 실수를 돌려줘요. 따라서 t가 r보다 작으면 nextAfter는 r보다 작은 가장 큰 나타낼 수 있는 부동소수점 수를 돌려줘요. r = t이면 r을 돌려줘요. 한 인자가 NaN이면 NaN을 돌려줘요. r이 +-infinity이면 +-infinity를 돌려줘요.
checkFloat x
x가 무한이면 Overflow를, x가 NaN이면 Div를 발생시켜요. 그렇지 않으면 자신의 인자를 돌려줘요. 이는 주어진 비포착 연산들에서 포착 산술을 합성하는 데 쓰일 수 있어요. 그러나 어떤 연산은 무한을 NaN으로 변환할 수 있으므로 정확한 예외가 필요하면 각 연산 후에 검사를 해야 한다는 점에 유의하세요.
realFloor r
realCeil r
realTrunc r
realRound r
이 함수들은 실수 값을 정수 값 실수로 변환해요. realFloor는 r보다 크지 않은 가장 큰 정수인 floor(r)을 만들어요. realCeil은 r보다 작지 않은 가장 작은 정수인 ceil(r)을 만들어요. realTrunc는 r을 0 방향으로 반올림하고, realRound는 r에 가장 가까운 정수 값 실수로 반올림해요. r이 NaN이거나 무한이면 이 함수들은 r을 돌려줘요.
floor r
ceil r
trunc r
round r
이 함수들은 실수를 정수로 변환해요. floor는 r보다 크지 않은 가장 큰 정수인 floor(r)을 만들어요. ceil은 r보다 작지 않은 가장 작은 정수인 ceil(r)을 만들어요. trunc는 r을 0 방향으로 반올림해요. round는 r에 가장 가까운 정수를 만들어요. 동률이면 가장 가까운 짝수 정수로 반올림해요. 결과 값이 정수로 표현될 수 없으면(예: 무한에서) Overflow를 발생시켜요. NaN 인자에서는 Domain을 발생시켜요. 이들은 각각 다음과 동등해요:
toInt IEEEReal.TO_NEGINF r
toInt IEEEReal.TO_POSINF r
toInt IEEEReal.TO_ZERO r
toInt IEEEReal.TO_NEAREST r
toInt mode x
toLargeInt mode x
이 함수들은 지정된 반올림 모드를 사용해 인자 x를 정수 타입으로 변환해요. 결과가 표현할 수 없으면, 특히 x가 무한이면 Overflow를 발생시켜요. 입력 실수가 NaN이면 Domain을 발생시켜요.
fromInt i
fromLargeInt i
이 함수들은 정수 i를 실수 값으로 변환해요. i의 절대값이 maxFinite보다 크면 적절한 무한을 돌려줘요. i를 실수 값으로 정확히 표현할 수 없으면 현재 반올림 모드로 결과 값을 결정해요. 최상위 함수 real은 Real.fromInt의 별칭이에요.
toLarge r
fromLarge r
이들은 real 타입과 LargeReal.real 타입의 값 사이를 변환해요. r이 실수로 나타내기에 너무 작거나 너무 크면 fromLarge는 그것을 0이나 무한으로 변환해요.
fmt spec r
toString r
이 함수들은 실수를 문자열로 변환해요. 함수 fmt가 제공하는 변환은 다음과 같은 형태와 해석을 가진 spec에 의해 매개변수화돼요.
SCI arg
과학적 표기법: [~]?[0-9].[0-9]+?E[0-9]+. 여기서 소수점 앞에 항상 한 자리가 있고, 수가 0이 아니면 그 자리는 0이 아니에요. arg는 소수점 뒤에 나타날 자리 수를 지정하며, arg가 NONE이면 기본값은 6이에요. arg가 SOME(0)이면 소수 자리도 소수점도 출력되지 않아요.
FIX arg
고정 소수점 표기법: [~]?[0-9]+.[0-9]+?. arg는 소수점 뒤에 나타날 자리 수를 지정하며, arg가 NONE이면 기본값은 6이에요. arg가 SOME(0)이면 소수 자리도 소수점도 출력되지 않아요.
GEN arg
적응 표기법: 변환되는 값에 따라 과학적 표기법 또는 고정 소수점 표기법이 사용돼요. arg는 사용되는 최대 유효 자릿수를 지정하며, arg가 NONE이면 기본값은 12예요.
EXACT
정확한 십진 표기법: 이 형식의 완전한 설명은 IEEEReal.toString을 참조하세요. 모든 경우에 양과 음의 무한은 각각 "inf"와 "~inf"로 변환되고, NaN 값은 "nan" 문자열로 변환돼요. 이 형식들, 특히 적응 형식 GEN에 관한 더 많은 세부 사항은 StringCvt.realfmt를 참조하세요. spec이 잘못된 정밀도이면, 즉 spec이 i < 0인 SCI (SOME i), i < 0인 FIX (SOME i), i < 1인 GEN (SOME i)이면 fmt는 Size를 발생시켜요. 예외는 fmt spec이 평가될 때 발생해야 해요. fmt 함수는 사용자가 결과 문자열의 형태를 정밀하게 제어할 수 있게 해요. 따라서 fmt가 유효한 SML 실수 값 문자열 표현이 아닌 결과를 만들어낼 수 있다는 점에 유의하세요. toString이 돌려주는 값은 다음과 동등해요:
(fmt (StringCvt.GEN NONE) r)
scan getc strm
fromString s
이 함수들은 문자 소스에서 실수 값을 스캔해요. 첫 번째 버전은 판독기 getc를 사용해 ARG/strm/에서 읽으며 앞부분 공백을 무시해요. 성공하면 SOME(r,rest)을 돌려줘요. 여기서 r은 스캔된 실수 값이고 rest는 문자 스트림 strm의 사용되지 않은 부분이에요. 너무 큰 크기의 값은 무한으로, 너무 작은 크기의 값은 0으로 표현돼요. 두 번째 버전은 어떤 접두부에서 앞부분 공백을 무시하고 실수 값을 스캔할 수 있으면 SOME(r)을, 그렇지 않으면 NONE을 돌려줘요. 이 함수는 StringCvt.scanString scan과 동등해요. 이 함수들은 다음 형식의 실수를 받아들여요: [+-]?([0-9]+.[0-9]+? | .[0-9]+)(e | E)[+-]?[0-9]+?. 또한 무한이 아닌 값의 다음 문자열 표현도 받아들여요: [+~-]?(inf | infinity | nan). 여기서 영문자는 대소문자를 구분하지 않아요.
toDecimal r
fromDecimal d
이들은 실수 값과 십진 근사값 사이를 변환해요. 십진 근사값은 IEEEReal.TO_NEAREST 반올림 모드를 사용해 변환돼야 해요. toDecimal은 fromDecimal이 같은 수로 다시 변환하는 데 필요한 만큼의 자리만 생성해야 해요. 특히 정상 또는 subnormal 실수 값 r에 대해 다음 비트 단위 동일성이 성립해요:
fromDecimal (toDecimal r) = r.
toDecimal에서 r이 정상도 subnormal도 아니면 exp 필드는 0으로 설정되고 digits 필드는 빈 리스트예요. 모든 경우에 sign과 class 필드가 r의 부호와 등급을 포착해요. fromDecimal에서 class가 ZERO 또는 INF이면 결과 실수는 적절한 부호의 0 또는 무한이에요. class가 NAN이면 부호 있는 NaN이 생성돼요. class가 NORMAL 또는 SUBNORMAL이면 sign, digits, exp 필드를 사용해 값이 s * 0.d(1)d(2)...d(n) 10(exp)인 실수를 만들어요. 여기서 digits = [d(1), d(2), ..., d(n)]이고 s는 sign이 true면 -1, 그렇지 않으면 1이에요. 변환 자체는 class 필드를 무시해야 하므로 결과 값은 NORMAL, SUBNORMAL, ZERO, INF 등급을 가질 수 있어요. 예를 들어 digits가 비어 있거나 모두 0의 리스트이면 결과는 부호 있는 0이어야 해요. 더 일반적으로 매우 크거나 작은 크기는 무한이나 0으로 변환돼요. fromDecimal의 인자가 유효한 형식이 아니면, 즉 digits 필드가 [0,9] 범위 밖의 정수를 담고 있으면 NONE을 돌려줘요. 구현 참고: 이진과 십진 실수 표현 사이를 정확하고 효율적으로 변환하는 알고리즘은 쉽게 구할 수 있어요. 예를 들어 Gay의 기술 보고서[CITE]를 참조하세요.## 더 알아보기 (Learn more)