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