43 / 52 · अवधारणा
Fixed-Point Arithmetic, Rounding, and Saturation
Define fixed-point range and scale, derive ties-to-even rounding, and apply saturation after rounding.
पाठ पढ़ना मुफ़्त है। प्रगति सेव करने के लिए नामांकन करें।
अनुवाद अभी उपलब्ध नहीं है। मूल पाठ दिखाया गया है। (한국어)
선수 지식: signed 덧셈·곱셈의 비트폭, 산술 오른쪽 시프트, overflow를 이해해야 합니다.
비트열에 소수점의 위치를 계약하기
고정소수점은 정수 X를 로 읽는 표현입니다. 하드웨어에 소수점 비트가 저장되는 것은 아닙니다. 이 강의는 signed 전체 폭 W에 부호 비트를 포함하고 소수 비트 수를 F라고 정의합니다. Q 표기는 문헌마다 정수부에 부호 비트를 포함하는지가 달라서, 인터페이스에 W,F를 함께 쓰는 편이 명확합니다.
W=8,F=4라면 간격은 1/16이고 범위는 -8~7.9375입니다. 0x18은 정수 24가 아니라 이 계약에서 1.5입니다. 같은 0x18을 F=3으로 해석하면 3이 됩니다. 선을 연결했다고 수치 의미까지 맞는 것은 아니므로 각 포트의 scale을 문서화해야 합니다.
덧셈은 소수점 위치를 먼저 맞춰야 합니다. 서로 F가 다르면 작은 F 쪽을 충분히 넓힌 뒤 왼쪽으로 이동하거나, 큰 F 쪽을 정해진 반올림 방식으로 줄입니다. 같은 W,F의 두 수를 정확히 더하려면 W+1비트와 같은 F가 필요합니다. 곱셈에서는 raw 정수를 곱하고 소수 비트 수를 더합니다.
8비트 F=4 두 수의 완전한 곱은 signed 16비트 F=8입니다. 다시 8비트 F=4로 출력하려면 소수부 4비트를 줄인 뒤 signed 8비트 범위를 확인해야 합니다. 곱을 먼저 8비트로 잘라 놓으면 후속 포화 회로가 원래 크기를 알 수 없습니다.
버림과 반올림의 차이
d비트를 버리는 산술 오른쪽 시프트는 입니다. 음수도 아래쪽으로 내려갑니다. 예를 들어 라면 정확한 몫은 -1.5지만 q는 -2입니다. 이는 0 방향 버림과 다릅니다. 양수에서 맞던 “그냥 상위 비트만 선택”이 음수에도 같은 오차 성질을 가진다고 가정하면 안 됩니다.
가장 가까운 값으로 반올림하되 정확히 중간이면 짝수 정수를 택하는 round-to-nearest, ties-to-even을 설계해 봅시다. 버리는 영역의 최상위 비트를 guard g, 나머지 비트의 OR를 sticky t, 남기는 q의 최하위 비트를 l이라고 둡니다.
g=0이면 절반 미만이므로 그대로 둡니다. g=1,t=1이면 절반보다 크므로 올립니다. g=1,t=0이면 정확한 절반이어서 q가 홀수일 때만 1을 더합니다. 음수도 같은 규칙입니다. 바닥 몫 q와 나머지 를 쓰면 항상 이기 때문입니다.
예를 들어 -24를 16으로 나눈 -1.5는 q=-2가 짝수라 -2, -40을 나눈 -2.5는 q=-3이 홀수라 -2가 됩니다. “음수는 무조건 1을 뺀다” 같은 별도 규칙은 오히려 틀립니다. 포화되지 않는 경우 최종 수치 오차는 출력 LSB의 절반 이하입니다. ties-to-even이 모든 입력 분포의 평균 오차를 반드시 0으로 만드는 것은 아니지만, tie를 항상 한쪽으로 보내는 편향을 줄입니다.
16비트 F=8의 raw P=2040을 8비트 F=4로 변환합니다. 127.5가 짝수 128로 반올림된 뒤 signed 8비트 최댓값 127로 제한됩니다. 마지막 저장 전까지 넓은 폭을 보존해야 합니다.
- 입력 P=2040: 16비트 · F=8
- 스케일 축소: 2040 / 16 = 127.5
- ties-to-even: 반올림 raw = 128
- 포화 후 저장: raw 127 → 7.9375
반올림을 끝낸 뒤 포화하기
포화는 최댓값보다 크면 최댓값, 최솟값보다 작으면 최솟값으로 제한합니다. wrap과 달리 큰 양수가 음수로 뒤집히지 않습니다. 다만 이미 좁혀서 wrap된 값에는 정확한 포화를 적용할 수 없습니다.
아래는 signed 16비트 F=8 값을 signed 8비트 F=4로 바꾸는 완전한 조합 모듈입니다. d=4로 고정했으므로 guard는 p[3], sticky는 p[2:0]입니다. 반올림 증가와 범위 비교를 17비트 signed 공간에서 수행한 뒤 마지막에만 8비트를 취합니다.
module requantize (
input logic signed [15:0] p,
output logic signed [7:0] y,
output logic saturated
);
logic signed [16:0] wide, q, rounded;
logic inc;
always_comb begin
wide = {p[15], p};
q = wide >>> 4;
inc = p[3] & ((|p[2:0]) | q[0]);
rounded = q + (inc ? 17'sd1 : 17'sd0);
saturated = 1'b0;
if (rounded > 17'sd127) begin
y = 8'sh7f;
saturated = 1'b1;
end else if (rounded < -17'sd128) begin
y = 8'sh80;
saturated = 1'b1;
end else begin
y = rounded[7:0];
end
end
endmoduleP=2040이면 P/16=127.5이므로 짝수 128로 반올림된 후 127로 포화됩니다. 최종 값은 7.9375입니다. 반올림 전 q=127만 검사하면 이 초과를 놓칩니다. saturated는 수치가 범위 밖으로 나가 제한되었음을 뜻하며, 단지 하위 소수 비트를 잃었다는 뜻은 아닙니다.
범용 모듈로 바꿀 때 d=0은 버릴 비트가 없고 d=1은 sticky 영역이 없다는 점을 분리해야 합니다. 범위를 벗어난 part-select를 조건문 안에 감추는 것만으로는 elaboration 오류를 해결하지 못할 수 있습니다.
반올림과 포화는 덧셈기·비교기·MUX 비용과 지연을 더하며 별도 정책으로 선택됩니다. 이런 구분은 AMD 고정소수점 형식 문서에도 나타납니다. 여러 항을 누산할 때는 중간 폭을 유지하고 마지막에 한 번 변환할지 먼저 결정하십시오. 매 단계 포화하면 덧셈의 결합법칙이 깨질 수 있고, 매 단계 반올림하면 작은 오차가 반복해서 쌓일 수 있습니다.
खुद आज़माएँ
signed 16비트 F=8 입력 P를 signed 8비트 F=4로 변환합니다. P가 24,40,−24,−40,2040일 때 floor 몫 q, guard/sticky, 반올림 정수, 최종 raw 출력 및 실제 값을 구하세요. 2040에서 포화 검사를 먼저 하면 어떤 문제가 생기나요?
व्याख्या पढ़ें
모든 입력의 하위 4비트가 1000이므로 guard=1,sticky=0입니다. P=24는 q=1(홀수)→2, raw=2, 실제 값=0.125입니다. P=40은 q=2(짝수)→2, raw=2, 0.125입니다. P=−24는 q=−2(짝수)→−2, raw=−2, −0.125입니다. P=−40은 q=−3(홀수)→−2, raw=−2, −0.125입니다. P=2040은 q=127(홀수)→128이며 signed 8비트 최댓값을 넘으므로 raw=127, 실제 값=7.9375, saturated=1입니다. q=127만 먼저 검사하고 8비트에서 1을 더하면 0x80으로 wrap되어 −8을 출력할 수 있습니다. 증가와 비교를 넓은 signed 값에서 끝내야 합니다.