곱셈 관련 명령어는 네 가지가 있다.
mul : 하위 32비트를 곱한다.
mulh : 상위 32비르를 곱한다.
32비트 숫자 두 개를 곱하기 위해 mul과 mulh를 이용해서 비트를 하위/상위로 나누어 계산한다. 숫자가 작을 때는 mul 하나만 사용할 때도 많다.
mulhu : 오퍼랜드가 모두 unsigned라고 가정하고 때 상위 32비트를 계산한다.
mulhsu : 두 오퍼랜드 중 하나는 unsigned, 하나는 signed라고 가정하고 상위 32비트를 계산한다.
div, rem : signed divide, remainder
divu, remu : unsigned divide, remainder
overflow와 devision-by-zero가 발생하면 예외처리를 하지 않고 잘못된 값이라도 리턴한다. 예외처리에 하드웨어 자원이 더 많이 소모되기 때문이다.
floating point를 가진 수 중 일의 자리가 1~9인 숫자를 normalized되었다고 한다.
ex) 1.1 * 10^54
2진수에서는 1.xxxx로 나타내었을 때 normalized form이다.
ex) 1.xxxxxx * 2^yyyy
32-bit : float
64-bit : double
binary 16(16-bit) : half
| S | Exponent | Fraction |
|---|---|---|
| single:8, double:11 | single:23, double:52 |
x = (-1)^S (1+Fraction) 2^(Exponent-Bias)
2진수를 normalization하면 첫 번째 비트는 무조건 1이므로 이것을 빼고 31, 63비트로 나타낸다. Bias는 Single에서 127, Double에서 1023이다.
ex1) -0.75를 부동 소수점 포맷으로 나타내보자.
1. 2진수로 변환
-0.75 = -(0.5+0.25) = -0.11 = (-1) 1.1 2^(-1)
2. binary format
S=1, Exponent는 126이므로 2진수로 변환하면 01111110이다.
1+Fraction은 1.1인데, Fraction이 0.1이면 전체 비트 중 첫 번째 비트가 1이 된다.
Fraction은 소수 부분이라고 생각하면 된다.
따라서 Fraction은 10000...000(23또는 52비트)이다.
이것을 전부 합치면 10111111010000...000이다.
ex2)11000000101000...00(single)
S=1, Exponent=10000001, Fraction=01000...00이므로
-1 1+.01(2) 2^(129-127) = -1.25 * 4 = -5.0
ex3)
sign 1b, fraction 4b, exponent 3b, bias=3 인 부동 소수점 표현이 있다.
4.25를 binary representation으로 나타내면?
100.01 -> 1.0001 2^2 -> (-1)^0 (1+0001) * 2^(5-3)
-> S=0, Fraction=0001, Exponent=101이므로 합치면 01010001
exponent가 숫자를 담지 못하는 경우 오버플로우, 언더플로우가 발생한다.
만약 어떤 숫자가 0.0000000000000000...001 이라면 1이 24번째 비트에 위치할 때 언더플로우가 발생할 수 있다.
Single range
single에서 나타낼 수 있는 값은 최소 ±1.0 2^-126, 최대 ±2.0 2^127이다. exponent의 최대값이 11111110이라는 것을 기억하자. 10^6정도의 오차율을 가진다.
Double range
최소 ±1.0 2^-1022, 최대 ±2.0 2^1023이다. 10^16정도의 오차율을 가진다.
Denormal numbers
Fraction의 앞에 붙는 1을 없애서 정확도를 상승시킴으로서 일반적인 숫자보다 굉장히 작은 숫자의 언더플로우를 방지할 수 있다.
Infinites & NaNs
Exponent = 111...1, Fraction = 000...0인 경우 음수, 양수의 무한대를 나타낸다.
Exponent = 111...1인데 Fraction ≠ 000...0인 경우 에러가 발생한 NaN(not a number)값을 표현한다.
9.999 10^1 + 1.610 10^(-1)을 계산해보자.
이번에는 2진수로 0.5 + -0.4375를 덧셈해보자.
주의할 점!
곱셈할 때 지수 2^n과 2^m을 단순히 2^(n+m)으로 계산할 수 있다.
하지마 저 값은 순수 exponent가 아닌 bias가 빠진 값이므로, 먼저 각각에 bias를 더해 원래 값을 복구한 후 다시 계산해야 한다.
따라서 n+127 + m+127에서 127을 빼서 진짜 지수를 알 수 있다.