X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fadd%2Ffsqrt.py;h=02449b0f75b41b0ba2e004711d9570ccca49ca3d;hb=aa8c754e7d66345a67faa0804e97f38612b283c1;hp=c2d32a7acbbdf4c3e3cb84d0465be4ba52bcc392;hpb=7c76f6c047bfb3110d611e9038bc8fd9a1293a73;p=ieee754fpu.git diff --git a/src/add/fsqrt.py b/src/add/fsqrt.py index c2d32a7a..02449b0f 100644 --- a/src/add/fsqrt.py +++ b/src/add/fsqrt.py @@ -1,9 +1,13 @@ +from sfpy import Float32 + + +# XXX DO NOT USE, fails on num=65536. wark-wark... def sqrtsimple(num): res = 0 - bit = 1 << 14 + bit = 1 - while (bit > num): - bit >>= 2 + while (bit < num): + bit <<= 2 while (bit != 0): if (num >= res + bit): @@ -16,34 +20,27 @@ def sqrtsimple(num): return res -# XXX DO NOT USE, fails on num=65536. wark-wark... def sqrt(num): D = num # D is input (from num) - Q = 0 - R = 0 - r = 0 # remainder - for i in range(15, -1, -1): # negative ranges are weird... - - if (R>=0): - - R = (R<<2)|((D>>(i+i))&3) - R = R-((Q<<2)|1) #/*-Q01*/ - - else: + Q = 0 # quotient + R = 0 # remainder + for i in range(64, -1, -1): # negative ranges are weird... - R = (R<<2)|((D>>(i+i))&3) - R = R+((Q<<2)|3) #/*+Q11*/ - - if (R>=0): - Q = (Q<<1)|1 #/*new Q:*/ + R = (R<<2)|((D>>(i+i))&3) + + if R >= 0: + R -= ((Q<<2)|1) # -Q01 else: - Q = (Q<<1)|0 #/*new Q:*/ - + R += ((Q<<2)|3) # +Q11 + + Q <<= 1 + if R >= 0: + Q |= 1 # new Q - if (R<0): - R = R+((Q<<1)|1) - r = R - return Q + if R < 0: + R = R + ((Q<<1)|1) + + return Q, R # grabbed these from unit_test_single (convenience, this is just experimenting) @@ -60,24 +57,109 @@ def set_exponent(x, e): def get_sign(x): return ((x & 0x80000000) >> 31) +# convert FP32 to s/e/m +def create_fp32(s, e, m): + """ receive sign, exponent, mantissa, return FP32 """ + return set_exponent((s << 31) | get_mantissa(m)) + +# convert s/e/m to FP32 +def decode_fp32(x): + """ receive FP32, return sign, exponent, mantissa """ + return get_sign(x), get_exponent(x), get_mantissa(x) + + # main function, takes mantissa and exponent as separate arguments # returns a tuple, sqrt'd mantissa, sqrt'd exponent def main(mantissa, exponent): if exponent & 1 != 0: - return sqrt(mantissa << 1), # shift mantissa up - ((exponent - 1) / 2) # subtract 1 from exp to compensate - return sqrt(mantissa), # mantissa as-is - (exponent / 2) # no compensating needed on exp + # shift mantissa up, subtract 1 from exp to compensate + mantissa <<= 1 + exponent -= 1 + m, r = sqrt(mantissa) + return m, r, exponent >> 1 + + +#normalization function +def normalise(s, m, e, lowbits): + if (lowbits >= 2): + m += 1 + if get_mantissa(m) == ((1<<24)-1): + e += 1 + return s, m, e + +def fsqrt_test(x): + + xbits = x.bits + print ("x", x, type(x)) + sq_test = x.sqrt() + print ("sqrt", sq_test) + + print (xbits, type(xbits)) + s, e, m = decode_fp32(xbits) + print("x decode", s, e, m, hex(m)) + + m |= 1<<23 # set top bit (the missing "1" from mantissa) + m <<= 27 + + sm, sr, se = main(m, e) + lowbits = sm & 0x3 + sm >>= 2 + sm = get_mantissa(sm) + #sm += 2 + + s, sm, se = normalise(s, sm, se, lowbits) + + print("our sqrt", s, se, sm, hex(sm), bin(sm), "lowbits", lowbits, + "rem", hex(sr)) + if lowbits >= 2: + print ("probably needs rounding (+1 on mantissa)") + + sq_xbits = sq_test.bits + s, e, m = decode_fp32(sq_xbits) + print ("sf32 sqrt", s, e, m, hex(m), bin(m)) + print () if __name__ == '__main__': - for Q in range(1, int(1e7)): + + # quick test up to 1000 of two sqrt functions + for Q in range(1, int(1e4)): print(Q, sqrt(Q), sqrtsimple(Q), int(Q**0.5)) assert int(Q**0.5) == sqrtsimple(Q), "Q sqrtsimpl fail %d" % Q - assert int(Q**0.5) == sqrt(Q), "Q sqrt fail %d" % Q + assert int(Q**0.5) == sqrt(Q)[0], "Q sqrt fail %d" % Q + + # quick mantissa/exponent demo + for e in range(26): + for m in range(26): + ms, mr, es = main(m, e) + print("m:%d e:%d sqrt: m:%d-%d e:%d" % (m, e, ms, mr, es)) + + x = Float32(1234.123456789) + fsqrt_test(x) + x = Float32(32.1) + fsqrt_test(x) + x = Float32(16.0) + fsqrt_test(x) + x = Float32(8.0) + fsqrt_test(x) + x = Float32(8.5) + fsqrt_test(x) + x = Float32(3.14159265358979323) + fsqrt_test(x) + x = Float32(12.99392923123123) + fsqrt_test(x) + x = Float32(0.123456) + fsqrt_test(x) + + + """ + +Notes: +https://pdfs.semanticscholar.org/5060/4e9aff0e37089c4ab9a376c3f35761ffe28b.pdf + //This is the main code of integer sqrt function found here:http://verilogcodes.blogspot.com/2017/11/a-verilog-function-for-finding-square-root.html //