17db96d56Sopenharmony_ci# 27db96d56Sopenharmony_ci# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. 37db96d56Sopenharmony_ci# 47db96d56Sopenharmony_ci# Redistribution and use in source and binary forms, with or without 57db96d56Sopenharmony_ci# modification, are permitted provided that the following conditions 67db96d56Sopenharmony_ci# are met: 77db96d56Sopenharmony_ci# 87db96d56Sopenharmony_ci# 1. Redistributions of source code must retain the above copyright 97db96d56Sopenharmony_ci# notice, this list of conditions and the following disclaimer. 107db96d56Sopenharmony_ci# 117db96d56Sopenharmony_ci# 2. Redistributions in binary form must reproduce the above copyright 127db96d56Sopenharmony_ci# notice, this list of conditions and the following disclaimer in the 137db96d56Sopenharmony_ci# documentation and/or other materials provided with the distribution. 147db96d56Sopenharmony_ci# 157db96d56Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND 167db96d56Sopenharmony_ci# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 177db96d56Sopenharmony_ci# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 187db96d56Sopenharmony_ci# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 197db96d56Sopenharmony_ci# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 207db96d56Sopenharmony_ci# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 217db96d56Sopenharmony_ci# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 227db96d56Sopenharmony_ci# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 237db96d56Sopenharmony_ci# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 247db96d56Sopenharmony_ci# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 257db96d56Sopenharmony_ci# SUCH DAMAGE. 267db96d56Sopenharmony_ci# 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ci# 297db96d56Sopenharmony_ci# Usage: python deccheck.py [--short|--medium|--long|--all] 307db96d56Sopenharmony_ci# 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ciimport random 347db96d56Sopenharmony_ciimport time 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ciRANDSEED = int(time.time()) 377db96d56Sopenharmony_cirandom.seed(RANDSEED) 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ciimport sys 407db96d56Sopenharmony_ciimport os 417db96d56Sopenharmony_cifrom copy import copy 427db96d56Sopenharmony_cifrom collections import defaultdict 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ciimport argparse 457db96d56Sopenharmony_ciimport subprocess 467db96d56Sopenharmony_cifrom subprocess import PIPE, STDOUT 477db96d56Sopenharmony_cifrom queue import Queue, Empty 487db96d56Sopenharmony_cifrom threading import Thread, Event, Lock 497db96d56Sopenharmony_ci 507db96d56Sopenharmony_cifrom test.support.import_helper import import_fresh_module 517db96d56Sopenharmony_cifrom randdec import randfloat, all_unary, all_binary, all_ternary 527db96d56Sopenharmony_cifrom randdec import unary_optarg, binary_optarg, ternary_optarg 537db96d56Sopenharmony_cifrom formathelper import rand_format, rand_locale 547db96d56Sopenharmony_cifrom _pydecimal import _dec_from_triple 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ciC = import_fresh_module('decimal', fresh=['_decimal']) 577db96d56Sopenharmony_ciP = import_fresh_module('decimal', blocked=['_decimal']) 587db96d56Sopenharmony_ciEXIT_STATUS = 0 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci# Contains all categories of Decimal methods. 627db96d56Sopenharmony_ciFunctions = { 637db96d56Sopenharmony_ci # Plain unary: 647db96d56Sopenharmony_ci 'unary': ( 657db96d56Sopenharmony_ci '__abs__', '__bool__', '__ceil__', '__complex__', '__copy__', 667db96d56Sopenharmony_ci '__floor__', '__float__', '__hash__', '__int__', '__neg__', 677db96d56Sopenharmony_ci '__pos__', '__reduce__', '__repr__', '__str__', '__trunc__', 687db96d56Sopenharmony_ci 'adjusted', 'as_integer_ratio', 'as_tuple', 'canonical', 'conjugate', 697db96d56Sopenharmony_ci 'copy_abs', 'copy_negate', 'is_canonical', 'is_finite', 'is_infinite', 707db96d56Sopenharmony_ci 'is_nan', 'is_qnan', 'is_signed', 'is_snan', 'is_zero', 'radix' 717db96d56Sopenharmony_ci ), 727db96d56Sopenharmony_ci # Unary with optional context: 737db96d56Sopenharmony_ci 'unary_ctx': ( 747db96d56Sopenharmony_ci 'exp', 'is_normal', 'is_subnormal', 'ln', 'log10', 'logb', 757db96d56Sopenharmony_ci 'logical_invert', 'next_minus', 'next_plus', 'normalize', 767db96d56Sopenharmony_ci 'number_class', 'sqrt', 'to_eng_string' 777db96d56Sopenharmony_ci ), 787db96d56Sopenharmony_ci # Unary with optional rounding mode and context: 797db96d56Sopenharmony_ci 'unary_rnd_ctx': ('to_integral', 'to_integral_exact', 'to_integral_value'), 807db96d56Sopenharmony_ci # Plain binary: 817db96d56Sopenharmony_ci 'binary': ( 827db96d56Sopenharmony_ci '__add__', '__divmod__', '__eq__', '__floordiv__', '__ge__', '__gt__', 837db96d56Sopenharmony_ci '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__pow__', 847db96d56Sopenharmony_ci '__radd__', '__rdivmod__', '__rfloordiv__', '__rmod__', '__rmul__', 857db96d56Sopenharmony_ci '__rpow__', '__rsub__', '__rtruediv__', '__sub__', '__truediv__', 867db96d56Sopenharmony_ci 'compare_total', 'compare_total_mag', 'copy_sign', 'quantize', 877db96d56Sopenharmony_ci 'same_quantum' 887db96d56Sopenharmony_ci ), 897db96d56Sopenharmony_ci # Binary with optional context: 907db96d56Sopenharmony_ci 'binary_ctx': ( 917db96d56Sopenharmony_ci 'compare', 'compare_signal', 'logical_and', 'logical_or', 'logical_xor', 927db96d56Sopenharmony_ci 'max', 'max_mag', 'min', 'min_mag', 'next_toward', 'remainder_near', 937db96d56Sopenharmony_ci 'rotate', 'scaleb', 'shift' 947db96d56Sopenharmony_ci ), 957db96d56Sopenharmony_ci # Plain ternary: 967db96d56Sopenharmony_ci 'ternary': ('__pow__',), 977db96d56Sopenharmony_ci # Ternary with optional context: 987db96d56Sopenharmony_ci 'ternary_ctx': ('fma',), 997db96d56Sopenharmony_ci # Special: 1007db96d56Sopenharmony_ci 'special': ('__format__', '__reduce_ex__', '__round__', 'from_float', 1017db96d56Sopenharmony_ci 'quantize'), 1027db96d56Sopenharmony_ci # Properties: 1037db96d56Sopenharmony_ci 'property': ('real', 'imag') 1047db96d56Sopenharmony_ci} 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci# Contains all categories of Context methods. The n-ary classification 1077db96d56Sopenharmony_ci# applies to the number of Decimal arguments. 1087db96d56Sopenharmony_ciContextFunctions = { 1097db96d56Sopenharmony_ci # Plain nullary: 1107db96d56Sopenharmony_ci 'nullary': ('context.__hash__', 'context.__reduce__', 'context.radix'), 1117db96d56Sopenharmony_ci # Plain unary: 1127db96d56Sopenharmony_ci 'unary': ('context.abs', 'context.canonical', 'context.copy_abs', 1137db96d56Sopenharmony_ci 'context.copy_decimal', 'context.copy_negate', 1147db96d56Sopenharmony_ci 'context.create_decimal', 'context.exp', 'context.is_canonical', 1157db96d56Sopenharmony_ci 'context.is_finite', 'context.is_infinite', 'context.is_nan', 1167db96d56Sopenharmony_ci 'context.is_normal', 'context.is_qnan', 'context.is_signed', 1177db96d56Sopenharmony_ci 'context.is_snan', 'context.is_subnormal', 'context.is_zero', 1187db96d56Sopenharmony_ci 'context.ln', 'context.log10', 'context.logb', 1197db96d56Sopenharmony_ci 'context.logical_invert', 'context.minus', 'context.next_minus', 1207db96d56Sopenharmony_ci 'context.next_plus', 'context.normalize', 'context.number_class', 1217db96d56Sopenharmony_ci 'context.plus', 'context.sqrt', 'context.to_eng_string', 1227db96d56Sopenharmony_ci 'context.to_integral', 'context.to_integral_exact', 1237db96d56Sopenharmony_ci 'context.to_integral_value', 'context.to_sci_string' 1247db96d56Sopenharmony_ci ), 1257db96d56Sopenharmony_ci # Plain binary: 1267db96d56Sopenharmony_ci 'binary': ('context.add', 'context.compare', 'context.compare_signal', 1277db96d56Sopenharmony_ci 'context.compare_total', 'context.compare_total_mag', 1287db96d56Sopenharmony_ci 'context.copy_sign', 'context.divide', 'context.divide_int', 1297db96d56Sopenharmony_ci 'context.divmod', 'context.logical_and', 'context.logical_or', 1307db96d56Sopenharmony_ci 'context.logical_xor', 'context.max', 'context.max_mag', 1317db96d56Sopenharmony_ci 'context.min', 'context.min_mag', 'context.multiply', 1327db96d56Sopenharmony_ci 'context.next_toward', 'context.power', 'context.quantize', 1337db96d56Sopenharmony_ci 'context.remainder', 'context.remainder_near', 'context.rotate', 1347db96d56Sopenharmony_ci 'context.same_quantum', 'context.scaleb', 'context.shift', 1357db96d56Sopenharmony_ci 'context.subtract' 1367db96d56Sopenharmony_ci ), 1377db96d56Sopenharmony_ci # Plain ternary: 1387db96d56Sopenharmony_ci 'ternary': ('context.fma', 'context.power'), 1397db96d56Sopenharmony_ci # Special: 1407db96d56Sopenharmony_ci 'special': ('context.__reduce_ex__', 'context.create_decimal_from_float') 1417db96d56Sopenharmony_ci} 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci# Functions that set no context flags but whose result can differ depending 1447db96d56Sopenharmony_ci# on prec, Emin and Emax. 1457db96d56Sopenharmony_ciMaxContextSkip = ['is_normal', 'is_subnormal', 'logical_invert', 'next_minus', 1467db96d56Sopenharmony_ci 'next_plus', 'number_class', 'logical_and', 'logical_or', 1477db96d56Sopenharmony_ci 'logical_xor', 'next_toward', 'rotate', 'shift'] 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci# Functions that require a restricted exponent range for reasonable runtimes. 1507db96d56Sopenharmony_ciUnaryRestricted = [ 1517db96d56Sopenharmony_ci '__ceil__', '__floor__', '__int__', '__trunc__', 1527db96d56Sopenharmony_ci 'as_integer_ratio', 'to_integral', 'to_integral_value' 1537db96d56Sopenharmony_ci] 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ciBinaryRestricted = ['__round__'] 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ciTernaryRestricted = ['__pow__', 'context.power'] 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci# ====================================================================== 1617db96d56Sopenharmony_ci# Unified Context 1627db96d56Sopenharmony_ci# ====================================================================== 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci# Translate symbols. 1657db96d56Sopenharmony_ciCondMap = { 1667db96d56Sopenharmony_ci C.Clamped: P.Clamped, 1677db96d56Sopenharmony_ci C.ConversionSyntax: P.ConversionSyntax, 1687db96d56Sopenharmony_ci C.DivisionByZero: P.DivisionByZero, 1697db96d56Sopenharmony_ci C.DivisionImpossible: P.InvalidOperation, 1707db96d56Sopenharmony_ci C.DivisionUndefined: P.DivisionUndefined, 1717db96d56Sopenharmony_ci C.Inexact: P.Inexact, 1727db96d56Sopenharmony_ci C.InvalidContext: P.InvalidContext, 1737db96d56Sopenharmony_ci C.InvalidOperation: P.InvalidOperation, 1747db96d56Sopenharmony_ci C.Overflow: P.Overflow, 1757db96d56Sopenharmony_ci C.Rounded: P.Rounded, 1767db96d56Sopenharmony_ci C.Subnormal: P.Subnormal, 1777db96d56Sopenharmony_ci C.Underflow: P.Underflow, 1787db96d56Sopenharmony_ci C.FloatOperation: P.FloatOperation, 1797db96d56Sopenharmony_ci} 1807db96d56Sopenharmony_ci 1817db96d56Sopenharmony_ciRoundModes = [C.ROUND_UP, C.ROUND_DOWN, C.ROUND_CEILING, C.ROUND_FLOOR, 1827db96d56Sopenharmony_ci C.ROUND_HALF_UP, C.ROUND_HALF_DOWN, C.ROUND_HALF_EVEN, 1837db96d56Sopenharmony_ci C.ROUND_05UP] 1847db96d56Sopenharmony_ci 1857db96d56Sopenharmony_ci 1867db96d56Sopenharmony_ciclass Context(object): 1877db96d56Sopenharmony_ci """Provides a convenient way of syncing the C and P contexts""" 1887db96d56Sopenharmony_ci 1897db96d56Sopenharmony_ci __slots__ = ['c', 'p'] 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_ci def __init__(self, c_ctx=None, p_ctx=None): 1927db96d56Sopenharmony_ci """Initialization is from the C context""" 1937db96d56Sopenharmony_ci self.c = C.getcontext() if c_ctx is None else c_ctx 1947db96d56Sopenharmony_ci self.p = P.getcontext() if p_ctx is None else p_ctx 1957db96d56Sopenharmony_ci self.p.prec = self.c.prec 1967db96d56Sopenharmony_ci self.p.Emin = self.c.Emin 1977db96d56Sopenharmony_ci self.p.Emax = self.c.Emax 1987db96d56Sopenharmony_ci self.p.rounding = self.c.rounding 1997db96d56Sopenharmony_ci self.p.capitals = self.c.capitals 2007db96d56Sopenharmony_ci self.settraps([sig for sig in self.c.traps if self.c.traps[sig]]) 2017db96d56Sopenharmony_ci self.setstatus([sig for sig in self.c.flags if self.c.flags[sig]]) 2027db96d56Sopenharmony_ci self.p.clamp = self.c.clamp 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci def __str__(self): 2057db96d56Sopenharmony_ci return str(self.c) + '\n' + str(self.p) 2067db96d56Sopenharmony_ci 2077db96d56Sopenharmony_ci def getprec(self): 2087db96d56Sopenharmony_ci assert(self.c.prec == self.p.prec) 2097db96d56Sopenharmony_ci return self.c.prec 2107db96d56Sopenharmony_ci 2117db96d56Sopenharmony_ci def setprec(self, val): 2127db96d56Sopenharmony_ci self.c.prec = val 2137db96d56Sopenharmony_ci self.p.prec = val 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci def getemin(self): 2167db96d56Sopenharmony_ci assert(self.c.Emin == self.p.Emin) 2177db96d56Sopenharmony_ci return self.c.Emin 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci def setemin(self, val): 2207db96d56Sopenharmony_ci self.c.Emin = val 2217db96d56Sopenharmony_ci self.p.Emin = val 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci def getemax(self): 2247db96d56Sopenharmony_ci assert(self.c.Emax == self.p.Emax) 2257db96d56Sopenharmony_ci return self.c.Emax 2267db96d56Sopenharmony_ci 2277db96d56Sopenharmony_ci def setemax(self, val): 2287db96d56Sopenharmony_ci self.c.Emax = val 2297db96d56Sopenharmony_ci self.p.Emax = val 2307db96d56Sopenharmony_ci 2317db96d56Sopenharmony_ci def getround(self): 2327db96d56Sopenharmony_ci assert(self.c.rounding == self.p.rounding) 2337db96d56Sopenharmony_ci return self.c.rounding 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci def setround(self, val): 2367db96d56Sopenharmony_ci self.c.rounding = val 2377db96d56Sopenharmony_ci self.p.rounding = val 2387db96d56Sopenharmony_ci 2397db96d56Sopenharmony_ci def getcapitals(self): 2407db96d56Sopenharmony_ci assert(self.c.capitals == self.p.capitals) 2417db96d56Sopenharmony_ci return self.c.capitals 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ci def setcapitals(self, val): 2447db96d56Sopenharmony_ci self.c.capitals = val 2457db96d56Sopenharmony_ci self.p.capitals = val 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_ci def getclamp(self): 2487db96d56Sopenharmony_ci assert(self.c.clamp == self.p.clamp) 2497db96d56Sopenharmony_ci return self.c.clamp 2507db96d56Sopenharmony_ci 2517db96d56Sopenharmony_ci def setclamp(self, val): 2527db96d56Sopenharmony_ci self.c.clamp = val 2537db96d56Sopenharmony_ci self.p.clamp = val 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ci prec = property(getprec, setprec) 2567db96d56Sopenharmony_ci Emin = property(getemin, setemin) 2577db96d56Sopenharmony_ci Emax = property(getemax, setemax) 2587db96d56Sopenharmony_ci rounding = property(getround, setround) 2597db96d56Sopenharmony_ci clamp = property(getclamp, setclamp) 2607db96d56Sopenharmony_ci capitals = property(getcapitals, setcapitals) 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci def clear_traps(self): 2637db96d56Sopenharmony_ci self.c.clear_traps() 2647db96d56Sopenharmony_ci for trap in self.p.traps: 2657db96d56Sopenharmony_ci self.p.traps[trap] = False 2667db96d56Sopenharmony_ci 2677db96d56Sopenharmony_ci def clear_status(self): 2687db96d56Sopenharmony_ci self.c.clear_flags() 2697db96d56Sopenharmony_ci self.p.clear_flags() 2707db96d56Sopenharmony_ci 2717db96d56Sopenharmony_ci def settraps(self, lst): 2727db96d56Sopenharmony_ci """lst: C signal list""" 2737db96d56Sopenharmony_ci self.clear_traps() 2747db96d56Sopenharmony_ci for signal in lst: 2757db96d56Sopenharmony_ci self.c.traps[signal] = True 2767db96d56Sopenharmony_ci self.p.traps[CondMap[signal]] = True 2777db96d56Sopenharmony_ci 2787db96d56Sopenharmony_ci def setstatus(self, lst): 2797db96d56Sopenharmony_ci """lst: C signal list""" 2807db96d56Sopenharmony_ci self.clear_status() 2817db96d56Sopenharmony_ci for signal in lst: 2827db96d56Sopenharmony_ci self.c.flags[signal] = True 2837db96d56Sopenharmony_ci self.p.flags[CondMap[signal]] = True 2847db96d56Sopenharmony_ci 2857db96d56Sopenharmony_ci def assert_eq_status(self): 2867db96d56Sopenharmony_ci """assert equality of C and P status""" 2877db96d56Sopenharmony_ci for signal in self.c.flags: 2887db96d56Sopenharmony_ci if self.c.flags[signal] == (not self.p.flags[CondMap[signal]]): 2897db96d56Sopenharmony_ci return False 2907db96d56Sopenharmony_ci return True 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ci# We don't want exceptions so that we can compare the status flags. 2947db96d56Sopenharmony_cicontext = Context() 2957db96d56Sopenharmony_cicontext.Emin = C.MIN_EMIN 2967db96d56Sopenharmony_cicontext.Emax = C.MAX_EMAX 2977db96d56Sopenharmony_cicontext.clear_traps() 2987db96d56Sopenharmony_ci 2997db96d56Sopenharmony_ci# When creating decimals, _decimal is ultimately limited by the maximum 3007db96d56Sopenharmony_ci# context values. We emulate this restriction for decimal.py. 3017db96d56Sopenharmony_cimaxcontext = P.Context( 3027db96d56Sopenharmony_ci prec=C.MAX_PREC, 3037db96d56Sopenharmony_ci Emin=C.MIN_EMIN, 3047db96d56Sopenharmony_ci Emax=C.MAX_EMAX, 3057db96d56Sopenharmony_ci rounding=P.ROUND_HALF_UP, 3067db96d56Sopenharmony_ci capitals=1 3077db96d56Sopenharmony_ci) 3087db96d56Sopenharmony_cimaxcontext.clamp = 0 3097db96d56Sopenharmony_ci 3107db96d56Sopenharmony_cidef RestrictedDecimal(value): 3117db96d56Sopenharmony_ci maxcontext.traps = copy(context.p.traps) 3127db96d56Sopenharmony_ci maxcontext.clear_flags() 3137db96d56Sopenharmony_ci if isinstance(value, str): 3147db96d56Sopenharmony_ci value = value.strip() 3157db96d56Sopenharmony_ci dec = maxcontext.create_decimal(value) 3167db96d56Sopenharmony_ci if maxcontext.flags[P.Inexact] or \ 3177db96d56Sopenharmony_ci maxcontext.flags[P.Rounded] or \ 3187db96d56Sopenharmony_ci maxcontext.flags[P.Clamped] or \ 3197db96d56Sopenharmony_ci maxcontext.flags[P.InvalidOperation]: 3207db96d56Sopenharmony_ci return context.p._raise_error(P.InvalidOperation) 3217db96d56Sopenharmony_ci if maxcontext.flags[P.FloatOperation]: 3227db96d56Sopenharmony_ci context.p.flags[P.FloatOperation] = True 3237db96d56Sopenharmony_ci return dec 3247db96d56Sopenharmony_ci 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci# ====================================================================== 3277db96d56Sopenharmony_ci# TestSet: Organize data and events during a single test case 3287db96d56Sopenharmony_ci# ====================================================================== 3297db96d56Sopenharmony_ci 3307db96d56Sopenharmony_ciclass RestrictedList(list): 3317db96d56Sopenharmony_ci """List that can only be modified by appending items.""" 3327db96d56Sopenharmony_ci def __getattribute__(self, name): 3337db96d56Sopenharmony_ci if name != 'append': 3347db96d56Sopenharmony_ci raise AttributeError("unsupported operation") 3357db96d56Sopenharmony_ci return list.__getattribute__(self, name) 3367db96d56Sopenharmony_ci def unsupported(self, *_): 3377db96d56Sopenharmony_ci raise AttributeError("unsupported operation") 3387db96d56Sopenharmony_ci __add__ = __delattr__ = __delitem__ = __iadd__ = __imul__ = unsupported 3397db96d56Sopenharmony_ci __mul__ = __reversed__ = __rmul__ = __setattr__ = __setitem__ = unsupported 3407db96d56Sopenharmony_ci 3417db96d56Sopenharmony_ciclass TestSet(object): 3427db96d56Sopenharmony_ci """A TestSet contains the original input operands, converted operands, 3437db96d56Sopenharmony_ci Python exceptions that occurred either during conversion or during 3447db96d56Sopenharmony_ci execution of the actual function, and the final results. 3457db96d56Sopenharmony_ci 3467db96d56Sopenharmony_ci For safety, most attributes are lists that only support the append 3477db96d56Sopenharmony_ci operation. 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci If a function name is prefixed with 'context.', the corresponding 3507db96d56Sopenharmony_ci context method is called. 3517db96d56Sopenharmony_ci """ 3527db96d56Sopenharmony_ci def __init__(self, funcname, operands): 3537db96d56Sopenharmony_ci if funcname.startswith("context."): 3547db96d56Sopenharmony_ci self.funcname = funcname.replace("context.", "") 3557db96d56Sopenharmony_ci self.contextfunc = True 3567db96d56Sopenharmony_ci else: 3577db96d56Sopenharmony_ci self.funcname = funcname 3587db96d56Sopenharmony_ci self.contextfunc = False 3597db96d56Sopenharmony_ci self.op = operands # raw operand tuple 3607db96d56Sopenharmony_ci self.context = context # context used for the operation 3617db96d56Sopenharmony_ci self.cop = RestrictedList() # converted C.Decimal operands 3627db96d56Sopenharmony_ci self.cex = RestrictedList() # Python exceptions for C.Decimal 3637db96d56Sopenharmony_ci self.cresults = RestrictedList() # C.Decimal results 3647db96d56Sopenharmony_ci self.pop = RestrictedList() # converted P.Decimal operands 3657db96d56Sopenharmony_ci self.pex = RestrictedList() # Python exceptions for P.Decimal 3667db96d56Sopenharmony_ci self.presults = RestrictedList() # P.Decimal results 3677db96d56Sopenharmony_ci 3687db96d56Sopenharmony_ci # If the above results are exact, unrounded and not clamped, repeat 3697db96d56Sopenharmony_ci # the operation with a maxcontext to ensure that huge intermediate 3707db96d56Sopenharmony_ci # values do not cause a MemoryError. 3717db96d56Sopenharmony_ci self.with_maxcontext = False 3727db96d56Sopenharmony_ci self.maxcontext = context.c.copy() 3737db96d56Sopenharmony_ci self.maxcontext.prec = C.MAX_PREC 3747db96d56Sopenharmony_ci self.maxcontext.Emax = C.MAX_EMAX 3757db96d56Sopenharmony_ci self.maxcontext.Emin = C.MIN_EMIN 3767db96d56Sopenharmony_ci self.maxcontext.clear_flags() 3777db96d56Sopenharmony_ci 3787db96d56Sopenharmony_ci self.maxop = RestrictedList() # converted C.Decimal operands 3797db96d56Sopenharmony_ci self.maxex = RestrictedList() # Python exceptions for C.Decimal 3807db96d56Sopenharmony_ci self.maxresults = RestrictedList() # C.Decimal results 3817db96d56Sopenharmony_ci 3827db96d56Sopenharmony_ci 3837db96d56Sopenharmony_ci# ====================================================================== 3847db96d56Sopenharmony_ci# SkipHandler: skip known discrepancies 3857db96d56Sopenharmony_ci# ====================================================================== 3867db96d56Sopenharmony_ci 3877db96d56Sopenharmony_ciclass SkipHandler: 3887db96d56Sopenharmony_ci """Handle known discrepancies between decimal.py and _decimal.so. 3897db96d56Sopenharmony_ci These are either ULP differences in the power function or 3907db96d56Sopenharmony_ci extremely minor issues.""" 3917db96d56Sopenharmony_ci 3927db96d56Sopenharmony_ci def __init__(self): 3937db96d56Sopenharmony_ci self.ulpdiff = 0 3947db96d56Sopenharmony_ci self.powmod_zeros = 0 3957db96d56Sopenharmony_ci self.maxctx = P.Context(Emax=10**18, Emin=-10**18) 3967db96d56Sopenharmony_ci 3977db96d56Sopenharmony_ci def default(self, t): 3987db96d56Sopenharmony_ci return False 3997db96d56Sopenharmony_ci __ge__ = __gt__ = __le__ = __lt__ = __ne__ = __eq__ = default 4007db96d56Sopenharmony_ci __reduce__ = __format__ = __repr__ = __str__ = default 4017db96d56Sopenharmony_ci 4027db96d56Sopenharmony_ci def harrison_ulp(self, dec): 4037db96d56Sopenharmony_ci """ftp://ftp.inria.fr/INRIA/publication/publi-pdf/RR/RR-5504.pdf""" 4047db96d56Sopenharmony_ci a = dec.next_plus() 4057db96d56Sopenharmony_ci b = dec.next_minus() 4067db96d56Sopenharmony_ci return abs(a - b) 4077db96d56Sopenharmony_ci 4087db96d56Sopenharmony_ci def standard_ulp(self, dec, prec): 4097db96d56Sopenharmony_ci return _dec_from_triple(0, '1', dec._exp+len(dec._int)-prec) 4107db96d56Sopenharmony_ci 4117db96d56Sopenharmony_ci def rounding_direction(self, x, mode): 4127db96d56Sopenharmony_ci """Determine the effective direction of the rounding when 4137db96d56Sopenharmony_ci the exact result x is rounded according to mode. 4147db96d56Sopenharmony_ci Return -1 for downwards, 0 for undirected, 1 for upwards, 4157db96d56Sopenharmony_ci 2 for ROUND_05UP.""" 4167db96d56Sopenharmony_ci cmp = 1 if x.compare_total(P.Decimal("+0")) >= 0 else -1 4177db96d56Sopenharmony_ci 4187db96d56Sopenharmony_ci if mode in (P.ROUND_HALF_EVEN, P.ROUND_HALF_UP, P.ROUND_HALF_DOWN): 4197db96d56Sopenharmony_ci return 0 4207db96d56Sopenharmony_ci elif mode == P.ROUND_CEILING: 4217db96d56Sopenharmony_ci return 1 4227db96d56Sopenharmony_ci elif mode == P.ROUND_FLOOR: 4237db96d56Sopenharmony_ci return -1 4247db96d56Sopenharmony_ci elif mode == P.ROUND_UP: 4257db96d56Sopenharmony_ci return cmp 4267db96d56Sopenharmony_ci elif mode == P.ROUND_DOWN: 4277db96d56Sopenharmony_ci return -cmp 4287db96d56Sopenharmony_ci elif mode == P.ROUND_05UP: 4297db96d56Sopenharmony_ci return 2 4307db96d56Sopenharmony_ci else: 4317db96d56Sopenharmony_ci raise ValueError("Unexpected rounding mode: %s" % mode) 4327db96d56Sopenharmony_ci 4337db96d56Sopenharmony_ci def check_ulpdiff(self, exact, rounded): 4347db96d56Sopenharmony_ci # current precision 4357db96d56Sopenharmony_ci p = context.p.prec 4367db96d56Sopenharmony_ci 4377db96d56Sopenharmony_ci # Convert infinities to the largest representable number + 1. 4387db96d56Sopenharmony_ci x = exact 4397db96d56Sopenharmony_ci if exact.is_infinite(): 4407db96d56Sopenharmony_ci x = _dec_from_triple(exact._sign, '10', context.p.Emax) 4417db96d56Sopenharmony_ci y = rounded 4427db96d56Sopenharmony_ci if rounded.is_infinite(): 4437db96d56Sopenharmony_ci y = _dec_from_triple(rounded._sign, '10', context.p.Emax) 4447db96d56Sopenharmony_ci 4457db96d56Sopenharmony_ci # err = (rounded - exact) / ulp(rounded) 4467db96d56Sopenharmony_ci self.maxctx.prec = p * 2 4477db96d56Sopenharmony_ci t = self.maxctx.subtract(y, x) 4487db96d56Sopenharmony_ci if context.c.flags[C.Clamped] or \ 4497db96d56Sopenharmony_ci context.c.flags[C.Underflow]: 4507db96d56Sopenharmony_ci # The standard ulp does not work in Underflow territory. 4517db96d56Sopenharmony_ci ulp = self.harrison_ulp(y) 4527db96d56Sopenharmony_ci else: 4537db96d56Sopenharmony_ci ulp = self.standard_ulp(y, p) 4547db96d56Sopenharmony_ci # Error in ulps. 4557db96d56Sopenharmony_ci err = self.maxctx.divide(t, ulp) 4567db96d56Sopenharmony_ci 4577db96d56Sopenharmony_ci dir = self.rounding_direction(x, context.p.rounding) 4587db96d56Sopenharmony_ci if dir == 0: 4597db96d56Sopenharmony_ci if P.Decimal("-0.6") < err < P.Decimal("0.6"): 4607db96d56Sopenharmony_ci return True 4617db96d56Sopenharmony_ci elif dir == 1: # directed, upwards 4627db96d56Sopenharmony_ci if P.Decimal("-0.1") < err < P.Decimal("1.1"): 4637db96d56Sopenharmony_ci return True 4647db96d56Sopenharmony_ci elif dir == -1: # directed, downwards 4657db96d56Sopenharmony_ci if P.Decimal("-1.1") < err < P.Decimal("0.1"): 4667db96d56Sopenharmony_ci return True 4677db96d56Sopenharmony_ci else: # ROUND_05UP 4687db96d56Sopenharmony_ci if P.Decimal("-1.1") < err < P.Decimal("1.1"): 4697db96d56Sopenharmony_ci return True 4707db96d56Sopenharmony_ci 4717db96d56Sopenharmony_ci print("ulp: %s error: %s exact: %s c_rounded: %s" 4727db96d56Sopenharmony_ci % (ulp, err, exact, rounded)) 4737db96d56Sopenharmony_ci return False 4747db96d56Sopenharmony_ci 4757db96d56Sopenharmony_ci def bin_resolve_ulp(self, t): 4767db96d56Sopenharmony_ci """Check if results of _decimal's power function are within the 4777db96d56Sopenharmony_ci allowed ulp ranges.""" 4787db96d56Sopenharmony_ci # NaNs are beyond repair. 4797db96d56Sopenharmony_ci if t.rc.is_nan() or t.rp.is_nan(): 4807db96d56Sopenharmony_ci return False 4817db96d56Sopenharmony_ci 4827db96d56Sopenharmony_ci # "exact" result, double precision, half_even 4837db96d56Sopenharmony_ci self.maxctx.prec = context.p.prec * 2 4847db96d56Sopenharmony_ci 4857db96d56Sopenharmony_ci op1, op2 = t.pop[0], t.pop[1] 4867db96d56Sopenharmony_ci if t.contextfunc: 4877db96d56Sopenharmony_ci exact = getattr(self.maxctx, t.funcname)(op1, op2) 4887db96d56Sopenharmony_ci else: 4897db96d56Sopenharmony_ci exact = getattr(op1, t.funcname)(op2, context=self.maxctx) 4907db96d56Sopenharmony_ci 4917db96d56Sopenharmony_ci # _decimal's rounded result 4927db96d56Sopenharmony_ci rounded = P.Decimal(t.cresults[0]) 4937db96d56Sopenharmony_ci 4947db96d56Sopenharmony_ci self.ulpdiff += 1 4957db96d56Sopenharmony_ci return self.check_ulpdiff(exact, rounded) 4967db96d56Sopenharmony_ci 4977db96d56Sopenharmony_ci ############################ Correct rounding ############################# 4987db96d56Sopenharmony_ci def resolve_underflow(self, t): 4997db96d56Sopenharmony_ci """In extremely rare cases where the infinite precision result is just 5007db96d56Sopenharmony_ci below etiny, cdecimal does not set Subnormal/Underflow. Example: 5017db96d56Sopenharmony_ci 5027db96d56Sopenharmony_ci setcontext(Context(prec=21, rounding=ROUND_UP, Emin=-55, Emax=85)) 5037db96d56Sopenharmony_ci Decimal("1.00000000000000000000000000000000000000000000000" 5047db96d56Sopenharmony_ci "0000000100000000000000000000000000000000000000000" 5057db96d56Sopenharmony_ci "0000000000000025").ln() 5067db96d56Sopenharmony_ci """ 5077db96d56Sopenharmony_ci if t.cresults != t.presults: 5087db96d56Sopenharmony_ci return False # Results must be identical. 5097db96d56Sopenharmony_ci if context.c.flags[C.Rounded] and \ 5107db96d56Sopenharmony_ci context.c.flags[C.Inexact] and \ 5117db96d56Sopenharmony_ci context.p.flags[P.Rounded] and \ 5127db96d56Sopenharmony_ci context.p.flags[P.Inexact]: 5137db96d56Sopenharmony_ci return True # Subnormal/Underflow may be missing. 5147db96d56Sopenharmony_ci return False 5157db96d56Sopenharmony_ci 5167db96d56Sopenharmony_ci def exp(self, t): 5177db96d56Sopenharmony_ci """Resolve Underflow or ULP difference.""" 5187db96d56Sopenharmony_ci return self.resolve_underflow(t) 5197db96d56Sopenharmony_ci 5207db96d56Sopenharmony_ci def log10(self, t): 5217db96d56Sopenharmony_ci """Resolve Underflow or ULP difference.""" 5227db96d56Sopenharmony_ci return self.resolve_underflow(t) 5237db96d56Sopenharmony_ci 5247db96d56Sopenharmony_ci def ln(self, t): 5257db96d56Sopenharmony_ci """Resolve Underflow or ULP difference.""" 5267db96d56Sopenharmony_ci return self.resolve_underflow(t) 5277db96d56Sopenharmony_ci 5287db96d56Sopenharmony_ci def __pow__(self, t): 5297db96d56Sopenharmony_ci """Always calls the resolve function. C.Decimal does not have correct 5307db96d56Sopenharmony_ci rounding for the power function.""" 5317db96d56Sopenharmony_ci if context.c.flags[C.Rounded] and \ 5327db96d56Sopenharmony_ci context.c.flags[C.Inexact] and \ 5337db96d56Sopenharmony_ci context.p.flags[P.Rounded] and \ 5347db96d56Sopenharmony_ci context.p.flags[P.Inexact]: 5357db96d56Sopenharmony_ci return self.bin_resolve_ulp(t) 5367db96d56Sopenharmony_ci else: 5377db96d56Sopenharmony_ci return False 5387db96d56Sopenharmony_ci power = __rpow__ = __pow__ 5397db96d56Sopenharmony_ci 5407db96d56Sopenharmony_ci ############################## Technicalities ############################# 5417db96d56Sopenharmony_ci def __float__(self, t): 5427db96d56Sopenharmony_ci """NaN comparison in the verify() function obviously gives an 5437db96d56Sopenharmony_ci incorrect answer: nan == nan -> False""" 5447db96d56Sopenharmony_ci if t.cop[0].is_nan() and t.pop[0].is_nan(): 5457db96d56Sopenharmony_ci return True 5467db96d56Sopenharmony_ci return False 5477db96d56Sopenharmony_ci __complex__ = __float__ 5487db96d56Sopenharmony_ci 5497db96d56Sopenharmony_ci def __radd__(self, t): 5507db96d56Sopenharmony_ci """decimal.py gives precedence to the first NaN; this is 5517db96d56Sopenharmony_ci not important, as __radd__ will not be called for 5527db96d56Sopenharmony_ci two decimal arguments.""" 5537db96d56Sopenharmony_ci if t.rc.is_nan() and t.rp.is_nan(): 5547db96d56Sopenharmony_ci return True 5557db96d56Sopenharmony_ci return False 5567db96d56Sopenharmony_ci __rmul__ = __radd__ 5577db96d56Sopenharmony_ci 5587db96d56Sopenharmony_ci ################################ Various ################################## 5597db96d56Sopenharmony_ci def __round__(self, t): 5607db96d56Sopenharmony_ci """Exception: Decimal('1').__round__(-100000000000000000000000000) 5617db96d56Sopenharmony_ci Should it really be InvalidOperation?""" 5627db96d56Sopenharmony_ci if t.rc is None and t.rp.is_nan(): 5637db96d56Sopenharmony_ci return True 5647db96d56Sopenharmony_ci return False 5657db96d56Sopenharmony_ci 5667db96d56Sopenharmony_cishandler = SkipHandler() 5677db96d56Sopenharmony_cidef skip_error(t): 5687db96d56Sopenharmony_ci return getattr(shandler, t.funcname, shandler.default)(t) 5697db96d56Sopenharmony_ci 5707db96d56Sopenharmony_ci 5717db96d56Sopenharmony_ci# ====================================================================== 5727db96d56Sopenharmony_ci# Handling verification errors 5737db96d56Sopenharmony_ci# ====================================================================== 5747db96d56Sopenharmony_ci 5757db96d56Sopenharmony_ciclass VerifyError(Exception): 5767db96d56Sopenharmony_ci """Verification failed.""" 5777db96d56Sopenharmony_ci pass 5787db96d56Sopenharmony_ci 5797db96d56Sopenharmony_cidef function_as_string(t): 5807db96d56Sopenharmony_ci if t.contextfunc: 5817db96d56Sopenharmony_ci cargs = t.cop 5827db96d56Sopenharmony_ci pargs = t.pop 5837db96d56Sopenharmony_ci maxargs = t.maxop 5847db96d56Sopenharmony_ci cfunc = "c_func: %s(" % t.funcname 5857db96d56Sopenharmony_ci pfunc = "p_func: %s(" % t.funcname 5867db96d56Sopenharmony_ci maxfunc = "max_func: %s(" % t.funcname 5877db96d56Sopenharmony_ci else: 5887db96d56Sopenharmony_ci cself, cargs = t.cop[0], t.cop[1:] 5897db96d56Sopenharmony_ci pself, pargs = t.pop[0], t.pop[1:] 5907db96d56Sopenharmony_ci maxself, maxargs = t.maxop[0], t.maxop[1:] 5917db96d56Sopenharmony_ci cfunc = "c_func: %s.%s(" % (repr(cself), t.funcname) 5927db96d56Sopenharmony_ci pfunc = "p_func: %s.%s(" % (repr(pself), t.funcname) 5937db96d56Sopenharmony_ci maxfunc = "max_func: %s.%s(" % (repr(maxself), t.funcname) 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci err = cfunc 5967db96d56Sopenharmony_ci for arg in cargs: 5977db96d56Sopenharmony_ci err += "%s, " % repr(arg) 5987db96d56Sopenharmony_ci err = err.rstrip(", ") 5997db96d56Sopenharmony_ci err += ")\n" 6007db96d56Sopenharmony_ci 6017db96d56Sopenharmony_ci err += pfunc 6027db96d56Sopenharmony_ci for arg in pargs: 6037db96d56Sopenharmony_ci err += "%s, " % repr(arg) 6047db96d56Sopenharmony_ci err = err.rstrip(", ") 6057db96d56Sopenharmony_ci err += ")" 6067db96d56Sopenharmony_ci 6077db96d56Sopenharmony_ci if t.with_maxcontext: 6087db96d56Sopenharmony_ci err += "\n" 6097db96d56Sopenharmony_ci err += maxfunc 6107db96d56Sopenharmony_ci for arg in maxargs: 6117db96d56Sopenharmony_ci err += "%s, " % repr(arg) 6127db96d56Sopenharmony_ci err = err.rstrip(", ") 6137db96d56Sopenharmony_ci err += ")" 6147db96d56Sopenharmony_ci 6157db96d56Sopenharmony_ci return err 6167db96d56Sopenharmony_ci 6177db96d56Sopenharmony_cidef raise_error(t): 6187db96d56Sopenharmony_ci global EXIT_STATUS 6197db96d56Sopenharmony_ci 6207db96d56Sopenharmony_ci if skip_error(t): 6217db96d56Sopenharmony_ci return 6227db96d56Sopenharmony_ci EXIT_STATUS = 1 6237db96d56Sopenharmony_ci 6247db96d56Sopenharmony_ci err = "Error in %s:\n\n" % t.funcname 6257db96d56Sopenharmony_ci err += "input operands: %s\n\n" % (t.op,) 6267db96d56Sopenharmony_ci err += function_as_string(t) 6277db96d56Sopenharmony_ci 6287db96d56Sopenharmony_ci err += "\n\nc_result: %s\np_result: %s\n" % (t.cresults, t.presults) 6297db96d56Sopenharmony_ci if t.with_maxcontext: 6307db96d56Sopenharmony_ci err += "max_result: %s\n\n" % (t.maxresults) 6317db96d56Sopenharmony_ci else: 6327db96d56Sopenharmony_ci err += "\n" 6337db96d56Sopenharmony_ci 6347db96d56Sopenharmony_ci err += "c_exceptions: %s\np_exceptions: %s\n" % (t.cex, t.pex) 6357db96d56Sopenharmony_ci if t.with_maxcontext: 6367db96d56Sopenharmony_ci err += "max_exceptions: %s\n\n" % t.maxex 6377db96d56Sopenharmony_ci else: 6387db96d56Sopenharmony_ci err += "\n" 6397db96d56Sopenharmony_ci 6407db96d56Sopenharmony_ci err += "%s\n" % str(t.context) 6417db96d56Sopenharmony_ci if t.with_maxcontext: 6427db96d56Sopenharmony_ci err += "%s\n" % str(t.maxcontext) 6437db96d56Sopenharmony_ci else: 6447db96d56Sopenharmony_ci err += "\n" 6457db96d56Sopenharmony_ci 6467db96d56Sopenharmony_ci raise VerifyError(err) 6477db96d56Sopenharmony_ci 6487db96d56Sopenharmony_ci 6497db96d56Sopenharmony_ci# ====================================================================== 6507db96d56Sopenharmony_ci# Main testing functions 6517db96d56Sopenharmony_ci# 6527db96d56Sopenharmony_ci# The procedure is always (t is the TestSet): 6537db96d56Sopenharmony_ci# 6547db96d56Sopenharmony_ci# convert(t) -> Initialize the TestSet as necessary. 6557db96d56Sopenharmony_ci# 6567db96d56Sopenharmony_ci# Return 0 for early abortion (e.g. if a TypeError 6577db96d56Sopenharmony_ci# occurs during conversion, there is nothing to test). 6587db96d56Sopenharmony_ci# 6597db96d56Sopenharmony_ci# Return 1 for continuing with the test case. 6607db96d56Sopenharmony_ci# 6617db96d56Sopenharmony_ci# callfuncs(t) -> Call the relevant function for each implementation 6627db96d56Sopenharmony_ci# and record the results in the TestSet. 6637db96d56Sopenharmony_ci# 6647db96d56Sopenharmony_ci# verify(t) -> Verify the results. If verification fails, details 6657db96d56Sopenharmony_ci# are printed to stdout. 6667db96d56Sopenharmony_ci# ====================================================================== 6677db96d56Sopenharmony_ci 6687db96d56Sopenharmony_cidef all_nan(a): 6697db96d56Sopenharmony_ci if isinstance(a, C.Decimal): 6707db96d56Sopenharmony_ci return a.is_nan() 6717db96d56Sopenharmony_ci elif isinstance(a, tuple): 6727db96d56Sopenharmony_ci return all(all_nan(v) for v in a) 6737db96d56Sopenharmony_ci return False 6747db96d56Sopenharmony_ci 6757db96d56Sopenharmony_cidef convert(t, convstr=True): 6767db96d56Sopenharmony_ci """ t is the testset. At this stage the testset contains a tuple of 6777db96d56Sopenharmony_ci operands t.op of various types. For decimal methods the first 6787db96d56Sopenharmony_ci operand (self) is always converted to Decimal. If 'convstr' is 6797db96d56Sopenharmony_ci true, string operands are converted as well. 6807db96d56Sopenharmony_ci 6817db96d56Sopenharmony_ci Context operands are of type deccheck.Context, rounding mode 6827db96d56Sopenharmony_ci operands are given as a tuple (C.rounding, P.rounding). 6837db96d56Sopenharmony_ci 6847db96d56Sopenharmony_ci Other types (float, int, etc.) are left unchanged. 6857db96d56Sopenharmony_ci """ 6867db96d56Sopenharmony_ci for i, op in enumerate(t.op): 6877db96d56Sopenharmony_ci 6887db96d56Sopenharmony_ci context.clear_status() 6897db96d56Sopenharmony_ci t.maxcontext.clear_flags() 6907db96d56Sopenharmony_ci 6917db96d56Sopenharmony_ci if op in RoundModes: 6927db96d56Sopenharmony_ci t.cop.append(op) 6937db96d56Sopenharmony_ci t.pop.append(op) 6947db96d56Sopenharmony_ci t.maxop.append(op) 6957db96d56Sopenharmony_ci 6967db96d56Sopenharmony_ci elif not t.contextfunc and i == 0 or \ 6977db96d56Sopenharmony_ci convstr and isinstance(op, str): 6987db96d56Sopenharmony_ci try: 6997db96d56Sopenharmony_ci c = C.Decimal(op) 7007db96d56Sopenharmony_ci cex = None 7017db96d56Sopenharmony_ci except (TypeError, ValueError, OverflowError) as e: 7027db96d56Sopenharmony_ci c = None 7037db96d56Sopenharmony_ci cex = e.__class__ 7047db96d56Sopenharmony_ci 7057db96d56Sopenharmony_ci try: 7067db96d56Sopenharmony_ci p = RestrictedDecimal(op) 7077db96d56Sopenharmony_ci pex = None 7087db96d56Sopenharmony_ci except (TypeError, ValueError, OverflowError) as e: 7097db96d56Sopenharmony_ci p = None 7107db96d56Sopenharmony_ci pex = e.__class__ 7117db96d56Sopenharmony_ci 7127db96d56Sopenharmony_ci try: 7137db96d56Sopenharmony_ci C.setcontext(t.maxcontext) 7147db96d56Sopenharmony_ci maxop = C.Decimal(op) 7157db96d56Sopenharmony_ci maxex = None 7167db96d56Sopenharmony_ci except (TypeError, ValueError, OverflowError) as e: 7177db96d56Sopenharmony_ci maxop = None 7187db96d56Sopenharmony_ci maxex = e.__class__ 7197db96d56Sopenharmony_ci finally: 7207db96d56Sopenharmony_ci C.setcontext(context.c) 7217db96d56Sopenharmony_ci 7227db96d56Sopenharmony_ci t.cop.append(c) 7237db96d56Sopenharmony_ci t.cex.append(cex) 7247db96d56Sopenharmony_ci 7257db96d56Sopenharmony_ci t.pop.append(p) 7267db96d56Sopenharmony_ci t.pex.append(pex) 7277db96d56Sopenharmony_ci 7287db96d56Sopenharmony_ci t.maxop.append(maxop) 7297db96d56Sopenharmony_ci t.maxex.append(maxex) 7307db96d56Sopenharmony_ci 7317db96d56Sopenharmony_ci if cex is pex: 7327db96d56Sopenharmony_ci if str(c) != str(p) or not context.assert_eq_status(): 7337db96d56Sopenharmony_ci raise_error(t) 7347db96d56Sopenharmony_ci if cex and pex: 7357db96d56Sopenharmony_ci # nothing to test 7367db96d56Sopenharmony_ci return 0 7377db96d56Sopenharmony_ci else: 7387db96d56Sopenharmony_ci raise_error(t) 7397db96d56Sopenharmony_ci 7407db96d56Sopenharmony_ci # The exceptions in the maxcontext operation can legitimately 7417db96d56Sopenharmony_ci # differ, only test that maxex implies cex: 7427db96d56Sopenharmony_ci if maxex is not None and cex is not maxex: 7437db96d56Sopenharmony_ci raise_error(t) 7447db96d56Sopenharmony_ci 7457db96d56Sopenharmony_ci elif isinstance(op, Context): 7467db96d56Sopenharmony_ci t.context = op 7477db96d56Sopenharmony_ci t.cop.append(op.c) 7487db96d56Sopenharmony_ci t.pop.append(op.p) 7497db96d56Sopenharmony_ci t.maxop.append(t.maxcontext) 7507db96d56Sopenharmony_ci 7517db96d56Sopenharmony_ci else: 7527db96d56Sopenharmony_ci t.cop.append(op) 7537db96d56Sopenharmony_ci t.pop.append(op) 7547db96d56Sopenharmony_ci t.maxop.append(op) 7557db96d56Sopenharmony_ci 7567db96d56Sopenharmony_ci return 1 7577db96d56Sopenharmony_ci 7587db96d56Sopenharmony_cidef callfuncs(t): 7597db96d56Sopenharmony_ci """ t is the testset. At this stage the testset contains operand lists 7607db96d56Sopenharmony_ci t.cop and t.pop for the C and Python versions of decimal. 7617db96d56Sopenharmony_ci For Decimal methods, the first operands are of type C.Decimal and 7627db96d56Sopenharmony_ci P.Decimal respectively. The remaining operands can have various types. 7637db96d56Sopenharmony_ci For Context methods, all operands can have any type. 7647db96d56Sopenharmony_ci 7657db96d56Sopenharmony_ci t.rc and t.rp are the results of the operation. 7667db96d56Sopenharmony_ci """ 7677db96d56Sopenharmony_ci context.clear_status() 7687db96d56Sopenharmony_ci t.maxcontext.clear_flags() 7697db96d56Sopenharmony_ci 7707db96d56Sopenharmony_ci try: 7717db96d56Sopenharmony_ci if t.contextfunc: 7727db96d56Sopenharmony_ci cargs = t.cop 7737db96d56Sopenharmony_ci t.rc = getattr(context.c, t.funcname)(*cargs) 7747db96d56Sopenharmony_ci else: 7757db96d56Sopenharmony_ci cself = t.cop[0] 7767db96d56Sopenharmony_ci cargs = t.cop[1:] 7777db96d56Sopenharmony_ci t.rc = getattr(cself, t.funcname)(*cargs) 7787db96d56Sopenharmony_ci t.cex.append(None) 7797db96d56Sopenharmony_ci except (TypeError, ValueError, OverflowError, MemoryError) as e: 7807db96d56Sopenharmony_ci t.rc = None 7817db96d56Sopenharmony_ci t.cex.append(e.__class__) 7827db96d56Sopenharmony_ci 7837db96d56Sopenharmony_ci try: 7847db96d56Sopenharmony_ci if t.contextfunc: 7857db96d56Sopenharmony_ci pargs = t.pop 7867db96d56Sopenharmony_ci t.rp = getattr(context.p, t.funcname)(*pargs) 7877db96d56Sopenharmony_ci else: 7887db96d56Sopenharmony_ci pself = t.pop[0] 7897db96d56Sopenharmony_ci pargs = t.pop[1:] 7907db96d56Sopenharmony_ci t.rp = getattr(pself, t.funcname)(*pargs) 7917db96d56Sopenharmony_ci t.pex.append(None) 7927db96d56Sopenharmony_ci except (TypeError, ValueError, OverflowError, MemoryError) as e: 7937db96d56Sopenharmony_ci t.rp = None 7947db96d56Sopenharmony_ci t.pex.append(e.__class__) 7957db96d56Sopenharmony_ci 7967db96d56Sopenharmony_ci # If the above results are exact, unrounded, normal etc., repeat the 7977db96d56Sopenharmony_ci # operation with a maxcontext to ensure that huge intermediate values 7987db96d56Sopenharmony_ci # do not cause a MemoryError. 7997db96d56Sopenharmony_ci if (t.funcname not in MaxContextSkip and 8007db96d56Sopenharmony_ci not context.c.flags[C.InvalidOperation] and 8017db96d56Sopenharmony_ci not context.c.flags[C.Inexact] and 8027db96d56Sopenharmony_ci not context.c.flags[C.Rounded] and 8037db96d56Sopenharmony_ci not context.c.flags[C.Subnormal] and 8047db96d56Sopenharmony_ci not context.c.flags[C.Clamped] and 8057db96d56Sopenharmony_ci not context.clamp and # results are padded to context.prec if context.clamp==1. 8067db96d56Sopenharmony_ci not any(isinstance(v, C.Context) for v in t.cop)): # another context is used. 8077db96d56Sopenharmony_ci t.with_maxcontext = True 8087db96d56Sopenharmony_ci try: 8097db96d56Sopenharmony_ci if t.contextfunc: 8107db96d56Sopenharmony_ci maxargs = t.maxop 8117db96d56Sopenharmony_ci t.rmax = getattr(t.maxcontext, t.funcname)(*maxargs) 8127db96d56Sopenharmony_ci else: 8137db96d56Sopenharmony_ci maxself = t.maxop[0] 8147db96d56Sopenharmony_ci maxargs = t.maxop[1:] 8157db96d56Sopenharmony_ci try: 8167db96d56Sopenharmony_ci C.setcontext(t.maxcontext) 8177db96d56Sopenharmony_ci t.rmax = getattr(maxself, t.funcname)(*maxargs) 8187db96d56Sopenharmony_ci finally: 8197db96d56Sopenharmony_ci C.setcontext(context.c) 8207db96d56Sopenharmony_ci t.maxex.append(None) 8217db96d56Sopenharmony_ci except (TypeError, ValueError, OverflowError, MemoryError) as e: 8227db96d56Sopenharmony_ci t.rmax = None 8237db96d56Sopenharmony_ci t.maxex.append(e.__class__) 8247db96d56Sopenharmony_ci 8257db96d56Sopenharmony_cidef verify(t, stat): 8267db96d56Sopenharmony_ci """ t is the testset. At this stage the testset contains the following 8277db96d56Sopenharmony_ci tuples: 8287db96d56Sopenharmony_ci 8297db96d56Sopenharmony_ci t.op: original operands 8307db96d56Sopenharmony_ci t.cop: C.Decimal operands (see convert for details) 8317db96d56Sopenharmony_ci t.pop: P.Decimal operands (see convert for details) 8327db96d56Sopenharmony_ci t.rc: C result 8337db96d56Sopenharmony_ci t.rp: Python result 8347db96d56Sopenharmony_ci 8357db96d56Sopenharmony_ci t.rc and t.rp can have various types. 8367db96d56Sopenharmony_ci """ 8377db96d56Sopenharmony_ci t.cresults.append(str(t.rc)) 8387db96d56Sopenharmony_ci t.presults.append(str(t.rp)) 8397db96d56Sopenharmony_ci if t.with_maxcontext: 8407db96d56Sopenharmony_ci t.maxresults.append(str(t.rmax)) 8417db96d56Sopenharmony_ci 8427db96d56Sopenharmony_ci if isinstance(t.rc, C.Decimal) and isinstance(t.rp, P.Decimal): 8437db96d56Sopenharmony_ci # General case: both results are Decimals. 8447db96d56Sopenharmony_ci t.cresults.append(t.rc.to_eng_string()) 8457db96d56Sopenharmony_ci t.cresults.append(t.rc.as_tuple()) 8467db96d56Sopenharmony_ci t.cresults.append(str(t.rc.imag)) 8477db96d56Sopenharmony_ci t.cresults.append(str(t.rc.real)) 8487db96d56Sopenharmony_ci t.presults.append(t.rp.to_eng_string()) 8497db96d56Sopenharmony_ci t.presults.append(t.rp.as_tuple()) 8507db96d56Sopenharmony_ci t.presults.append(str(t.rp.imag)) 8517db96d56Sopenharmony_ci t.presults.append(str(t.rp.real)) 8527db96d56Sopenharmony_ci 8537db96d56Sopenharmony_ci if t.with_maxcontext and isinstance(t.rmax, C.Decimal): 8547db96d56Sopenharmony_ci t.maxresults.append(t.rmax.to_eng_string()) 8557db96d56Sopenharmony_ci t.maxresults.append(t.rmax.as_tuple()) 8567db96d56Sopenharmony_ci t.maxresults.append(str(t.rmax.imag)) 8577db96d56Sopenharmony_ci t.maxresults.append(str(t.rmax.real)) 8587db96d56Sopenharmony_ci 8597db96d56Sopenharmony_ci nc = t.rc.number_class().lstrip('+-s') 8607db96d56Sopenharmony_ci stat[nc] += 1 8617db96d56Sopenharmony_ci else: 8627db96d56Sopenharmony_ci # Results from e.g. __divmod__ can only be compared as strings. 8637db96d56Sopenharmony_ci if not isinstance(t.rc, tuple) and not isinstance(t.rp, tuple): 8647db96d56Sopenharmony_ci if t.rc != t.rp: 8657db96d56Sopenharmony_ci raise_error(t) 8667db96d56Sopenharmony_ci if t.with_maxcontext and not isinstance(t.rmax, tuple): 8677db96d56Sopenharmony_ci if t.rmax != t.rc: 8687db96d56Sopenharmony_ci raise_error(t) 8697db96d56Sopenharmony_ci stat[type(t.rc).__name__] += 1 8707db96d56Sopenharmony_ci 8717db96d56Sopenharmony_ci # The return value lists must be equal. 8727db96d56Sopenharmony_ci if t.cresults != t.presults: 8737db96d56Sopenharmony_ci raise_error(t) 8747db96d56Sopenharmony_ci # The Python exception lists (TypeError, etc.) must be equal. 8757db96d56Sopenharmony_ci if t.cex != t.pex: 8767db96d56Sopenharmony_ci raise_error(t) 8777db96d56Sopenharmony_ci # The context flags must be equal. 8787db96d56Sopenharmony_ci if not t.context.assert_eq_status(): 8797db96d56Sopenharmony_ci raise_error(t) 8807db96d56Sopenharmony_ci 8817db96d56Sopenharmony_ci if t.with_maxcontext: 8827db96d56Sopenharmony_ci # NaN payloads etc. depend on precision and clamp. 8837db96d56Sopenharmony_ci if all_nan(t.rc) and all_nan(t.rmax): 8847db96d56Sopenharmony_ci return 8857db96d56Sopenharmony_ci # The return value lists must be equal. 8867db96d56Sopenharmony_ci if t.maxresults != t.cresults: 8877db96d56Sopenharmony_ci raise_error(t) 8887db96d56Sopenharmony_ci # The Python exception lists (TypeError, etc.) must be equal. 8897db96d56Sopenharmony_ci if t.maxex != t.cex: 8907db96d56Sopenharmony_ci raise_error(t) 8917db96d56Sopenharmony_ci # The context flags must be equal. 8927db96d56Sopenharmony_ci if t.maxcontext.flags != t.context.c.flags: 8937db96d56Sopenharmony_ci raise_error(t) 8947db96d56Sopenharmony_ci 8957db96d56Sopenharmony_ci 8967db96d56Sopenharmony_ci# ====================================================================== 8977db96d56Sopenharmony_ci# Main test loops 8987db96d56Sopenharmony_ci# 8997db96d56Sopenharmony_ci# test_method(method, testspecs, testfunc) -> 9007db96d56Sopenharmony_ci# 9017db96d56Sopenharmony_ci# Loop through various context settings. The degree of 9027db96d56Sopenharmony_ci# thoroughness is determined by 'testspec'. For each 9037db96d56Sopenharmony_ci# setting, call 'testfunc'. Generally, 'testfunc' itself 9047db96d56Sopenharmony_ci# a loop, iterating through many test cases generated 9057db96d56Sopenharmony_ci# by the functions in randdec.py. 9067db96d56Sopenharmony_ci# 9077db96d56Sopenharmony_ci# test_n-ary(method, prec, exp_range, restricted_range, itr, stat) -> 9087db96d56Sopenharmony_ci# 9097db96d56Sopenharmony_ci# 'test_unary', 'test_binary' and 'test_ternary' are the 9107db96d56Sopenharmony_ci# main test functions passed to 'test_method'. They deal 9117db96d56Sopenharmony_ci# with the regular cases. The thoroughness of testing is 9127db96d56Sopenharmony_ci# determined by 'itr'. 9137db96d56Sopenharmony_ci# 9147db96d56Sopenharmony_ci# 'prec', 'exp_range' and 'restricted_range' are passed 9157db96d56Sopenharmony_ci# to the test-generating functions and limit the generated 9167db96d56Sopenharmony_ci# values. In some cases, for reasonable run times a 9177db96d56Sopenharmony_ci# maximum exponent of 9999 is required. 9187db96d56Sopenharmony_ci# 9197db96d56Sopenharmony_ci# The 'stat' parameter is passed down to the 'verify' 9207db96d56Sopenharmony_ci# function, which records statistics for the result values. 9217db96d56Sopenharmony_ci# ====================================================================== 9227db96d56Sopenharmony_ci 9237db96d56Sopenharmony_cidef log(fmt, args=None): 9247db96d56Sopenharmony_ci if args: 9257db96d56Sopenharmony_ci sys.stdout.write(''.join((fmt, '\n')) % args) 9267db96d56Sopenharmony_ci else: 9277db96d56Sopenharmony_ci sys.stdout.write(''.join((str(fmt), '\n'))) 9287db96d56Sopenharmony_ci sys.stdout.flush() 9297db96d56Sopenharmony_ci 9307db96d56Sopenharmony_cidef test_method(method, testspecs, testfunc): 9317db96d56Sopenharmony_ci """Iterate a test function through many context settings.""" 9327db96d56Sopenharmony_ci log("testing %s ...", method) 9337db96d56Sopenharmony_ci stat = defaultdict(int) 9347db96d56Sopenharmony_ci for spec in testspecs: 9357db96d56Sopenharmony_ci if 'samples' in spec: 9367db96d56Sopenharmony_ci spec['prec'] = sorted(random.sample(range(1, 101), 9377db96d56Sopenharmony_ci spec['samples'])) 9387db96d56Sopenharmony_ci for prec in spec['prec']: 9397db96d56Sopenharmony_ci context.prec = prec 9407db96d56Sopenharmony_ci for expts in spec['expts']: 9417db96d56Sopenharmony_ci emin, emax = expts 9427db96d56Sopenharmony_ci if emin == 'rand': 9437db96d56Sopenharmony_ci context.Emin = random.randrange(-1000, 0) 9447db96d56Sopenharmony_ci context.Emax = random.randrange(prec, 1000) 9457db96d56Sopenharmony_ci else: 9467db96d56Sopenharmony_ci context.Emin, context.Emax = emin, emax 9477db96d56Sopenharmony_ci if prec > context.Emax: continue 9487db96d56Sopenharmony_ci log(" prec: %d emin: %d emax: %d", 9497db96d56Sopenharmony_ci (context.prec, context.Emin, context.Emax)) 9507db96d56Sopenharmony_ci restr_range = 9999 if context.Emax > 9999 else context.Emax+99 9517db96d56Sopenharmony_ci for rounding in RoundModes: 9527db96d56Sopenharmony_ci context.rounding = rounding 9537db96d56Sopenharmony_ci context.capitals = random.randrange(2) 9547db96d56Sopenharmony_ci if spec['clamp'] == 'rand': 9557db96d56Sopenharmony_ci context.clamp = random.randrange(2) 9567db96d56Sopenharmony_ci else: 9577db96d56Sopenharmony_ci context.clamp = spec['clamp'] 9587db96d56Sopenharmony_ci exprange = context.c.Emax 9597db96d56Sopenharmony_ci testfunc(method, prec, exprange, restr_range, 9607db96d56Sopenharmony_ci spec['iter'], stat) 9617db96d56Sopenharmony_ci log(" result types: %s" % sorted([t for t in stat.items()])) 9627db96d56Sopenharmony_ci 9637db96d56Sopenharmony_cidef test_unary(method, prec, exp_range, restricted_range, itr, stat): 9647db96d56Sopenharmony_ci """Iterate a unary function through many test cases.""" 9657db96d56Sopenharmony_ci if method in UnaryRestricted: 9667db96d56Sopenharmony_ci exp_range = restricted_range 9677db96d56Sopenharmony_ci for op in all_unary(prec, exp_range, itr): 9687db96d56Sopenharmony_ci t = TestSet(method, op) 9697db96d56Sopenharmony_ci try: 9707db96d56Sopenharmony_ci if not convert(t): 9717db96d56Sopenharmony_ci continue 9727db96d56Sopenharmony_ci callfuncs(t) 9737db96d56Sopenharmony_ci verify(t, stat) 9747db96d56Sopenharmony_ci except VerifyError as err: 9757db96d56Sopenharmony_ci log(err) 9767db96d56Sopenharmony_ci 9777db96d56Sopenharmony_ci if not method.startswith('__'): 9787db96d56Sopenharmony_ci for op in unary_optarg(prec, exp_range, itr): 9797db96d56Sopenharmony_ci t = TestSet(method, op) 9807db96d56Sopenharmony_ci try: 9817db96d56Sopenharmony_ci if not convert(t): 9827db96d56Sopenharmony_ci continue 9837db96d56Sopenharmony_ci callfuncs(t) 9847db96d56Sopenharmony_ci verify(t, stat) 9857db96d56Sopenharmony_ci except VerifyError as err: 9867db96d56Sopenharmony_ci log(err) 9877db96d56Sopenharmony_ci 9887db96d56Sopenharmony_cidef test_binary(method, prec, exp_range, restricted_range, itr, stat): 9897db96d56Sopenharmony_ci """Iterate a binary function through many test cases.""" 9907db96d56Sopenharmony_ci if method in BinaryRestricted: 9917db96d56Sopenharmony_ci exp_range = restricted_range 9927db96d56Sopenharmony_ci for op in all_binary(prec, exp_range, itr): 9937db96d56Sopenharmony_ci t = TestSet(method, op) 9947db96d56Sopenharmony_ci try: 9957db96d56Sopenharmony_ci if not convert(t): 9967db96d56Sopenharmony_ci continue 9977db96d56Sopenharmony_ci callfuncs(t) 9987db96d56Sopenharmony_ci verify(t, stat) 9997db96d56Sopenharmony_ci except VerifyError as err: 10007db96d56Sopenharmony_ci log(err) 10017db96d56Sopenharmony_ci 10027db96d56Sopenharmony_ci if not method.startswith('__'): 10037db96d56Sopenharmony_ci for op in binary_optarg(prec, exp_range, itr): 10047db96d56Sopenharmony_ci t = TestSet(method, op) 10057db96d56Sopenharmony_ci try: 10067db96d56Sopenharmony_ci if not convert(t): 10077db96d56Sopenharmony_ci continue 10087db96d56Sopenharmony_ci callfuncs(t) 10097db96d56Sopenharmony_ci verify(t, stat) 10107db96d56Sopenharmony_ci except VerifyError as err: 10117db96d56Sopenharmony_ci log(err) 10127db96d56Sopenharmony_ci 10137db96d56Sopenharmony_cidef test_ternary(method, prec, exp_range, restricted_range, itr, stat): 10147db96d56Sopenharmony_ci """Iterate a ternary function through many test cases.""" 10157db96d56Sopenharmony_ci if method in TernaryRestricted: 10167db96d56Sopenharmony_ci exp_range = restricted_range 10177db96d56Sopenharmony_ci for op in all_ternary(prec, exp_range, itr): 10187db96d56Sopenharmony_ci t = TestSet(method, op) 10197db96d56Sopenharmony_ci try: 10207db96d56Sopenharmony_ci if not convert(t): 10217db96d56Sopenharmony_ci continue 10227db96d56Sopenharmony_ci callfuncs(t) 10237db96d56Sopenharmony_ci verify(t, stat) 10247db96d56Sopenharmony_ci except VerifyError as err: 10257db96d56Sopenharmony_ci log(err) 10267db96d56Sopenharmony_ci 10277db96d56Sopenharmony_ci if not method.startswith('__'): 10287db96d56Sopenharmony_ci for op in ternary_optarg(prec, exp_range, itr): 10297db96d56Sopenharmony_ci t = TestSet(method, op) 10307db96d56Sopenharmony_ci try: 10317db96d56Sopenharmony_ci if not convert(t): 10327db96d56Sopenharmony_ci continue 10337db96d56Sopenharmony_ci callfuncs(t) 10347db96d56Sopenharmony_ci verify(t, stat) 10357db96d56Sopenharmony_ci except VerifyError as err: 10367db96d56Sopenharmony_ci log(err) 10377db96d56Sopenharmony_ci 10387db96d56Sopenharmony_cidef test_format(method, prec, exp_range, restricted_range, itr, stat): 10397db96d56Sopenharmony_ci """Iterate the __format__ method through many test cases.""" 10407db96d56Sopenharmony_ci for op in all_unary(prec, exp_range, itr): 10417db96d56Sopenharmony_ci fmt1 = rand_format(chr(random.randrange(0, 128)), 'EeGgn') 10427db96d56Sopenharmony_ci fmt2 = rand_locale() 10437db96d56Sopenharmony_ci for fmt in (fmt1, fmt2): 10447db96d56Sopenharmony_ci fmtop = (op[0], fmt) 10457db96d56Sopenharmony_ci t = TestSet(method, fmtop) 10467db96d56Sopenharmony_ci try: 10477db96d56Sopenharmony_ci if not convert(t, convstr=False): 10487db96d56Sopenharmony_ci continue 10497db96d56Sopenharmony_ci callfuncs(t) 10507db96d56Sopenharmony_ci verify(t, stat) 10517db96d56Sopenharmony_ci except VerifyError as err: 10527db96d56Sopenharmony_ci log(err) 10537db96d56Sopenharmony_ci for op in all_unary(prec, 9999, itr): 10547db96d56Sopenharmony_ci fmt1 = rand_format(chr(random.randrange(0, 128)), 'Ff%') 10557db96d56Sopenharmony_ci fmt2 = rand_locale() 10567db96d56Sopenharmony_ci for fmt in (fmt1, fmt2): 10577db96d56Sopenharmony_ci fmtop = (op[0], fmt) 10587db96d56Sopenharmony_ci t = TestSet(method, fmtop) 10597db96d56Sopenharmony_ci try: 10607db96d56Sopenharmony_ci if not convert(t, convstr=False): 10617db96d56Sopenharmony_ci continue 10627db96d56Sopenharmony_ci callfuncs(t) 10637db96d56Sopenharmony_ci verify(t, stat) 10647db96d56Sopenharmony_ci except VerifyError as err: 10657db96d56Sopenharmony_ci log(err) 10667db96d56Sopenharmony_ci 10677db96d56Sopenharmony_cidef test_round(method, prec, exprange, restricted_range, itr, stat): 10687db96d56Sopenharmony_ci """Iterate the __round__ method through many test cases.""" 10697db96d56Sopenharmony_ci for op in all_unary(prec, 9999, itr): 10707db96d56Sopenharmony_ci n = random.randrange(10) 10717db96d56Sopenharmony_ci roundop = (op[0], n) 10727db96d56Sopenharmony_ci t = TestSet(method, roundop) 10737db96d56Sopenharmony_ci try: 10747db96d56Sopenharmony_ci if not convert(t): 10757db96d56Sopenharmony_ci continue 10767db96d56Sopenharmony_ci callfuncs(t) 10777db96d56Sopenharmony_ci verify(t, stat) 10787db96d56Sopenharmony_ci except VerifyError as err: 10797db96d56Sopenharmony_ci log(err) 10807db96d56Sopenharmony_ci 10817db96d56Sopenharmony_cidef test_from_float(method, prec, exprange, restricted_range, itr, stat): 10827db96d56Sopenharmony_ci """Iterate the __float__ method through many test cases.""" 10837db96d56Sopenharmony_ci for rounding in RoundModes: 10847db96d56Sopenharmony_ci context.rounding = rounding 10857db96d56Sopenharmony_ci for i in range(1000): 10867db96d56Sopenharmony_ci f = randfloat() 10877db96d56Sopenharmony_ci op = (f,) if method.startswith("context.") else ("sNaN", f) 10887db96d56Sopenharmony_ci t = TestSet(method, op) 10897db96d56Sopenharmony_ci try: 10907db96d56Sopenharmony_ci if not convert(t): 10917db96d56Sopenharmony_ci continue 10927db96d56Sopenharmony_ci callfuncs(t) 10937db96d56Sopenharmony_ci verify(t, stat) 10947db96d56Sopenharmony_ci except VerifyError as err: 10957db96d56Sopenharmony_ci log(err) 10967db96d56Sopenharmony_ci 10977db96d56Sopenharmony_cidef randcontext(exprange): 10987db96d56Sopenharmony_ci c = Context(C.Context(), P.Context()) 10997db96d56Sopenharmony_ci c.Emax = random.randrange(1, exprange+1) 11007db96d56Sopenharmony_ci c.Emin = random.randrange(-exprange, 0) 11017db96d56Sopenharmony_ci maxprec = 100 if c.Emax >= 100 else c.Emax 11027db96d56Sopenharmony_ci c.prec = random.randrange(1, maxprec+1) 11037db96d56Sopenharmony_ci c.clamp = random.randrange(2) 11047db96d56Sopenharmony_ci c.clear_traps() 11057db96d56Sopenharmony_ci return c 11067db96d56Sopenharmony_ci 11077db96d56Sopenharmony_cidef test_quantize_api(method, prec, exprange, restricted_range, itr, stat): 11087db96d56Sopenharmony_ci """Iterate the 'quantize' method through many test cases, using 11097db96d56Sopenharmony_ci the optional arguments.""" 11107db96d56Sopenharmony_ci for op in all_binary(prec, restricted_range, itr): 11117db96d56Sopenharmony_ci for rounding in RoundModes: 11127db96d56Sopenharmony_ci c = randcontext(exprange) 11137db96d56Sopenharmony_ci quantizeop = (op[0], op[1], rounding, c) 11147db96d56Sopenharmony_ci t = TestSet(method, quantizeop) 11157db96d56Sopenharmony_ci try: 11167db96d56Sopenharmony_ci if not convert(t): 11177db96d56Sopenharmony_ci continue 11187db96d56Sopenharmony_ci callfuncs(t) 11197db96d56Sopenharmony_ci verify(t, stat) 11207db96d56Sopenharmony_ci except VerifyError as err: 11217db96d56Sopenharmony_ci log(err) 11227db96d56Sopenharmony_ci 11237db96d56Sopenharmony_ci 11247db96d56Sopenharmony_cidef check_untested(funcdict, c_cls, p_cls): 11257db96d56Sopenharmony_ci """Determine untested, C-only and Python-only attributes. 11267db96d56Sopenharmony_ci Uncomment print lines for debugging.""" 11277db96d56Sopenharmony_ci c_attr = set(dir(c_cls)) 11287db96d56Sopenharmony_ci p_attr = set(dir(p_cls)) 11297db96d56Sopenharmony_ci intersect = c_attr & p_attr 11307db96d56Sopenharmony_ci 11317db96d56Sopenharmony_ci funcdict['c_only'] = tuple(sorted(c_attr-intersect)) 11327db96d56Sopenharmony_ci funcdict['p_only'] = tuple(sorted(p_attr-intersect)) 11337db96d56Sopenharmony_ci 11347db96d56Sopenharmony_ci tested = set() 11357db96d56Sopenharmony_ci for lst in funcdict.values(): 11367db96d56Sopenharmony_ci for v in lst: 11377db96d56Sopenharmony_ci v = v.replace("context.", "") if c_cls == C.Context else v 11387db96d56Sopenharmony_ci tested.add(v) 11397db96d56Sopenharmony_ci 11407db96d56Sopenharmony_ci funcdict['untested'] = tuple(sorted(intersect-tested)) 11417db96d56Sopenharmony_ci 11427db96d56Sopenharmony_ci # for key in ('untested', 'c_only', 'p_only'): 11437db96d56Sopenharmony_ci # s = 'Context' if c_cls == C.Context else 'Decimal' 11447db96d56Sopenharmony_ci # print("\n%s %s:\n%s" % (s, key, funcdict[key])) 11457db96d56Sopenharmony_ci 11467db96d56Sopenharmony_ci 11477db96d56Sopenharmony_ciif __name__ == '__main__': 11487db96d56Sopenharmony_ci 11497db96d56Sopenharmony_ci parser = argparse.ArgumentParser(prog="deccheck.py") 11507db96d56Sopenharmony_ci 11517db96d56Sopenharmony_ci group = parser.add_mutually_exclusive_group() 11527db96d56Sopenharmony_ci group.add_argument('--short', dest='time', action="store_const", const='short', default='short', help="short test (default)") 11537db96d56Sopenharmony_ci group.add_argument('--medium', dest='time', action="store_const", const='medium', default='short', help="medium test (reasonable run time)") 11547db96d56Sopenharmony_ci group.add_argument('--long', dest='time', action="store_const", const='long', default='short', help="long test (long run time)") 11557db96d56Sopenharmony_ci group.add_argument('--all', dest='time', action="store_const", const='all', default='short', help="all tests (excessive run time)") 11567db96d56Sopenharmony_ci 11577db96d56Sopenharmony_ci group = parser.add_mutually_exclusive_group() 11587db96d56Sopenharmony_ci group.add_argument('--single', dest='single', nargs=1, default=False, metavar="TEST", help="run a single test") 11597db96d56Sopenharmony_ci group.add_argument('--multicore', dest='multicore', action="store_true", default=False, help="use all available cores") 11607db96d56Sopenharmony_ci 11617db96d56Sopenharmony_ci args = parser.parse_args() 11627db96d56Sopenharmony_ci assert args.single is False or args.multicore is False 11637db96d56Sopenharmony_ci if args.single: 11647db96d56Sopenharmony_ci args.single = args.single[0] 11657db96d56Sopenharmony_ci 11667db96d56Sopenharmony_ci 11677db96d56Sopenharmony_ci # Set up the testspecs list. A testspec is simply a dictionary 11687db96d56Sopenharmony_ci # that determines the amount of different contexts that 'test_method' 11697db96d56Sopenharmony_ci # will generate. 11707db96d56Sopenharmony_ci base_expts = [(C.MIN_EMIN, C.MAX_EMAX)] 11717db96d56Sopenharmony_ci if C.MAX_EMAX == 999999999999999999: 11727db96d56Sopenharmony_ci base_expts.append((-999999999, 999999999)) 11737db96d56Sopenharmony_ci 11747db96d56Sopenharmony_ci # Basic contexts. 11757db96d56Sopenharmony_ci base = { 11767db96d56Sopenharmony_ci 'expts': base_expts, 11777db96d56Sopenharmony_ci 'prec': [], 11787db96d56Sopenharmony_ci 'clamp': 'rand', 11797db96d56Sopenharmony_ci 'iter': None, 11807db96d56Sopenharmony_ci 'samples': None, 11817db96d56Sopenharmony_ci } 11827db96d56Sopenharmony_ci # Contexts with small values for prec, emin, emax. 11837db96d56Sopenharmony_ci small = { 11847db96d56Sopenharmony_ci 'prec': [1, 2, 3, 4, 5], 11857db96d56Sopenharmony_ci 'expts': [(-1, 1), (-2, 2), (-3, 3), (-4, 4), (-5, 5)], 11867db96d56Sopenharmony_ci 'clamp': 'rand', 11877db96d56Sopenharmony_ci 'iter': None 11887db96d56Sopenharmony_ci } 11897db96d56Sopenharmony_ci # IEEE interchange format. 11907db96d56Sopenharmony_ci ieee = [ 11917db96d56Sopenharmony_ci # DECIMAL32 11927db96d56Sopenharmony_ci {'prec': [7], 'expts': [(-95, 96)], 'clamp': 1, 'iter': None}, 11937db96d56Sopenharmony_ci # DECIMAL64 11947db96d56Sopenharmony_ci {'prec': [16], 'expts': [(-383, 384)], 'clamp': 1, 'iter': None}, 11957db96d56Sopenharmony_ci # DECIMAL128 11967db96d56Sopenharmony_ci {'prec': [34], 'expts': [(-6143, 6144)], 'clamp': 1, 'iter': None} 11977db96d56Sopenharmony_ci ] 11987db96d56Sopenharmony_ci 11997db96d56Sopenharmony_ci if args.time == 'medium': 12007db96d56Sopenharmony_ci base['expts'].append(('rand', 'rand')) 12017db96d56Sopenharmony_ci # 5 random precisions 12027db96d56Sopenharmony_ci base['samples'] = 5 12037db96d56Sopenharmony_ci testspecs = [small] + ieee + [base] 12047db96d56Sopenharmony_ci elif args.time == 'long': 12057db96d56Sopenharmony_ci base['expts'].append(('rand', 'rand')) 12067db96d56Sopenharmony_ci # 10 random precisions 12077db96d56Sopenharmony_ci base['samples'] = 10 12087db96d56Sopenharmony_ci testspecs = [small] + ieee + [base] 12097db96d56Sopenharmony_ci elif args.time == 'all': 12107db96d56Sopenharmony_ci base['expts'].append(('rand', 'rand')) 12117db96d56Sopenharmony_ci # All precisions in [1, 100] 12127db96d56Sopenharmony_ci base['samples'] = 100 12137db96d56Sopenharmony_ci testspecs = [small] + ieee + [base] 12147db96d56Sopenharmony_ci else: # --short 12157db96d56Sopenharmony_ci rand_ieee = random.choice(ieee) 12167db96d56Sopenharmony_ci base['iter'] = small['iter'] = rand_ieee['iter'] = 1 12177db96d56Sopenharmony_ci # 1 random precision and exponent pair 12187db96d56Sopenharmony_ci base['samples'] = 1 12197db96d56Sopenharmony_ci base['expts'] = [random.choice(base_expts)] 12207db96d56Sopenharmony_ci # 1 random precision and exponent pair 12217db96d56Sopenharmony_ci prec = random.randrange(1, 6) 12227db96d56Sopenharmony_ci small['prec'] = [prec] 12237db96d56Sopenharmony_ci small['expts'] = [(-prec, prec)] 12247db96d56Sopenharmony_ci testspecs = [small, rand_ieee, base] 12257db96d56Sopenharmony_ci 12267db96d56Sopenharmony_ci 12277db96d56Sopenharmony_ci check_untested(Functions, C.Decimal, P.Decimal) 12287db96d56Sopenharmony_ci check_untested(ContextFunctions, C.Context, P.Context) 12297db96d56Sopenharmony_ci 12307db96d56Sopenharmony_ci 12317db96d56Sopenharmony_ci if args.multicore: 12327db96d56Sopenharmony_ci q = Queue() 12337db96d56Sopenharmony_ci elif args.single: 12347db96d56Sopenharmony_ci log("Random seed: %d", RANDSEED) 12357db96d56Sopenharmony_ci else: 12367db96d56Sopenharmony_ci log("\n\nRandom seed: %d\n\n", RANDSEED) 12377db96d56Sopenharmony_ci 12387db96d56Sopenharmony_ci 12397db96d56Sopenharmony_ci FOUND_METHOD = False 12407db96d56Sopenharmony_ci def do_single(method, f): 12417db96d56Sopenharmony_ci global FOUND_METHOD 12427db96d56Sopenharmony_ci if args.multicore: 12437db96d56Sopenharmony_ci q.put(method) 12447db96d56Sopenharmony_ci elif not args.single or args.single == method: 12457db96d56Sopenharmony_ci FOUND_METHOD = True 12467db96d56Sopenharmony_ci f() 12477db96d56Sopenharmony_ci 12487db96d56Sopenharmony_ci # Decimal methods: 12497db96d56Sopenharmony_ci for method in Functions['unary'] + Functions['unary_ctx'] + \ 12507db96d56Sopenharmony_ci Functions['unary_rnd_ctx']: 12517db96d56Sopenharmony_ci do_single(method, lambda: test_method(method, testspecs, test_unary)) 12527db96d56Sopenharmony_ci 12537db96d56Sopenharmony_ci for method in Functions['binary'] + Functions['binary_ctx']: 12547db96d56Sopenharmony_ci do_single(method, lambda: test_method(method, testspecs, test_binary)) 12557db96d56Sopenharmony_ci 12567db96d56Sopenharmony_ci for method in Functions['ternary'] + Functions['ternary_ctx']: 12577db96d56Sopenharmony_ci name = '__powmod__' if method == '__pow__' else method 12587db96d56Sopenharmony_ci do_single(name, lambda: test_method(method, testspecs, test_ternary)) 12597db96d56Sopenharmony_ci 12607db96d56Sopenharmony_ci do_single('__format__', lambda: test_method('__format__', testspecs, test_format)) 12617db96d56Sopenharmony_ci do_single('__round__', lambda: test_method('__round__', testspecs, test_round)) 12627db96d56Sopenharmony_ci do_single('from_float', lambda: test_method('from_float', testspecs, test_from_float)) 12637db96d56Sopenharmony_ci do_single('quantize_api', lambda: test_method('quantize', testspecs, test_quantize_api)) 12647db96d56Sopenharmony_ci 12657db96d56Sopenharmony_ci # Context methods: 12667db96d56Sopenharmony_ci for method in ContextFunctions['unary']: 12677db96d56Sopenharmony_ci do_single(method, lambda: test_method(method, testspecs, test_unary)) 12687db96d56Sopenharmony_ci 12697db96d56Sopenharmony_ci for method in ContextFunctions['binary']: 12707db96d56Sopenharmony_ci do_single(method, lambda: test_method(method, testspecs, test_binary)) 12717db96d56Sopenharmony_ci 12727db96d56Sopenharmony_ci for method in ContextFunctions['ternary']: 12737db96d56Sopenharmony_ci name = 'context.powmod' if method == 'context.power' else method 12747db96d56Sopenharmony_ci do_single(name, lambda: test_method(method, testspecs, test_ternary)) 12757db96d56Sopenharmony_ci 12767db96d56Sopenharmony_ci do_single('context.create_decimal_from_float', 12777db96d56Sopenharmony_ci lambda: test_method('context.create_decimal_from_float', 12787db96d56Sopenharmony_ci testspecs, test_from_float)) 12797db96d56Sopenharmony_ci 12807db96d56Sopenharmony_ci if args.multicore: 12817db96d56Sopenharmony_ci error = Event() 12827db96d56Sopenharmony_ci write_lock = Lock() 12837db96d56Sopenharmony_ci 12847db96d56Sopenharmony_ci def write_output(out, returncode): 12857db96d56Sopenharmony_ci if returncode != 0: 12867db96d56Sopenharmony_ci error.set() 12877db96d56Sopenharmony_ci 12887db96d56Sopenharmony_ci with write_lock: 12897db96d56Sopenharmony_ci sys.stdout.buffer.write(out + b"\n") 12907db96d56Sopenharmony_ci sys.stdout.buffer.flush() 12917db96d56Sopenharmony_ci 12927db96d56Sopenharmony_ci def tfunc(): 12937db96d56Sopenharmony_ci while not error.is_set(): 12947db96d56Sopenharmony_ci try: 12957db96d56Sopenharmony_ci test = q.get(block=False, timeout=-1) 12967db96d56Sopenharmony_ci except Empty: 12977db96d56Sopenharmony_ci return 12987db96d56Sopenharmony_ci 12997db96d56Sopenharmony_ci cmd = [sys.executable, "deccheck.py", "--%s" % args.time, "--single", test] 13007db96d56Sopenharmony_ci p = subprocess.Popen(cmd, stdout=PIPE, stderr=STDOUT) 13017db96d56Sopenharmony_ci out, _ = p.communicate() 13027db96d56Sopenharmony_ci write_output(out, p.returncode) 13037db96d56Sopenharmony_ci 13047db96d56Sopenharmony_ci N = os.cpu_count() 13057db96d56Sopenharmony_ci t = N * [None] 13067db96d56Sopenharmony_ci 13077db96d56Sopenharmony_ci for i in range(N): 13087db96d56Sopenharmony_ci t[i] = Thread(target=tfunc) 13097db96d56Sopenharmony_ci t[i].start() 13107db96d56Sopenharmony_ci 13117db96d56Sopenharmony_ci for i in range(N): 13127db96d56Sopenharmony_ci t[i].join() 13137db96d56Sopenharmony_ci 13147db96d56Sopenharmony_ci sys.exit(1 if error.is_set() else 0) 13157db96d56Sopenharmony_ci 13167db96d56Sopenharmony_ci elif args.single: 13177db96d56Sopenharmony_ci if not FOUND_METHOD: 13187db96d56Sopenharmony_ci log("\nerror: cannot find method \"%s\"" % args.single) 13197db96d56Sopenharmony_ci EXIT_STATUS = 1 13207db96d56Sopenharmony_ci sys.exit(EXIT_STATUS) 13217db96d56Sopenharmony_ci else: 13227db96d56Sopenharmony_ci sys.exit(EXIT_STATUS) 1323