Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Modules/_decimal/tests/randdec.py
12 views
1
#
2
# Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
3
#
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions
6
# are met:
7
#
8
# 1. Redistributions of source code must retain the above copyright
9
# notice, this list of conditions and the following disclaimer.
10
#
11
# 2. Redistributions in binary form must reproduce the above copyright
12
# notice, this list of conditions and the following disclaimer in the
13
# documentation and/or other materials provided with the distribution.
14
#
15
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
16
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
# SUCH DAMAGE.
26
#
27
28
29
# Generate test cases for deccheck.py.
30
31
32
#
33
# Grammar from http://speleotrove.com/decimal/daconvs.html
34
#
35
# sign ::= '+' | '-'
36
# digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
37
# '8' | '9'
38
# indicator ::= 'e' | 'E'
39
# digits ::= digit [digit]...
40
# decimal-part ::= digits '.' [digits] | ['.'] digits
41
# exponent-part ::= indicator [sign] digits
42
# infinity ::= 'Infinity' | 'Inf'
43
# nan ::= 'NaN' [digits] | 'sNaN' [digits]
44
# numeric-value ::= decimal-part [exponent-part] | infinity
45
# numeric-string ::= [sign] numeric-value | [sign] nan
46
#
47
48
49
from random import randrange, sample
50
from fractions import Fraction
51
from randfloat import un_randfloat, bin_randfloat, tern_randfloat
52
53
54
def sign():
55
if randrange(2):
56
if randrange(2): return '+'
57
return ''
58
return '-'
59
60
def indicator():
61
return "eE"[randrange(2)]
62
63
def digits(maxprec):
64
if maxprec == 0: return ''
65
return str(randrange(10**maxprec))
66
67
def dot():
68
if randrange(2): return '.'
69
return ''
70
71
def decimal_part(maxprec):
72
if randrange(100) > 60: # integers
73
return digits(maxprec)
74
if randrange(2):
75
intlen = randrange(1, maxprec+1)
76
fraclen = maxprec-intlen
77
intpart = digits(intlen)
78
fracpart = digits(fraclen)
79
return ''.join((intpart, '.', fracpart))
80
else:
81
return ''.join((dot(), digits(maxprec)))
82
83
def expdigits(maxexp):
84
return str(randrange(maxexp))
85
86
def exponent_part(maxexp):
87
return ''.join((indicator(), sign(), expdigits(maxexp)))
88
89
def infinity():
90
if randrange(2): return 'Infinity'
91
return 'Inf'
92
93
def nan():
94
d = ''
95
if randrange(2):
96
d = digits(randrange(99))
97
if randrange(2):
98
return ''.join(('NaN', d))
99
else:
100
return ''.join(('sNaN', d))
101
102
def numeric_value(maxprec, maxexp):
103
if randrange(100) > 90:
104
return infinity()
105
exp_part = ''
106
if randrange(100) > 60:
107
exp_part = exponent_part(maxexp)
108
return ''.join((decimal_part(maxprec), exp_part))
109
110
def numeric_string(maxprec, maxexp):
111
if randrange(100) > 95:
112
return ''.join((sign(), nan()))
113
else:
114
return ''.join((sign(), numeric_value(maxprec, maxexp)))
115
116
def randdec(maxprec, maxexp):
117
return numeric_string(maxprec, maxexp)
118
119
def rand_adjexp(maxprec, maxadjexp):
120
d = digits(maxprec)
121
maxexp = maxadjexp-len(d)+1
122
if maxexp == 0: maxexp = 1
123
exp = str(randrange(maxexp-2*(abs(maxexp)), maxexp))
124
return ''.join((sign(), d, 'E', exp))
125
126
127
def ndigits(n):
128
if n < 1: return 0
129
return randrange(10**(n-1), 10**n)
130
131
def randtuple(maxprec, maxexp):
132
n = randrange(100)
133
sign = randrange(2)
134
coeff = ndigits(maxprec)
135
if n >= 95:
136
coeff = ()
137
exp = 'F'
138
elif n >= 85:
139
coeff = tuple(map(int, str(ndigits(maxprec))))
140
exp = "nN"[randrange(2)]
141
else:
142
coeff = tuple(map(int, str(ndigits(maxprec))))
143
exp = randrange(-maxexp, maxexp)
144
return (sign, coeff, exp)
145
146
def from_triple(sign, coeff, exp):
147
return ''.join((str(sign*coeff), indicator(), str(exp)))
148
149
150
# Close to 10**n
151
def un_close_to_pow10(prec, maxexp, itr=None):
152
if itr is None:
153
lst = range(prec+30)
154
else:
155
lst = sample(range(prec+30), itr)
156
nines = [10**n - 1 for n in lst]
157
pow10 = [10**n for n in lst]
158
for coeff in nines:
159
yield coeff
160
yield -coeff
161
yield from_triple(1, coeff, randrange(2*maxexp))
162
yield from_triple(-1, coeff, randrange(2*maxexp))
163
for coeff in pow10:
164
yield coeff
165
yield -coeff
166
167
# Close to 10**n
168
def bin_close_to_pow10(prec, maxexp, itr=None):
169
if itr is None:
170
lst = range(prec+30)
171
else:
172
lst = sample(range(prec+30), itr)
173
nines = [10**n - 1 for n in lst]
174
pow10 = [10**n for n in lst]
175
for coeff in nines:
176
yield coeff, 1
177
yield -coeff, -1
178
yield 1, coeff
179
yield -1, -coeff
180
yield from_triple(1, coeff, randrange(2*maxexp)), 1
181
yield from_triple(-1, coeff, randrange(2*maxexp)), -1
182
yield 1, from_triple(1, coeff, -randrange(2*maxexp))
183
yield -1, from_triple(-1, coeff, -randrange(2*maxexp))
184
for coeff in pow10:
185
yield coeff, -1
186
yield -coeff, 1
187
yield 1, -coeff
188
yield -coeff, 1
189
190
# Close to 1:
191
def close_to_one_greater(prec, emax, emin):
192
rprec = 10**prec
193
return ''.join(("1.", '0'*randrange(prec),
194
str(randrange(rprec))))
195
196
def close_to_one_less(prec, emax, emin):
197
rprec = 10**prec
198
return ''.join(("0.9", '9'*randrange(prec),
199
str(randrange(rprec))))
200
201
# Close to 0:
202
def close_to_zero_greater(prec, emax, emin):
203
rprec = 10**prec
204
return ''.join(("0.", '0'*randrange(prec),
205
str(randrange(rprec))))
206
207
def close_to_zero_less(prec, emax, emin):
208
rprec = 10**prec
209
return ''.join(("-0.", '0'*randrange(prec),
210
str(randrange(rprec))))
211
212
# Close to emax:
213
def close_to_emax_less(prec, emax, emin):
214
rprec = 10**prec
215
return ''.join(("9.", '9'*randrange(prec),
216
str(randrange(rprec)), "E", str(emax)))
217
218
def close_to_emax_greater(prec, emax, emin):
219
rprec = 10**prec
220
return ''.join(("1.", '0'*randrange(prec),
221
str(randrange(rprec)), "E", str(emax+1)))
222
223
# Close to emin:
224
def close_to_emin_greater(prec, emax, emin):
225
rprec = 10**prec
226
return ''.join(("1.", '0'*randrange(prec),
227
str(randrange(rprec)), "E", str(emin)))
228
229
def close_to_emin_less(prec, emax, emin):
230
rprec = 10**prec
231
return ''.join(("9.", '9'*randrange(prec),
232
str(randrange(rprec)), "E", str(emin-1)))
233
234
# Close to etiny:
235
def close_to_etiny_greater(prec, emax, emin):
236
rprec = 10**prec
237
etiny = emin - (prec - 1)
238
return ''.join(("1.", '0'*randrange(prec),
239
str(randrange(rprec)), "E", str(etiny)))
240
241
def close_to_etiny_less(prec, emax, emin):
242
rprec = 10**prec
243
etiny = emin - (prec - 1)
244
return ''.join(("9.", '9'*randrange(prec),
245
str(randrange(rprec)), "E", str(etiny-1)))
246
247
248
def close_to_min_etiny_greater(prec, max_prec, min_emin):
249
rprec = 10**prec
250
etiny = min_emin - (max_prec - 1)
251
return ''.join(("1.", '0'*randrange(prec),
252
str(randrange(rprec)), "E", str(etiny)))
253
254
def close_to_min_etiny_less(prec, max_prec, min_emin):
255
rprec = 10**prec
256
etiny = min_emin - (max_prec - 1)
257
return ''.join(("9.", '9'*randrange(prec),
258
str(randrange(rprec)), "E", str(etiny-1)))
259
260
261
close_funcs = [
262
close_to_one_greater, close_to_one_less, close_to_zero_greater,
263
close_to_zero_less, close_to_emax_less, close_to_emax_greater,
264
close_to_emin_greater, close_to_emin_less, close_to_etiny_greater,
265
close_to_etiny_less, close_to_min_etiny_greater, close_to_min_etiny_less
266
]
267
268
269
def un_close_numbers(prec, emax, emin, itr=None):
270
if itr is None:
271
itr = 1000
272
for _ in range(itr):
273
for func in close_funcs:
274
yield func(prec, emax, emin)
275
276
def bin_close_numbers(prec, emax, emin, itr=None):
277
if itr is None:
278
itr = 1000
279
for _ in range(itr):
280
for func1 in close_funcs:
281
for func2 in close_funcs:
282
yield func1(prec, emax, emin), func2(prec, emax, emin)
283
for func in close_funcs:
284
yield randdec(prec, emax), func(prec, emax, emin)
285
yield func(prec, emax, emin), randdec(prec, emax)
286
287
def tern_close_numbers(prec, emax, emin, itr):
288
if itr is None:
289
itr = 1000
290
for _ in range(itr):
291
for func1 in close_funcs:
292
for func2 in close_funcs:
293
for func3 in close_funcs:
294
yield (func1(prec, emax, emin), func2(prec, emax, emin),
295
func3(prec, emax, emin))
296
for func in close_funcs:
297
yield (randdec(prec, emax), func(prec, emax, emin),
298
func(prec, emax, emin))
299
yield (func(prec, emax, emin), randdec(prec, emax),
300
func(prec, emax, emin))
301
yield (func(prec, emax, emin), func(prec, emax, emin),
302
randdec(prec, emax))
303
for func in close_funcs:
304
yield (randdec(prec, emax), randdec(prec, emax),
305
func(prec, emax, emin))
306
yield (randdec(prec, emax), func(prec, emax, emin),
307
randdec(prec, emax))
308
yield (func(prec, emax, emin), randdec(prec, emax),
309
randdec(prec, emax))
310
311
312
# If itr == None, test all digit lengths up to prec + 30
313
def un_incr_digits(prec, maxexp, itr):
314
if itr is None:
315
lst = range(prec+30)
316
else:
317
lst = sample(range(prec+30), itr)
318
for m in lst:
319
yield from_triple(1, ndigits(m), 0)
320
yield from_triple(-1, ndigits(m), 0)
321
yield from_triple(1, ndigits(m), randrange(maxexp))
322
yield from_triple(-1, ndigits(m), randrange(maxexp))
323
324
# If itr == None, test all digit lengths up to prec + 30
325
# Also output decimals im tuple form.
326
def un_incr_digits_tuple(prec, maxexp, itr):
327
if itr is None:
328
lst = range(prec+30)
329
else:
330
lst = sample(range(prec+30), itr)
331
for m in lst:
332
yield from_triple(1, ndigits(m), 0)
333
yield from_triple(-1, ndigits(m), 0)
334
yield from_triple(1, ndigits(m), randrange(maxexp))
335
yield from_triple(-1, ndigits(m), randrange(maxexp))
336
# test from tuple
337
yield (0, tuple(map(int, str(ndigits(m)))), 0)
338
yield (1, tuple(map(int, str(ndigits(m)))), 0)
339
yield (0, tuple(map(int, str(ndigits(m)))), randrange(maxexp))
340
yield (1, tuple(map(int, str(ndigits(m)))), randrange(maxexp))
341
342
# If itr == None, test all combinations of digit lengths up to prec + 30
343
def bin_incr_digits(prec, maxexp, itr):
344
if itr is None:
345
lst1 = range(prec+30)
346
lst2 = range(prec+30)
347
else:
348
lst1 = sample(range(prec+30), itr)
349
lst2 = sample(range(prec+30), itr)
350
for m in lst1:
351
x = from_triple(1, ndigits(m), 0)
352
yield x, x
353
x = from_triple(-1, ndigits(m), 0)
354
yield x, x
355
x = from_triple(1, ndigits(m), randrange(maxexp))
356
yield x, x
357
x = from_triple(-1, ndigits(m), randrange(maxexp))
358
yield x, x
359
for m in lst1:
360
for n in lst2:
361
x = from_triple(1, ndigits(m), 0)
362
y = from_triple(1, ndigits(n), 0)
363
yield x, y
364
x = from_triple(-1, ndigits(m), 0)
365
y = from_triple(1, ndigits(n), 0)
366
yield x, y
367
x = from_triple(1, ndigits(m), 0)
368
y = from_triple(-1, ndigits(n), 0)
369
yield x, y
370
x = from_triple(-1, ndigits(m), 0)
371
y = from_triple(-1, ndigits(n), 0)
372
yield x, y
373
x = from_triple(1, ndigits(m), randrange(maxexp))
374
y = from_triple(1, ndigits(n), randrange(maxexp))
375
yield x, y
376
x = from_triple(-1, ndigits(m), randrange(maxexp))
377
y = from_triple(1, ndigits(n), randrange(maxexp))
378
yield x, y
379
x = from_triple(1, ndigits(m), randrange(maxexp))
380
y = from_triple(-1, ndigits(n), randrange(maxexp))
381
yield x, y
382
x = from_triple(-1, ndigits(m), randrange(maxexp))
383
y = from_triple(-1, ndigits(n), randrange(maxexp))
384
yield x, y
385
386
387
def randsign():
388
return (1, -1)[randrange(2)]
389
390
# If itr == None, test all combinations of digit lengths up to prec + 30
391
def tern_incr_digits(prec, maxexp, itr):
392
if itr is None:
393
lst1 = range(prec+30)
394
lst2 = range(prec+30)
395
lst3 = range(prec+30)
396
else:
397
lst1 = sample(range(prec+30), itr)
398
lst2 = sample(range(prec+30), itr)
399
lst3 = sample(range(prec+30), itr)
400
for m in lst1:
401
for n in lst2:
402
for p in lst3:
403
x = from_triple(randsign(), ndigits(m), 0)
404
y = from_triple(randsign(), ndigits(n), 0)
405
z = from_triple(randsign(), ndigits(p), 0)
406
yield x, y, z
407
408
409
# Tests for the 'logical' functions
410
def bindigits(prec):
411
z = 0
412
for i in range(prec):
413
z += randrange(2) * 10**i
414
return z
415
416
def logical_un_incr_digits(prec, itr):
417
if itr is None:
418
lst = range(prec+30)
419
else:
420
lst = sample(range(prec+30), itr)
421
for m in lst:
422
yield from_triple(1, bindigits(m), 0)
423
424
def logical_bin_incr_digits(prec, itr):
425
if itr is None:
426
lst1 = range(prec+30)
427
lst2 = range(prec+30)
428
else:
429
lst1 = sample(range(prec+30), itr)
430
lst2 = sample(range(prec+30), itr)
431
for m in lst1:
432
x = from_triple(1, bindigits(m), 0)
433
yield x, x
434
for m in lst1:
435
for n in lst2:
436
x = from_triple(1, bindigits(m), 0)
437
y = from_triple(1, bindigits(n), 0)
438
yield x, y
439
440
441
def randint():
442
p = randrange(1, 100)
443
return ndigits(p) * (1,-1)[randrange(2)]
444
445
def randfloat():
446
p = randrange(1, 100)
447
s = numeric_value(p, 383)
448
try:
449
f = float(numeric_value(p, 383))
450
except ValueError:
451
f = 0.0
452
return f
453
454
def randcomplex():
455
real = randfloat()
456
if randrange(100) > 30:
457
imag = 0.0
458
else:
459
imag = randfloat()
460
return complex(real, imag)
461
462
def randfraction():
463
num = randint()
464
denom = randint()
465
if denom == 0:
466
denom = 1
467
return Fraction(num, denom)
468
469
number_funcs = [randint, randfloat, randcomplex, randfraction]
470
471
def un_random_mixed_op(itr=None):
472
if itr is None:
473
itr = 1000
474
for _ in range(itr):
475
for func in number_funcs:
476
yield func()
477
# Test garbage input
478
for x in (['x'], ('y',), {'z'}, {1:'z'}):
479
yield x
480
481
def bin_random_mixed_op(prec, emax, emin, itr=None):
482
if itr is None:
483
itr = 1000
484
for _ in range(itr):
485
for func in number_funcs:
486
yield randdec(prec, emax), func()
487
yield func(), randdec(prec, emax)
488
for number in number_funcs:
489
for dec in close_funcs:
490
yield dec(prec, emax, emin), number()
491
# Test garbage input
492
for x in (['x'], ('y',), {'z'}, {1:'z'}):
493
for y in (['x'], ('y',), {'z'}, {1:'z'}):
494
yield x, y
495
496
def tern_random_mixed_op(prec, emax, emin, itr):
497
if itr is None:
498
itr = 1000
499
for _ in range(itr):
500
for func in number_funcs:
501
yield randdec(prec, emax), randdec(prec, emax), func()
502
yield randdec(prec, emax), func(), func()
503
yield func(), func(), func()
504
# Test garbage input
505
for x in (['x'], ('y',), {'z'}, {1:'z'}):
506
for y in (['x'], ('y',), {'z'}, {1:'z'}):
507
for z in (['x'], ('y',), {'z'}, {1:'z'}):
508
yield x, y, z
509
510
def all_unary(prec, exp_range, itr):
511
for a in un_close_to_pow10(prec, exp_range, itr):
512
yield (a,)
513
for a in un_close_numbers(prec, exp_range, -exp_range, itr):
514
yield (a,)
515
for a in un_incr_digits_tuple(prec, exp_range, itr):
516
yield (a,)
517
for a in un_randfloat():
518
yield (a,)
519
for a in un_random_mixed_op(itr):
520
yield (a,)
521
for a in logical_un_incr_digits(prec, itr):
522
yield (a,)
523
for _ in range(100):
524
yield (randdec(prec, exp_range),)
525
for _ in range(100):
526
yield (randtuple(prec, exp_range),)
527
528
def unary_optarg(prec, exp_range, itr):
529
for _ in range(100):
530
yield randdec(prec, exp_range), None
531
yield randdec(prec, exp_range), None, None
532
533
def all_binary(prec, exp_range, itr):
534
for a, b in bin_close_to_pow10(prec, exp_range, itr):
535
yield a, b
536
for a, b in bin_close_numbers(prec, exp_range, -exp_range, itr):
537
yield a, b
538
for a, b in bin_incr_digits(prec, exp_range, itr):
539
yield a, b
540
for a, b in bin_randfloat():
541
yield a, b
542
for a, b in bin_random_mixed_op(prec, exp_range, -exp_range, itr):
543
yield a, b
544
for a, b in logical_bin_incr_digits(prec, itr):
545
yield a, b
546
for _ in range(100):
547
yield randdec(prec, exp_range), randdec(prec, exp_range)
548
549
def binary_optarg(prec, exp_range, itr):
550
for _ in range(100):
551
yield randdec(prec, exp_range), randdec(prec, exp_range), None
552
yield randdec(prec, exp_range), randdec(prec, exp_range), None, None
553
554
def all_ternary(prec, exp_range, itr):
555
for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr):
556
yield a, b, c
557
for a, b, c in tern_incr_digits(prec, exp_range, itr):
558
yield a, b, c
559
for a, b, c in tern_randfloat():
560
yield a, b, c
561
for a, b, c in tern_random_mixed_op(prec, exp_range, -exp_range, itr):
562
yield a, b, c
563
for _ in range(100):
564
a = randdec(prec, 2*exp_range)
565
b = randdec(prec, 2*exp_range)
566
c = randdec(prec, 2*exp_range)
567
yield a, b, c
568
569
def ternary_optarg(prec, exp_range, itr):
570
for _ in range(100):
571
a = randdec(prec, 2*exp_range)
572
b = randdec(prec, 2*exp_range)
573
c = randdec(prec, 2*exp_range)
574
yield a, b, c, None
575
yield a, b, c, None, None
576
577