epoch.mx raw

   1  // Package epoch formalizes the synchronization between binary-aligned
   2  // (2^b) and decimal-aligned (10^a) cadences.
   3  package epoch
   4  
   5  import "git.smesh.lol/gnarl-hamadryad/moxie/ratio"
   6  
   7  // Epoch represents a synchronization period between a decimal cadence
   8  // (10^DecExp) and a binary cadence (2^BinExp).
   9  type Epoch struct {
  10  	DecExp    int32
  11  	BinExp    int32
  12  	DecFactor int64
  13  	BinFactor int64
  14  	Period    int64
  15  }
  16  
  17  // New creates an Epoch from the decimal exponent a and binary exponent b.
  18  func New(decExp, binExp int32) (e Epoch) {
  19  	if decExp < 0 || binExp < 0 {
  20  		panic("epoch: negative exponent")
  21  	}
  22  	dec := pow10(decExp)
  23  	bin := pow2(binExp)
  24  	period := dec * bin
  25  	if dec != 0 && period/dec != bin {
  26  		panic("epoch: period overflow")
  27  	}
  28  	return Epoch{
  29  		DecExp:    decExp,
  30  		BinExp:    binExp,
  31  		DecFactor: dec,
  32  		BinFactor: bin,
  33  		Period:    period,
  34  	}
  35  }
  36  
  37  // Named epochs for dendrite subsystem synchronization.
  38  var Colony Epoch
  39  var EngineDissolveLCM Epoch
  40  var FitnessSampling Epoch
  41  var CryptoWalk128 Epoch
  42  var CryptoWalk192 Epoch
  43  var CryptoWalk256 Epoch
  44  var EWMACap Epoch
  45  
  46  func main() {
  47  	Colony = New(2, 8)
  48  	EngineDissolveLCM = New(2, 4)
  49  	FitnessSampling = New(2, 8)
  50  	CryptoWalk128 = New(0, 10)
  51  	CryptoWalk192 = New(2, 4)
  52  	CryptoWalk256 = New(3, 1)
  53  	EWMACap = New(9, 0)
  54  }
  55  
  56  // OnBoundary reports whether step n falls on the epoch boundary.
  57  func (e *Epoch) OnBoundary(n int64) (result bool) {
  58  	return n > 0 && n%e.Period == 0
  59  }
  60  
  61  // OnDecimal reports whether step n falls on the decimal cadence boundary.
  62  func (e *Epoch) OnDecimal(n int64) (result bool) {
  63  	return n > 0 && n%e.DecFactor == 0
  64  }
  65  
  66  // OnBinary reports whether step n falls on the binary cadence boundary.
  67  func (e *Epoch) OnBinary(n int64) (result bool) {
  68  	return n > 0 && n%e.BinFactor == 0
  69  }
  70  
  71  // Phase returns the drift between the binary and decimal clocks at step n.
  72  func (e *Epoch) Phase(n int64) (result ratio.Ratio) {
  73  	binFrac := ratio.New(n%e.BinFactor, e.BinFactor)
  74  	decFrac := ratio.New(n%e.DecFactor, e.DecFactor)
  75  	return binFrac.Sub(&decFrac)
  76  }
  77  
  78  // ComplexPhase holds the real and imaginary components of the
  79  // binary/decimal clock relationship at a step.
  80  type ComplexPhase struct {
  81  	Re ratio.Ratio
  82  	Im ratio.Ratio
  83  }
  84  
  85  // ImagPhase returns the cross-correlation between the binary and
  86  // decimal clocks at step n.
  87  func (e *Epoch) ImagPhase(n int64) (result ratio.Ratio) {
  88  	binFrac := ratio.New(n%e.BinFactor, e.BinFactor)
  89  	decFrac := ratio.New(n%e.DecFactor, e.DecFactor)
  90  	return binFrac.Mul(&decFrac)
  91  }
  92  
  93  // ComplexPhase returns both the real drift and imaginary cross-correlation.
  94  func (e *Epoch) ComplexPhaseAt(n int64) (result ComplexPhase) {
  95  	return ComplexPhase{
  96  		Re: e.Phase(n),
  97  		Im: e.ImagPhase(n),
  98  	}
  99  }
 100  
 101  // BinaryStepsPerDecimal returns the exact ratio BinFactor / DecFactor.
 102  func (e *Epoch) BinaryStepsPerDecimal() (result ratio.Ratio) {
 103  	return ratio.New(e.BinFactor, e.DecFactor)
 104  }
 105  
 106  // DecimalStepsPerBinary returns the exact ratio DecFactor / BinFactor.
 107  func (e *Epoch) DecimalStepsPerBinary() (result ratio.Ratio) {
 108  	return ratio.New(e.DecFactor, e.BinFactor)
 109  }
 110  
 111  // String returns "10^a x 2^b=N" for debugging.
 112  func (e *Epoch) String() (s string) {
 113  	return "10^" | e.DecExp.String() | "x2^" | e.BinExp.String() | "=" | e.Period.String()
 114  }
 115  
 116  // pow10 returns 10^n using integer multiplication.
 117  func pow10(n int32) (r int64) {
 118  	r = 1
 119  	for i := int32(0); i < n; i++ {
 120  		next := r * 10
 121  		if next/10 != r {
 122  			panic("epoch: 10^n overflow")
 123  		}
 124  		r = next
 125  	}
 126  	return r
 127  }
 128  
 129  // pow2 returns 2^n using bit shift.
 130  func pow2(n int32) (r int64) {
 131  	if n >= 63 {
 132  		panic("epoch: 2^n overflow")
 133  	}
 134  	return 1 << uint(n)
 135  }
 136