decoint 0.1.0__tar.gz
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.
- decoint-0.1.0/LICENSE +21 -0
- decoint-0.1.0/PKG-INFO +23 -0
- decoint-0.1.0/README.md +10 -0
- decoint-0.1.0/decoint/__init__.py +23 -0
- decoint-0.1.0/decoint/arithmetic.py +181 -0
- decoint-0.1.0/decoint/constants.py +6 -0
- decoint-0.1.0/decoint/decorated_arithmetic.py +98 -0
- decoint-0.1.0/decoint/decorated_functions.py +566 -0
- decoint-0.1.0/decoint/decorated_interval.py +377 -0
- decoint-0.1.0/decoint/decorations.py +18 -0
- decoint-0.1.0/decoint/functions.py +564 -0
- decoint-0.1.0/decoint/interval.py +546 -0
- decoint-0.1.0/decoint/rounding.py +312 -0
- decoint-0.1.0/decoint.egg-info/PKG-INFO +23 -0
- decoint-0.1.0/decoint.egg-info/SOURCES.txt +18 -0
- decoint-0.1.0/decoint.egg-info/dependency_links.txt +1 -0
- decoint-0.1.0/decoint.egg-info/requires.txt +1 -0
- decoint-0.1.0/decoint.egg-info/top_level.txt +1 -0
- decoint-0.1.0/pyproject.toml +24 -0
- decoint-0.1.0/setup.cfg +4 -0
decoint-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 arjavsharma91
|
|
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.
|
decoint-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: decoint
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An IEEE 1788-2015 compliant interval arithmetic library
|
|
5
|
+
Author-email: Arjav Sharma <arjav.sharma.91@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/arjavsharma91/IEEE-1788.1-2017-Interval-Arithmetic
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: gmpy2>=2.1.0
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# IEEE-1788.1-2017 Simplified Standard For Interval Arithmetic Python Implementation
|
|
15
|
+
|
|
16
|
+
## Key Features
|
|
17
|
+
|
|
18
|
+
* **IEEE 1788.1-2017 Compliant:** Tested against the official Interval Test Framework (ITF) suite.
|
|
19
|
+
* **Rigorous Enclosure:** Guarantees interval enclosure using directed rounding modes.
|
|
20
|
+
* **Decorated Intervals:** Complete support for interval decorations (`com`, `dac`, `def`, `trv`, `ill`).
|
|
21
|
+
* **High Precision:** Powered by `gmpy2`'s MPFR bindings for fast, arbitrary-precision floating-point arithmetic.
|
|
22
|
+
* **Full Operator Set:** Includes basic arithmetic, set relations/operations, interval queries, functions, and string parsing.
|
|
23
|
+
|
decoint-0.1.0/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# IEEE-1788.1-2017 Simplified Standard For Interval Arithmetic Python Implementation
|
|
2
|
+
|
|
3
|
+
## Key Features
|
|
4
|
+
|
|
5
|
+
* **IEEE 1788.1-2017 Compliant:** Tested against the official Interval Test Framework (ITF) suite.
|
|
6
|
+
* **Rigorous Enclosure:** Guarantees interval enclosure using directed rounding modes.
|
|
7
|
+
* **Decorated Intervals:** Complete support for interval decorations (`com`, `dac`, `def`, `trv`, `ill`).
|
|
8
|
+
* **High Precision:** Powered by `gmpy2`'s MPFR bindings for fast, arbitrary-precision floating-point arithmetic.
|
|
9
|
+
* **Full Operator Set:** Includes basic arithmetic, set relations/operations, interval queries, functions, and string parsing.
|
|
10
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .interval import Interval
|
|
2
|
+
from .decorated_interval import DecoratedInterval
|
|
3
|
+
from .decorations import Decoration
|
|
4
|
+
|
|
5
|
+
# 2. Fully Tracked Core Arithmetic (Using your decorated module)
|
|
6
|
+
from .decorated_arithmetic import add, sub, mul, div, reciprocal, fma
|
|
7
|
+
|
|
8
|
+
# 3. Tracked Elementary Functions
|
|
9
|
+
from .decorated_functions import (
|
|
10
|
+
exp, log, sqrt, pow_int, sign,
|
|
11
|
+
sin, cos, tan, asin, acos, atan,
|
|
12
|
+
sinh, cosh, tanh, asinh, acosh, atanh,
|
|
13
|
+
abs, atan2, interval_min, interval_max, nth_root, sqr, pow_interval, exp2, exp10, log2, log10, interval_trunc, interval_ceil, interval_floor
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'Interval', 'DecoratedInterval', 'Decoration',
|
|
18
|
+
'add', 'sub', 'mul', 'div', 'reciprocal',
|
|
19
|
+
'exp', 'log', 'sqrt', 'pow_int', 'sign',
|
|
20
|
+
'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
|
|
21
|
+
'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh',
|
|
22
|
+
'abs', 'atan2', 'interval_min', 'interval_max', 'nth_root', 'sqr', 'fma', 'pow_interval', 'exp2', 'exp10', 'log2', 'log10', 'interval_trunc', 'interval_ceil', 'interval_floor'
|
|
23
|
+
]
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from .interval import Interval
|
|
2
|
+
from .rounding import add_down, add_up, sub_down, sub_up, div_down, div_up, mul_down, mul_up, fma_up, fma_down
|
|
3
|
+
from gmpy2 import mpfr, is_infinite, is_signed, sign, context, get_context
|
|
4
|
+
|
|
5
|
+
ctx = get_context()
|
|
6
|
+
ctx.precision = 53
|
|
7
|
+
ctx.emin = -1073
|
|
8
|
+
ctx.emax = 1024
|
|
9
|
+
|
|
10
|
+
def add(x, y) -> Interval:
|
|
11
|
+
x = Interval._coerce(x)
|
|
12
|
+
y = Interval._coerce(y)
|
|
13
|
+
if x.is_empty or y.is_empty:
|
|
14
|
+
return Interval.empty()
|
|
15
|
+
lo = add_down(x.lo, y.lo)
|
|
16
|
+
hi = add_up(x.hi, y.hi)
|
|
17
|
+
return Interval(lo, hi)
|
|
18
|
+
|
|
19
|
+
def sub(x, y) -> Interval:
|
|
20
|
+
x = Interval._coerce(x)
|
|
21
|
+
y = Interval._coerce(y)
|
|
22
|
+
if x.is_empty or y.is_empty:
|
|
23
|
+
return Interval.empty()
|
|
24
|
+
lo = sub_down(x.lo, y.hi)
|
|
25
|
+
hi = sub_up(x.hi, y.lo)
|
|
26
|
+
return Interval(lo, hi)
|
|
27
|
+
|
|
28
|
+
def mul(x, y) -> Interval:
|
|
29
|
+
x = Interval._coerce(x)
|
|
30
|
+
y = Interval._coerce(y)
|
|
31
|
+
if x.is_empty or y.is_empty:
|
|
32
|
+
return Interval.empty()
|
|
33
|
+
|
|
34
|
+
def safe_mul_down(a, b):
|
|
35
|
+
if (a == 0 and is_infinite(b)) or (b == 0 and is_infinite(a)):
|
|
36
|
+
is_neg = is_signed(a) * is_signed(b)
|
|
37
|
+
return mpfr('0') if is_neg else mpfr('-0.0')
|
|
38
|
+
return mul_down(a, b)
|
|
39
|
+
|
|
40
|
+
def safe_mul_up(a, b):
|
|
41
|
+
if (a == 0 and is_infinite(b)) or (b == 0 and is_infinite(a)):
|
|
42
|
+
is_neg = is_signed(a) * is_signed(b)
|
|
43
|
+
return mpfr('0') if is_neg else mpfr('-0.0')
|
|
44
|
+
return mul_up(a, b)
|
|
45
|
+
|
|
46
|
+
p1 = safe_mul_down(x.lo, y.lo)
|
|
47
|
+
p2 = safe_mul_down(x.lo, y.hi)
|
|
48
|
+
p3 = safe_mul_down(x.hi, y.lo)
|
|
49
|
+
p4 = safe_mul_down(x.hi, y.hi)
|
|
50
|
+
|
|
51
|
+
lo = min(p1, p2, p3, p4)
|
|
52
|
+
|
|
53
|
+
q1 = safe_mul_up(x.lo, y.lo)
|
|
54
|
+
q2 = safe_mul_up(x.lo, y.hi)
|
|
55
|
+
q3 = safe_mul_up(x.hi, y.lo)
|
|
56
|
+
q4 = safe_mul_up(x.hi, y.hi)
|
|
57
|
+
|
|
58
|
+
hi = max(q1, q2, q3, q4)
|
|
59
|
+
|
|
60
|
+
return Interval(lo, hi)
|
|
61
|
+
|
|
62
|
+
def reciprocal(x) -> Interval:
|
|
63
|
+
x = Interval._coerce(x)
|
|
64
|
+
if x.is_empty:
|
|
65
|
+
return Interval.empty()
|
|
66
|
+
if x.contains_zero:
|
|
67
|
+
if x.lo == 0 and x.hi == 0:
|
|
68
|
+
return Interval.empty()
|
|
69
|
+
if x.lo == 0:
|
|
70
|
+
return Interval(div_down(mpfr(1), x.hi), mpfr('inf'))
|
|
71
|
+
if x.hi == 0:
|
|
72
|
+
return Interval(mpfr('-inf'), div_up(mpfr(1), x.lo))
|
|
73
|
+
return Interval.entire()
|
|
74
|
+
|
|
75
|
+
return Interval(div_down(mpfr(1), x.hi), div_up(mpfr(1), x.lo))
|
|
76
|
+
|
|
77
|
+
def div(x, y) -> Interval:
|
|
78
|
+
x = Interval._coerce(x)
|
|
79
|
+
y = Interval._coerce(y)
|
|
80
|
+
if x.is_empty or y.is_empty:
|
|
81
|
+
return Interval.empty()
|
|
82
|
+
|
|
83
|
+
if x.is_entire and not y.contains(0):
|
|
84
|
+
return Interval.entire()
|
|
85
|
+
|
|
86
|
+
if y.contains(0):
|
|
87
|
+
if y.hi == 0 and y.lo == 0:
|
|
88
|
+
return Interval.empty()
|
|
89
|
+
if x.hi == 0 and x.lo == 0:
|
|
90
|
+
return Interval(mpfr('0'), mpfr('0'))
|
|
91
|
+
if x.lo >= 0:
|
|
92
|
+
if y.lo == 0:
|
|
93
|
+
return Interval(div_down(x.lo, y.hi), mpfr('inf'))
|
|
94
|
+
elif y.hi == 0:
|
|
95
|
+
return Interval(mpfr('-inf'), div_up(x.lo, y.lo))
|
|
96
|
+
else:
|
|
97
|
+
return Interval.entire()
|
|
98
|
+
elif x.hi <= 0:
|
|
99
|
+
if y.lo == 0:
|
|
100
|
+
return Interval(mpfr('-inf'), div_up(x.hi, y.hi))
|
|
101
|
+
elif y.hi == 0:
|
|
102
|
+
return Interval(div_down(x.hi, y.lo), mpfr('inf'))
|
|
103
|
+
else:
|
|
104
|
+
return Interval.entire()
|
|
105
|
+
else:
|
|
106
|
+
return Interval.entire()
|
|
107
|
+
|
|
108
|
+
# --- CLEAN DIRECT REPLACEMENT FOR mul(x, reciprocal(y)) ---
|
|
109
|
+
if y.lo > 0: # Denominator is strictly positive
|
|
110
|
+
# Lower bound logic
|
|
111
|
+
if x.lo == mpfr('-inf'):
|
|
112
|
+
lo = mpfr('-inf')
|
|
113
|
+
else:
|
|
114
|
+
lo = div_down(x.lo, y.hi if x.lo >= 0 else y.lo)
|
|
115
|
+
|
|
116
|
+
# Upper bound logic
|
|
117
|
+
if x.hi == mpfr('inf'):
|
|
118
|
+
hi = mpfr('inf')
|
|
119
|
+
else:
|
|
120
|
+
hi = div_up(x.hi, y.lo if x.hi >= 0 else y.hi)
|
|
121
|
+
|
|
122
|
+
else: # Denominator is strictly negative (y.hi < 0)
|
|
123
|
+
# Lower bound logic
|
|
124
|
+
if x.hi == mpfr('inf'):
|
|
125
|
+
lo = mpfr('-inf')
|
|
126
|
+
else:
|
|
127
|
+
lo = div_down(x.hi, y.hi if x.hi >= 0 else y.lo)
|
|
128
|
+
|
|
129
|
+
# Upper bound logic
|
|
130
|
+
if x.lo == mpfr('-inf'):
|
|
131
|
+
hi = mpfr('inf')
|
|
132
|
+
else:
|
|
133
|
+
hi = div_up(x.lo, y.lo if x.lo >= 0 else y.hi)
|
|
134
|
+
|
|
135
|
+
return Interval(lo, hi)
|
|
136
|
+
|
|
137
|
+
def evaluate_fma_corner(x, y, z, round_up=False):
|
|
138
|
+
# 1. Handle 0 * inf indeterminate form -> results in 0, so 0 + z = z
|
|
139
|
+
if (x == 0 and is_infinite(y)) or (is_infinite(x) and y == 0):
|
|
140
|
+
return z
|
|
141
|
+
|
|
142
|
+
# 2. Handle true inf - inf indeterminate form
|
|
143
|
+
if is_infinite(x) or is_infinite(y):
|
|
144
|
+
if is_infinite(z):
|
|
145
|
+
prod_neg = (x < 0) != (y < 0)
|
|
146
|
+
z_neg = z < 0
|
|
147
|
+
# If the infinite product's sign opposes z's infinite sign, it's inf - inf
|
|
148
|
+
if prod_neg != z_neg:
|
|
149
|
+
return None # Signal containment explosion
|
|
150
|
+
|
|
151
|
+
# Safe to compute standard hardware rounded FMA
|
|
152
|
+
return fma_up(x, y, z) if round_up else fma_down(x, y, z)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def fma(x, y, z):
|
|
156
|
+
x = Interval._coerce(x)
|
|
157
|
+
y = Interval._coerce(y)
|
|
158
|
+
z = Interval._coerce(z)
|
|
159
|
+
|
|
160
|
+
if x.is_empty or y.is_empty or z.is_empty:
|
|
161
|
+
return Interval.empty()
|
|
162
|
+
|
|
163
|
+
# Evaluate lower bound corner combinations
|
|
164
|
+
v_down = []
|
|
165
|
+
for cx in (x.lo, x.hi):
|
|
166
|
+
for cy in (y.lo, y.hi):
|
|
167
|
+
val = evaluate_fma_corner(cx, cy, z.lo, round_up=False)
|
|
168
|
+
if val is None:
|
|
169
|
+
return Interval.entire()
|
|
170
|
+
v_down.append(val)
|
|
171
|
+
|
|
172
|
+
# Evaluate upper bound corner combinations
|
|
173
|
+
v_up = []
|
|
174
|
+
for cx in (x.lo, x.hi):
|
|
175
|
+
for cy in (y.lo, y.hi):
|
|
176
|
+
val = evaluate_fma_corner(cx, cy, z.hi, round_up=True)
|
|
177
|
+
if val is None:
|
|
178
|
+
return Interval.entire()
|
|
179
|
+
v_up.append(val)
|
|
180
|
+
|
|
181
|
+
return Interval(min(v_down), max(v_up))
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from .interval import Interval
|
|
2
|
+
from .arithmetic import add as bare_add, sub as bare_sub, mul as bare_mul, div as bare_div, reciprocal as bare_reciprocal, fma as bare_fma
|
|
3
|
+
from .decorations import Decoration, combine
|
|
4
|
+
from .decorated_interval import DecoratedInterval
|
|
5
|
+
|
|
6
|
+
def _finalize_decoration(base_dec: Decoration, interval: Interval) -> Decoration:
|
|
7
|
+
if base_dec == Decoration.COM and not interval.is_bounded:
|
|
8
|
+
return Decoration.DAC
|
|
9
|
+
return base_dec
|
|
10
|
+
|
|
11
|
+
def add(x, y):
|
|
12
|
+
x = DecoratedInterval._coerce(x)
|
|
13
|
+
y = DecoratedInterval._coerce(y)
|
|
14
|
+
|
|
15
|
+
if x.is_nai or y.is_nai:
|
|
16
|
+
return DecoratedInterval.new_nai()
|
|
17
|
+
|
|
18
|
+
interval = bare_add(x.interval, y.interval)
|
|
19
|
+
dec = combine(x.decoration, y.decoration)
|
|
20
|
+
dec = _finalize_decoration(dec, interval)
|
|
21
|
+
|
|
22
|
+
return DecoratedInterval(interval, dec)
|
|
23
|
+
|
|
24
|
+
def sub(x, y):
|
|
25
|
+
x = DecoratedInterval._coerce(x)
|
|
26
|
+
y = DecoratedInterval._coerce(y)
|
|
27
|
+
|
|
28
|
+
if x.is_nai or y.is_nai:
|
|
29
|
+
return DecoratedInterval.new_nai()
|
|
30
|
+
|
|
31
|
+
interval = bare_sub(x.interval, y.interval)
|
|
32
|
+
dec = combine(x.decoration, y.decoration)
|
|
33
|
+
dec = _finalize_decoration(dec, interval)
|
|
34
|
+
|
|
35
|
+
return DecoratedInterval(interval, dec)
|
|
36
|
+
|
|
37
|
+
def mul(x, y):
|
|
38
|
+
x = DecoratedInterval._coerce(x)
|
|
39
|
+
y = DecoratedInterval._coerce(y)
|
|
40
|
+
|
|
41
|
+
if x.is_nai or y.is_nai:
|
|
42
|
+
return DecoratedInterval.new_nai()
|
|
43
|
+
|
|
44
|
+
interval = bare_mul(x.interval, y.interval)
|
|
45
|
+
dec = combine(x.decoration, y.decoration)
|
|
46
|
+
dec = _finalize_decoration(dec, interval)
|
|
47
|
+
|
|
48
|
+
return DecoratedInterval(interval, dec)
|
|
49
|
+
|
|
50
|
+
def reciprocal(x):
|
|
51
|
+
x = DecoratedInterval._coerce(x)
|
|
52
|
+
if x.is_nai:
|
|
53
|
+
return DecoratedInterval.new_nai()
|
|
54
|
+
if x.interval.contains(0):
|
|
55
|
+
if x.interval.lo < 0 and x.interval.hi > 0:
|
|
56
|
+
return DecoratedInterval(Interval.entire(), Decoration.TRV)
|
|
57
|
+
interval = bare_reciprocal(x.interval)
|
|
58
|
+
return DecoratedInterval(interval, Decoration.TRV)
|
|
59
|
+
interval = bare_reciprocal(x.interval)
|
|
60
|
+
dec = x.decoration
|
|
61
|
+
dec = _finalize_decoration(dec, interval)
|
|
62
|
+
return DecoratedInterval(interval, dec)
|
|
63
|
+
|
|
64
|
+
def div(x, y):
|
|
65
|
+
x = DecoratedInterval._coerce(x)
|
|
66
|
+
y = DecoratedInterval._coerce(y)
|
|
67
|
+
|
|
68
|
+
if x.is_nai or y.is_nai:
|
|
69
|
+
return DecoratedInterval.new_nai()
|
|
70
|
+
|
|
71
|
+
if x.is_empty or y.is_empty:
|
|
72
|
+
return DecoratedInterval.empty()
|
|
73
|
+
|
|
74
|
+
if y.interval.contains(0):
|
|
75
|
+
interval = bare_div(x.interval, y.interval)
|
|
76
|
+
dec = combine(x.decoration, y.decoration, Decoration.TRV)
|
|
77
|
+
return DecoratedInterval(interval, Decoration.TRV)
|
|
78
|
+
|
|
79
|
+
interval = bare_div(x.interval, y.interval)
|
|
80
|
+
dec = combine(x.decoration, y.decoration)
|
|
81
|
+
dec = _finalize_decoration(dec, interval)
|
|
82
|
+
|
|
83
|
+
return DecoratedInterval(interval, dec)
|
|
84
|
+
|
|
85
|
+
def fma(x, y, z):
|
|
86
|
+
x = DecoratedInterval._coerce(x)
|
|
87
|
+
y = DecoratedInterval._coerce(y)
|
|
88
|
+
z = DecoratedInterval._coerce(z)
|
|
89
|
+
|
|
90
|
+
if x.is_nai or y.is_nai or z.is_nai:
|
|
91
|
+
return DecoratedInterval.new_nai()
|
|
92
|
+
|
|
93
|
+
interval = bare_fma(x.interval, y.interval, z.interval)
|
|
94
|
+
dec = combine(x.decoration, y.decoration, z.decoration)
|
|
95
|
+
|
|
96
|
+
dec = _finalize_decoration(dec, interval)
|
|
97
|
+
|
|
98
|
+
return DecoratedInterval(interval, dec)
|