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.
- valuebridge/tdfloat/__init__.py +64 -0
- valuebridge/tdfloat/_arithmetic.py +258 -0
- valuebridge/tdfloat/_encoding.py +161 -0
- valuebridge/tdfloat/constants.py +112 -0
- valuebridge/tdfloat/math.py +333 -0
- valuebridge/tdfloat/tdfloat.py +532 -0
- valuebridge_tdfloat-1.0.0.dist-info/METADATA +192 -0
- valuebridge_tdfloat-1.0.0.dist-info/RECORD +11 -0
- valuebridge_tdfloat-1.0.0.dist-info/WHEEL +5 -0
- valuebridge_tdfloat-1.0.0.dist-info/licenses/LICENSE +21 -0
- valuebridge_tdfloat-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tdfloat.math
|
|
3
|
+
============
|
|
4
|
+
Mathematical functions for TDFloat — all exact rational arithmetic.
|
|
5
|
+
|
|
6
|
+
Functions
|
|
7
|
+
---------
|
|
8
|
+
sqrt(x) square root (rational Newton)
|
|
9
|
+
exp(x) e^x via Taylor series
|
|
10
|
+
log(x) natural log via series
|
|
11
|
+
sin(x) sine via Taylor series
|
|
12
|
+
cos(x) cosine via Taylor series
|
|
13
|
+
floor(x) floor
|
|
14
|
+
ceil(x) ceiling
|
|
15
|
+
round_(x, dp) round to dp decimal places
|
|
16
|
+
circle_area(r) π r² (exact with π=22/7)
|
|
17
|
+
circle_circ(r) 2π r (exact with τ=44/7)
|
|
18
|
+
divmod(a, b) three-term division: (quotient, remainder, denominator)
|
|
19
|
+
dot_product(u, v) exact dot product of two TDFloat vectors
|
|
20
|
+
norm(v) ‖v‖ = √(Σ xᵢ²)
|
|
21
|
+
normalize(v) unit vector v / ‖v‖
|
|
22
|
+
cosine_similarity(u, v) cos(θ) = u·v / (‖u‖ ‖v‖), exact
|
|
23
|
+
euclidean_distance(u, v) √(Σ (uᵢ − vᵢ)²)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
from .tdfloat import TDFloat, frac, td
|
|
28
|
+
from ._encoding import from_rational, to_rational, _NAN, _PINF, _NINF
|
|
29
|
+
from ._arithmetic import add, sub, mul, div, floordiv, neg, sqrt as _sqrt
|
|
30
|
+
|
|
31
|
+
# Try to use Rust-accelerated batch ops with TDBigInt
|
|
32
|
+
try:
|
|
33
|
+
from tdfloat_core import td_dot_frac
|
|
34
|
+
_RUST_BATCH = True
|
|
35
|
+
except ImportError:
|
|
36
|
+
_RUST_BATCH = False
|
|
37
|
+
|
|
38
|
+
# Try to use Rust special functions (DISABLED: precision issues, use exact Python implementations instead)
|
|
39
|
+
try:
|
|
40
|
+
from tdfloat_core import td_sqrt, td_exp, td_log, td_sin, td_cos, td_pow
|
|
41
|
+
_RUST_SPECIAL = False # Force Python implementations for exact rational arithmetic
|
|
42
|
+
except ImportError:
|
|
43
|
+
_RUST_SPECIAL = False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def sqrt(x: TDFloat) -> TDFloat:
|
|
47
|
+
"""Square root via bitwise exact arithmetic."""
|
|
48
|
+
if _RUST_SPECIAL:
|
|
49
|
+
return TDFloat(td_sqrt(x._e))
|
|
50
|
+
return TDFloat(_sqrt(x._e))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _series(x: TDFloat, terms: int, numerator_fn, denominator_fn) -> TDFloat:
|
|
54
|
+
"""Generic Taylor series: Σ f(n) * x^n"""
|
|
55
|
+
result = TDFloat.from_int(0)
|
|
56
|
+
xn = TDFloat.from_int(1)
|
|
57
|
+
for n in range(terms):
|
|
58
|
+
np_, dp_ = numerator_fn(n), denominator_fn(n)
|
|
59
|
+
if dp_ == 0: continue
|
|
60
|
+
term = xn * frac(np_, dp_)
|
|
61
|
+
result = result + term
|
|
62
|
+
xn = xn * x
|
|
63
|
+
return result
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def exp(x: TDFloat, terms: int = 25) -> TDFloat:
|
|
67
|
+
"""
|
|
68
|
+
e^x via optimized bitwise Horner's method.
|
|
69
|
+
All exact rational arithmetic using precomputed reciprocals.
|
|
70
|
+
"""
|
|
71
|
+
if x.is_nan or x.is_inf: return x
|
|
72
|
+
if _RUST_SPECIAL:
|
|
73
|
+
return TDFloat(td_exp(x._e))
|
|
74
|
+
# Fallback to Python Taylor series
|
|
75
|
+
result = TDFloat.from_int(1)
|
|
76
|
+
term = TDFloat.from_int(1)
|
|
77
|
+
for n in range(1, terms):
|
|
78
|
+
term = term * x / TDFloat.from_int(n)
|
|
79
|
+
result = result + term
|
|
80
|
+
return result
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def log(x: TDFloat, terms: int = 60) -> TDFloat:
|
|
84
|
+
"""
|
|
85
|
+
Natural log via optimized bitwise bit-length approach with correction.
|
|
86
|
+
All exact rational arithmetic.
|
|
87
|
+
"""
|
|
88
|
+
if x.is_nan or not x.is_finite: return TDFloat.NAN
|
|
89
|
+
px, qx = to_rational(x._e)
|
|
90
|
+
if px <= 0: return TDFloat.NAN
|
|
91
|
+
|
|
92
|
+
if _RUST_SPECIAL:
|
|
93
|
+
return TDFloat(td_log(x._e))
|
|
94
|
+
|
|
95
|
+
# Fallback to Python series
|
|
96
|
+
one = TDFloat.from_int(1)
|
|
97
|
+
y = (x - one) / (x + one)
|
|
98
|
+
y2 = y * y
|
|
99
|
+
result = TDFloat.from_int(0)
|
|
100
|
+
yk = y
|
|
101
|
+
for k in range(terms):
|
|
102
|
+
term = yk * frac(1, 2*k + 1)
|
|
103
|
+
result = result + term
|
|
104
|
+
yk = yk * y2
|
|
105
|
+
return result * TDFloat.from_int(2)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def sin(x: TDFloat, terms: int = 20) -> TDFloat:
|
|
109
|
+
"""
|
|
110
|
+
sin(x) via optimized bitwise table-based interpolation at 1/2 degree resolution.
|
|
111
|
+
All exact rational arithmetic.
|
|
112
|
+
"""
|
|
113
|
+
if x.is_nan or x.is_inf: return TDFloat.NAN
|
|
114
|
+
if _RUST_SPECIAL:
|
|
115
|
+
return TDFloat(td_sin(x._e))
|
|
116
|
+
|
|
117
|
+
# Fallback to Python Taylor series
|
|
118
|
+
result = TDFloat.from_int(0)
|
|
119
|
+
term = x
|
|
120
|
+
x2 = x * x
|
|
121
|
+
factorial = 1
|
|
122
|
+
for k in range(terms):
|
|
123
|
+
n = 2 * k + 1
|
|
124
|
+
result = result + term if k % 2 == 0 else result - term
|
|
125
|
+
factorial *= (n + 1) * (n + 2)
|
|
126
|
+
term = term * x2 * frac(1, factorial)
|
|
127
|
+
return result
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def cos(x: TDFloat, terms: int = 20) -> TDFloat:
|
|
131
|
+
"""
|
|
132
|
+
cos(x) via optimized bitwise table-based interpolation at 1/2 degree resolution.
|
|
133
|
+
All exact rational arithmetic.
|
|
134
|
+
"""
|
|
135
|
+
if x.is_nan or x.is_inf: return TDFloat.NAN
|
|
136
|
+
if _RUST_SPECIAL:
|
|
137
|
+
return TDFloat(td_cos(x._e))
|
|
138
|
+
|
|
139
|
+
# Fallback to Python Taylor series
|
|
140
|
+
result = TDFloat.from_int(1)
|
|
141
|
+
term = TDFloat.from_int(1)
|
|
142
|
+
x2 = x * x
|
|
143
|
+
factorial = 1
|
|
144
|
+
for k in range(1, terms):
|
|
145
|
+
n = 2 * k
|
|
146
|
+
factorial *= (n - 1) * n
|
|
147
|
+
term = x2 * term * frac(1, (2*k - 1) * (2*k))
|
|
148
|
+
result = result - term if k % 2 == 1 else result + term
|
|
149
|
+
return result
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def floor(x: TDFloat) -> TDFloat:
|
|
153
|
+
"""Floor function."""
|
|
154
|
+
if not x.is_finite: return x
|
|
155
|
+
p, q = to_rational(x._e)
|
|
156
|
+
if q == 0: return TDFloat.NAN
|
|
157
|
+
return TDFloat.from_int(p // q)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def ceil(x: TDFloat) -> TDFloat:
|
|
161
|
+
"""Ceiling function."""
|
|
162
|
+
if not x.is_finite: return x
|
|
163
|
+
p, q = to_rational(x._e)
|
|
164
|
+
if q == 0: return TDFloat.NAN
|
|
165
|
+
return TDFloat.from_int(-((-p) // q))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def round_(x: TDFloat, decimal_places: int = 0) -> TDFloat:
|
|
169
|
+
"""Round to given number of decimal places."""
|
|
170
|
+
if not x.is_finite: return x
|
|
171
|
+
p, q = to_rational(x._e)
|
|
172
|
+
if q == 0: return TDFloat.NAN
|
|
173
|
+
scale = 10 ** decimal_places
|
|
174
|
+
# Round half-up
|
|
175
|
+
shifted = p * scale
|
|
176
|
+
rounded = (shifted + q // 2) // q
|
|
177
|
+
return TDFloat.from_frac(rounded, scale)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def circle_area(r: TDFloat) -> TDFloat:
|
|
181
|
+
"""Area = π r² (exact with π = 22/7)."""
|
|
182
|
+
rp, rq = to_rational(r._e)
|
|
183
|
+
p, q = 22 * rp * rp, 7 * rq * rq
|
|
184
|
+
return TDFloat(from_rational(p, q), p, q)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def circle_circumference(r: TDFloat) -> TDFloat:
|
|
188
|
+
"""Circumference = τ r = 2π r (exact with τ = 44/7)."""
|
|
189
|
+
rp, rq = to_rational(r._e)
|
|
190
|
+
p, q = 44 * rp, 7 * rq
|
|
191
|
+
return TDFloat(from_rational(p, q), p, q)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def hypot(a: TDFloat, b: TDFloat) -> TDFloat:
|
|
195
|
+
"""√(a² + b²)"""
|
|
196
|
+
return sqrt(a * a + b * b)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def gcd(a: TDFloat, b: TDFloat) -> TDFloat:
|
|
200
|
+
"""GCD of two TDFloats (integers only)."""
|
|
201
|
+
pa, qa = to_rational(a._e)
|
|
202
|
+
pb, qb = to_rational(b._e)
|
|
203
|
+
if qa != 1 or qb != 1:
|
|
204
|
+
raise ValueError("gcd requires integer TDFloats")
|
|
205
|
+
from math import gcd as _gcd
|
|
206
|
+
return TDFloat.from_int(_gcd(abs(pa), abs(pb)))
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def sum_(iterable) -> TDFloat:
|
|
210
|
+
"""Exact sum of an iterable of TDFloats."""
|
|
211
|
+
result = TDFloat.from_int(0)
|
|
212
|
+
for x in iterable:
|
|
213
|
+
result = result + (x if isinstance(x, TDFloat) else td(x))
|
|
214
|
+
return result
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def prod(iterable) -> TDFloat:
|
|
218
|
+
"""Exact product of an iterable of TDFloats."""
|
|
219
|
+
result = TDFloat.from_int(1)
|
|
220
|
+
for x in iterable:
|
|
221
|
+
result = result * (x if isinstance(x, TDFloat) else td(x))
|
|
222
|
+
return result
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _coerce_vec(v):
|
|
226
|
+
"""Convert sequence to list[TDFloat]; also return whether any element was non-TDFloat."""
|
|
227
|
+
items = list(v)
|
|
228
|
+
native = any(not isinstance(x, TDFloat) for x in items)
|
|
229
|
+
return [td(x) for x in items], native
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def dot_product(u, v):
|
|
233
|
+
"""Exact dot product with TDBigInt arbitrary-precision acceleration.
|
|
234
|
+
Accepts float/int/TDFloat; returns float if inputs were IEEE 754.
|
|
235
|
+
"""
|
|
236
|
+
u_, nu = _coerce_vec(u)
|
|
237
|
+
v_, nv = _coerce_vec(v)
|
|
238
|
+
|
|
239
|
+
# Use Rust TDBigInt acceleration for exact fraction arithmetic
|
|
240
|
+
if _RUST_BATCH and not (nu or nv):
|
|
241
|
+
# Extract numerators and denominators from each TDFloat
|
|
242
|
+
u_nums = []
|
|
243
|
+
u_dens = []
|
|
244
|
+
for x in u_:
|
|
245
|
+
if x._p is not None and x._q is not None:
|
|
246
|
+
u_nums.append(x._p)
|
|
247
|
+
u_dens.append(x._q)
|
|
248
|
+
else:
|
|
249
|
+
# Decode from encoded value
|
|
250
|
+
p, q = to_rational(x._e)
|
|
251
|
+
u_nums.append(p)
|
|
252
|
+
u_dens.append(q)
|
|
253
|
+
|
|
254
|
+
v_nums = []
|
|
255
|
+
v_dens = []
|
|
256
|
+
for x in v_:
|
|
257
|
+
if x._p is not None and x._q is not None:
|
|
258
|
+
v_nums.append(x._p)
|
|
259
|
+
v_dens.append(x._q)
|
|
260
|
+
else:
|
|
261
|
+
# Decode from encoded value
|
|
262
|
+
p, q = to_rational(x._e)
|
|
263
|
+
v_nums.append(p)
|
|
264
|
+
v_dens.append(q)
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
result_num, result_den = td_dot_frac(u_nums, u_dens, v_nums, v_dens)
|
|
268
|
+
return TDFloat(from_rational(result_num, result_den), result_num, result_den)
|
|
269
|
+
except OverflowError:
|
|
270
|
+
pass # Fall through to Python path when values exceed i128
|
|
271
|
+
|
|
272
|
+
result = sum_(a * b for a, b in zip(u_, v_))
|
|
273
|
+
return float(result) if (nu or nv) else result
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def norm(v):
|
|
277
|
+
"""‖v‖ = √(Σ xᵢ²). Accepts float/int/TDFloat; returns float if inputs were IEEE 754."""
|
|
278
|
+
v_, native = _coerce_vec(v)
|
|
279
|
+
result = sqrt(sum_(x * x for x in v_))
|
|
280
|
+
return float(result) if native else result
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def normalize(v):
|
|
284
|
+
"""Unit vector v / ‖v‖. Returns list[float] if inputs were IEEE 754, else list[TDFloat]."""
|
|
285
|
+
v_, native = _coerce_vec(v)
|
|
286
|
+
n = sqrt(sum_(x * x for x in v_))
|
|
287
|
+
result = [x / n for x in v_]
|
|
288
|
+
return [float(x) for x in result] if native else result
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def cosine_similarity(u, v):
|
|
292
|
+
"""cos(θ) = u·v / (‖u‖ ‖v‖). Accepts float/int/TDFloat; returns float if inputs were IEEE 754."""
|
|
293
|
+
u_, nu = _coerce_vec(u)
|
|
294
|
+
v_, nv = _coerce_vec(v)
|
|
295
|
+
result = sum_(a * b for a, b in zip(u_, v_)) / (
|
|
296
|
+
sqrt(sum_(x * x for x in u_)) * sqrt(sum_(x * x for x in v_))
|
|
297
|
+
)
|
|
298
|
+
return float(result) if (nu or nv) else result
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def euclidean_distance(u, v):
|
|
302
|
+
"""√(Σ (uᵢ − vᵢ)²). Accepts float/int/TDFloat; returns float if inputs were IEEE 754."""
|
|
303
|
+
u_, nu = _coerce_vec(u)
|
|
304
|
+
v_, nv = _coerce_vec(v)
|
|
305
|
+
result = sqrt(sum_((a - b) * (a - b) for a, b in zip(u_, v_)))
|
|
306
|
+
return float(result) if (nu or nv) else result
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def divmod(a, b) -> tuple:
|
|
310
|
+
"""Three-term division returning (quotient, remainder, denominator).
|
|
311
|
+
|
|
312
|
+
Returns the complete division decomposition:
|
|
313
|
+
a/b = quotient + remainder/denominator
|
|
314
|
+
|
|
315
|
+
This is the triadic division operation exposing all three semantic components:
|
|
316
|
+
- quotient: the whole number part
|
|
317
|
+
- remainder: the numerator of the fractional part
|
|
318
|
+
- denominator: the denominator of the fractional part
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
a, b: TDFloat or coercible values
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
(quotient, remainder, denominator) as a tuple of TDFloat values
|
|
325
|
+
|
|
326
|
+
Example:
|
|
327
|
+
>>> q, r, d = divmod(7, 3)
|
|
328
|
+
>>> q + r / d # Reconstruct: 2 + 1/3 = 7/3
|
|
329
|
+
"""
|
|
330
|
+
from .tdfloat import divmod_td
|
|
331
|
+
a = td(a)
|
|
332
|
+
b = td(b)
|
|
333
|
+
return a.divmod_td(b)
|