File size: 1,696 Bytes
b86c469 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | """
MACROGROK Q-format simulator — matches infer4.asm semantics.
Q1.14: 1 sign + 1 int + 14 frac (range [-2, 2) but used as [-1,1) for INPUT)
Q3.12: 3 int + 12 frac, Q7.24 32-bit ACC.
"""
WEIGHTS_Q1_14 = [2458, -1638, 819, 3277]
BIAS_Q3_12 = -256
ALPHA_Q1_14 = 12288 # 0.75
def q1_14_to_float(x): return x / 16384.0
def float_to_q1_14(f): return max(-16384, min(16383, int(round(f*16384))))
def q3_12_to_float(x): return x / 4096.0
def infer4(input_q1_14):
assert len(input_q1_14)==4
# DOT4 Q1.14*Q1.14 -> Q3.24 in 32-bit, >>4 per product
acc = 0 # Q7.24 but we use Python int as Q3.24 accum
for w, inp in zip(WEIGHTS_Q1_14, input_q1_14):
prod = w * inp # Q2.28
prod_q3_24 = prod >> 4 # arithmetic shift
acc += prod_q3_24
# ACC Q3.24 -> Q3.12
tmp0 = acc >> 12 # arithmetic
tmp0 = tmp0 + BIAS_Q3_12
# SAT Q3.12 [-8192,8191]
sat = False
if tmp0 < -8192: tmp0=-8192; sat=True
if tmp0 > 8191: tmp0=8191; sat=True
tmp1 = 16384 if tmp0 >=0 else -16384
flags = 0
if tmp0>=0: flags|=0x4
if sat: flags|=0x2
# UPDATE_STATE 3/4 low-pass (STATE persists, init 0)
global STATE
try: STATE
except NameError: globals()['STATE']=0
STATE = (3*STATE + tmp1)//4 # arithmetic, Q1.14 scale
flags|=0x1
return STATE, tmp0, flags
if __name__=="__main__":
for vec in [[16384,0,0,0],[0,16384,0,0],[-16384,-16384,0,0],[8192,8192,8192,8192]]:
out, score, flags = infer4(vec)
print(f"in={[q1_14_to_float(x) for x in vec]} -> score Q3.12 {score} ({q3_12_to_float(score):.3f}) out Q1.14 {out} ({q1_14_to_float(out):.3f}) flags {flags:03b}")
|