valuebridge-tdfloat 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ """
2
+ tdfloat — Triadic Dot Float
3
+ ============================
4
+ A floating-point library where every number is a single Python integer
5
+ on the half-step rational line.
6
+
7
+ The "." is the info_bit (from encoding_any_symbol.v):
8
+ position = 2 * rank + info_bit
9
+ info_bit = 0 → integer axis (no dot)
10
+ info_bit = 1 → half-step axis (has dot)
11
+
12
+ All arithmetic is exact rational arithmetic.
13
+ No IEEE 754 rounding. No transcendentals. No approximation.
14
+
15
+ Quick start
16
+ -----------
17
+ from valuebridge.tdfloat import td, frac, TDFloat
18
+
19
+ a = td('0.1')
20
+ b = td('0.2')
21
+ c = td('0.3')
22
+ assert (a + b) + c == a + (b + c) # always True
23
+
24
+ print(TDFloat.PI) # 22/7 (exact definition of π)
25
+ print(TDFloat.E) # 19/7
26
+ print(TDFloat.PHI) # 3/2 (the golden ratio = the half-step)
27
+
28
+ from valuebridge.tdfloat.math import circle_area, circle_circumference
29
+ r7 = td(7)
30
+ print(circle_circumference(r7)) # 44 (exact integer!)
31
+ print(circle_area(r7)) # 154 (exact integer!)
32
+
33
+ Constants
34
+ ---------
35
+ All constants are exact rationals:
36
+ π = 22/7, τ = 44/7, e = 19/7, φ = 3/2, √2 = 7/5, ½ = 1/2
37
+ """
38
+
39
+ from .tdfloat import TDFloat, td, frac, divmod_td
40
+ from . import math
41
+ from . import constants
42
+
43
+ # Expose constants at package level
44
+ PI = TDFloat.PI
45
+ TAU = TDFloat.TAU
46
+ E = TDFloat.E
47
+ PHI = TDFloat.PHI
48
+ SQRT2 = TDFloat.SQRT2
49
+ SQRT3 = TDFloat.SQRT3
50
+ HALF = TDFloat.HALF
51
+ ZERO = TDFloat.ZERO
52
+ ONE = TDFloat.ONE
53
+ TWO = TDFloat.TWO
54
+ NAN = TDFloat.NAN
55
+ INF = TDFloat.INF
56
+
57
+ __version__ = '1.0.0'
58
+ __author__ = 'Tushar Dadlani'
59
+ __all__ = [
60
+ 'TDFloat', 'td', 'frac', 'divmod_td',
61
+ 'PI', 'TAU', 'E', 'PHI', 'SQRT2', 'SQRT3', 'HALF',
62
+ 'ZERO', 'ONE', 'TWO', 'NAN', 'INF',
63
+ 'math', 'constants',
64
+ ]
@@ -0,0 +1,258 @@
1
+ """
2
+ tdfloat._arithmetic
3
+ ===================
4
+ Exact rational arithmetic on encoded half-step integers.
5
+
6
+ Every operation goes: encoded → (p,q) → exact integer arithmetic → encoded.
7
+ No Python float is ever used.
8
+ """
9
+
10
+ from ._encoding import (
11
+ _NAN, _PINF, _NINF, _SPECIALS,
12
+ to_rational, from_rational,
13
+ )
14
+
15
+ # Try to use Rust-accelerated versions
16
+ try:
17
+ from tdfloat_core import td_gcd, td_tddiv
18
+ _RUST_ARITHMETIC = True
19
+ except ImportError:
20
+ _RUST_ARITHMETIC = False
21
+ td_tddiv = None
22
+
23
+ def _sign_of(encoded: int) -> int:
24
+ return 1 if encoded < 0 and encoded not in _SPECIALS else 0
25
+
26
+ def _gcd(a: int, b: int) -> int:
27
+ if _RUST_ARITHMETIC:
28
+ # Use Rust GCD for unsigned integers only
29
+ try:
30
+ return td_gcd(a, b)
31
+ except (OverflowError, ValueError):
32
+ # Fall back to Python if Rust can't handle it
33
+ while b: a, b = b, a % b
34
+ return a
35
+ while b: a, b = b, a % b
36
+ return a
37
+
38
+ def _simplify(p: int, q: int) -> tuple:
39
+ # Use Python _simplify to avoid overflow issues with large numbers
40
+ # (Python uses arbitrary-precision integers)
41
+ if q < 0: p, q = -p, -q
42
+ g = _gcd(abs(p), q) if q else 1
43
+ return p // g, q // g
44
+
45
+ def add(a: int, b: int) -> int:
46
+ if _NAN in (a, b): return _NAN
47
+ if a == _PINF: return _NAN if b == _NINF else _PINF
48
+ if a == _NINF: return _NAN if b == _PINF else _NINF
49
+ if b in (_PINF, _NINF): return b
50
+ na, da = to_rational(a)
51
+ nb, db = to_rational(b)
52
+ p, q = _simplify(na * db + nb * da, da * db)
53
+ return from_rational(p, q)
54
+
55
+ def sub(a: int, b: int) -> int:
56
+ return add(a, neg(b))
57
+
58
+ def neg(a: int) -> int:
59
+ if a == _NAN: return _NAN
60
+ if a == _PINF: return _NINF
61
+ if a == _NINF: return _PINF
62
+ return -a # sign lives in Python int sign
63
+
64
+ def mul(a: int, b: int) -> int:
65
+ if _NAN in (a, b): return _NAN
66
+ if a in (_PINF, _NINF) or b in (_PINF, _NINF):
67
+ sa = 1 if (a == _NINF or (a < 0 and a not in _SPECIALS)) else 0
68
+ sb = 1 if (b == _NINF or (b < 0 and b not in _SPECIALS)) else 0
69
+ return _NINF if (sa ^ sb) else _PINF
70
+ na, da = to_rational(a)
71
+ nb, db = to_rational(b)
72
+ p, q = _simplify(na * nb, da * db)
73
+ return from_rational(p, q)
74
+
75
+ def div(a: int, b: int) -> int:
76
+ """Division using tddiv internally.
77
+ Returns the full rational result: quotient + remainder/denominator as encoded value.
78
+ """
79
+ if _NAN in (a, b): return _NAN
80
+ nb, db = to_rational(b)
81
+ if nb == 0:
82
+ # division by zero: return signed infinity based on sign of a
83
+ na, da = to_rational(a)
84
+ if na == 0: return _NAN # 0/0 = nan
85
+ return _NINF if na < 0 else _PINF
86
+
87
+ # Use tddiv internally for exact three-term semantics
88
+ quot_e, rem_e, den_e = divmod_td(a, b)
89
+
90
+ # Reconstruct: result = quotient + remainder/denominator as a single encoded value
91
+ if rem_e == 0:
92
+ return quot_e
93
+
94
+ # Extract the rational components
95
+ # Note: divmod_td returns integers encoded as rationals with denominator 1
96
+ p_q, q_q = to_rational(quot_e) # quotient as integer
97
+ p_r, q_r = to_rational(rem_e) # remainder as integer
98
+ p_d, q_d = to_rational(den_e) # denominator as integer
99
+
100
+ # Compute: result = quotient + remainder/denominator
101
+ # = (quotient * denominator + remainder) / denominator
102
+ # Since q_q = q_r = q_d = 1 (they're all integers):
103
+ num = p_q * p_d + p_r
104
+ den = p_d
105
+ p, q = _simplify(num, den)
106
+ return from_rational(p, q)
107
+
108
+ def floordiv(a: int, b: int) -> int:
109
+ """Floor division using tddiv internally.
110
+ Returns only the quotient part (whole number).
111
+ """
112
+ if _NAN in (a, b) or b in (_PINF, _NINF): return _NAN
113
+ nb, db = to_rational(b)
114
+ if nb == 0: return _NAN
115
+
116
+ # Use tddiv to get quotient directly
117
+ quot_e, rem_e, den_e = divmod_td(a, b)
118
+ return quot_e
119
+
120
+ def mod(a: int, b: int) -> int:
121
+ """Modulo using tddiv internally.
122
+ Computes: a mod b = a - b * floor(a/b)
123
+ Returns the remainder from the division.
124
+ """
125
+ if _NAN in (a, b) or b in (_PINF, _NINF): return _NAN
126
+ nb, db = to_rational(b)
127
+ if nb == 0: return _NAN
128
+
129
+ # Use tddiv to get quotient directly
130
+ quot_e, rem_e, den_e = divmod_td(a, b)
131
+
132
+ # Compute: a - b * quotient
133
+ return sub(a, mul(b, quot_e))
134
+
135
+ def divmod_td(a: int, b: int) -> tuple:
136
+ """Three-term division: returns (quotient, remainder, denominator).
137
+
138
+ Semantics: a/b = quotient + remainder/denominator
139
+ All three terms are encoded as half-step integers.
140
+
141
+ Args:
142
+ a, b: encoded half-step integers
143
+
144
+ Returns:
145
+ (quotient_enc, remainder_enc, denominator_enc) where each is encoded
146
+ """
147
+ if _NAN in (a, b): return (_NAN, _NAN, _NAN)
148
+ if b in (_PINF, _NINF) or b == 0: return (_NAN, _NAN, _NAN)
149
+ if a == 0: return (0, 0, 1) # 0/b = (0, 0, 1)
150
+
151
+ if _RUST_ARITHMETIC and td_tddiv is not None:
152
+ return td_tddiv(a, b)
153
+
154
+ # Pure Python fallback (less efficient but correct)
155
+ na, da = to_rational(a)
156
+ nb, db = to_rational(b)
157
+
158
+ # a/b = (na/da) / (nb/db) = (na*db) / (da*nb)
159
+ p = na * db
160
+ q = da * nb
161
+
162
+ # Reduce via GCD
163
+ from math import gcd as py_gcd
164
+ g = py_gcd(abs(p), abs(q))
165
+ p, q = p // g, q // g
166
+
167
+ # Ensure q is positive
168
+ if q < 0:
169
+ p, q = -p, -q
170
+
171
+ # Get quotient and remainder
172
+ quot = p // q
173
+ rem = p % q
174
+
175
+ # Encode all three terms
176
+ sign_q = quot < 0
177
+ quot_enc = from_rational(abs(quot), 1) if quot != 0 else 0
178
+ if sign_q and quot != 0:
179
+ quot_enc = -quot_enc if quot_enc >= 0 else quot_enc
180
+
181
+ sign_r = rem < 0
182
+ rem_enc = from_rational(abs(rem), 1) if rem != 0 else 0
183
+ if sign_r and rem != 0:
184
+ rem_enc = -rem_enc if rem_enc >= 0 else rem_enc
185
+
186
+ den_enc = from_rational(q, 1)
187
+
188
+ return (quot_enc, rem_enc, den_enc)
189
+
190
+ def eq(a: int, b: int) -> bool:
191
+ if a in _SPECIALS or b in _SPECIALS:
192
+ return a == b and a != _NAN
193
+ na, da = to_rational(a)
194
+ nb, db = to_rational(b)
195
+ return na * db == nb * da
196
+
197
+ def lt(a: int, b: int) -> bool:
198
+ if _NAN in (a, b): return False
199
+ if a == _NINF: return b != _NINF
200
+ if b == _PINF: return a != _PINF
201
+ if a == _PINF or b == _NINF: return False
202
+ na, da = to_rational(a)
203
+ nb, db = to_rational(b)
204
+ # na/da < nb/db iff na*db < nb*da (both denominators positive)
205
+ return na * db < nb * da
206
+
207
+ def abs_val(a: int) -> int:
208
+ if a in _SPECIALS: return a
209
+ return -a if a < 0 else a
210
+
211
+ def pow_int(a: int, n: int) -> int:
212
+ """Integer power via repeated squaring."""
213
+ if n < 0:
214
+ return div(from_rational(1, 1), pow_int(a, -n))
215
+ result = from_rational(1, 1)
216
+ base = a
217
+ while n:
218
+ if n & 1: result = mul(result, base)
219
+ base = mul(base, base)
220
+ n >>= 1
221
+ return result
222
+
223
+ def isqrt_rational(p: int, q: int) -> tuple:
224
+ """
225
+ Integer square root of p/q as a rational.
226
+ Returns (rp, rq) such that (rp/rq)^2 ≈ p/q.
227
+ Uses Newton's method on integers.
228
+ """
229
+ if p < 0: return (0, 0) # NaN
230
+ if p == 0: return (0, 1)
231
+
232
+ # sqrt(p/q) = sqrt(p*q) / q
233
+ # We compute isqrt(p*q) then divide by q
234
+ target = p * q
235
+ # Scale up for precision: sqrt(target * 10^(2k)) = sqrt(target) * 10^k
236
+ PREC = 80 # decimal digits of precision
237
+ scale = 10 ** (PREC * 2)
238
+ n = target * scale
239
+ x = 1 << (n.bit_length() // 2 + 1)
240
+ while True:
241
+ x1 = (x + n // x) >> 1
242
+ if x1 >= x: break
243
+ x = x1
244
+ # result = x / (sqrt(scale) * q) = x / (10^PREC * q)
245
+ rp, rq = _simplify(x, (10 ** PREC) * q)
246
+ return rp, rq
247
+
248
+ def sqrt(a: int) -> int:
249
+ """Square root via exact rational Newton's method."""
250
+ from ._encoding import _NAN, _PINF, _NINF
251
+ if a == _NAN: return _NAN
252
+ if a == _NINF: return _NAN
253
+ if a == _PINF: return _PINF
254
+ na, da = to_rational(a)
255
+ if na < 0: return _NAN
256
+ if na == 0: return from_rational(0, 1)
257
+ rp, rq = isqrt_rational(na, da)
258
+ return from_rational(rp, rq)
@@ -0,0 +1,161 @@
1
+ """
2
+ tdfloat._encoding
3
+ =================
4
+ The half-step symbol encoding from encoding_any_symbol.v
5
+
6
+ position = 2 * rank + info_bit encode_symbol
7
+ rank = position >> 1 decode_rank
8
+ info_bit = position & 1 decode_info
9
+
10
+ The "." is the info_bit:
11
+ info_bit = 0 → integer axis (even position, no dot)
12
+ info_bit = 1 → half-step axis (odd position, has dot)
13
+ """
14
+
15
+ # ── Layout ────────────────────────────────────────────────────────────
16
+ MAX_DOT_POS = 77 # maximum fractional decimal places
17
+ DOT_POSITIONS = MAX_DOT_POS + 1 # 78 distinct scale values (0..77)
18
+
19
+ # Sentinel values for special numbers (outside the half-step line)
20
+ _NAN = -1
21
+ _PINF = -2
22
+ _NINF = -3
23
+ _SPECIALS = (_NAN, _PINF, _NINF)
24
+
25
+
26
+ # ── The three primitives from encoding_any_symbol.v ──────────────────
27
+
28
+ def encode_symbol(rank: int, info_bit: int) -> int:
29
+ """position = 2 * rank + info_bit"""
30
+ return 2 * rank + (info_bit & 1)
31
+
32
+ def decode_rank(position: int) -> int:
33
+ """rank = position // 2"""
34
+ return position >> 1
35
+
36
+ def decode_info(position: int) -> int:
37
+ """info_bit = position mod 2 (0=integer axis, 1=half-step axis)"""
38
+ return position & 1
39
+
40
+
41
+ # ── Pack / unpack a float as (sign, abs_digits, dot_pos) ─────────────
42
+
43
+ def pack(sign: int, abs_digits: int, dot_pos: int) -> int:
44
+ """
45
+ Encode (sign, digits, dot_pos) as a single integer on the half-step line.
46
+ sign=0 positive, sign=1 negative.
47
+ dot_pos=0 means integer (no dot, info_bit=0).
48
+ dot_pos>0 means fractional (dot present, info_bit=1).
49
+ """
50
+ assert 0 <= dot_pos <= MAX_DOT_POS, f"dot_pos {dot_pos} out of range"
51
+ info_bit = 1 if dot_pos > 0 else 0
52
+ rank = abs_digits * DOT_POSITIONS + dot_pos
53
+ position = encode_symbol(rank, info_bit)
54
+ return -position if sign else position
55
+
56
+ def unpack(encoded: int) -> tuple:
57
+ """Return (sign, abs_digits, dot_pos). sign=0 positive, 1 negative."""
58
+ if encoded < 0:
59
+ sign, position = 1, -encoded
60
+ else:
61
+ sign, position = 0, encoded
62
+ rank = decode_rank(position)
63
+ dot_pos = rank % DOT_POSITIONS
64
+ abs_digits = rank // DOT_POSITIONS
65
+ return sign, abs_digits, dot_pos
66
+
67
+
68
+ # ── Exact rational ↔ encoded int ─────────────────────────────────────
69
+
70
+ def to_rational(encoded: int) -> tuple:
71
+ """Return (numerator, denominator). numerator may be negative."""
72
+ if encoded in _SPECIALS:
73
+ return (0, 0)
74
+ sign, digits, dot_pos = unpack(encoded)
75
+ denom = 10 ** dot_pos
76
+ return (-digits if sign else digits), denom
77
+
78
+ def from_rational(num: int, den: int) -> int:
79
+ """Build encoded int from exact integer ratio num/den.
80
+ Uses pure Python with arbitrary-precision integers to handle all rationals.
81
+ """
82
+ if den == 0:
83
+ return _NAN
84
+ if num == 0:
85
+ return pack(0, 0, 0)
86
+
87
+ sign = 1 if num < 0 else 0
88
+ num = abs(num)
89
+
90
+ # Find shortest exact decimal representation up to MAX_DOT_POS
91
+ for dot_pos in range(MAX_DOT_POS + 1):
92
+ scaled = num * (10 ** dot_pos)
93
+ if scaled % den == 0:
94
+ return pack(sign, scaled // den, dot_pos)
95
+
96
+ # Inexact — round to MAX_DOT_POS places
97
+ scaled = num * (10 ** MAX_DOT_POS)
98
+ digits = (scaled + den // 2) // den
99
+ return pack(sign, digits, MAX_DOT_POS)
100
+
101
+
102
+ # ── String ↔ encoded int ──────────────────────────────────────────────
103
+
104
+ def from_str(s: str) -> int:
105
+ """Parse decimal string to encoded int. No Python float used."""
106
+ s = s.strip().lower()
107
+ for alias, val in (('inf',_PINF),('+inf',_PINF),('-inf',_NINF),('nan',_NAN)):
108
+ if s == alias: return val
109
+
110
+ sign = 0
111
+ if s.startswith('-'): sign = 1; s = s[1:]
112
+ elif s.startswith('+'): s = s[1:]
113
+
114
+ exp10 = 0
115
+ if 'e' in s:
116
+ s, ep = s.split('e', 1); exp10 = int(ep)
117
+
118
+ has_dot = '.' in s
119
+ if has_dot:
120
+ ipart, fpart = s.split('.', 1)
121
+ else:
122
+ ipart, fpart = s, ''
123
+
124
+ ipart = ipart or '0'
125
+ digits = int(ipart + fpart) if (ipart + fpart) else 0
126
+
127
+ raw_dot = len(fpart) - exp10
128
+
129
+ if raw_dot < 0:
130
+ digits *= 10 ** (-raw_dot)
131
+ dot_pos = 0
132
+ elif raw_dot > MAX_DOT_POS:
133
+ excess = raw_dot - MAX_DOT_POS
134
+ digits = (digits + 10**(excess-1)*5) // (10 ** excess)
135
+ dot_pos = MAX_DOT_POS
136
+ else:
137
+ dot_pos = raw_dot
138
+
139
+ # Strip trailing fractional zeros, but preserve the dot presence
140
+ min_dot = 1 if has_dot or exp10 < 0 else 0
141
+ while dot_pos > min_dot and digits % 10 == 0:
142
+ digits //= 10
143
+ dot_pos -= 1
144
+
145
+ return pack(sign, digits, dot_pos)
146
+
147
+ def to_str(encoded: int, max_digits: int = 40) -> str:
148
+ """Convert encoded int to decimal string."""
149
+ if encoded == _NAN: return 'nan'
150
+ if encoded == _PINF: return 'inf'
151
+ if encoded == _NINF: return '-inf'
152
+ sign, digits, dot_pos = unpack(encoded)
153
+ s = '-' if sign else ''
154
+ ds = str(digits)
155
+ if dot_pos == 0:
156
+ return s + ds + '.0' if False else s + ds # integers: no trailing .0
157
+ if len(ds) <= dot_pos:
158
+ ds = '0' * (dot_pos - len(ds) + 1) + ds
159
+ int_part = ds[:-dot_pos] or '0'
160
+ frac_part = ds[-dot_pos:].rstrip('0') or '0'
161
+ return s + int_part + '.' + frac_part
@@ -0,0 +1,112 @@
1
+ """
2
+ tdfloat.constants
3
+ =================
4
+ Every mathematical constant defined as an exact rational p/q.
5
+
6
+ In the tdfloat universe there are no transcendentals.
7
+ Every constant occupies a unique, permanent position on the half-step line.
8
+ The "." is the info_bit; its presence places a constant on the half-step axis.
9
+
10
+ Constant definitions
11
+ --------------------
12
+ π = 22/7 circumference/diameter in the 45°-rotated Gaussian plane
13
+ τ = 44/7 full rotation (2π)
14
+ e = 19/7 natural growth base in 3-step algebra
15
+ ln2 = 2/3 half-life constant
16
+ φ = 3/2 golden ratio = the fundamental half-step
17
+ √2 = 7/5 diagonal of unit square (first CF convergent)
18
+ √3 = 7/4 equilateral triangle height ratio
19
+ √5 = 9/4 from the golden ratio construction
20
+ ½ = 1/2 the half-step atom itself
21
+ """
22
+
23
+ from __future__ import annotations
24
+ from ._encoding import from_rational, _NAN
25
+
26
+ def _gcd(a, b):
27
+ while b: a, b = b, a % b
28
+ return a
29
+
30
+ def _s(p, q):
31
+ if q < 0: p, q = -p, -q
32
+ g = _gcd(abs(p), q)
33
+ return p // g, q // g
34
+
35
+
36
+ class Constant:
37
+ """
38
+ A named rational constant.
39
+ Stores (p, q) as the canonical fraction and provides
40
+ exact arithmetic without going through decimal encoding.
41
+ """
42
+ __slots__ = ('name', 'p', 'q', '_encoded')
43
+
44
+ def __init__(self, name: str, p: int, q: int):
45
+ self.name = name
46
+ self.p, self.q = _s(p, q)
47
+ self._encoded = from_rational(self.p, self.q)
48
+
49
+ def encoded(self) -> int:
50
+ return self._encoded
51
+
52
+ def as_tdf(self):
53
+ """Return this constant as a TDFloat."""
54
+ from .tdfloat import TDFloat
55
+ return TDFloat(self._encoded)
56
+
57
+ def __repr__(self) -> str:
58
+ from ._encoding import to_str
59
+ return f'{self.name} = {self.p}/{self.q} ({to_str(self._encoded)!r})'
60
+
61
+ def __float__(self) -> float:
62
+ return self.p / self.q
63
+
64
+ # Exact arithmetic returning (p, q) tuples
65
+ def __mul__(self, other: 'Constant') -> 'Constant':
66
+ p, q = _s(self.p * other.p, self.q * other.q)
67
+ return Constant(f'{self.name}*{other.name}', p, q)
68
+
69
+ def __add__(self, other: 'Constant') -> 'Constant':
70
+ p, q = _s(self.p * other.q + other.p * self.q, self.q * other.q)
71
+ return Constant(f'{self.name}+{other.name}', p, q)
72
+
73
+ def __sub__(self, other: 'Constant') -> 'Constant':
74
+ p, q = _s(self.p * other.q - other.p * self.q, self.q * other.q)
75
+ return Constant(f'{self.name}-{other.name}', p, q)
76
+
77
+ def __truediv__(self, other: 'Constant') -> 'Constant':
78
+ p, q = _s(self.p * other.q, self.q * other.p)
79
+ return Constant(f'{self.name}/{other.name}', p, q)
80
+
81
+ def __neg__(self) -> 'Constant':
82
+ return Constant(f'-{self.name}', -self.p, self.q)
83
+
84
+
85
+ # ── The registry ──────────────────────────────────────────────────────
86
+
87
+ PI = Constant('π', 22, 7) # circumference / diameter
88
+ TAU = Constant('τ', 44, 7) # 2π
89
+ E = Constant('e', 19, 7) # natural base
90
+ LN2 = Constant('ln2', 2, 3) # log(2)
91
+ LN10 = Constant('ln10', 7, 3) # log(10)
92
+ LOG2E = Constant('log2e', 3, 2) # log₂(e) = 1/ln2 = φ
93
+ SQRT2 = Constant('√2', 7, 5) # √2
94
+ SQRT3 = Constant('√3', 7, 4) # √3
95
+ SQRT5 = Constant('√5', 9, 4) # √5
96
+ PHI = Constant('φ', 3, 2) # golden ratio = the half-step
97
+ SIN45 = Constant('sin45', 1, 2) # sin(45°) in identity-axis geometry
98
+ COS45 = Constant('cos45', 1, 2)
99
+ SIN30 = Constant('sin30', 1, 2)
100
+ COS30 = Constant('cos30', 7, 8) # √3/2
101
+ SIN60 = Constant('sin60', 7, 8)
102
+ COS60 = Constant('cos60', 1, 2)
103
+ HALF = Constant('½', 1, 2) # the fundamental half-step atom
104
+ ALPHA = Constant('α', 1, 137) # fine structure constant
105
+
106
+ ALL: dict[str, Constant] = {
107
+ 'pi': PI, 'tau': TAU, 'e': E, 'ln2': LN2, 'ln10': LN10,
108
+ 'log2e': LOG2E, 'sqrt2': SQRT2, 'sqrt3': SQRT3, 'sqrt5': SQRT5,
109
+ 'phi': PHI, 'sin45': SIN45, 'cos45': COS45, 'sin30': SIN30,
110
+ 'cos30': COS30, 'sin60': SIN60, 'cos60': COS60,
111
+ 'half': HALF, 'alpha': ALPHA,
112
+ }