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  }