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
49from random import randrange, sample
50from fractions import Fraction
51from randfloat import un_randfloat, bin_randfloat, tern_randfloat
52
53
54def sign():
55    if randrange(2):
56        if randrange(2): return '+'
57        return ''
58    return '-'
59
60def indicator():
61    return "eE"[randrange(2)]
62
63def digits(maxprec):
64    if maxprec == 0: return ''
65    return str(randrange(10**maxprec))
66
67def dot():
68    if randrange(2): return '.'
69    return ''
70
71def 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
83def expdigits(maxexp):
84    return str(randrange(maxexp))
85
86def exponent_part(maxexp):
87    return ''.join((indicator(), sign(), expdigits(maxexp)))
88
89def infinity():
90    if randrange(2): return 'Infinity'
91    return 'Inf'
92
93def 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
102def 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
110def 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
116def randdec(maxprec, maxexp):
117    return numeric_string(maxprec, maxexp)
118
119def 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
127def ndigits(n):
128    if n < 1: return 0
129    return randrange(10**(n-1), 10**n)
130
131def 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
146def from_triple(sign, coeff, exp):
147    return ''.join((str(sign*coeff), indicator(), str(exp)))
148
149
150# Close to 10**n
151def 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
168def 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:
191def close_to_one_greater(prec, emax, emin):
192    rprec = 10**prec
193    return ''.join(("1.", '0'*randrange(prec),
194                   str(randrange(rprec))))
195
196def 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:
202def close_to_zero_greater(prec, emax, emin):
203    rprec = 10**prec
204    return ''.join(("0.", '0'*randrange(prec),
205                   str(randrange(rprec))))
206
207def 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:
213def 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
218def 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:
224def 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
229def 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:
235def 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
241def 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
248def 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
254def 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
261close_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
269def 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
276def 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
287def 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
313def 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.
326def 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
343def 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
387def randsign():
388    return (1, -1)[randrange(2)]
389
390# If itr == None, test all combinations of digit lengths up to prec + 30
391def 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
410def bindigits(prec):
411    z = 0
412    for i in range(prec):
413        z += randrange(2) * 10**i
414    return z
415
416def 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
424def 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
441def randint():
442    p = randrange(1, 100)
443    return ndigits(p) * (1,-1)[randrange(2)]
444
445def 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
454def randcomplex():
455    real = randfloat()
456    if randrange(100) > 30:
457        imag = 0.0
458    else:
459        imag = randfloat()
460    return complex(real, imag)
461
462def randfraction():
463    num = randint()
464    denom = randint()
465    if denom == 0:
466        denom = 1
467    return Fraction(num, denom)
468
469number_funcs = [randint, randfloat, randcomplex, randfraction]
470
471def 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
481def 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
496def 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
510def 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
528def 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
533def 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
549def 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
554def 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
569def 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