| #!/usr/bin/env python |
| |
| # |
| # Copyright (c) 2008-2012 Stefan Krah. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND |
| # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| # SUCH DAMAGE. |
| # |
| |
| |
| # Generate test cases for deccheck.py. |
| |
| |
| # |
| # Grammar from http://speleotrove.com/decimal/daconvs.html |
| # |
| # sign ::= '+' | '-' |
| # digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | |
| # '8' | '9' |
| # indicator ::= 'e' | 'E' |
| # digits ::= digit [digit]... |
| # decimal-part ::= digits '.' [digits] | ['.'] digits |
| # exponent-part ::= indicator [sign] digits |
| # infinity ::= 'Infinity' | 'Inf' |
| # nan ::= 'NaN' [digits] | 'sNaN' [digits] |
| # numeric-value ::= decimal-part [exponent-part] | infinity |
| # numeric-string ::= [sign] numeric-value | [sign] nan |
| # |
| |
| |
| from random import randrange, sample |
| from fractions import Fraction |
| from randfloat import un_randfloat, bin_randfloat, tern_randfloat |
| |
| |
| def sign(): |
| if randrange(2): |
| if randrange(2): return '+' |
| return '' |
| return '-' |
| |
| def indicator(): |
| return "eE"[randrange(2)] |
| |
| def digits(maxprec): |
| if maxprec == 0: return '' |
| return str(randrange(10**maxprec)) |
| |
| def dot(): |
| if randrange(2): return '.' |
| return '' |
| |
| def decimal_part(maxprec): |
| if randrange(100) > 60: # integers |
| return digits(maxprec) |
| if randrange(2): |
| intlen = randrange(1, maxprec+1) |
| fraclen = maxprec-intlen |
| intpart = digits(intlen) |
| fracpart = digits(fraclen) |
| return ''.join((intpart, '.', fracpart)) |
| else: |
| return ''.join((dot(), digits(maxprec))) |
| |
| def expdigits(maxexp): |
| return str(randrange(maxexp)) |
| |
| def exponent_part(maxexp): |
| return ''.join((indicator(), sign(), expdigits(maxexp))) |
| |
| def infinity(): |
| if randrange(2): return 'Infinity' |
| return 'Inf' |
| |
| def nan(): |
| d = '' |
| if randrange(2): |
| d = digits(randrange(99)) |
| if randrange(2): |
| return ''.join(('NaN', d)) |
| else: |
| return ''.join(('sNaN', d)) |
| |
| def numeric_value(maxprec, maxexp): |
| if randrange(100) > 90: |
| return infinity() |
| exp_part = '' |
| if randrange(100) > 60: |
| exp_part = exponent_part(maxexp) |
| return ''.join((decimal_part(maxprec), exp_part)) |
| |
| def numeric_string(maxprec, maxexp): |
| if randrange(100) > 95: |
| return ''.join((sign(), nan())) |
| else: |
| return ''.join((sign(), numeric_value(maxprec, maxexp))) |
| |
| def randdec(maxprec, maxexp): |
| return numeric_string(maxprec, maxexp) |
| |
| def rand_adjexp(maxprec, maxadjexp): |
| d = digits(maxprec) |
| maxexp = maxadjexp-len(d)+1 |
| if maxexp == 0: maxexp = 1 |
| exp = str(randrange(maxexp-2*(abs(maxexp)), maxexp)) |
| return ''.join((sign(), d, 'E', exp)) |
| |
| |
| def ndigits(n): |
| if n < 1: return 0 |
| return randrange(10**(n-1), 10**n) |
| |
| def randtuple(maxprec, maxexp): |
| n = randrange(100) |
| sign = randrange(2) |
| coeff = ndigits(maxprec) |
| if n >= 95: |
| coeff = () |
| exp = 'F' |
| elif n >= 85: |
| coeff = tuple(map(int, str(ndigits(maxprec)))) |
| exp = "nN"[randrange(2)] |
| else: |
| coeff = tuple(map(int, str(ndigits(maxprec)))) |
| exp = randrange(-maxexp, maxexp) |
| return (sign, coeff, exp) |
| |
| def from_triple(sign, coeff, exp): |
| return ''.join((str(sign*coeff), indicator(), str(exp))) |
| |
| |
| # Close to 10**n |
| def un_close_to_pow10(prec, maxexp, itr=None): |
| if itr is None: |
| lst = range(prec+30) |
| else: |
| lst = sample(range(prec+30), itr) |
| nines = [10**n - 1 for n in lst] |
| pow10 = [10**n for n in lst] |
| for coeff in nines: |
| yield coeff |
| yield -coeff |
| yield from_triple(1, coeff, randrange(2*maxexp)) |
| yield from_triple(-1, coeff, randrange(2*maxexp)) |
| for coeff in pow10: |
| yield coeff |
| yield -coeff |
| |
| # Close to 10**n |
| def bin_close_to_pow10(prec, maxexp, itr=None): |
| if itr is None: |
| lst = range(prec+30) |
| else: |
| lst = sample(range(prec+30), itr) |
| nines = [10**n - 1 for n in lst] |
| pow10 = [10**n for n in lst] |
| for coeff in nines: |
| yield coeff, 1 |
| yield -coeff, -1 |
| yield 1, coeff |
| yield -1, -coeff |
| yield from_triple(1, coeff, randrange(2*maxexp)), 1 |
| yield from_triple(-1, coeff, randrange(2*maxexp)), -1 |
| yield 1, from_triple(1, coeff, -randrange(2*maxexp)) |
| yield -1, from_triple(-1, coeff, -randrange(2*maxexp)) |
| for coeff in pow10: |
| yield coeff, -1 |
| yield -coeff, 1 |
| yield 1, -coeff |
| yield -coeff, 1 |
| |
| # Close to 1: |
| def close_to_one_greater(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("1.", '0'*randrange(prec), |
| str(randrange(rprec)))) |
| |
| def close_to_one_less(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("0.9", '9'*randrange(prec), |
| str(randrange(rprec)))) |
| |
| # Close to 0: |
| def close_to_zero_greater(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("0.", '0'*randrange(prec), |
| str(randrange(rprec)))) |
| |
| def close_to_zero_less(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("-0.", '0'*randrange(prec), |
| str(randrange(rprec)))) |
| |
| # Close to emax: |
| def close_to_emax_less(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("9.", '9'*randrange(prec), |
| str(randrange(rprec)), "E", str(emax))) |
| |
| def close_to_emax_greater(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("1.", '0'*randrange(prec), |
| str(randrange(rprec)), "E", str(emax+1))) |
| |
| # Close to emin: |
| def close_to_emin_greater(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("1.", '0'*randrange(prec), |
| str(randrange(rprec)), "E", str(emin))) |
| |
| def close_to_emin_less(prec, emax, emin): |
| rprec = 10**prec |
| return ''.join(("9.", '9'*randrange(prec), |
| str(randrange(rprec)), "E", str(emin-1))) |
| |
| # Close to etiny: |
| def close_to_etiny_greater(prec, emax, emin): |
| rprec = 10**prec |
| etiny = emin - (prec - 1) |
| return ''.join(("1.", '0'*randrange(prec), |
| str(randrange(rprec)), "E", str(etiny))) |
| |
| def close_to_etiny_less(prec, emax, emin): |
| rprec = 10**prec |
| etiny = emin - (prec - 1) |
| return ''.join(("9.", '9'*randrange(prec), |
| str(randrange(rprec)), "E", str(etiny-1))) |
| |
| |
| def close_to_min_etiny_greater(prec, max_prec, min_emin): |
| rprec = 10**prec |
| etiny = min_emin - (max_prec - 1) |
| return ''.join(("1.", '0'*randrange(prec), |
| str(randrange(rprec)), "E", str(etiny))) |
| |
| def close_to_min_etiny_less(prec, max_prec, min_emin): |
| rprec = 10**prec |
| etiny = min_emin - (max_prec - 1) |
| return ''.join(("9.", '9'*randrange(prec), |
| str(randrange(rprec)), "E", str(etiny-1))) |
| |
| |
| close_funcs = [ |
| close_to_one_greater, close_to_one_less, close_to_zero_greater, |
| close_to_zero_less, close_to_emax_less, close_to_emax_greater, |
| close_to_emin_greater, close_to_emin_less, close_to_etiny_greater, |
| close_to_etiny_less, close_to_min_etiny_greater, close_to_min_etiny_less |
| ] |
| |
| |
| def un_close_numbers(prec, emax, emin, itr=None): |
| if itr is None: |
| itr = 1000 |
| for _ in range(itr): |
| for func in close_funcs: |
| yield func(prec, emax, emin) |
| |
| def bin_close_numbers(prec, emax, emin, itr=None): |
| if itr is None: |
| itr = 1000 |
| for _ in range(itr): |
| for func1 in close_funcs: |
| for func2 in close_funcs: |
| yield func1(prec, emax, emin), func2(prec, emax, emin) |
| for func in close_funcs: |
| yield randdec(prec, emax), func(prec, emax, emin) |
| yield func(prec, emax, emin), randdec(prec, emax) |
| |
| def tern_close_numbers(prec, emax, emin, itr): |
| if itr is None: |
| itr = 1000 |
| for _ in range(itr): |
| for func1 in close_funcs: |
| for func2 in close_funcs: |
| for func3 in close_funcs: |
| yield (func1(prec, emax, emin), func2(prec, emax, emin), |
| func3(prec, emax, emin)) |
| for func in close_funcs: |
| yield (randdec(prec, emax), func(prec, emax, emin), |
| func(prec, emax, emin)) |
| yield (func(prec, emax, emin), randdec(prec, emax), |
| func(prec, emax, emin)) |
| yield (func(prec, emax, emin), func(prec, emax, emin), |
| randdec(prec, emax)) |
| for func in close_funcs: |
| yield (randdec(prec, emax), randdec(prec, emax), |
| func(prec, emax, emin)) |
| yield (randdec(prec, emax), func(prec, emax, emin), |
| randdec(prec, emax)) |
| yield (func(prec, emax, emin), randdec(prec, emax), |
| randdec(prec, emax)) |
| |
| |
| # If itr == None, test all digit lengths up to prec + 30 |
| def un_incr_digits(prec, maxexp, itr): |
| if itr is None: |
| lst = range(prec+30) |
| else: |
| lst = sample(range(prec+30), itr) |
| for m in lst: |
| yield from_triple(1, ndigits(m), 0) |
| yield from_triple(-1, ndigits(m), 0) |
| yield from_triple(1, ndigits(m), randrange(maxexp)) |
| yield from_triple(-1, ndigits(m), randrange(maxexp)) |
| |
| # If itr == None, test all digit lengths up to prec + 30 |
| # Also output decimals im tuple form. |
| def un_incr_digits_tuple(prec, maxexp, itr): |
| if itr is None: |
| lst = range(prec+30) |
| else: |
| lst = sample(range(prec+30), itr) |
| for m in lst: |
| yield from_triple(1, ndigits(m), 0) |
| yield from_triple(-1, ndigits(m), 0) |
| yield from_triple(1, ndigits(m), randrange(maxexp)) |
| yield from_triple(-1, ndigits(m), randrange(maxexp)) |
| # test from tuple |
| yield (0, tuple(map(int, str(ndigits(m)))), 0) |
| yield (1, tuple(map(int, str(ndigits(m)))), 0) |
| yield (0, tuple(map(int, str(ndigits(m)))), randrange(maxexp)) |
| yield (1, tuple(map(int, str(ndigits(m)))), randrange(maxexp)) |
| |
| # If itr == None, test all combinations of digit lengths up to prec + 30 |
| def bin_incr_digits(prec, maxexp, itr): |
| if itr is None: |
| lst1 = range(prec+30) |
| lst2 = range(prec+30) |
| else: |
| lst1 = sample(range(prec+30), itr) |
| lst2 = sample(range(prec+30), itr) |
| for m in lst1: |
| x = from_triple(1, ndigits(m), 0) |
| yield x, x |
| x = from_triple(-1, ndigits(m), 0) |
| yield x, x |
| x = from_triple(1, ndigits(m), randrange(maxexp)) |
| yield x, x |
| x = from_triple(-1, ndigits(m), randrange(maxexp)) |
| yield x, x |
| for m in lst1: |
| for n in lst2: |
| x = from_triple(1, ndigits(m), 0) |
| y = from_triple(1, ndigits(n), 0) |
| yield x, y |
| x = from_triple(-1, ndigits(m), 0) |
| y = from_triple(1, ndigits(n), 0) |
| yield x, y |
| x = from_triple(1, ndigits(m), 0) |
| y = from_triple(-1, ndigits(n), 0) |
| yield x, y |
| x = from_triple(-1, ndigits(m), 0) |
| y = from_triple(-1, ndigits(n), 0) |
| yield x, y |
| x = from_triple(1, ndigits(m), randrange(maxexp)) |
| y = from_triple(1, ndigits(n), randrange(maxexp)) |
| yield x, y |
| x = from_triple(-1, ndigits(m), randrange(maxexp)) |
| y = from_triple(1, ndigits(n), randrange(maxexp)) |
| yield x, y |
| x = from_triple(1, ndigits(m), randrange(maxexp)) |
| y = from_triple(-1, ndigits(n), randrange(maxexp)) |
| yield x, y |
| x = from_triple(-1, ndigits(m), randrange(maxexp)) |
| y = from_triple(-1, ndigits(n), randrange(maxexp)) |
| yield x, y |
| |
| |
| def randsign(): |
| return (1, -1)[randrange(2)] |
| |
| # If itr == None, test all combinations of digit lengths up to prec + 30 |
| def tern_incr_digits(prec, maxexp, itr): |
| if itr is None: |
| lst1 = range(prec+30) |
| lst2 = range(prec+30) |
| lst3 = range(prec+30) |
| else: |
| lst1 = sample(range(prec+30), itr) |
| lst2 = sample(range(prec+30), itr) |
| lst3 = sample(range(prec+30), itr) |
| for m in lst1: |
| for n in lst2: |
| for p in lst3: |
| x = from_triple(randsign(), ndigits(m), 0) |
| y = from_triple(randsign(), ndigits(n), 0) |
| z = from_triple(randsign(), ndigits(p), 0) |
| yield x, y, z |
| |
| |
| # Tests for the 'logical' functions |
| def bindigits(prec): |
| z = 0 |
| for i in range(prec): |
| z += randrange(2) * 10**i |
| return z |
| |
| def logical_un_incr_digits(prec, itr): |
| if itr is None: |
| lst = range(prec+30) |
| else: |
| lst = sample(range(prec+30), itr) |
| for m in lst: |
| yield from_triple(1, bindigits(m), 0) |
| |
| def logical_bin_incr_digits(prec, itr): |
| if itr is None: |
| lst1 = range(prec+30) |
| lst2 = range(prec+30) |
| else: |
| lst1 = sample(range(prec+30), itr) |
| lst2 = sample(range(prec+30), itr) |
| for m in lst1: |
| x = from_triple(1, bindigits(m), 0) |
| yield x, x |
| for m in lst1: |
| for n in lst2: |
| x = from_triple(1, bindigits(m), 0) |
| y = from_triple(1, bindigits(n), 0) |
| yield x, y |
| |
| |
| def randint(): |
| p = randrange(1, 100) |
| return ndigits(p) * (1,-1)[randrange(2)] |
| |
| def randfloat(): |
| p = randrange(1, 100) |
| s = numeric_value(p, 383) |
| try: |
| f = float(numeric_value(p, 383)) |
| except ValueError: |
| f = 0.0 |
| return f |
| |
| def randcomplex(): |
| real = randfloat() |
| if randrange(100) > 30: |
| imag = 0.0 |
| else: |
| imag = randfloat() |
| return complex(real, imag) |
| |
| def randfraction(): |
| num = randint() |
| denom = randint() |
| if denom == 0: |
| denom = 1 |
| return Fraction(num, denom) |
| |
| number_funcs = [randint, randfloat, randcomplex, randfraction] |
| |
| def un_random_mixed_op(itr=None): |
| if itr is None: |
| itr = 1000 |
| for _ in range(itr): |
| for func in number_funcs: |
| yield func() |
| # Test garbage input |
| for x in (['x'], ('y',), {'z'}, {1:'z'}): |
| yield x |
| |
| def bin_random_mixed_op(prec, emax, emin, itr=None): |
| if itr is None: |
| itr = 1000 |
| for _ in range(itr): |
| for func in number_funcs: |
| yield randdec(prec, emax), func() |
| yield func(), randdec(prec, emax) |
| for number in number_funcs: |
| for dec in close_funcs: |
| yield dec(prec, emax, emin), number() |
| # Test garbage input |
| for x in (['x'], ('y',), {'z'}, {1:'z'}): |
| for y in (['x'], ('y',), {'z'}, {1:'z'}): |
| yield x, y |
| |
| def tern_random_mixed_op(prec, emax, emin, itr): |
| if itr is None: |
| itr = 1000 |
| for _ in range(itr): |
| for func in number_funcs: |
| yield randdec(prec, emax), randdec(prec, emax), func() |
| yield randdec(prec, emax), func(), func() |
| yield func(), func(), func() |
| # Test garbage input |
| for x in (['x'], ('y',), {'z'}, {1:'z'}): |
| for y in (['x'], ('y',), {'z'}, {1:'z'}): |
| for z in (['x'], ('y',), {'z'}, {1:'z'}): |
| yield x, y, z |
| |
| def all_unary(prec, exp_range, itr): |
| for a in un_close_to_pow10(prec, exp_range, itr): |
| yield (a,) |
| for a in un_close_numbers(prec, exp_range, -exp_range, itr): |
| yield (a,) |
| for a in un_incr_digits_tuple(prec, exp_range, itr): |
| yield (a,) |
| for a in un_randfloat(): |
| yield (a,) |
| for a in un_random_mixed_op(itr): |
| yield (a,) |
| for a in logical_un_incr_digits(prec, itr): |
| yield (a,) |
| for _ in range(100): |
| yield (randdec(prec, exp_range),) |
| for _ in range(100): |
| yield (randtuple(prec, exp_range),) |
| |
| def all_binary(prec, exp_range, itr): |
| for a, b in bin_close_to_pow10(prec, exp_range, itr): |
| yield a, b |
| for a, b in bin_close_numbers(prec, exp_range, -exp_range, itr): |
| yield a, b |
| for a, b in bin_incr_digits(prec, exp_range, itr): |
| yield a, b |
| for a, b in bin_randfloat(): |
| yield a, b |
| for a, b in bin_random_mixed_op(prec, exp_range, -exp_range, itr): |
| yield a, b |
| for a, b in logical_bin_incr_digits(prec, itr): |
| yield a, b |
| for _ in range(100): |
| yield randdec(prec, exp_range), randdec(prec, exp_range) |
| |
| def all_ternary(prec, exp_range, itr): |
| for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr): |
| yield a, b, c |
| for a, b, c in tern_incr_digits(prec, exp_range, itr): |
| yield a, b, c |
| for a, b, c in tern_randfloat(): |
| yield a, b, c |
| for a, b, c in tern_random_mixed_op(prec, exp_range, -exp_range, itr): |
| yield a, b, c |
| for _ in range(100): |
| a = randdec(prec, 2*exp_range) |
| b = randdec(prec, 2*exp_range) |
| c = randdec(prec, 2*exp_range) |
| yield a, b, c |