decoint 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.
- decoint/__init__.py +23 -0
- decoint/arithmetic.py +181 -0
- decoint/constants.py +6 -0
- decoint/decorated_arithmetic.py +98 -0
- decoint/decorated_functions.py +566 -0
- decoint/decorated_interval.py +377 -0
- decoint/decorations.py +18 -0
- decoint/functions.py +564 -0
- decoint/interval.py +546 -0
- decoint/rounding.py +312 -0
- decoint-0.1.0.dist-info/METADATA +23 -0
- decoint-0.1.0.dist-info/RECORD +15 -0
- decoint-0.1.0.dist-info/WHEEL +5 -0
- decoint-0.1.0.dist-info/licenses/LICENSE +21 -0
- decoint-0.1.0.dist-info/top_level.txt +1 -0
decoint/functions.py
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
from .interval import Interval
|
|
2
|
+
from .rounding import add_up, add_down, sub_up, sub_down, mul_up, mul_down, div_up, div_down, sqrt_up, sqrt_down, exp_down, exp_up, log_up, log_down, pow_up, pow_down, root_up, root_down, sin_up, sin_down, tan_up, tan_down, asin_up, asin_down, acos_up, acos_down, atan_up, atan_down, sinh_up, sinh_down, cosh_up, cosh_down, tanh_up, tanh_down, atanh_up, atanh_down, asinh_up, asinh_down, acosh_up, acosh_down, cos_up, cos_down, sqr_up, sqr_down, pow_down_interval, pow_up_interval, exp2_up, exp2_down, log2_up, log2_down, exp10_up, exp10_down, log10_up, log10_down, atan2_down, atan2_up
|
|
3
|
+
from gmpy2 import mpfr, floor, ceil, context, get_context, is_zero, RoundDown, RoundUp, trunc
|
|
4
|
+
from .arithmetic import reciprocal
|
|
5
|
+
from .constants import PI, TWO_PI, HALF_PI
|
|
6
|
+
import builtins
|
|
7
|
+
|
|
8
|
+
Number = mpfr
|
|
9
|
+
ctx = get_context()
|
|
10
|
+
ctx.precision = 53
|
|
11
|
+
ctx.emin = -1073
|
|
12
|
+
ctx.emax = 1024
|
|
13
|
+
|
|
14
|
+
ZERO = mpfr(0)
|
|
15
|
+
with context(get_context(), round = RoundDown):
|
|
16
|
+
PI_DN = Number(PI)
|
|
17
|
+
HALF_PI_DN = Number(HALF_PI)
|
|
18
|
+
TWO_PI_DN = Number(TWO_PI)
|
|
19
|
+
with context(get_context(), round = RoundUp):
|
|
20
|
+
PI_UP = Number(PI)
|
|
21
|
+
HALF_PI_UP = Number(HALF_PI)
|
|
22
|
+
TWO_PI_UP = Number(TWO_PI)
|
|
23
|
+
|
|
24
|
+
MPI_DN = -PI_UP
|
|
25
|
+
MPI_UP = -PI_DN
|
|
26
|
+
MHALF_PI_DN = -HALF_PI_UP
|
|
27
|
+
MHALF_PI_UP = -HALF_PI_DN
|
|
28
|
+
|
|
29
|
+
def sqrt(x: Interval) -> Interval:
|
|
30
|
+
x = Interval._coerce(x)
|
|
31
|
+
if x.is_empty:
|
|
32
|
+
return Interval.empty()
|
|
33
|
+
if x.hi < 0:
|
|
34
|
+
return Interval.empty()
|
|
35
|
+
lo = max(x.lo, mpfr(0))
|
|
36
|
+
return Interval(sqrt_down(lo), sqrt_up(x.hi))
|
|
37
|
+
|
|
38
|
+
def exp(x) -> Interval:
|
|
39
|
+
x = Interval._coerce(x)
|
|
40
|
+
if x.is_empty:
|
|
41
|
+
return Interval.empty()
|
|
42
|
+
return Interval(exp_down(x.lo), exp_up(x.hi))
|
|
43
|
+
|
|
44
|
+
def log(x) -> Interval:
|
|
45
|
+
x = Interval._coerce(x)
|
|
46
|
+
if x.is_empty:
|
|
47
|
+
return Interval.empty()
|
|
48
|
+
if x.hi <= 0:
|
|
49
|
+
return Interval.empty()
|
|
50
|
+
if x.lo <= 0:
|
|
51
|
+
lo = mpfr('-inf')
|
|
52
|
+
else:
|
|
53
|
+
lo = log_down(x.lo)
|
|
54
|
+
hi = log_up(x.hi)
|
|
55
|
+
return Interval(lo, hi)
|
|
56
|
+
|
|
57
|
+
def pow_int(x, n):
|
|
58
|
+
x = Interval._coerce(x)
|
|
59
|
+
if x.is_empty:
|
|
60
|
+
return Interval.empty()
|
|
61
|
+
try:
|
|
62
|
+
n_int = int(n)
|
|
63
|
+
if n_int != n:
|
|
64
|
+
return Interval(mpfr('nan'), mpfr('nan'))
|
|
65
|
+
except Exception:
|
|
66
|
+
return Interval(mpfr('nan'), mpfr('nan'))
|
|
67
|
+
if n_int == 0:
|
|
68
|
+
return Interval(mpfr(1), mpfr(1))
|
|
69
|
+
if n_int < 0:
|
|
70
|
+
return reciprocal(pow_int(x, -n_int))
|
|
71
|
+
if n_int % 2 == 1:
|
|
72
|
+
lo = pow_down(x.lo, n_int)
|
|
73
|
+
hi = pow_up(x.hi, n_int)
|
|
74
|
+
return Interval(lo, hi)
|
|
75
|
+
if n_int % 2 == 0:
|
|
76
|
+
if x.lo >= 0:
|
|
77
|
+
lo = pow_down(x.lo, n_int)
|
|
78
|
+
hi = pow_up(x.hi, n_int)
|
|
79
|
+
return Interval(lo, hi)
|
|
80
|
+
if x.hi <= 0:
|
|
81
|
+
hi_sub = builtins.abs(x.hi)
|
|
82
|
+
lo_sub = builtins.abs(x.lo)
|
|
83
|
+
lo = pow_down(hi_sub, n_int)
|
|
84
|
+
hi = pow_up(lo_sub, n_int)
|
|
85
|
+
return Interval(lo, hi)
|
|
86
|
+
hi_sub = builtins.abs(x.hi)
|
|
87
|
+
lo_sub = builtins.abs(x.lo)
|
|
88
|
+
hi = max(
|
|
89
|
+
pow_up(hi_sub, n_int),
|
|
90
|
+
pow_up(lo_sub, n_int)
|
|
91
|
+
)
|
|
92
|
+
return Interval(mpfr(0), hi)
|
|
93
|
+
|
|
94
|
+
def sign(x) -> Interval:
|
|
95
|
+
x = Interval._coerce(x)
|
|
96
|
+
if x.is_empty:
|
|
97
|
+
return Interval.empty()
|
|
98
|
+
if x.lo > 0:
|
|
99
|
+
return Interval(Number(1), Number(1))
|
|
100
|
+
if x.hi < 0:
|
|
101
|
+
return Interval(Number(-1), Number(-1))
|
|
102
|
+
if x.lo == 0 and x.hi == 0:
|
|
103
|
+
return Interval(Number(0), Number(0))
|
|
104
|
+
if x.lo == 0:
|
|
105
|
+
return Interval(Number(0), Number(1))
|
|
106
|
+
if x.hi == 0:
|
|
107
|
+
return Interval(Number(-1), Number(0))
|
|
108
|
+
return Interval(Number(-1), Number(1))
|
|
109
|
+
|
|
110
|
+
def interval_min(x, y) -> Interval:
|
|
111
|
+
x = Interval._coerce(x)
|
|
112
|
+
y = Interval._coerce(y)
|
|
113
|
+
if x.is_empty or y.is_empty:
|
|
114
|
+
return Interval.empty()
|
|
115
|
+
return Interval(min(x.lo, y.lo), min(x.hi, y.hi))
|
|
116
|
+
|
|
117
|
+
def interval_max(x, y) -> Interval:
|
|
118
|
+
x = Interval._coerce(x)
|
|
119
|
+
y = Interval._coerce(y)
|
|
120
|
+
|
|
121
|
+
if x.is_empty or y.is_empty:
|
|
122
|
+
return Interval.empty()
|
|
123
|
+
return Interval(max(x.lo, y.lo), max(x.hi, y.hi))
|
|
124
|
+
|
|
125
|
+
def nth_root(x, n) -> Interval:
|
|
126
|
+
x = Interval._coerce(x)
|
|
127
|
+
try:
|
|
128
|
+
n_int = int(n)
|
|
129
|
+
if n_int != n:
|
|
130
|
+
return Interval(mpfr('nan'), mpfr('nan'))
|
|
131
|
+
except Exception:
|
|
132
|
+
return Interval(mpfr('nan'), mpfr('nan'))
|
|
133
|
+
if n_int <= 0:
|
|
134
|
+
return Interval(mpfr('nan'), mpfr('nan'))
|
|
135
|
+
if x.is_empty:
|
|
136
|
+
return Interval.empty()
|
|
137
|
+
if n_int % 2 == 1:
|
|
138
|
+
return Interval(root_down(x.lo, n), root_up(x.hi, n))
|
|
139
|
+
if x.hi < 0:
|
|
140
|
+
return Interval.empty()
|
|
141
|
+
lo = max(x.lo, mpfr(0))
|
|
142
|
+
return Interval(root_down(lo, n_int), root_up(x.hi, n_int))
|
|
143
|
+
|
|
144
|
+
def contains_periodic_point(x, offset, period, prec = 128):
|
|
145
|
+
with context(get_context(), precision = prec):
|
|
146
|
+
off_val = offset() if callable(offset) else offset
|
|
147
|
+
per_val = period() if callable(offset) else period
|
|
148
|
+
|
|
149
|
+
lo_mpfr = mpfr(str(x.lo))
|
|
150
|
+
hi_mpfr = mpfr(str(x.hi))
|
|
151
|
+
off_mpfr = mpfr(str(off_val))
|
|
152
|
+
per_mpfr = mpfr(str(per_val))
|
|
153
|
+
|
|
154
|
+
if hi_mpfr - lo_mpfr >= per_mpfr:
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
k_lo = (lo_mpfr - off_mpfr) / per_mpfr
|
|
158
|
+
k_hi = (hi_mpfr - off_mpfr) / per_mpfr
|
|
159
|
+
|
|
160
|
+
return ceil(k_lo) <= floor(k_hi)
|
|
161
|
+
def sin(x) -> Interval:
|
|
162
|
+
x = Interval._coerce(x)
|
|
163
|
+
if x.is_empty:
|
|
164
|
+
return Interval.empty()
|
|
165
|
+
if x.width >= TWO_PI:
|
|
166
|
+
return Interval(mpfr(-1), mpfr(1))
|
|
167
|
+
s1 = sin_down(x.lo)
|
|
168
|
+
s2 = sin_down(x.hi)
|
|
169
|
+
t1 = sin_up(x.lo)
|
|
170
|
+
t2 = sin_up(x.hi)
|
|
171
|
+
lo = min(s1, s2)
|
|
172
|
+
hi = max(t1, t2)
|
|
173
|
+
|
|
174
|
+
if contains_periodic_point(x, HALF_PI, TWO_PI):
|
|
175
|
+
hi = mpfr(1)
|
|
176
|
+
if contains_periodic_point(x, -HALF_PI, TWO_PI):
|
|
177
|
+
lo = mpfr(-1)
|
|
178
|
+
return Interval(lo, hi)
|
|
179
|
+
|
|
180
|
+
def cos(x) -> Interval:
|
|
181
|
+
x = Interval._coerce(x)
|
|
182
|
+
if x.is_empty:
|
|
183
|
+
return Interval.empty()
|
|
184
|
+
if x.width >= TWO_PI:
|
|
185
|
+
return Interval(mpfr(-1), mpfr(1))
|
|
186
|
+
|
|
187
|
+
c1 = cos_down(x.lo)
|
|
188
|
+
c2 = cos_down(x.hi)
|
|
189
|
+
d1 = cos_up(x.lo)
|
|
190
|
+
d2 = cos_up(x.hi)
|
|
191
|
+
lo = min(c1, c2)
|
|
192
|
+
hi = max(d1, d2)
|
|
193
|
+
|
|
194
|
+
# Cosine peaks at 0 (mod 2pi), troughs at pi (mod 2pi)
|
|
195
|
+
if contains_periodic_point(x, mpfr(0), TWO_PI):
|
|
196
|
+
hi = mpfr(1)
|
|
197
|
+
if contains_periodic_point(x, PI, TWO_PI):
|
|
198
|
+
lo = mpfr(-1)
|
|
199
|
+
return Interval(lo, hi)
|
|
200
|
+
|
|
201
|
+
def tan(x):
|
|
202
|
+
x = Interval._coerce(x)
|
|
203
|
+
if x.is_empty:
|
|
204
|
+
return Interval.empty()
|
|
205
|
+
if x.width >= PI:
|
|
206
|
+
return Interval.entire()
|
|
207
|
+
if contains_periodic_point(x, HALF_PI, PI):
|
|
208
|
+
return Interval.entire()
|
|
209
|
+
lo = tan_down(x.lo)
|
|
210
|
+
hi = tan_up(x.hi)
|
|
211
|
+
return Interval(lo, hi)
|
|
212
|
+
|
|
213
|
+
def asin(x):
|
|
214
|
+
x = Interval._coerce(x)
|
|
215
|
+
if x.is_empty:
|
|
216
|
+
return Interval.empty()
|
|
217
|
+
x = x.intersection(Interval(-1, 1))
|
|
218
|
+
|
|
219
|
+
if x.is_empty:
|
|
220
|
+
return Interval.empty()
|
|
221
|
+
return Interval(asin_down(x.lo), asin_up(x.hi))
|
|
222
|
+
|
|
223
|
+
def acos(x):
|
|
224
|
+
x = Interval._coerce(x)
|
|
225
|
+
if x.is_empty:
|
|
226
|
+
return Interval.empty()
|
|
227
|
+
x = x.intersection(Interval(-1, 1))
|
|
228
|
+
if x.is_empty:
|
|
229
|
+
return Interval.empty()
|
|
230
|
+
return Interval(acos_down(x.hi), acos_up(x.lo))
|
|
231
|
+
|
|
232
|
+
def atan(x):
|
|
233
|
+
x = Interval._coerce(x)
|
|
234
|
+
|
|
235
|
+
if x.is_empty:
|
|
236
|
+
return Interval.empty()
|
|
237
|
+
|
|
238
|
+
return Interval(
|
|
239
|
+
atan_down(x.lo),
|
|
240
|
+
atan_up(x.hi)
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
def sinh(x):
|
|
244
|
+
x = Interval._coerce(x)
|
|
245
|
+
if x.is_empty:
|
|
246
|
+
return Interval.empty()
|
|
247
|
+
return Interval(sinh_down(x.lo), sinh_up(x.hi))
|
|
248
|
+
|
|
249
|
+
def tanh(x):
|
|
250
|
+
x = Interval._coerce(x)
|
|
251
|
+
if x.is_empty:
|
|
252
|
+
return Interval.empty()
|
|
253
|
+
return Interval(tanh_down(x.lo), tanh_up(x.hi))
|
|
254
|
+
|
|
255
|
+
def cosh(x):
|
|
256
|
+
x = Interval._coerce(x)
|
|
257
|
+
if x.is_empty:
|
|
258
|
+
return Interval.empty()
|
|
259
|
+
|
|
260
|
+
if x.lo >= 0:
|
|
261
|
+
return Interval(cosh_down(x.lo), cosh_up(x.hi))
|
|
262
|
+
if x.hi <= 0:
|
|
263
|
+
return Interval(cosh_down(x.hi), cosh_up(x.lo))
|
|
264
|
+
return Interval(mpfr(1), max(cosh_up(x.lo), cosh_up(x.hi)))
|
|
265
|
+
|
|
266
|
+
def asinh(x) -> Interval:
|
|
267
|
+
x = Interval._coerce(x)
|
|
268
|
+
if x.is_empty:
|
|
269
|
+
return Interval.empty()
|
|
270
|
+
return Interval(asinh_down(x.lo), asinh_up(x.hi))
|
|
271
|
+
|
|
272
|
+
def acosh(x) -> Interval:
|
|
273
|
+
x = Interval._coerce(x)
|
|
274
|
+
if x.is_empty:
|
|
275
|
+
return Interval.empty()
|
|
276
|
+
if x.hi < 1:
|
|
277
|
+
return Interval.empty()
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
lo = max(x.lo, mpfr(1))
|
|
281
|
+
return Interval(acosh_down(lo), acosh_up(x.hi))
|
|
282
|
+
|
|
283
|
+
def atanh(x) -> Interval:
|
|
284
|
+
x = Interval._coerce(x)
|
|
285
|
+
if x.is_empty:
|
|
286
|
+
return Interval.empty()
|
|
287
|
+
|
|
288
|
+
x = x.intersection(Interval(-1, 1))
|
|
289
|
+
if x.is_empty:
|
|
290
|
+
return Interval.empty()
|
|
291
|
+
|
|
292
|
+
lo = mpfr('-inf') if x.lo <= -1 else atanh_down(x.lo)
|
|
293
|
+
hi = mpfr('inf') if x.hi >= 1 else atanh_up(x.hi)
|
|
294
|
+
|
|
295
|
+
return Interval(lo, hi)
|
|
296
|
+
|
|
297
|
+
def abs(x):
|
|
298
|
+
x = Interval._coerce(x)
|
|
299
|
+
if x.is_empty:
|
|
300
|
+
return Interval.empty()
|
|
301
|
+
if x.lo >= 0:
|
|
302
|
+
return Interval(x.lo, x.hi)
|
|
303
|
+
elif x.hi <= 0:
|
|
304
|
+
return Interval(-x.hi, -x.lo)
|
|
305
|
+
|
|
306
|
+
hi = max(-x.lo, x.hi)
|
|
307
|
+
return Interval(Number(0), hi)
|
|
308
|
+
|
|
309
|
+
def safe_atan2_dn(y, x):
|
|
310
|
+
y_val = ZERO if is_zero(y) else y
|
|
311
|
+
x_val = ZERO if is_zero(x) else x
|
|
312
|
+
return atan2_down(y_val, x_val)
|
|
313
|
+
|
|
314
|
+
def safe_atan2_up(y, x):
|
|
315
|
+
y_val = ZERO if is_zero(y) else y
|
|
316
|
+
x_val = ZERO if is_zero(x) else x
|
|
317
|
+
return atan2_up(y_val, x_val)
|
|
318
|
+
|
|
319
|
+
def atan2(y, x):
|
|
320
|
+
y = Interval._coerce(y)
|
|
321
|
+
x = Interval._coerce(x)
|
|
322
|
+
|
|
323
|
+
# 1. Empty set handling
|
|
324
|
+
if y.is_empty or x.is_empty:
|
|
325
|
+
return Interval.empty()
|
|
326
|
+
|
|
327
|
+
# 2. Undefined origin point (0, 0) handling
|
|
328
|
+
if y.lo == ZERO and y.hi == ZERO and x.lo == ZERO and x.hi == ZERO:
|
|
329
|
+
return Interval.empty()
|
|
330
|
+
|
|
331
|
+
y1, y2 = y.lo, y.hi
|
|
332
|
+
x1, x2 = x.lo, x.hi
|
|
333
|
+
|
|
334
|
+
# Case 1: X is strictly positive (x1 > 0)
|
|
335
|
+
if x1 > ZERO:
|
|
336
|
+
if y1 >= ZERO:
|
|
337
|
+
lo = safe_atan2_dn(y1, x2)
|
|
338
|
+
hi = safe_atan2_up(y2, x1)
|
|
339
|
+
elif y2 <= ZERO:
|
|
340
|
+
lo = safe_atan2_dn(y1, x1)
|
|
341
|
+
hi = safe_atan2_up(y2, x2)
|
|
342
|
+
else:
|
|
343
|
+
lo = safe_atan2_dn(y1, x1)
|
|
344
|
+
hi = safe_atan2_up(y2, x1)
|
|
345
|
+
|
|
346
|
+
# Case 2: X is strictly negative (x2 < 0)
|
|
347
|
+
elif x2 < ZERO:
|
|
348
|
+
if y1 > ZERO:
|
|
349
|
+
lo = safe_atan2_dn(y2, x2)
|
|
350
|
+
hi = safe_atan2_up(y1, x1)
|
|
351
|
+
elif y2 < ZERO:
|
|
352
|
+
lo = safe_atan2_dn(y2, x1)
|
|
353
|
+
hi = safe_atan2_up(y1, x2)
|
|
354
|
+
elif y1 == ZERO and y2 == ZERO:
|
|
355
|
+
lo, hi = PI_DN, PI_UP
|
|
356
|
+
elif y1 == ZERO and y2 > ZERO:
|
|
357
|
+
lo = safe_atan2_dn(y2, x2)
|
|
358
|
+
hi = PI_UP
|
|
359
|
+
else: # y1 < ZERO and y2 >= ZERO
|
|
360
|
+
lo, hi = MPI_DN, PI_UP
|
|
361
|
+
|
|
362
|
+
# Case 3: X contains zero (x1 <= 0 <= x2)
|
|
363
|
+
else:
|
|
364
|
+
# Subcase 3.0: X is degenerate [0, 0]
|
|
365
|
+
if x1 == ZERO and x2 == ZERO:
|
|
366
|
+
if y1 >= ZERO:
|
|
367
|
+
lo, hi = HALF_PI_DN, HALF_PI_UP
|
|
368
|
+
elif y2 <= ZERO:
|
|
369
|
+
lo, hi = MHALF_PI_DN, MHALF_PI_UP
|
|
370
|
+
else: # y1 < ZERO and y2 > ZERO
|
|
371
|
+
lo, hi = MHALF_PI_DN, HALF_PI_UP
|
|
372
|
+
|
|
373
|
+
# Subcase 3.1: Y is strictly positive
|
|
374
|
+
elif y1 > ZERO:
|
|
375
|
+
lo = safe_atan2_dn(y1, x2)
|
|
376
|
+
hi = safe_atan2_up(y1, x1)
|
|
377
|
+
|
|
378
|
+
# Subcase 3.2: Y is strictly negative
|
|
379
|
+
elif y2 < ZERO:
|
|
380
|
+
lo = safe_atan2_dn(y2, x1)
|
|
381
|
+
hi = safe_atan2_up(y2, x2)
|
|
382
|
+
|
|
383
|
+
# Subcase 3.3: Y contains zero (y1 <= 0 <= y2) and X is non-degenerate
|
|
384
|
+
else:
|
|
385
|
+
if x1 < ZERO:
|
|
386
|
+
if y1 < ZERO and y2 > ZERO:
|
|
387
|
+
lo, hi = MPI_DN, PI_UP
|
|
388
|
+
elif y1 == ZERO and y2 == ZERO:
|
|
389
|
+
if x2 > ZERO:
|
|
390
|
+
lo, hi = ZERO, PI_UP
|
|
391
|
+
else: # x2 == ZERO
|
|
392
|
+
lo, hi = PI_DN, PI_UP
|
|
393
|
+
elif y1 == ZERO and y2 > ZERO:
|
|
394
|
+
if x2 > ZERO:
|
|
395
|
+
lo, hi = ZERO, PI_UP
|
|
396
|
+
else: # x2 == ZERO
|
|
397
|
+
lo, hi = HALF_PI_DN, PI_UP
|
|
398
|
+
else: # y1 < ZERO and y2 == ZERO
|
|
399
|
+
lo, hi = MPI_DN, PI_UP
|
|
400
|
+
else: # x1 == ZERO and x2 > ZERO
|
|
401
|
+
if y1 < ZERO and y2 > ZERO:
|
|
402
|
+
lo, hi = MHALF_PI_DN, HALF_PI_UP
|
|
403
|
+
elif y1 == ZERO and y2 == ZERO:
|
|
404
|
+
lo, hi = ZERO, ZERO
|
|
405
|
+
elif y1 == ZERO and y2 > ZERO:
|
|
406
|
+
lo, hi = ZERO, HALF_PI_UP
|
|
407
|
+
else: # y1 < ZERO and y2 == ZERO
|
|
408
|
+
lo, hi = MHALF_PI_DN, ZERO
|
|
409
|
+
|
|
410
|
+
return Interval(lo, hi)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def sqr(x):
|
|
415
|
+
x = Interval._coerce(x)
|
|
416
|
+
if x.is_empty:
|
|
417
|
+
return Interval.empty()
|
|
418
|
+
if x.lo >= 0:
|
|
419
|
+
lo = sqr_down(x.lo)
|
|
420
|
+
hi = sqr_up(x.hi)
|
|
421
|
+
return Interval(lo, hi)
|
|
422
|
+
elif x.hi <= 0:
|
|
423
|
+
lo = sqr_down(builtins.abs(x.hi))
|
|
424
|
+
hi = sqr_up(builtins.abs(x.lo))
|
|
425
|
+
return Interval(lo, hi)
|
|
426
|
+
hi = max(sqr_up(builtins.abs(x.hi)), sqr_up(builtins.abs(x.lo)))
|
|
427
|
+
return Interval(mpfr(0), hi)
|
|
428
|
+
|
|
429
|
+
def pow_interval(x, y):
|
|
430
|
+
x = Interval._coerce(x)
|
|
431
|
+
y = Interval._coerce(y)
|
|
432
|
+
|
|
433
|
+
if x.is_empty or y.is_empty:
|
|
434
|
+
return Interval.empty()
|
|
435
|
+
|
|
436
|
+
x_lo = max(0, x.lo)
|
|
437
|
+
x_hi = x.hi
|
|
438
|
+
|
|
439
|
+
if x_lo > x_hi:
|
|
440
|
+
return Interval.empty()
|
|
441
|
+
|
|
442
|
+
if x_hi == 0:
|
|
443
|
+
if y.hi <= 0:
|
|
444
|
+
return Interval.empty()
|
|
445
|
+
return Interval(mpfr(0), mpfr(0))
|
|
446
|
+
|
|
447
|
+
if x_lo == 0:
|
|
448
|
+
v_down = [
|
|
449
|
+
pow_down_interval(x_hi, y.lo),
|
|
450
|
+
pow_down_interval(x_hi, y.hi)
|
|
451
|
+
]
|
|
452
|
+
v_up = [
|
|
453
|
+
pow_up_interval(x_hi, y.lo),
|
|
454
|
+
pow_up_interval(x_hi, y.hi)
|
|
455
|
+
]
|
|
456
|
+
|
|
457
|
+
if y.lo > 0 or y.hi > 0:
|
|
458
|
+
v_down.append(mpfr(0))
|
|
459
|
+
v_up.append(mpfr(0))
|
|
460
|
+
|
|
461
|
+
if y.lo < 0 or y.hi < 0:
|
|
462
|
+
v_down.append(mpfr('inf'))
|
|
463
|
+
v_up.append(mpfr('inf'))
|
|
464
|
+
|
|
465
|
+
if y.lo <= 0 <= y.hi:
|
|
466
|
+
v_down.append(mpfr(1))
|
|
467
|
+
v_up.append(mpfr(1))
|
|
468
|
+
|
|
469
|
+
else:
|
|
470
|
+
v_down = [
|
|
471
|
+
pow_down_interval(x_lo, y.lo),
|
|
472
|
+
pow_down_interval(x_lo, y.hi),
|
|
473
|
+
pow_down_interval(x_hi, y.lo),
|
|
474
|
+
pow_down_interval(x_hi, y.hi)
|
|
475
|
+
]
|
|
476
|
+
v_up = [
|
|
477
|
+
pow_up_interval(x_lo, y.lo),
|
|
478
|
+
pow_up_interval(x_lo, y.hi),
|
|
479
|
+
pow_up_interval(x_hi, y.lo),
|
|
480
|
+
pow_up_interval(x_hi, y.hi)
|
|
481
|
+
]
|
|
482
|
+
|
|
483
|
+
return Interval(min(v_down), max(v_up))
|
|
484
|
+
|
|
485
|
+
def exp2(x):
|
|
486
|
+
x = Interval._coerce(x)
|
|
487
|
+
|
|
488
|
+
if x.is_empty:
|
|
489
|
+
return Interval.empty()
|
|
490
|
+
|
|
491
|
+
return Interval(exp2_down(x.lo), exp2_up(x.hi))
|
|
492
|
+
|
|
493
|
+
def exp10(x):
|
|
494
|
+
x = Interval._coerce(x)
|
|
495
|
+
|
|
496
|
+
if x.is_empty:
|
|
497
|
+
return Interval.empty()
|
|
498
|
+
|
|
499
|
+
return Interval(exp10_down(x.lo), exp10_up(x.hi))
|
|
500
|
+
|
|
501
|
+
def log2(x):
|
|
502
|
+
x = Interval._coerce(x)
|
|
503
|
+
if x.is_empty:
|
|
504
|
+
return Interval.empty()
|
|
505
|
+
if x.hi <= 0:
|
|
506
|
+
return Interval.empty()
|
|
507
|
+
if x.lo <= 0:
|
|
508
|
+
lo = mpfr('-inf')
|
|
509
|
+
else:
|
|
510
|
+
lo = log2_down(x.lo)
|
|
511
|
+
hi = log2_up(x.hi)
|
|
512
|
+
return Interval(lo, hi)
|
|
513
|
+
|
|
514
|
+
def log10(x):
|
|
515
|
+
x = Interval._coerce(x)
|
|
516
|
+
if x.is_empty:
|
|
517
|
+
return Interval.empty()
|
|
518
|
+
if x.hi <= 0:
|
|
519
|
+
return Interval.empty()
|
|
520
|
+
if x.lo <= 0:
|
|
521
|
+
lo = mpfr('-inf')
|
|
522
|
+
else:
|
|
523
|
+
lo = log10_down(x.lo)
|
|
524
|
+
hi = log10_up(x.hi)
|
|
525
|
+
return Interval(lo, hi)
|
|
526
|
+
|
|
527
|
+
def interval_ceil(x):
|
|
528
|
+
if x.is_empty:
|
|
529
|
+
return Interval.empty()
|
|
530
|
+
if x.lo == mpfr('-inf'):
|
|
531
|
+
lo = mpfr('-inf')
|
|
532
|
+
else:
|
|
533
|
+
lo = ceil(x.lo)
|
|
534
|
+
if x.hi == mpfr('inf'):
|
|
535
|
+
hi = mpfr('inf')
|
|
536
|
+
else:
|
|
537
|
+
hi = ceil(x.hi)
|
|
538
|
+
return Interval(lo, hi)
|
|
539
|
+
|
|
540
|
+
def interval_floor(x):
|
|
541
|
+
if x.is_empty:
|
|
542
|
+
return Interval.empty()
|
|
543
|
+
if x.lo == mpfr('-inf'):
|
|
544
|
+
lo = mpfr('-inf')
|
|
545
|
+
else:
|
|
546
|
+
lo = floor(x.lo)
|
|
547
|
+
if x.hi == mpfr('inf'):
|
|
548
|
+
hi = mpfr('inf')
|
|
549
|
+
else:
|
|
550
|
+
hi = floor(x.hi)
|
|
551
|
+
return Interval(lo, hi)
|
|
552
|
+
|
|
553
|
+
def interval_trunc(x):
|
|
554
|
+
if x.is_empty:
|
|
555
|
+
return Interval.empty()
|
|
556
|
+
if x.lo == mpfr('-inf'):
|
|
557
|
+
lo = mpfr('-inf')
|
|
558
|
+
else:
|
|
559
|
+
lo = trunc(x.lo)
|
|
560
|
+
if x.hi == mpfr('inf'):
|
|
561
|
+
hi = mpfr('inf')
|
|
562
|
+
else:
|
|
563
|
+
hi = trunc(x.hi)
|
|
564
|
+
return Interval(lo, hi)
|