sourcelibs/Fixed/src/Fixed.xtl

1⍝# Fixed: fixed-width two's complement numbers at a stated width, the arithmetic a w-bit circuit does 2⍝# Import it with an alias of your choice: "fx:" u_se< "Fixed". 3⍝# Put libs/Fixed/src on XETAL_PATH ("just path"); the reference is libs/Fixed/docs. 4⍝# Names with l: are exported; the others are private to this file. 5⍝# 6⍝# X_eTaL's Int is 64 bits wide; hardware is 8, 16 or 32. Until X_eTaL 7⍝# has sized integer types (ask F3 in docs/xetal-asks.md), the width is 8⍝# written in the program: 16 ᶠˣw̲rap x + y is what a 16-bit adder 9⍝# gives, and the evaluator computes exactly that, so it is the 10⍝# reference the circuit must match bit for bit. Every function takes 11⍝# the width first (one number) and works on whole arrays of any 12⍝# shape. A function of three arguments is used curried: bind the 13⍝# width once, ᵘa̲dd ← ᶠˣa̲dd 16, then x ᵘa̲dd y. 14 15⍝## The ranges 16 17⍝# l_owest w: the lowest signed value of w bits, -2^(w-1) (-128 at 8 bits). 18⍝# >> "fx:" u_se< "Fixed" 19⍝# >> fx:l_owest 8 16 20⍝# -128 -32768 21ˡl̲owest ← { w → n̲eg 2 ^ w − 1 } 22 23⍝# h_ighest w: the highest signed value of w bits, 2^(w-1) - 1 (127 at 8 bits). 24⍝# >> "fx:" u_se< "Fixed" 25⍝# >> fx:h_ighest 8 16 26⍝# 127 32767 27ˡh̲ighest ← { w → (2 ^ w − 1) − 1 } 28 29⍝## Wrapping 30 31⍝# w u_wrap x: x reduced to the unsigned range of w bits, 0 to 2^w - 1: 32⍝# the bit pattern a w-bit register holds, read unsigned. 33⍝# >> "fx:" u_se< "Fixed" 34⍝# >> 8 fx:u_wrap 100 200 -1 256 35⍝# 100 200 255 0 36ˡu̲wrap ← { w x → x m̲od 2 ^ w } 37 38⍝# w w_rap x: x reduced to the signed range of w bits: the same bits, 39⍝# read as two's complement (a pattern at or above 2^(w-1) is negative). 40⍝# >> "fx:" u_se< "Fixed" 41⍝# >> 8 fx:w_rap 100 200 -1 -129 42⍝# 100 -56 -1 127 43ˡw̲rap ← { w x → 44 u ← w ˡu̲wrap x 45 u − (2 ^ w) × u ≥ 2 ^ w − 1 46} 47 48⍝# w o_verflow? x: whether x does not fit in w signed bits, so a 49⍝# w-bit unit holding it has wrapped. 50⍝# >> "fx:" u_se< "Fixed" 51⍝# >> 8 fx:o_verflow? 127 128 52⍝# 0 1 53ˡo̲verflow? ← { w x → x ≠ w ˡw̲rap x } 54 55⍝# w s_at x: x clamped to the signed range (saturating arithmetic: 56⍝# what a DSP does instead of wrapping). 57⍝# >> "fx:" u_se< "Fixed" 58⍝# >> 8 fx:s_at 300 -300 5 59⍝# 127 -128 5 60ˡs̲at ← { w x → (ˡl̲owest w) m̲ax x m̲in ˡh̲ighest w } 61 62⍝## Arithmetic, wrapped: what a w-bit adder, subtractor, multiplier gives 63 64⍝# w a_dd x y: the sum wrapped to w bits, item by item, with scalar 65⍝# extension: what a w-bit adder gives. Bind the width once: 66⍝# u:a_dd := fx:a_dd 16, then x u:a_dd y. 67⍝# >> "fx:" u_se< "Fixed" 68⍝# >> u:a_dd := fx:a_dd 8 69⍝# >> 100 u:a_dd 100 70⍝# -56 71ˡa̲dd ← { w x y → w ˡw̲rap x + y } 72 73⍝# w s_ub x y: the difference wrapped to w bits (a w-bit subtractor). 74⍝# >> "fx:" u_se< "Fixed" 75⍝# >> u:s_ub := fx:s_ub 8 76⍝# >> -100 u:s_ub 100 77⍝# 56 78ˡs̲ub ← { w x y → w ˡw̲rap x − y } 79 80⍝# w m_ul x y: the product wrapped to w bits (a w-bit multiplier keeps 81⍝# the low w bits). 82⍝# >> "fx:" u_se< "Fixed" 83⍝# >> u:m_ul := fx:m_ul 8 84⍝# >> 16 u:m_ul 16 85⍝# 0 86ˡm̲ul ← { w x y → w ˡw̲rap x × y } 87 88⍝# w n_eg x: the negation wrapped (the lowest value is its own negation). 89⍝# >> "fx:" u_se< "Fixed" 90⍝# >> 8 fx:n_eg 5 -128 91⍝# -5 -128 92ˡn̲eg ← { w x → w ˡw̲rap n̲eg x } 93 94⍝## Bits 95 96⍝# w b_its x: the two's complement bits of each number, most 97⍝# significant first: a vector for one number, a row per number for a 98⍝# vector (as Bits' b_its, which reads numbers unsigned). 99⍝# >> "fx:" u_se< "Fixed" 100⍝# >> 8 fx:b_its 5 -1 101⍝# 0 0 0 0 0 1 0 1 102⍝# 1 1 1 1 1 1 1 1 103ˡb̲its ← { w x → o̲\ (w r̲eshape 2) e̲ncode w ˡu̲wrap x } 104 105⍝# v_alue bits: the signed number each row of bits (or the vector) 106⍝# stands for, the inverse of b_its; the width is the row's length. 107⍝# >> "fx:" u_se< "Fixed" 108⍝# >> fx:v_alue 1 1 1 1 1 0 1 1 109⍝# -5 110ˡv̲alue ← { bits → (t̲ally o̲\ bits) ˡw̲rap 2 d̲ecode o̲\ bits } 111 112⍝# w h_ex x: the bit pattern of each number as hexadecimal text, w/4 113⍝# digits: text for one number, a row per number for a vector. 114⍝# >> "fx:" u_se< "Fixed" 115⍝# >> 16 fx:h_ex -1 48879 116⍝# FFFF 117⍝# BEEF 118ˡh̲ex ← { w x → (1 + o̲\ ((w d̲iv 4) r̲eshape 16) e̲ncode w ˡu̲wrap x) s̲elect ⎕D c̲at 6 t̲ake ⎕A }