daatypes 0.1.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.
daatypes/__init__.py ADDED
@@ -0,0 +1,75 @@
1
+ # hello! welcome to daatypes where i propose my own datatypes i find useful in my work
2
+
3
+ # unsigned integer
4
+ # represents the natural numbers starting from zero
5
+ # can also do saturating and modular arithmetic
6
+ from .uint import UInt
7
+
8
+ # 2's complement signed integer
9
+ # represents the integers
10
+ # can also do saturating and modular arithmetic
11
+ from .int import Int
12
+
13
+ # unsigned binary fixed point number format
14
+ # represents the non-negative binary rationals
15
+ # can also do saturating and modular arithmetic
16
+ from .uqint import UQInt
17
+
18
+ # signed binary fixed point number format
19
+ # represents the binary rationals
20
+ # can also do saturating and modular arithmetic
21
+ from .qint import QInt
22
+
23
+ # fixed point numbers
24
+ from .fixed import Fixed
25
+
26
+ # scientific notation in arbitrary radix
27
+ # represents the rational numbers
28
+ from .float import Float, ieee_binary, ieee_decimal, f16, f32, f64, f128, f256, d32, d64, d128
29
+
30
+ # a composed datatype
31
+ # two arrays of int primes[] and int exponents[]
32
+ # represents the rationals
33
+ # conducive to slow additive but fast multiplicative arithmetic
34
+ from .monzo import Monzo
35
+
36
+ # (simple)? continued fraction
37
+ from .cf import CF, SCF
38
+
39
+ # a composed datatype
40
+ # an ordered pair of (any lower, any upper)
41
+ # represents a closed-closed interval on the real number line
42
+ # conducive to fast tolerance-aware arithmetic
43
+ from .interval import Interval
44
+
45
+ # a composed datatype
46
+ # an ordered pair of (centre, +ve radius)
47
+ # represents a ball in an R-vector space
48
+ # conducive to tolerance-aware arithmetic with accurate tolerance
49
+ from .ball import Ball
50
+
51
+ # vectors of real numbers ------------------------------------------------------
52
+
53
+ from .vector import Vector
54
+
55
+ # represents the real numbers
56
+ from .real import Real
57
+
58
+ # a composed datatype
59
+ # represents the complexes in cartesian form
60
+ from .comp import Comp
61
+
62
+ # a composed datatype
63
+ # represents the quaternions in cartesian form
64
+ from .quat import Quat
65
+
66
+ # a composed datatype
67
+ # represents the quaternions in cartesian form
68
+ from .octo import Octo
69
+
70
+ # a composed datatype
71
+ # an ordered pair of (qint magnitude, float angle) where angle is from real axis to imaginary axis
72
+ # represents the complex numbers
73
+ # conducive to slow additive but fast multiplicative arithmetic, and uniform angle precision
74
+ from .polar import Polar
75
+
daatypes/ball.py ADDED
@@ -0,0 +1,22 @@
1
+ from numbers import Number, Real
2
+ import daacorations
3
+ from dataclasses import dataclass, Field
4
+
5
+ @dataclass
6
+ class Ball(Number):
7
+ 'a composed datatype representing an axially symmetric (i think) p-norm ball in an R-vector space'
8
+
9
+ midpoint: Number
10
+ radius: Real
11
+ power: Real
12
+
13
+ def __post_init__(self):
14
+ if self.radius < 0:
15
+ raise ValueError(f'{self.radius=} must be non-negative')
16
+ if self.power < 0:
17
+ raise ValueError(f'{self.radius=} must be non-negative')
18
+
19
+ __repr__ = daacorations.pretty_repr
20
+
21
+ class EBall:
22
+ 'a Ball but with p = 2 (euclidean), thus representing a hypersphere'
daatypes/cf.py ADDED
@@ -0,0 +1,79 @@
1
+ import math, builtins
2
+ from dataclasses import dataclass
3
+ from numbers import Number, Rational, Integral
4
+ from collections.abc import Sequence, MutableSequence
5
+ from typing import Literal
6
+ from daacorations import pretty_repr
7
+ from fractions import Fraction
8
+
9
+ @dataclass
10
+ class CF(Number):
11
+ 'a continued fraction'
12
+ numerators: Sequence
13
+ denominators: Sequence
14
+ signum: Literal[-1, 0, +1] = +1
15
+ numerators_repeat: None | int = None
16
+ denominators_repeat: None | int = None
17
+
18
+ @property
19
+ def integral(self) -> Integral:
20
+ return self.denominators[0]
21
+
22
+ @property
23
+ def fractional(self) -> Rational:
24
+ ...
25
+
26
+ def __str__(self) -> str:
27
+ sign = {-1: '-', 0: '', +1: '+'}[self.signum]
28
+ return f'{sign}({self.denominators[0]} + {" + ".join(f"{n}/{d}"for n, d in zip(self.numerators[1:], self.denominators[1:]))})'
29
+
30
+ __repr__ = pretty_repr
31
+
32
+ def quotrem_nearest_even(n, d):
33
+ q = round(n / d)
34
+ return q, n - q * d
35
+
36
+ class SCF(CF, Sequence):
37
+ 'a simple continued fraction with a Sequence interface'
38
+ def __init__(self, denominators: Sequence, signum = +1):
39
+ super().__init__([0, 1], denominators, signum, numerators_repeat = 1)
40
+
41
+ # Sequence methods
42
+ def __getitem__(self, index: int) -> int:
43
+ return self.denominators[index]
44
+ def __len__(self) -> int:
45
+ return len(self.denominators)
46
+
47
+ @classmethod
48
+ def from_rational(cls, rational: Rational, round = math.floor) -> SCF:
49
+ 'set round=builtins.round or round=math.ceil for interesting partial denominators'
50
+ signum = (rational > 0) - (rational < 0)
51
+ rational = abs(rational)
52
+
53
+ denominators: MutableSequence[int] = list()
54
+
55
+ while True:
56
+ quotient = round(rational)
57
+ denominators.append(quotient)
58
+ remainder = rational.numerator - quotient * rational.denominator
59
+ if remainder == 0:
60
+ break
61
+ rational = Fraction(rational.denominator, remainder)
62
+
63
+ return cls(denominators, signum)
64
+
65
+ def to_rational(self) -> Rational:
66
+ if len(self.denominators) == 1:
67
+ return self.signum * self.denominators[0]
68
+
69
+ ac = Fraction(self.denominators[-1], 1)
70
+
71
+ for d in reversed(self.denominators[:-1]):
72
+ ac = d + 1 / ac
73
+
74
+ return self.signum * ac
75
+
76
+ def __str__(self) -> str:
77
+ return f'[{self.denominators[0]};{",".join(str(d) for d in self.denominators[1:])}]'
78
+
79
+ __repr__ = pretty_repr
daatypes/comp.py ADDED
@@ -0,0 +1,49 @@
1
+ import math
2
+ from numbers import Complex, Real
3
+ from .vector import Vector
4
+
5
+ class Comp(Vector, Complex):
6
+ 'a complex number. a vector of 2 real numbers'
7
+ def __init__(self, real, imag):
8
+ self.real = real
9
+ self.imag = imag
10
+ super.__init__((real, imag))
11
+
12
+ @classmethod
13
+ def from_complex(cls, c: Complex) -> Comp:
14
+ return cls(c.real, c.imag)
15
+
16
+ def norm(self) -> Real:
17
+ return math.sqrt(self.real * self.real + self.imag * self.imag)
18
+
19
+ def unit(self) -> Real:
20
+ return type(self)(self.real / self.norm(), self.imag / self.norm())
21
+
22
+ def conjugate(self) -> Comp:
23
+ return type(self)(self.real, -self.imag)
24
+
25
+ __abs__ = norm
26
+
27
+ def __neg__(self) -> Comp:
28
+ return type(self)(-self.real, -self.imag)
29
+ def __pos__(self) -> Comp:
30
+ return type(self)(+self.real, +self.imag)
31
+
32
+ def __add__(self, other) -> Comp:
33
+ return type(self)(self.real + other.real, self.imag + other.imag)
34
+
35
+ def __mul__(self, other) -> Comp:
36
+ return type(self)(self.real*other.real-self.imag*other.imag, self.real*other.imag+self.imag*other.real)
37
+
38
+ def __complex__(self) -> complex:
39
+ return complex(self.real, self.imag)
40
+
41
+ def __eq__(self, other) -> bool:
42
+ return self.real == other.real and self.imag == other.imag
43
+
44
+ # '__pow__',
45
+ # '__radd__',
46
+ # '__rmul__',
47
+ # '__rpow__',
48
+ # '__rtruediv__',
49
+ # '__truediv__',
daatypes/fixed.py ADDED
@@ -0,0 +1,243 @@
1
+ from __future__ import annotations
2
+ from stringman.unicode import to_subscript
3
+ from numbers import Rational, Integral
4
+ from collections.abc import Sequence, MutableSequence, Iterable
5
+ from typing import Literal
6
+ from dataclasses import dataclass, field
7
+ from itertools import chain, cycle, repeat
8
+ from fractions import Fraction
9
+ import math
10
+
11
+ @dataclass(kw_only = True)
12
+ class Fixed(Rational):
13
+ 'a rational number with a fixed radix point. could potentially be an n-adic number class some day…'
14
+ signum: Literal[-1, 0, +1]
15
+ radix: Integral
16
+ left: Sequence[Integral] = field(default_factory = tuple)
17
+ right: Sequence[Integral] = field(default_factory = tuple)
18
+ left_repeat: None | Integral = None
19
+ right_repeat: None | Integral = None
20
+
21
+ def to_fraction(self) -> Fraction:
22
+ value = self.signum * sum(chain(
23
+ (digit * self.radix ** i for i, digit in enumerate(self.left, start = 0)),
24
+ (digit * self.radix ** -i for i, digit in enumerate(self.right, start = 1))))
25
+
26
+ @property
27
+ def numerator(self) -> Integral:
28
+ if self.left_repeat is not None:
29
+ raise ValueError(f'{self} is not a rational number')
30
+ return
31
+ @property
32
+ def denominator(self) -> Integral:
33
+ if self.left_repeat is not None:
34
+ raise ValueError(f'{self} is not a rational number')
35
+ return
36
+
37
+ @property
38
+ def left_preperiod(self):
39
+ return self.left if self.left_repeat is None else self.left[:self.left_repeat]
40
+ @property
41
+ def right_preperiod(self):
42
+ return self.right if self.right_repeat is None else self.right[:self.right_repeat]
43
+ @property
44
+ def left_repetend(self):
45
+ return () if self.left_repeat is None else self.left[self.left_repeat:]
46
+ @property
47
+ def right_repetend(self):
48
+ return () if self.right_repeat is None else self.right[self.right_repeat:]
49
+
50
+ @property
51
+ def left_iterable(self) -> Iterable:
52
+ yield from self.left_preperiod
53
+ if self.left_repetend:
54
+ yield from cycle(self.left_repetend)
55
+ else:
56
+ yield from repeat(0)
57
+ @property
58
+ def right_iterable(self) -> Iterable:
59
+ yield from self.right_preperiod
60
+ if self.right_repetend:
61
+ yield from cycle(self.right_repetend)
62
+ else:
63
+ yield from repeat(0)
64
+
65
+ @classmethod
66
+ def from_integral(cls, integral: Integral, radix: Integral) -> Fixed:
67
+ if integral == 0:
68
+ return cls(signum=0, radix=radix)
69
+ signum = (integral > 0) - (integral < 0)
70
+ integral = abs(integral)
71
+
72
+ left: MutableSequence[Integral] = list()
73
+ while integral > 0:
74
+ integral, index = divmod(integral, radix)
75
+ left.append(index)
76
+
77
+ return cls(signum=signum, left=left, radix=radix)
78
+
79
+ @classmethod
80
+ def from_rational(cls, rational: Rational, radix: Integral, right_limit: None | int = None) -> Fixed:
81
+ if rational == 0:
82
+ return cls(signum=0, radix=radix)
83
+
84
+ signum = (rational > 0) - (rational < 0)
85
+ rational = abs(rational)
86
+
87
+ integral, remainder = divmod(rational.numerator, rational.denominator)
88
+
89
+ left: MutableSequence[Integral] = list()
90
+ while integral > 0:
91
+ integral, index = divmod(integral, radix)
92
+ left.append(index)
93
+
94
+ right: MutableSequence = list()
95
+ remainders: dict[int, int] = dict() # remainders[remainder] = index
96
+
97
+ while True:
98
+ if remainder == 0 or remainder in remainders:
99
+ break
100
+
101
+ remainders[remainder] = len(right)
102
+
103
+ digit, remainder = divmod(remainder * radix, rational.denominator)
104
+ right.append(digit)
105
+
106
+ if right_limit is not None and len(right) >= right_limit:
107
+ break
108
+
109
+ return cls(signum = signum, radix = radix, left=left, right=right, right_repeat = remainders.get(remainder, None))
110
+
111
+ def __pos__(self) -> Fixed:
112
+ return self
113
+ def __neg__(self) -> Fixed:
114
+ return type(self)(signum=-self.signum, radix=self.radix, left=left, right=right, left_repeat=left_repeat, right_repeat=right_repeat)
115
+ def __abs__(self) -> Fixed:
116
+ return type(self)(signum=+1, radix=self.radix, left=left, right=right, left_repeat=left_repeat, right_repeat=right_repeat)
117
+ def __add__(self, other) -> Fixed:
118
+ ...
119
+ def __floor__(self) -> Fixed:
120
+ return type(self)(signum=self.signum, radix=self.radix, left=left, right=right, left_repeat=left_repeat, right_repeat=right_repeat)
121
+ def __ceil__(self) -> Fixed:
122
+ return
123
+ def __trunc__(self) -> Fixed:
124
+ return type(self)(signum=self.signum, radix=self.radix, left=left, left_repeat=left_repeat)
125
+ def __floordiv__(self, other) -> Fixed:
126
+ return
127
+ def __le__(self, other) -> bool:
128
+ return
129
+ def __lt__(self, other) -> bool:
130
+ return self <= other and not other <= self
131
+ def __mod__(self, other) -> Fixed:
132
+ return
133
+ def __mul__(self, other) -> Fixed:
134
+ return
135
+ def __pow__(self, other) -> Fixed:
136
+ return
137
+ def __radd__(self) -> Fixed:
138
+ return
139
+ def __rfloordiv__(self) -> Fixed:
140
+ return
141
+ def __rmod__(self) -> Fixed:
142
+ return
143
+ def __rmul__(self) -> Fixed:
144
+ return
145
+ def __round__(self) -> Fixed:
146
+ return
147
+ def __rpow__(self) -> Fixed:
148
+ return
149
+ def __rtruediv__(self) -> Fixed:
150
+ return
151
+ def __truediv__(self) -> Fixed:
152
+ return
153
+
154
+ def __float__(self) -> float:
155
+ if self.left_repeat is not None:
156
+ return self.signum * math.inf
157
+ return self.signum * sum(chain(
158
+ (digit * self.radix ** i for i, digit in enumerate(self.left, start = 0)),
159
+ (digit * self.radix ** -i for i, digit in enumerate(self.right, start = 1))))
160
+
161
+ def __str__(self,
162
+ char_set = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
163
+ left_precision: None | int = None,
164
+ right_precision: None | int = None
165
+ ) -> str:
166
+
167
+ sign: str = {-1: '−', 0: '', +1: '+'}[self.signum]
168
+
169
+ if left_precision is not None:
170
+ if self.left_repeat is None:
171
+ # left terminates
172
+ left: str = ''.join(char_set[digit] for digit in reversed(self.left_preperiod))
173
+ else:
174
+ # left has repeating digits
175
+ left: str = ...
176
+ else:
177
+ repetend: str = ''.join(char_set[digit] for digit in reversed(self.left_repetend)) if len(self.left_repetend) != 0 else '0'
178
+ preperiod: str = ''.join(char_set[digit] for digit in reversed(self.left_preperiod))
179
+ left: str = '(' + repetend + ')' + preperiod
180
+
181
+ if right_precision is not None:
182
+ if self.right_repeat is None:
183
+ # right terminates
184
+ right: str = ''.join(char_set[digit] for digit in self.right_preperiod)
185
+ else:
186
+ # right has repeating digits
187
+ right: str = ...
188
+ else:
189
+ repetend: str = ''.join(char_set[digit] for digit in self.right_repetend) if len(self.right_repetend) != 0 else '0'
190
+ preperiod: str = ''.join(char_set[digit] for digit in self.right_preperiod)
191
+ right: str = preperiod + '(' + repetend + ')'
192
+
193
+ return f'{sign}{left}.{right}'
194
+
195
+ def round_expansion(integral, fractional, radix, tie):
196
+ 'round a positional number'
197
+ twice = 2 * remainder
198
+
199
+ if twice < divisor:
200
+ # round down/do nothing
201
+ return integral, fractional_digits, None
202
+ elif twice == divisor:
203
+ # a tie. like rounding 0.95 to 1 decimal digit. you have to choose a rule
204
+ match tie:
205
+ case 'up': fractional_digits[-1] += 1
206
+ case 'down': fractional_digits[-1] += 0
207
+ case 'even': fractional_digits[-1] += fractional_digits[-1] % 2 == 1
208
+ case 'odd': fractional_digits[-1] += fractional_digits[-1] % 2 == 0
209
+ elif twice > divisor:
210
+ fractional_digits[-1] += 1
211
+
212
+ # propagate the addition
213
+ for i in range(fractional_digit_count - 1, 0, -1):
214
+ if fractional_digits[i] >= radix:
215
+ fractional_digits[i] = 0
216
+ fractional_digits[i - 1] += 1
217
+ if fractional_digits[0] >= radix:
218
+ integral += 1
219
+ '''
220
+ def rational_to_scientific(rational: Rational, precision: int, radix: int = 10, exponent_marker: str = 'e', char_set: str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') -> str:
221
+ 'stringify a rational number to scientific format (e.g. 1/3 → +3.(3)e-1)'
222
+
223
+ if rational == 0:
224
+ return '0' + exponent_marker + '0'
225
+
226
+ # normalize significand and exponent so that 1 <= significand < radix
227
+ sig: Rational = abs(rational)
228
+ exp: int = 0
229
+ while not 1 <= sig:
230
+ sig *= radix
231
+ exp -= 1
232
+ while not sig < radix:
233
+ sig /= radix
234
+ exp += 1
235
+
236
+ # now we just need to convert sig rational to digits, and exponent integer to digits
237
+ sig_sign = '' if rational == 0 else ('-' if rational < 0 else '+').lstrip('+')
238
+ sig = rational_to_digits(sig, fractional_precision = precision - 1, radix = radix, char_set = char_set)
239
+ exp_sign = '' if exp == 0 else ('-' if exp < 0 else '+')
240
+ exp = integral_to_digits(exp, radix = radix, char_set = char_set).lstrip('+')
241
+
242
+ return sig_sign + sig + exponent_marker + exp_sign + exp
243
+ '''
daatypes/float.py ADDED
@@ -0,0 +1,232 @@
1
+ import daacorations, math, builtins
2
+ from numbers import Rational
3
+ from fractions import Fraction
4
+ from dataclasses import dataclass
5
+ def xor(a, b): return (a and b) or (not(a or b))
6
+
7
+ def fraction_to_radix(numerator: int, denominator: int, *,
8
+ radix: int,
9
+ alphabet: str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
10
+ fractional_digit_count: int = 99) -> str:
11
+
12
+ print(radix, numerator, denominator)
13
+
14
+ assert isinstance(numerator, int)
15
+ assert isinstance(denominator, int)
16
+
17
+ positive = xor(numerator >= 0, denominator >= 0)
18
+ sign = '' if positive else '-'
19
+
20
+ integral, fractional = divmod(abs(numerator), abs(denominator))
21
+
22
+ if integral == 0:
23
+ integral_str = '0'
24
+ else:
25
+ integral_digits: list[str] = []
26
+ while integral:
27
+ integral_digits.append(alphabet[integral % radix])
28
+ integral //= radix
29
+ integral_str = ''.join(reversed(integral_digits))
30
+
31
+ if fractional == 0:
32
+ return sign + integral_str
33
+
34
+ seen: dict[int, int] = dict()
35
+ fractional_digits: list[str] = list()
36
+
37
+ for _ in range(fractional_digit_count):
38
+ if not fractional:
39
+ break
40
+
41
+ if fractional in seen:
42
+ # repeating pattern
43
+ index = seen[fractional]
44
+ return sign + integral_str + '.' + ''.join(fractional_digits[:index]) + '(' + ''.join(fractional_digits[index:]) + ')'
45
+
46
+ seen[fractional] = len(fractional_digits)
47
+
48
+ fractional *= radix
49
+ digit = fractional // denominator
50
+ fractional %= denominator
51
+ fractional_digits.append(alphabet[digit])
52
+ else:
53
+ return sign + integral_str + '.' + ''.join(fractional_digits) + '…'
54
+
55
+ return sign + integral_str + '.' + ''.join(fractional_digits)
56
+
57
+ @dataclass(kw_only = True)
58
+ class Float(Rational):
59
+ """store a rational number in scientific notation as a floating-point number
60
+
61
+ example
62
+ -------
63
+ significand * radix ** (exponent - precision + 1)
64
+ S.SSSSSS * RR ^ (EE - P + 1)
65
+ 1.234567 * 10 ^ (89 - 7 + 1)
66
+
67
+ notes to myself
68
+ ---------------
69
+ when printing to another radix, if input radix and output radix are coprime, you need to specify precision to the equivalent of the input radix.
70
+ """
71
+ radix: int
72
+ precision: int
73
+ significand: int
74
+ exponent: int
75
+
76
+ @property
77
+ def numerator(self) -> int:
78
+ return self.significand * self.radix ** max(0, self.exponent - self.precision + 1)
79
+
80
+ @property
81
+ def denominator(self) -> int:
82
+ return self.radix ** max(0, self.precision - 1 - self.exponent)
83
+
84
+ @classmethod
85
+ def from_str(cls, string: str, *, radix: int = 10, precision: None | int = None, exponent_marker: str = 'e') -> Float:
86
+ 'construct a Float from a string. radix=10 by default (like builtins.int). precision is inferred.'
87
+ # '-0,1.2,3E-4,5'
88
+ string = string.replace(',', '').lower()
89
+ # '-01.23e-45'
90
+ significand_str, exponent_str = string.split(exponent_marker, 1) if exponent_marker in string else (string, '0')
91
+ # '-01.23', '-45'
92
+ negative = significand_str.startswith('-')
93
+ digits = significand_str.lstrip('+-0')
94
+ # -ve, '1.23', '-45'
95
+ point = digits.find('.') if '.' in digits else len(digits)
96
+ digits = digits.replace('.', '')
97
+ # -ve, '123', point=1, '-45'
98
+
99
+ precision = len(digits) if precision is None else precision
100
+ significand = int(('-' if negative else '') + digits, base=radix)
101
+ exponent = int(exponent_str, base=radix) + point - 1
102
+
103
+ return cls(radix=radix, precision=precision, significand=significand, exponent=exponent)
104
+
105
+ @classmethod
106
+ def from_rational(cls, rational: Rational, *, radix: int, precision: int) -> Float:
107
+ signum = (rational > 0) - (rational < 0)
108
+
109
+ significand = abs(rational)
110
+ exponent = 0
111
+
112
+ # get exponent
113
+ while significand >= radix:
114
+ exponent += 1
115
+ significand /= radix
116
+
117
+ # get significand
118
+
119
+ significand = Fixed.from_rational(significand)
120
+
121
+ return cls(radix=radix, precision=precision, significand=significand, exponent=exponent)
122
+
123
+ def __pos__(self): return Float.from_rational(+Fraction(self))
124
+ def __neg__(self): return Float.from_rational(-Fraction(self))
125
+ def __abs__(self): return Float.from_rational(abs(Fraction(self)))
126
+ def __ceil__(self): return Float.from_rational(math.ceil(Fraction(self)))
127
+ def __floor__(self): return Float.from_rational(math.floor(Fraction(self)))
128
+ def __round__(self): return Float.from_rational(round(Fraction(self)))
129
+ def __trunc__(self): return Float.from_rational(math.trunc(Fraction(self)))
130
+ def __floordiv__(self, other): return Float.from_rational(Fraction(self) // Fraction(other))
131
+ def __mod__(self, other): return Float.from_rational(Fraction(self) % Fraction(other))
132
+ def __le__(self, other): return Fraction(self) <= Fraction(other)
133
+ def __lt__(self, other): return Fraction(self) < Fraction(other)
134
+ def __add__(self, other): return Float.from_rational(Fraction(self) + Fraction(other))
135
+ def __mul__(self, other): return Float.from_rational(Fraction(self) * Fraction(other))
136
+ def __truediv__(self, other): return Float.from_rational(Fraction(self) / Fraction(other))
137
+ def __pow__(self, other): return Float.from_rational(Fraction(self) ** Fraction(other))
138
+ def __rfloordiv__(other, self): return Float.from_rational(Fraction(self) // Fraction(other))
139
+ def __radd__(other, self): return Float.from_rational(Fraction(self) + Fraction(other))
140
+ def __rmul__(other, self): return Float.from_rational(Fraction(self) * Fraction(other))
141
+ def __rmod__(other, self): return Float.from_rational(Fraction(self) % Fraction(other))
142
+ def __rpow__(other, self): return Float.from_rational(Fraction(self) ** Fraction(other))
143
+ def __rtruediv__(other, self): return Float.from_rational(Fraction(self) / Fraction(other))
144
+
145
+ def as_fraction(self) -> Fraction:
146
+ return Fraction(self)
147
+
148
+ def __float__(self) -> builtins.float:
149
+ return builtins.float(self.as_fraction())
150
+
151
+ def __str__(self, *, radix: int = 10, exponent_marker: str = 'e', alphabet: str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') -> str:
152
+ return fraction_to_radix(
153
+ numerator = self.numerator,
154
+ denominator = self.denominator,
155
+ radix = radix,
156
+ alphabet = alphabet)
157
+
158
+ str = __str__
159
+
160
+ __repr__ = daacorations.pretty_repr
161
+
162
+ def ieee_binary(bits: int) -> type:
163
+ match bits:
164
+ case 16: precision = 11; emin = - 14; emax = 15
165
+ case 32: precision = 24; emin = - 126; emax = 127
166
+ case 64: precision = 53; emin = -1022; emax = 1023
167
+ case _:
168
+ if bits < 128 or bits % 32 != 0:
169
+ raise ValueError('IEEE defines interchange formats for bits: 16, 32, 64, and multiples of 32 ≥128')
170
+
171
+ exponent_digits = round(4 * math.log2(bits)) - 13
172
+ precision = bits - exponent_digits
173
+ emax = 2 ** (exponent_digits - 1) - 1
174
+ emin = 1 - emax
175
+
176
+ class IEEE754Binary(Float):
177
+ 'an IEEE 754 binary float'
178
+
179
+ def __init__(self, significand: int, exponent: int):
180
+ super().__init__(radix=2, precision=precision, significand=significand, exponent=exponent)
181
+
182
+ @classmethod
183
+ def from_str(cls, string) -> IEEE754Binary:
184
+ return super().from_str(string, radix = 2, precision = precision)
185
+
186
+ return IEEE754Binary, emin, emax
187
+
188
+ def ieee_decimal(bits: int) -> type:
189
+ match bits:
190
+ case 32: precision = 7; emin = - 95; emax = 96
191
+ case 64: precision = 16; emin = -383; emax = 384
192
+ case _:
193
+ if bits < 128 or bits % 32 != 0:
194
+ raise ValueError('IEEE defines interchange formats for bits: 32, 64, and multiples of 32 ≥128')
195
+
196
+ precision = 9 * (bits // 32) - 2
197
+ emax = 3 * 2 ** ((2 * (bits // 32) + 4) - 1)
198
+ emin = 1 - emax
199
+
200
+ class IEEE754Decimal(Float):
201
+ 'an IEEE 754 decimal float'
202
+
203
+ def __init__(self, significand: int, exponent: int):
204
+ super().__init__(radix=10, precision=precision, significand=significand, exponent=exponent)
205
+
206
+ @classmethod
207
+ def from_str(cls, string, *, radix = 10) -> IEEE754Decimal:
208
+ return super().from_str(string, radix = radix, precision = precision)
209
+
210
+ return IEEE754Decimal, emin, emax
211
+
212
+ f16 = ieee_binary( 16)
213
+ f32 = ieee_binary( 32)
214
+ f64 = ieee_binary( 64)
215
+ f128 = ieee_binary(128)
216
+ f256 = ieee_binary(256)
217
+
218
+ d32 = ieee_decimal( 32)
219
+ d64 = ieee_decimal( 64)
220
+ d128 = ieee_decimal(128)
221
+
222
+
223
+ '''
224
+ f16:
225
+ 0 00000 0000000000
226
+ False/True 00001–11110 0000000000
227
+ −/+ [−14, +15] [0/2E10, 1023/2E10]
228
+
229
+ d32:
230
+ 0 000 0000000
231
+ −/+ −95, +96] [0/1E7, 9999999/1E7]
232
+ '''
daatypes/int.py ADDED
@@ -0,0 +1,4 @@
1
+ from numbers import Integral
2
+
3
+ class Int(Integral):
4
+ ...
daatypes/interval.py ADDED
@@ -0,0 +1,5 @@
1
+ import daacorations
2
+ from numbers import Number
3
+
4
+ class Interval(Number):
5
+ __repr__ = daacorations.pretty_repr
daatypes/monzo.py ADDED
@@ -0,0 +1,286 @@
1
+ import collections, math, daacorations
2
+ from collections.abc import Sequence, MutableSequence, Mapping, MutableMapping, Iterable, Hashable, Container
3
+ from itertools import pairwise, cycle
4
+ from numbers import Integral, Rational
5
+ from frozendefaultdict import frozendefaultdict
6
+ from fractions import Fraction
7
+ from typing import Literal
8
+ from functools import cached_property
9
+ from collections import defaultdict
10
+
11
+ class Wheel(collections.abc.Iterator):
12
+ """a wheel for generating primes. its iterator returns the residues of the given wheel size. you get diminishing returns as you go up in size:
13
+
14
+ >>> primes = [2,3,5,7,11,13,17,19,23]
15
+ >>> for i in range(len(primes)):
16
+ >>> size = math.prod(primes[:i])
17
+ >>> wheel_count = Wheel(size).cycle_size
18
+ >>> naïve_count = size
19
+ >>> efficiency = wheel_count / naïve_count
20
+ >>> print(size, f'{wheel_count}/{naïve_count}={efficiency:.2%}')
21
+ >>>
22
+ 1 1/1=100.00%
23
+ 2 1/2=50.00%
24
+ 6 2/6=33.33%
25
+ 30 8/30=26.67%
26
+ 210 48/210=22.86%
27
+ 2310 480/2310=20.78%
28
+ 30030 5760/30030=19.18%
29
+ 510510 92160/510510=18.05%
30
+ 9699690 1658880/9699690=17.10%
31
+ 223092870 36495360/223092870=16.36%
32
+ """
33
+
34
+ @staticmethod
35
+ def _generate_steps(size: int) -> Sequence[int]:
36
+ candidates = tuple(filter(lambda candidate: math.gcd(candidate, size) == 1, range(size)))
37
+ return [b - a for a, b in pairwise(candidates)] + [(candidates[0] - candidates[-1]) % size]
38
+
39
+ def __init__(self, factors: collections.abc.Iterable[int]):
40
+ 'if you pass non-primes as factors, you wont be able to track them at the start of your generator. thats on you, idiot. sorry, harsh words, sorry but if you do that youre kinda dumb.. a bit'
41
+ size = math.lcm(*factors)
42
+
43
+ if math.prod(factors) != size:
44
+ raise ValueError('factors must be coprime!')
45
+
46
+ self.size: int = size
47
+ self.candidate: int = 1
48
+
49
+ steps: Sequence[int] = Wheel._generate_steps(size)
50
+ self.cycle: cycle[int] = cycle(steps)
51
+ self.cycle_size: int = len(steps)
52
+
53
+ # initialize candidate properly
54
+ #for factor in factors: # indexitis
55
+ # next(self)
56
+
57
+ def __iter__(self):
58
+ return self
59
+
60
+ def __next__(self) -> int:
61
+ self.candidate += next(self.cycle)
62
+ return self.candidate
63
+
64
+ __repr__ = daacorations.pretty_repr
65
+
66
+ class PrimesIterableContainer(Iterable, Container):
67
+ """a singleton class representing the infinite sequence of prime numbers. you can do things like:
68
+
69
+ Primes = PrimeSequence()
70
+
71
+ Primes[0] == 2
72
+ Primes[1] == 3
73
+ Primes[2] == 5
74
+ Primes[3] == 7
75
+
76
+ assert 5 in Primes
77
+ assert 13 in Primes
78
+
79
+ primes = Primes[:10]
80
+
81
+ for prime in Primes[:100]:
82
+ print(prime)
83
+
84
+ uses a 2x3 wheel by default, thus only testing 6*1-1, 6*1+1, 6*2-1, 6*2+1, 6*3-1, 6*3+1, … for generation. larger wheels like 2x3x5, 2x3x5x7, … can be used for better efficiency (see Wheel class)
85
+ """
86
+
87
+ _cache: MutableSequence[Integral] = [2, 3]
88
+
89
+ def __init__(self, wheel_factors: Iterable[int] = [2, 3]):
90
+ self.wheel: Wheel = Wheel(wheel_factors)
91
+ self._cache.extend(wheel_factors[len(self._cache):])
92
+
93
+ def _extend_cache_by(self, count: int = 1) -> None:
94
+ 'grow cache by a certain .count of primes'
95
+
96
+ while count > 0:
97
+ candidate = next(self.wheel)
98
+
99
+ # "is candidate prime?"
100
+ if all(candidate % prime != 0 for prime in self._cache):
101
+ count -= 1
102
+ self._cache.append(candidate)
103
+
104
+ def __getitem__(self, index: slice | int):
105
+ if isinstance(index, slice):
106
+ self._extend_cache_by(index.stop - len(self._cache))
107
+ elif isinstance(index, int):
108
+ if index < 0:
109
+ raise ValueError('cannot use negative indices on an infinite sequence')
110
+ self._extend_cache_by(index + 1 - len(self._cache))
111
+ else:
112
+ raise TypeError('index must be either slice or int')
113
+
114
+ return self._cache[index]
115
+
116
+ def __iter__(self):
117
+ i = 0
118
+
119
+ while True:
120
+ yield self[i := i + 1]
121
+
122
+ @classmethod
123
+ def __contains__(cls, number: Natural) -> bool:
124
+ # number is known (from cache) to be prime
125
+ if number in cls._cache:
126
+ return True
127
+
128
+ # number is within cache
129
+ if cls._cache[-1] >= number:
130
+ return number in cls._cache
131
+
132
+ # number is not within cache. perform divisibility check
133
+ # this way, cache is generated up to ≥⌊√n⌋ instead of ≥n
134
+ limit: int = math.floor(math.sqrt(number))
135
+
136
+ for prime in Primes:
137
+ if prime > limit:
138
+ return True
139
+ if number % prime == 0:
140
+ return False
141
+
142
+ def index(self, number):
143
+ if number not in self:
144
+ raise numberError(f'{number} is not prime')
145
+
146
+ while self._cache[-1] < number:
147
+ self._extend_cache_by(1)
148
+
149
+ return self._cache.index(number)
150
+
151
+ __repr__ = daacorations.pretty_repr
152
+
153
+ Primes = PrimesIterableContainer()
154
+
155
+ '''
156
+ # here we dont subclass Rational because surds are not rational!
157
+ class Surd(Real):
158
+ 'like how Integral is a sub(Natural, Natural) pair, and Rational is a div(Integral, Integral) pair, Surd is a root(Integral, Integral) pair. its cousin is the log(Integral, Integral) pair, which i have not named yet. the equivalence class is op(a, b) = op(c, d). so, for example, 2√2 = 4√4'
159
+
160
+ def __init__(self, base: Rational, degree: Rational):
161
+ self.base = base
162
+ self.degree = degree
163
+
164
+ def __float__(self) -> float:
165
+ return self.base ** (1 / self.degree)
166
+
167
+ def __mul__(self, other) -> Surd:
168
+ return self.base
169
+ '''
170
+
171
+ class Monzo(Hashable, Sequence):#, Rational):
172
+ """a datatype that represents rational number stored as prime factors — conceptually as a sparse sequence, implemented as a mapping, but has the interface of a sequence :)
173
+
174
+ examples:
175
+ Monzo(2) = [1⟩ = {0: 1} = 2¹
176
+ Monzo(3) = [0 1⟩ = {1: 1} = 3¹
177
+ Monzo(4) = [2⟩ = {0: 2} = 2²
178
+ Monzo(5) = [0 0 1⟩ = {2: 1} = 5¹
179
+ """
180
+
181
+ def __init__(self, factors: HashableMapping, sign: Literal[-1, 0, +1] = 1):
182
+ self.factors: HashableMapping = factors
183
+ self.sign: Literal[-1, 0, +1] = sign
184
+
185
+ @cached_property
186
+ def numerator(self) -> Integral:
187
+ return self.sign * math.prod(Primes[prime_index] ** exponent for prime_index, exponent in self.factors.items() if exponent > 0)
188
+
189
+ @cached_property
190
+ def denominator(self) -> Integral:
191
+ return math.prod(Primes[prime_index] ** -exponent for prime_index, exponent in self.factors.items() if exponent < 0)
192
+
193
+ @cached_property
194
+ def prime_factors(self) -> Mapping[Integral, Integral]:
195
+ return frozendefaultdict.from_items(int, ((Primes[prime_index], exponent) for prime_index, exponent in self.factors.items()))
196
+
197
+ # to support Sequence interface
198
+ def __getitem__(self, index: int) -> int:
199
+ return self.factors[index] if index in self.factors else 0
200
+ def __len__(self) -> Cardinal:
201
+ keys = self.factors.keys()
202
+ return max(keys) + 1 if len(keys) > 0 else 1
203
+ def __iter__(self):
204
+ yield from (self.factors[index] for index in range(len(self)))
205
+
206
+ # to support Rational interface
207
+ def __add__(self, other) -> Monzo:
208
+ 'a / b + c / d = (a * d + b * c) / (b * d)'
209
+ a, b, c, d = self.numerator, self.denominator, other.numerator, other.denominator
210
+ return cls.from_parts(a * d + b * c, b * d)
211
+ def __eq__(self, other) -> bool:
212
+ 'a / b = c / d'
213
+ a, b, c, d = self.numerator, self.denominator, other.numerator, other.denominator
214
+ return a * d == b * c
215
+ def __float__(self) -> float:
216
+ return self.numerator / self.denominator
217
+
218
+ @classmethod
219
+ def from_prime_factors(cls, prime_factors: Mapping, *args, **kwargs) -> Monzo:
220
+ return cls(frozendefaultdict.from_items(int, ((Primes.index(factor), exponent) for factor, exponent in prime_factors.items())), *args, **kwargs)
221
+
222
+ @staticmethod
223
+ def _prime_factorize(number: Natural) -> HashableMapping[int, int]:
224
+ factors: MutableMapping = defaultdict(int)
225
+
226
+ prime_index = 0
227
+
228
+ while number > 1:
229
+ prime = Primes[prime_index]
230
+
231
+ if number % prime == 0:
232
+ number /= prime
233
+ if prime_index in factors:
234
+ factors[prime_index] += 1
235
+ else:
236
+ factors[prime_index] = 1
237
+ else:
238
+ prime_index += 1
239
+
240
+ return frozendefaultdict.from_items(int, factors.items())
241
+
242
+ @classmethod
243
+ def from_parts(cls, numerator: Integral, denominator: Integral) -> Monzo:
244
+ sign: Integral = int(math.copysign(1.0, numerator * denominator))
245
+
246
+ numerator = Monzo._prime_factorize(numerator)
247
+ denominator = Monzo._prime_factorize(denominator)
248
+
249
+ factors: MutableMapping = defaultdict(int, numerator)
250
+
251
+ for prime_factor, exponent in denominator.items():
252
+ if prime_factor in factors:
253
+ factors[prime_factor] -= exponent
254
+ else:
255
+ factors[prime_factor] = -exponent
256
+
257
+ return cls(frozendefaultdict.from_items(int, factors.items()), sign)
258
+
259
+ @classmethod
260
+ def from_rational(cls, number: Rational) -> Monzo:
261
+ return cls.from_parts(number.numerator, number.denominator)
262
+
263
+ @classmethod
264
+ def from_sequence(cls, exponents: Sequence[Integral]) -> Monzo:
265
+ 'construct from a sequence. has to use reversed, len, and indexing'
266
+ # because we dont want [1⟩ from [1 0 0], not [1 0 0⟩
267
+ trailing_zero_count: int = 0
268
+ for exponent in reversed(exponents):
269
+ if exponent != 0:
270
+ break
271
+ trailing_zero_count += 1
272
+
273
+ items = enumerate(exponents if trailing_zero_count == 0 else exponents[:-trailing_zero_count])
274
+
275
+ return cls(frozendefaultdict.from_items(int, items))
276
+
277
+ def __hash__(self) -> int:
278
+ return hash(Fraction(self))
279
+
280
+ __repr__ = daacorations.pretty_repr
281
+
282
+ def __str__(self) -> str:
283
+ return '[' + ' '.join(str(exponent) for exponent in self) + '⟩'
284
+
285
+ Rational.register(Monzo)
286
+
daatypes/octo.py ADDED
@@ -0,0 +1,29 @@
1
+ from numbers import Number
2
+ from .vector import Vector
3
+
4
+ class Octo(Number, Vector):
5
+ 'an octonion'
6
+
7
+ def __init__(self, e0, e1, e2, e3, e4, e5, e6, e7):
8
+ self.e0 = e0
9
+ self.e1 = e1
10
+ self.e2 = e2
11
+ self.e3 = e3
12
+ self.e4 = e4
13
+ self.e5 = e5
14
+ self.e6 = e6
15
+ self.e7 = e7
16
+
17
+ @classmethod
18
+ def from_complex(cls, c0, c1, c2, c3):
19
+ ...
20
+
21
+ @classmethod
22
+ def from_quaternion(cls, q0, q1):
23
+ ...
24
+
25
+ def as_real_matrix(self):
26
+ ...
27
+
28
+ def as_complex_matrix(self):
29
+ ...
daatypes/polar.py ADDED
@@ -0,0 +1,10 @@
1
+ from numbers import Complex, Rational
2
+ from dataclasses import dataclass
3
+
4
+ @dataclass
5
+ class Polar(Complex):
6
+ magnitude: Rational
7
+ angle: Rational
8
+
9
+
10
+
daatypes/qint.py ADDED
@@ -0,0 +1,4 @@
1
+ from numbers import Rational
2
+
3
+ class QInt(Rational):
4
+ ...
daatypes/quat.py ADDED
@@ -0,0 +1,60 @@
1
+ import math
2
+ from numbers import Number, Real, Complex
3
+ from dataclasses import dataclass
4
+ from daacorations import pretty_repr
5
+
6
+ @dataclass
7
+ class Quat(Number):
8
+ 'a quaternion. a vector of 4 real numbers with special multiplication rules'
9
+
10
+ w: Real
11
+ x: Real
12
+ y: Real
13
+ z: Real
14
+
15
+ # @property
16
+ # def real(self) -> float:
17
+ # return self.w
18
+ #
19
+ # @property
20
+ # def imag(self) -> tuple[float, float, float]:
21
+ # return self.x, self.y, self.z
22
+
23
+ def norm(self) -> Real:
24
+ #return math.hypot(self.w, self.x, self.y, self.z)
25
+ return math.sqrt(self.w*self.w + self.x*self.x + self.y*self.y + self.z*self.z)
26
+ __abs__ = norm
27
+
28
+ def unit(self) -> Real:
29
+ norm = self.norm()
30
+ return type(self)(self.w/norm, self.x/norm, self.y/norm, self.z/norm)
31
+
32
+ @classmethod
33
+ def from_complex(cls, a: Complex, b: Complex) -> Quat:
34
+ 'construct a quaternion from a pair of complex numbers, by cayley dickson construction'
35
+ return cls(a.real, a.imag, b.real, b.imag)
36
+
37
+ __repr__ = pretty_repr
38
+
39
+ def __add__(self, other) -> Quat:
40
+ return type(self)(self.w + other.w, self.x + other.x, self.y + other.y, self.z + other.z)
41
+
42
+ def __sub__(self, other) -> Quat:
43
+ return type(self)(self.w - other.w, self.x - other.x, self.y - other.y, self.z - other.z)
44
+
45
+ def __mul__(self, other) -> Quat:
46
+ return
47
+
48
+ def __str__(self) -> str:
49
+ return f'({self.w} + {self.x}i + {self.y}j + {self.z}k)'
50
+
51
+ def as_real_matrix(self):
52
+ return (( self.w, -self.x, -self.y, -self.z),
53
+ ( self.x, self.w, -self.z, self.y),
54
+ ( self.y, self.z, self.w, -self.x),
55
+ ( self.z, -self.y, self.x, self.w))
56
+
57
+ def as_complex_matrix(self):
58
+ return ((complex( self.w, self.x), complex(self.y, self.z)),
59
+ (complex(-self.y, self.z), complex(self.w, -self.x)))
60
+
daatypes/real.py ADDED
@@ -0,0 +1,16 @@
1
+ import numbers
2
+ from dataclasses import dataclass
3
+
4
+ @dataclass
5
+ class Real(numbers.Real):
6
+ value: Real
7
+
8
+ def norm(self) -> Real:
9
+ return abs(self.value)
10
+
11
+ def unit(self) -> Real:
12
+ return (self.value > 0) - (self.value < 0)
13
+
14
+
15
+
16
+
daatypes/uint.py ADDED
@@ -0,0 +1,4 @@
1
+ from numbers import Integral
2
+
3
+ class UInt(Integral):
4
+ ...
daatypes/uqint.py ADDED
@@ -0,0 +1,4 @@
1
+ from numbers import Rational
2
+
3
+ class UQInt(Rational):
4
+ ...
daatypes/vector.py ADDED
@@ -0,0 +1,33 @@
1
+ import math
2
+ from collections.abc import Sequence, Iterable
3
+ from numbers import Real
4
+
5
+ class Vector(Sequence):
6
+ 'an immutable vector'
7
+ def __init__(self, iterable: Iterable):
8
+ self.sequence: tuple = tuple(iterable)
9
+
10
+ def norm(self, power = 2) -> Real:
11
+ if power == 2:
12
+ return math.hypot(self.sequence)
13
+ else:
14
+ return sum(abs(x) ** power for x in self) ** (1 / power)
15
+ __abs__ = norm
16
+
17
+ def unit(self):
18
+ return self / self.norm()
19
+
20
+ # Sequence interface methods
21
+ def __len__(self):
22
+ return len(self.sequence)
23
+ def __getitem__(self, index):
24
+ return self.sequence[index]
25
+
26
+ def __mul__(self, other):
27
+ if isinstance(other, Real):
28
+ return type(self)(x * other for x in self)
29
+
30
+ def __truediv__(self, other):
31
+ if isinstance(other, Real):
32
+ return type(self)(x / other for x in self)
33
+
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: daatypes
3
+ Version: 0.1.0
4
+ Summary: i simulate datatypes that i find useful
5
+ Project-URL: Homepage, https://github.com/deftasparagusanaconda/daatypes
6
+ Project-URL: Repository, https://github.com/deftasparagusanaconda/daatypes
7
+ Project-URL: Issues, https://github.com/deftasparagusanaconda/daatypes/issues
8
+ Author: deftasparagusanaconda
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: math,numerical
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+
22
+ a collection of datatypes (or, rather, simulations thereof) that i find useful
@@ -0,0 +1,21 @@
1
+ daatypes/__init__.py,sha256=G2On_8PV0cXu5Ygk5QENLzgeDgcmNnOrH-hIjbJ18DU,2258
2
+ daatypes/ball.py,sha256=ezj8sxLNvImTnnruhOXu7xyd8PeEnJDoxSd3of3sJyI,647
3
+ daatypes/cf.py,sha256=RSCQ2MqYLd21Xs3IeBvlneQUMCc3IVtTZACCrm2acy8,2517
4
+ daatypes/comp.py,sha256=Y-TA15E7bF5DM2CeKaRrOJAkStZnAuw1KouODkQmuTM,1473
5
+ daatypes/fixed.py,sha256=ISS9mRVxJM0RRN63nf6tfQCsoJCLIugDu74I8DCMGCs,9475
6
+ daatypes/float.py,sha256=qoDrvFRJFLCCmyZ2SIck7Yjza3PksiOY_TQ3nl716mU,8953
7
+ daatypes/int.py,sha256=1OlqFY3fuVdq9pwAz0FG0gx4YO7Yv-pDXGfS9jeq4ZE,59
8
+ daatypes/interval.py,sha256=Ug-A-vvZXubXK6VrimMpbs15XhXC1AIrXTNXcDTqqjo,112
9
+ daatypes/monzo.py,sha256=uZPkolMfU1iRaAtvnAE3Nb3uTyJsvSMm9e2qQOFbeZo,10392
10
+ daatypes/octo.py,sha256=5INSYFpg6IWA1Ub0194EeuLCbV4dLP6nGgm0www2xoA,560
11
+ daatypes/polar.py,sha256=MwzMLR8I8lbaBt3HNtkvB0Ad6AZHWj625shsAY-avTQ,157
12
+ daatypes/qint.py,sha256=MMhrnfXK_51-3HzbmaaqmxnlZCddjs5igTnYS0SdgSw,60
13
+ daatypes/quat.py,sha256=eIOeG1zYjre7TgooBdBYSVazoc7NRmdTzTReawQftlw,1948
14
+ daatypes/real.py,sha256=riUSsTHuLdGVJEu3UZ2wrnAPtqICVPaJKk179zkv2bE,271
15
+ daatypes/uint.py,sha256=7QDbriz1dv6d2YzJc7b0wyQGtMa-ZzdO7Bj0fv4_iXU,60
16
+ daatypes/uqint.py,sha256=e_W80VNQx2Xn2KMYyenuHojw1jrjcrTaU5gu62P3Vps,61
17
+ daatypes/vector.py,sha256=LvOJ4-srjkI-vuWp9vj3l0E0QY8T2nxGgKWgVI7NsCc,925
18
+ daatypes-0.1.0.dist-info/METADATA,sha256=fjfl770bBtMvaZzsUoFyeFEUexbyxsWIzWVGK4cQMMM,960
19
+ daatypes-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
20
+ daatypes-0.1.0.dist-info/licenses/LICENSE,sha256=VB2xlcQdtOxvalPfPY4FykGdH2Aqqjr0NO9YeF_3cyk,1078
21
+ daatypes-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lalremruata Chongmang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.