github.com/jflude/taocp@v0.0.0-20240210234939-99f2a91af3c2/mix/word.go (about) 1 package mix 2 3 import ( 4 "fmt" 5 "math" 6 ) 7 8 const ( 9 // The largest and smallest values that are representable 10 // by a MIX word. 11 MaxWord = 1<<30 - 1 12 MinWord = -MaxWord 13 14 // The largest and smallest values that are representable 15 // by the MIX index registers and the jump register. 16 MaxIndex = 1<<12 - 1 17 MinIndex = -MaxIndex 18 19 signBit = math.MinInt32 20 ) 21 22 // Word represents a MIX machine word, which consists of five 6-bit bytes 23 // and a sign bit. 24 type Word int32 25 26 // NewWord returns a MIX word with the given integer value. It panics if 27 // the value is out of range. 28 func NewWord(val int) Word { 29 if val < MinWord || val > MaxWord { 30 panic("out of range") 31 } 32 if val < 0 { 33 return Word(signBit | -val) 34 } 35 return Word(val) 36 } 37 38 // Int returns the integer value of the given MIX word. 39 func (w Word) Int() int { 40 if int32(w) < 0 { 41 return -int(w & MaxWord) 42 43 } 44 return int(w & MaxWord) 45 } 46 47 // Sign returns the sign of a MIX word, +1 for positive, -1 for negative. 48 func (w Word) Sign() int { 49 if w&signBit == 0 { 50 return 1 51 } else { 52 return -1 53 } 54 } 55 56 // Negate returns the value of a MIX word with its sign inverted. 57 func (w Word) Negate() Word { 58 return w ^ signBit 59 } 60 61 // String returns a representation of the value of a MIX word as a decimal 62 // number. Note that a MIX word can have a value of negative zero. 63 func (w Word) String() string { 64 if int32(w) == signBit { 65 return "-0" 66 } 67 return fmt.Sprint(w.Int()) 68 } 69 70 // GoString returns a representation of a MIX word as an unsigned integer. 71 func (w Word) GoString() string { 72 s := "+" 73 if w&signBit != 0 { 74 s = "-" 75 } 76 return fmt.Sprintf("%s%#011o", s, uint64(uint32(w&^signBit))) 77 } 78 79 // AddWord adds an integer to a MIX word, returning the result as a MIX word, 80 // and whether overflow occurred. See Section 1.3.1. 81 func AddWord(w Word, v int) (result Word, overflow bool) { 82 v += w.Int() 83 if v < MinWord || v > MaxWord { 84 overflow = true 85 v &= MaxWord 86 } 87 if v == 0 { 88 w.SetField(Spec(1, 5), 0) 89 } else { 90 w = NewWord(v) 91 } 92 return w, overflow 93 } 94 95 // SubWord subtracts an integer from a MIX word, returning the result as a 96 // MIX word, and whether overflow occurred. See Section 1.3.1. 97 func SubWord(w Word, v int) (result Word, overflow bool) { 98 return AddWord(w, -v) 99 } 100 101 // MulWord multiplies a MIX word by an integer, returning the product as two 102 // (double-precision) MIX words. See Section 1.3.1. 103 func MulWord(w Word, v int) (high, low Word) { 104 p := int64(w.Int()) * int64(v) 105 n := uint64(abs64(p)) 106 high = NewWord(int((n >> 30) & MaxWord)) 107 low = NewWord(int(n & MaxWord)) 108 if p < 0 { 109 high = high.Negate() 110 low = low.Negate() 111 } 112 return 113 } 114 115 func abs64(v int64) int64 { 116 if v < 0 { 117 return -v 118 } 119 return v 120 } 121 122 // DivWord divides a double-precision MIX word by an integer, returning the 123 // quotient and remainder as MIX words, and whether overflow or division by 124 // zero occurred. See Section 1.3.1. 125 func DivWord(high, low Word, v int) (quot, rem Word, overflow bool) { 126 if v == 0 || abs(high.Int()) >= abs(v) { 127 overflow = true 128 return 129 } 130 d := int64(abs(high.Int()))<<30 | int64(abs(low.Int())) 131 s := high.Sign() 132 if s == -1 { 133 d = -d 134 } 135 q, r := d/int64(v), d%int64(v) 136 if (s == -1 && r >= 0) || (s == 1 && r < 0) { 137 r = -r 138 } 139 quot, rem = NewWord(int(q)), NewWord(int(abs64(r))) 140 if s == -1 { 141 rem = rem.Negate() 142 } 143 return 144 } 145 146 func abs(v int) int { 147 if v < 0 { 148 return -v 149 } 150 return v 151 } 152 153 // AndWord returns the bitwise-AND of a MIX word and an integer (the sign of 154 // the MIX word is preserved) 155 func AndWord(w Word, v int) Word { 156 return Word(int32(w) & (int32(v) | signBit)) 157 } 158 159 // OrWord returns the bitwise-OR of a MIX word and an integer (the sign of 160 // the MIX word is preserved) 161 func OrWord(w Word, v int) Word { 162 return Word(int32(w) | (int32(v) & MaxWord)) 163 } 164 165 // XorWord returns the bitwise-XOR of a MIX word and an integer (the sign of 166 // the MIX word is preserved) 167 func XorWord(w Word, v int) Word { 168 return Word(int32(w) ^ (int32(v) & MaxWord)) 169 } 170 171 // ShiftBitsLeft shifts a double MIX word left by the given number of bits. 172 func ShiftBitsLeft(high, low *Word, count int) { 173 if count >= 60 { 174 *high = Word(int32(*high) & signBit) 175 *low = Word(int32(*high) & signBit) 176 return 177 } 178 if count < 0 { 179 panic("invalid shift count") 180 } 181 n := (((int64(*high) & MaxWord) << 30) | (int64(*low) & MaxWord)) 182 n <<= count 183 *high = Word(int32((n>>30)&MaxWord) | (int32(*high) & signBit)) 184 *low = Word(int32(n&MaxWord) | (int32(*low) & signBit)) 185 } 186 187 // ShiftBitsRight shifts a double MIX word right by the given number of bits. 188 func ShiftBitsRight(high, low *Word, count int) { 189 if count >= 60 { 190 *high = Word(int32(*high) & signBit) 191 *low = Word(int32(*high) & signBit) 192 return 193 } 194 if count < 0 { 195 panic("invalid shift count") 196 } 197 n := (((int64(*high) & MaxWord) << 30) | (int64(*low) & MaxWord)) 198 n >>= count 199 *high = Word((n>>30)&MaxWord | (int64(*high) & signBit)) 200 *low = Word((n & MaxWord) | (int64(*low) & signBit)) 201 } 202 203 // RotateBitsLeft rotates a double MIX word left by the given number of bits. 204 func RotateBitsLeft(high, low *Word, count int) { 205 if count < 0 { 206 panic("invalid shift count") 207 } 208 count %= 60 209 n := (((int64(*high) & MaxWord) << 30) | (int64(*low) & MaxWord)) 210 n = (n << count) | (n >> (60 - count) & (1<<count - 1)) 211 *high = Word((n>>30)&MaxWord | (int64(*high) & signBit)) 212 *low = Word((n & MaxWord) | (int64(*low) & signBit)) 213 } 214 215 // RotateBitsRight rotates a double MIX word right by the given number of bits. 216 func RotateBitsRight(high, low *Word, count int) { 217 if count < 0 { 218 panic("invalid shift count") 219 } 220 count %= 60 221 n := (((int64(*high) & MaxWord) << 30) | (int64(*low) & MaxWord)) 222 n = (n >> count) | (n&(1<<count-1))<<(60-count) 223 *high = Word((n>>30)&MaxWord | (int64(*high) & signBit)) 224 *low = Word((n & MaxWord) | (int64(*low) & signBit)) 225 }