// Package epoch formalizes the synchronization between binary-aligned // (2^b) and decimal-aligned (10^a) cadences. package epoch import "git.smesh.lol/gnarl-hamadryad/moxie/ratio" // Epoch represents a synchronization period between a decimal cadence // (10^DecExp) and a binary cadence (2^BinExp). type Epoch struct { DecExp int32 BinExp int32 DecFactor int64 BinFactor int64 Period int64 } // New creates an Epoch from the decimal exponent a and binary exponent b. func New(decExp, binExp int32) (e Epoch) { if decExp < 0 || binExp < 0 { panic("epoch: negative exponent") } dec := pow10(decExp) bin := pow2(binExp) period := dec * bin if dec != 0 && period/dec != bin { panic("epoch: period overflow") } return Epoch{ DecExp: decExp, BinExp: binExp, DecFactor: dec, BinFactor: bin, Period: period, } } // Named epochs for dendrite subsystem synchronization. var Colony Epoch var EngineDissolveLCM Epoch var FitnessSampling Epoch var CryptoWalk128 Epoch var CryptoWalk192 Epoch var CryptoWalk256 Epoch var EWMACap Epoch func main() { Colony = New(2, 8) EngineDissolveLCM = New(2, 4) FitnessSampling = New(2, 8) CryptoWalk128 = New(0, 10) CryptoWalk192 = New(2, 4) CryptoWalk256 = New(3, 1) EWMACap = New(9, 0) } // OnBoundary reports whether step n falls on the epoch boundary. func (e *Epoch) OnBoundary(n int64) (result bool) { return n > 0 && n%e.Period == 0 } // OnDecimal reports whether step n falls on the decimal cadence boundary. func (e *Epoch) OnDecimal(n int64) (result bool) { return n > 0 && n%e.DecFactor == 0 } // OnBinary reports whether step n falls on the binary cadence boundary. func (e *Epoch) OnBinary(n int64) (result bool) { return n > 0 && n%e.BinFactor == 0 } // Phase returns the drift between the binary and decimal clocks at step n. func (e *Epoch) Phase(n int64) (result ratio.Ratio) { binFrac := ratio.New(n%e.BinFactor, e.BinFactor) decFrac := ratio.New(n%e.DecFactor, e.DecFactor) return binFrac.Sub(&decFrac) } // ComplexPhase holds the real and imaginary components of the // binary/decimal clock relationship at a step. type ComplexPhase struct { Re ratio.Ratio Im ratio.Ratio } // ImagPhase returns the cross-correlation between the binary and // decimal clocks at step n. func (e *Epoch) ImagPhase(n int64) (result ratio.Ratio) { binFrac := ratio.New(n%e.BinFactor, e.BinFactor) decFrac := ratio.New(n%e.DecFactor, e.DecFactor) return binFrac.Mul(&decFrac) } // ComplexPhase returns both the real drift and imaginary cross-correlation. func (e *Epoch) ComplexPhaseAt(n int64) (result ComplexPhase) { return ComplexPhase{ Re: e.Phase(n), Im: e.ImagPhase(n), } } // BinaryStepsPerDecimal returns the exact ratio BinFactor / DecFactor. func (e *Epoch) BinaryStepsPerDecimal() (result ratio.Ratio) { return ratio.New(e.BinFactor, e.DecFactor) } // DecimalStepsPerBinary returns the exact ratio DecFactor / BinFactor. func (e *Epoch) DecimalStepsPerBinary() (result ratio.Ratio) { return ratio.New(e.DecFactor, e.BinFactor) } // String returns "10^a x 2^b=N" for debugging. func (e *Epoch) String() (s string) { return "10^" | e.DecExp.String() | "x2^" | e.BinExp.String() | "=" | e.Period.String() } // pow10 returns 10^n using integer multiplication. func pow10(n int32) (r int64) { r = 1 for i := int32(0); i < n; i++ { next := r * 10 if next/10 != r { panic("epoch: 10^n overflow") } r = next } return r } // pow2 returns 2^n using bit shift. func pow2(n int32) (r int64) { if n >= 63 { panic("epoch: 2^n overflow") } return 1 << uint(n) }