def __call__(args): PRECISION = ML_Binary64 value_list = [ FP_PlusInfty(PRECISION), FP_MinusInfty(PRECISION), FP_PlusZero(PRECISION), FP_MinusZero(PRECISION), FP_QNaN(PRECISION), FP_SNaN(PRECISION), #FP_PlusOmega(PRECISION), #FP_MinusOmega(PRECISION), NumericValue(7.0), NumericValue(-3.0), ] op_map = { "+": operator.__add__, "-": operator.__sub__, "*": operator.__mul__, } for op in op_map: for lhs in value_list: for rhs in value_list: print("{} {} {} = {}".format(lhs, op, rhs, op_map[op](lhs, rhs))) return True
def __call__(args): for PRECISION in [ML_Binary32, ML_Binary64]: TEST_CASE = [ (FP_PlusOmega(PRECISION), "<", FP_SNaN(PRECISION), Unordered), (FP_PlusOmega(PRECISION), "<=", FP_SNaN(PRECISION), Unordered), (FP_PlusInfty(PRECISION), "==", FP_PlusInfty(PRECISION), True), (FP_PlusInfty(PRECISION), "==", FP_QNaN(PRECISION), False), (FP_PlusZero(PRECISION), "==", FP_MinusZero(PRECISION), True), (FP_PlusZero(PRECISION), "!=", FP_MinusZero(PRECISION), False), (FP_QNaN(PRECISION), "==", FP_QNaN(PRECISION), False), (FP_PlusInfty(PRECISION), "==", -FP_MinusInfty(PRECISION), True), (FP_MinusInfty(PRECISION), ">", 0, False), (FP_MinusInfty(PRECISION), ">", FP_PlusZero(PRECISION), False), (FP_MinusInfty(PRECISION), ">", FP_MinusZero(PRECISION), False), ] for lhs, op, rhs, expected in TEST_CASE: result = op_map[op](lhs, rhs) assert result == expected, "failure: {} {} {} = {} vs expected {} ".format(lhs, op, rhsresult, expected) return True
def standard_test_cases(self): fp64_list = [ # random test (sollya.parse("0x1.e906cc97d7cc1p+743"), sollya.parse("0x0.000001b84ba98p-1022")), (sollya.parse("0x1.9c4110b0dea4fp+279"), sollya.parse("0x0.000ccf2945bd8p-1022")), # OpenCL CTS error # infinite loop # ERROR: remquoD: {-inf, 77} ulp error at {0x0.eaffffffffb86p-1022, -0x0.0000000000202p-1022} ({ 0x000eaffffffffb86, 0x8000000000000202}): *{0x0.00000000000eap-1022, -78} ({ 0x00000000000000ea, 0xffffffb2}) vs. {-0x1.0000000000000p+0, -1} ({ 0xbff0000000000000, 0xffffffff}) (sollya.parse("0x0.eaffffffffb86p-1022"), sollya.parse("-0x0.0000000000202p-1022"), sollya.parse("0x0.00000000000eap-1022") if self.mode is REMAINDER_MODE else -78), # ERROR: remquoD: {0.000000, 92} ulp error at {-0x1.b9000000003e0p-982, -0x0.0000000000232p-1022} ({ 0x829b9000000003e0, 0x8000000000000232}): *{-0x0.0000000000000p+0, 0} ({ 0x8000000000000000, 0x00000000}) vs. {-0x0.0000000000000p+0, 92} ({ 0x8000000000000000, 0x0000005c}) (sollya.parse("-0x1.b9000000003e0p-982"), sollya.parse("-0x0.0000000000232p-1022"), FP_MinusZero(self.precision) if self.mode is REMAINDER_MODE else 0), # ERROR: remquoD: {-26458647810801664.000000, 1} ulp error at {-0x1.be000000005dfp+977, 0x1.78000000006f1p+975} ({ 0xfd0be000000005df, 0x7ce78000000006f1}): *{0x1.8000000002ce4p+973, -5} ({ 0x7cc8000000002ce4, 0xfffffffb}) vs. {-0x1.17ffffffffbb8p+975, -4} ({ 0xfce17ffffffffbb8, 0xfffffffc}) (sollya.parse("-0x1.be000000005dfp+977"), sollya.parse("0x1.78000000006f1p+975"), sollya.parse("0x1.8000000002ce4p+973") if self.mode is REMAINDER_MODE else -5), # ERROR: remquoD: {-171.000000, -1} ulp error at {-0x1.02ffffffffc2bp+489, -0x0.00000000000abp-1022} ({ 0xde802ffffffffc2b, 0x80000000000000ab}): *{0x0.0000000000055p-1022, 127} ({ 0x0000000000000055, 0x0000007f}) vs. {-0x0.0000000000056p-1022, 254} ({ 0x8000000000000056, 0x000000fe}) (sollya.parse("0x1.02ffffffffc2bp+489"), sollya.parse("0x0.00000000000abp-1022")), (sollya.parse("-0x1.02ffffffffc2bp+489"), sollya.parse("-0x0.00000000000abp-1022"), sollya.parse("0x0.0000000000055p-1022") if self.mode is REMAINDER_MODE else 127), # ERROR: remquoD: {nan, 0} ulp error at {-0x1.69000000001e1p+749, -inf} ({ 0xeec69000000001e1, 0xfff0000000000000}): *{-0x1.69000000001e1p+749, 0} ({ 0xeec69000000001e1, 0x00000000}) vs. {nan, 0} ({ 0x7ff8000000000000, 0x00000000}) (sollya.parse("-0x1.69000000001e1p+749"), FP_MinusInfty(self.precision), sollya.parse("-0x1.69000000001e1p+749") if self.mode is REMAINDER_MODE else 0), # ERROR: remquo: {0.000000, -126} ulp error at {0x1.921456p+70, -0x1.921456p+70} ({0x62c90a2b, 0xe2c90a2b}): *{0x0p+0, -1} ({0x00000000, 0xffffffff}) vs. {0x0p+0, 1} ({0x00000000, 0x00000001}) (sollya.parse("0x1.921456p+70"), sollya.parse("-0x1.921456p+70"), 0 if self.mode is REMAINDER_MODE else -1), # ERROR: remquoD: {10731233487093760.000000, 0} ulp error at {0x1.30fffffffff7ep-597, -0x1.13ffffffffed0p-596} ({ 0x1aa30fffffffff7e, 0x9ab13ffffffffed0}): *{-0x1.edffffffffc44p-598, -1} ({ 0x9a9edffffffffc44, 0xffffffff}) vs. {0x1.d000000000ae0p-600, -1} ({ 0x1a7d000000000ae0, 0xffffffff}) (sollya.parse("0x1.30fffffffff7ep-597"), sollya.parse("-0x1.13ffffffffed0p-596"), -1 if self.mode is QUOTIENT_MODE else sollya.parse("-0x1.edffffffffc44p-598")), # {-0x1.9bffffffffd38p+361, 0x0.00000000000a5p-1022} ({ 0xd689bffffffffd38, 0x00000000000000a5}): *{-0x0.000000000000fp-1022, -93} ({ 0x800000000000000f, 0xffffffa3}) vs. {0x0.000000000000fp-1022, -1171354717} ({ 0x000000000000000f, 0xba2e8ba3}) (sollya.parse("-0x1.9bffffffffd38p+361"), sollya.parse("0x0.00000000000a5p-1022")), (sollya.parse("0x0.ac0f94b9da13p-1022"), sollya.parse("-0x1.1e4580d7eb2e7p-1022")), (sollya.parse("0x1.fffffffffffffp+1023"), sollya.parse("-0x1.fffffffffffffp+1023")), (sollya.parse("0x0.a9f466178b1fcp-1022"), sollya.parse("0x0.b22f552dc829ap-1022")), (sollya.parse("0x1.4af8b07942537p-430"), sollya.parse("-0x0.f72be041645b7p-1022")), #result is 0x0.0000000000505p-1022 vs expected0x0.0000000000a3cp-1022 #(sollya.parse("0x1.9f9f4e9a29fcfp-421"), sollya.parse("0x0.0000000001b59p-1022"), sollya.parse("0x0.0000000000a3cp-1022")), (sollya.parse("0x1.9906165fb3e61p+62"), sollya.parse("0x1.9906165fb3e61p+60")), (sollya.parse("0x1.9906165fb3e61p+62"), sollya.parse("0x0.0000000005e7dp-1022")), (sollya.parse("0x1.77f00143ba3f4p+943"), sollya.parse("0x0.000000000001p-1022")), (sollya.parse("0x0.000000000001p-1022"), sollya.parse("0x0.000000000001p-1022")), (sollya.parse("0x0.000000000348bp-1022"), sollya.parse("0x0.000000000001p-1022")), (sollya.parse("0x1.bcf3955c3b244p-130"), sollya.parse("0x1.77aef33890951p-1003")), (sollya.parse("0x1.8de59bd84c51ep-866"), sollya.parse("0x1.045aa9bf14fb1p-774")), (sollya.parse("0x1.9f9f4e9a29fcfp-421"), sollya.parse("0x0.0000000001b59p-1022")), (sollya.parse("0x1.2e1c59b43a459p+953"), sollya.parse("0x0.0000001cf5319p-1022")), (sollya.parse("-0x1.86c83abe0854ep+268"), FP_MinusInfty(self.precision)), # bad sign of remainder (sollya.parse("0x1.d3fb9968850a5p-960"), sollya.parse("-0x0.23c1ed19c45fp-1022")), # bad sign of zero (FP_MinusZero(self.precision), sollya.parse("0x1.85200a9235193p-450")), # bad remainder (sollya.parse("0x1.fffffffffffffp+1023"), sollya.parse("0x1.1f31bcd002a7ap-803")), # bad sign (sollya.parse("-0x1.4607d0c9fc1a7p-878"), sollya.parse("-0x1.9b666b840b1bp-1023")), ] return fp64_list if self.precision.get_bit_size() >= 64 else []
def generate_scalar_scheme(self, vx, vy): # fixing inputs' node tag vx.set_attributes(tag="x") vy.set_attributes(tag="y") int_precision = self.precision.get_integer_format() # assuming x = m.2^e (m in [1, 2[) # n, positive or null integers # # pow(x, n) = x^(y) # = exp(y * log(x)) # = 2^(y * log2(x)) # = 2^(y * (log2(m) + e)) # e = ExponentExtraction(vx, tag="e", precision=int_precision) m = MantissaExtraction(vx, tag="m", precision=self.precision) # approximation log2(m) # retrieving processor inverse approximation table dummy_var = Variable("dummy", precision = self.precision) dummy_div_seed = ReciprocalSeed(dummy_var, precision = self.precision) inv_approx_table = self.processor.get_recursive_implementation( dummy_div_seed, language=None, table_getter= lambda self: self.approx_table_map) log_f = sollya.log(sollya.x) # /sollya.log(self.basis) ml_log_args = ML_GenericLog.get_default_args(precision=self.precision, basis=2) ml_log = ML_GenericLog(ml_log_args) log_table, log_table_tho, table_index_range = ml_log.generate_log_table(log_f, inv_approx_table) log_approx = ml_log.generate_reduced_log_split(Abs(m, precision=self.precision), log_f, inv_approx_table, log_table) log_approx = Select(Equal(vx, 0), FP_MinusInfty(self.precision), log_approx) log_approx.set_attributes(tag="log_approx", debug=debug_multi) r = Multiplication(log_approx, vy, tag="r", debug=debug_multi) # 2^(y * (log2(m) + e)) = 2^(y * log2(m)) * 2^(y * e) # # log_approx = log2(Abs(m)) # r = y * log_approx ~ y * log2(m) # # NOTES: manage cases where e is negative and # (y * log2(m)) AND (y * e) could cancel out # if e positive, whichever the sign of y (y * log2(m)) and (y * e) CANNOT # be of opposite signs # log2(m) in [0, 1[ so cancellation can occur only if e == -1 # we split 2^x in 2^x = 2^t0 * 2^t1 # if e < 0: t0 = y * (log2(m) + e), t1=0 # else: t0 = y * log2(m), t1 = y * e t_cond = e < 0 # e_y ~ e * y e_f = Conversion(e, precision=self.precision) #t0 = Select(t_cond, (e_f + log_approx) * vy, Multiplication(e_f, vy), tag="t0") #NearestInteger(t0, precision=self.precision, tag="t0_int") EY = NearestInteger(e_f * vy, tag="EY", precision=self.precision) LY = NearestInteger(log_approx * vy, tag="LY", precision=self.precision) t0_int = Select(t_cond, EY + LY, EY, tag="t0_int") t0_frac = Select(t_cond, FMA(e_f, vy, -EY) + FMA(log_approx, vy, -LY) ,EY - t0_int, tag="t0_frac") #t0_frac.set_attributes(tag="t0_frac") ml_exp2_args = ML_Exp2.get_default_args(precision=self.precision) ml_exp2 = ML_Exp2(ml_exp2_args) exp2_t0_frac = ml_exp2.generate_scalar_scheme(t0_frac, inline_select=True) exp2_t0_frac.set_attributes(tag="exp2_t0_frac", debug=debug_multi) exp2_t0_int = ExponentInsertion(Conversion(t0_int, precision=int_precision), precision=self.precision, tag="exp2_t0_int") t1 = Select(t_cond, Constant(0, precision=self.precision), r) exp2_t1 = ml_exp2.generate_scalar_scheme(t1, inline_select=True) exp2_t1.set_attributes(tag="exp2_t1", debug=debug_multi) result_sign = Constant(1.0, precision=self.precision) # Select(n_is_odd, CopySign(vx, Constant(1.0, precision=self.precision)), 1) y_int = NearestInteger(vy, precision=self.precision) y_is_integer = Equal(y_int, vy) y_is_even = LogicalOr( # if y is a number (exc. inf) greater than 2**mantissa_size * 2, # then it is an integer multiple of 2 => even Abs(vy) >= 2**(self.precision.get_mantissa_size()+1), LogicalAnd( y_is_integer and Abs(vy) < 2**(self.precision.get_mantissa_size()+1), # we want to limit the modulo computation to an integer input Equal(Modulo(Conversion(y_int, precision=int_precision), 2), 0) ) ) y_is_odd = LogicalAnd( LogicalAnd( Abs(vy) < 2**(self.precision.get_mantissa_size()+1), y_is_integer ), Equal(Modulo(Conversion(y_int, precision=int_precision), 2), 1) ) # special cases management special_case_results = Statement( # x is sNaN OR y is sNaN ConditionBlock( LogicalOr(Test(vx, specifier=Test.IsSignalingNaN), Test(vy, specifier=Test.IsSignalingNaN)), Return(FP_QNaN(self.precision)) ), # pow(x, ±0) is 1 if x is not a signaling NaN ConditionBlock( Test(vy, specifier=Test.IsZero), Return(Constant(1.0, precision=self.precision)) ), # pow(±0, y) is ±∞ and signals the divideByZero exception for y an odd integer <0 ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsZero), LogicalAnd(y_is_odd, vy < 0)), Return(Select(Test(vx, specifier=Test.IsPositiveZero), FP_PlusInfty(self.precision), FP_MinusInfty(self.precision))), ), # pow(±0, −∞) is +∞ with no exception ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsZero), Test(vy, specifier=Test.IsNegativeInfty)), Return(FP_MinusInfty(self.precision)), ), # pow(±0, +∞) is +0 with no exception ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsZero), Test(vy, specifier=Test.IsPositiveInfty)), Return(FP_PlusInfty(self.precision)), ), # pow(±0, y) is ±0 for finite y>0 an odd integer ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsZero), LogicalAnd(y_is_odd, vy > 0)), Return(vx), ), # pow(−1, ±∞) is 1 with no exception ConditionBlock( LogicalAnd(Equal(vx, -1), Test(vy, specifier=Test.IsInfty)), Return(Constant(1.0, precision=self.precision)), ), # pow(+1, y) is 1 for any y (even a quiet NaN) ConditionBlock( vx == 1, Return(Constant(1.0, precision=self.precision)), ), # pow(x, +∞) is +0 for −1<x<1 ConditionBlock( LogicalAnd(Abs(vx) < 1, Test(vy, specifier=Test.IsPositiveInfty)), Return(FP_PlusZero(self.precision)) ), # pow(x, +∞) is +∞ for x<−1 or for 1<x (including ±∞) ConditionBlock( LogicalAnd(Abs(vx) > 1, Test(vy, specifier=Test.IsPositiveInfty)), Return(FP_PlusInfty(self.precision)) ), # pow(x, −∞) is +∞ for −1<x<1 ConditionBlock( LogicalAnd(Abs(vx) < 1, Test(vy, specifier=Test.IsNegativeInfty)), Return(FP_PlusInfty(self.precision)) ), # pow(x, −∞) is +0 for x<−1 or for 1<x (including ±∞) ConditionBlock( LogicalAnd(Abs(vx) > 1, Test(vy, specifier=Test.IsNegativeInfty)), Return(FP_PlusZero(self.precision)) ), # pow(+∞, y) is +0 for a number y < 0 ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsPositiveInfty), vy < 0), Return(FP_PlusZero(self.precision)) ), # pow(+∞, y) is +∞ for a number y > 0 ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsPositiveInfty), vy > 0), Return(FP_PlusInfty(self.precision)) ), # pow(−∞, y) is −0 for finite y < 0 an odd integer # TODO: check y is finite ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsNegativeInfty), LogicalAnd(y_is_odd, vy < 0)), Return(FP_MinusZero(self.precision)), ), # pow(−∞, y) is −∞ for finite y > 0 an odd integer # TODO: check y is finite ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsNegativeInfty), LogicalAnd(y_is_odd, vy > 0)), Return(FP_MinusInfty(self.precision)), ), # pow(−∞, y) is +0 for finite y < 0 and not an odd integer # TODO: check y is finite ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsNegativeInfty), LogicalAnd(LogicalNot(y_is_odd), vy < 0)), Return(FP_PlusZero(self.precision)), ), # pow(−∞, y) is +∞ for finite y > 0 and not an odd integer # TODO: check y is finite ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsNegativeInfty), LogicalAnd(LogicalNot(y_is_odd), vy > 0)), Return(FP_PlusInfty(self.precision)), ), # pow(±0, y) is +∞ and signals the divideByZero exception for finite y<0 and not an odd integer # TODO: signal divideByZero exception ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsZero), LogicalAnd(LogicalNot(y_is_odd), vy < 0)), Return(FP_PlusInfty(self.precision)), ), # pow(±0, y) is +0 for finite y>0 and not an odd integer ConditionBlock( LogicalAnd(Test(vx, specifier=Test.IsZero), LogicalAnd(LogicalNot(y_is_odd), vy > 0)), Return(FP_PlusZero(self.precision)), ), ) # manage n=1 separately to avoid catastrophic propagation of errors # between log2 and exp2 to eventually compute the identity function # test-case #3 result = Statement( special_case_results, # fallback default cases Return(result_sign * exp2_t1 * exp2_t0_int * exp2_t0_frac)) return result
def numeric_emulate(self, vx, vy): """ Numeric emulation of pow """ if is_snan(vx) or is_snan(vy): return FP_QNaN(self.precision) # pow(x, ±0) is 1 if x is not a signaling NaN if is_zero(vy): return 1.0 # pow(±0, y) is ±∞ and signals the divideByZero exception for y an odd integer <0 if is_plus_zero(vx) and not is_special_value(vy) and (int(vy) == vy) and (int(vy) % 2 == 1) and vy < 0: return FP_PlusInfty(self.precision) if is_minus_zero(vx) and not is_special_value(vy) and (int(vy) == vy) and (int(vy) % 2 == 1) and vy < 0: return FP_MinusInfty(self.precision) # pow(±0, −∞) is +∞ with no exception if is_zero(vx) and is_minus_zero(vy): return FP_MinusInfty(self.precision) # pow(±0, +∞) is +0 with no exception if is_zero(vx) and is_plus_zero(vy): return FP_PlusZero(self.precision) # pow(±0, y) is ±0 for finite y>0 an odd integer if is_zero(vx) and not is_special_value(vy) and (int(vy) == vy) and (int(vy) % 2 == 1) and vy > 0: return vx # pow(−1, ±∞) is 1 with no exception if vx == -1.0 and is_infty(vy): return 1 # pow(+1, y) is 1 for any y (even a quiet NaN) if vx == 1.0: return 1.0 # pow(x, +∞) is +0 for −1<x<1 if -1 < vx < 1 and is_plus_infty(vy): return FP_PlusZero(self.precision) # pow(x, +∞) is +∞ for x<−1 or for 1<x (including ±∞) if (vx < -1 or vx > 1) and is_plus_infty(vy): return FP_PlusInfty(self.precision) # pow(x, −∞) is +∞ for −1<x<1 if -1 < vx < 1 and is_minus_infty(vy): return FP_PlusInfty(self.precision) # pow(x, −∞) is +0 for x<−1 or for 1<x (including ±∞) if is_minus_infty(vy) and (vx < -1 or vx > 1): return FP_PlusZero(self.precision) # pow(+∞, y) is +0 for a number y < 0 if is_plus_infty(vx) and vy < 0: return FP_PlusZero(self.precision) # pow(+∞, y) is +∞ for a number y > 0 if is_plus_infty(vx) and vy > 0: return FP_PlusInfty(self.precision) # pow(−∞, y) is −0 for finite y < 0 an odd integer if is_minus_infty(vx) and vy < 0 and not is_special_value(vy) and int(vy) == vy and int(vy) % 2 == 1: return FP_MinusZero(self.precision) # pow(−∞, y) is −∞ for finite y > 0 an odd integer if is_minus_infty(vx) and vy > 0 and not is_special_value(vy) and int(vy) == vy and int(vy) % 2 == 1: return FP_MinusInfty(self.precision) # pow(−∞, y) is +0 for finite y < 0 and not an odd integer if is_minus_infty(vx) and vy < 0 and not is_special_value(vy) and not(int(vy) == vy and int(vy) % 2 == 1): return FP_PlusZero(self.precision) # pow(−∞, y) is +∞ for finite y > 0 and not an odd integer if is_minus_infty(vx) and vy > 0 and not is_special_value(vy) and not(int(vy) == vy and int(vy) % 2 == 1): return FP_PlusInfty(self.precision) # pow(±0, y) is +∞ and signals the divideByZero exception for finite y<0 and not an odd integer if is_zero(vx) and vy < 0 and not is_special_value(vy) and not(int(vy) == vy and int(vy) % 2 == 1): return FP_PlusInfty(self.precision) # pow(±0, y) is +0 for finite y>0 and not an odd integer if is_zero(vx) and vy > 0 and not is_special_value(vy) and not(int(vy) == vy and int(vy) % 2 == 1): return FP_PlusZero(self.precision) # TODO # pow(x, y) signals the invalid operation exception for finite x<0 and finite non-integer y. return sollya.SollyaObject(vx)**sollya.SollyaObject(vy)
def generate_scheme(self): # We wish to compute vx / vy vx = self.implementation.add_input_variable( "x", self.precision, interval=self.input_intervals[0]) vy = self.implementation.add_input_variable( "y", self.precision, interval=self.input_intervals[1]) # maximum exponent magnitude (to avoid overflow/ underflow during # intermediary computations int_prec = self.precision.get_integer_format() max_exp_mag = Constant(self.precision.get_emax() - 1, precision=int_prec) exact_ex = ExponentExtraction(vx, tag="exact_ex", precision=int_prec, debug=debug_multi) exact_ey = ExponentExtraction(vy, tag="exact_ey", precision=int_prec, debug=debug_multi) ex = Max(Min(exact_ex, max_exp_mag, precision=int_prec), -max_exp_mag, tag="ex", precision=int_prec) ey = Max(Min(exact_ey, max_exp_mag, precision=int_prec), -max_exp_mag, tag="ey", precision=int_prec) Attributes.set_default_rounding_mode(ML_RoundToNearest) Attributes.set_default_silent(True) # computing the inverse square root init_approx = None scaling_factor_x = ExponentInsertion(-ex, tag="sfx_ei", precision=self.precision, debug=debug_multi) scaling_factor_y = ExponentInsertion(-ey, tag="sfy_ei", precision=self.precision, debug=debug_multi) def test_interval_out_of_bound_risk(x_range, y_range): """ Try to determine from x and y's interval if there is a risk of underflow or overflow """ div_range = abs(x_range / y_range) underflow_risk = sollya.inf(div_range) < S2**( self.precision.get_emin_normal() + 2) overflow_risk = sollya.sup(div_range) > S2**( self.precision.get_emax() - 2) return underflow_risk or overflow_risk out_of_bound_risk = (self.input_intervals[0] is None or self.input_intervals[1] is None ) or test_interval_out_of_bound_risk( self.input_intervals[0], self.input_intervals[1]) Log.report(Log.Debug, "out_of_bound_risk: {}".format(out_of_bound_risk)) # scaled version of vx and vy, to avoid overflow and underflow if out_of_bound_risk: scaled_vx = vx * scaling_factor_x scaled_vy = vy * scaling_factor_y scaled_interval = MetaIntervalList( [MetaInterval(Interval(-2, -1)), MetaInterval(Interval(1, 2))]) scaled_vx.set_attributes(tag="scaled_vx", debug=debug_multi, interval=scaled_interval) scaled_vy.set_attributes(tag="scaled_vy", debug=debug_multi, interval=scaled_interval) seed_interval = 1 / scaled_interval print("seed_interval=1/{}={}".format(scaled_interval, seed_interval)) else: scaled_vx = vx scaled_vy = vy seed_interval = 1 / scaled_vy.get_interval() # We need a first approximation to 1 / scaled_vy dummy_seed = ReciprocalSeed(EmptyOperand(precision=self.precision), precision=self.precision) if self.processor.is_supported_operation(dummy_seed, self.language): init_approx = ReciprocalSeed(scaled_vy, precision=self.precision, tag="init_approx", debug=debug_multi) else: # generate tabulated version of seed raise NotImplementedError current_approx_std = init_approx # correctly-rounded inverse computation num_iteration = self.num_iter Attributes.unset_default_rounding_mode() Attributes.unset_default_silent() # check if inputs are zeros x_zero = Test(vx, specifier=Test.IsZero, likely=False, precision=ML_Bool) y_zero = Test(vy, specifier=Test.IsZero, likely=False, precision=ML_Bool) comp_sign = Test(vx, vy, specifier=Test.CompSign, tag="comp_sign", debug=debug_multi) # check if divisor is NaN y_nan = Test(vy, specifier=Test.IsNaN, likely=False, precision=ML_Bool) # check if inputs are signaling NaNs x_snan = Test(vx, specifier=Test.IsSignalingNaN, likely=False, precision=ML_Bool) y_snan = Test(vy, specifier=Test.IsSignalingNaN, likely=False, precision=ML_Bool) # check if inputs are infinities x_inf = Test(vx, specifier=Test.IsInfty, likely=False, tag="x_inf", precision=ML_Bool) y_inf = Test(vy, specifier=Test.IsInfty, likely=False, tag="y_inf", debug=debug_multi, precision=ML_Bool) scheme = None gappa_vx, gappa_vy = None, None # initial reciprocal approximation of 1.0 / scaled_vy inv_iteration_list, recp_approx = compute_reduced_reciprocal( init_approx, scaled_vy, self.num_iter) recp_approx.set_attributes(tag="recp_approx", debug=debug_multi) # approximation of scaled_vx / scaled_vy yerr_last, reduced_div_approx, div_iteration_list = compute_reduced_division( scaled_vx, scaled_vy, recp_approx) eval_error_range, div_eval_error_range = self.solve_eval_error( init_approx, recp_approx, reduced_div_approx, scaled_vx, scaled_vy, inv_iteration_list, div_iteration_list, S2**-7, seed_interval) eval_error = sup(abs(eval_error_range)) recp_interval = 1 / scaled_vy.get_interval() + eval_error_range recp_approx.set_interval(recp_interval) div_interval = scaled_vx.get_interval() / scaled_vy.get_interval( ) + div_eval_error_range reduced_div_approx.set_interval(div_interval) reduced_div_approx.set_tag("reduced_div_approx") if out_of_bound_risk: unscaled_result = scaling_div_result(reduced_div_approx, ex, scaling_factor_y, self.precision) subnormal_result = subnormalize_result(recp_approx, reduced_div_approx, ex, ey, yerr_last, self.precision) else: unscaled_result = reduced_div_approx subnormal_result = reduced_div_approx x_inf_or_nan = Test(vx, specifier=Test.IsInfOrNaN, likely=False) y_inf_or_nan = Test(vy, specifier=Test.IsInfOrNaN, likely=False, tag="y_inf_or_nan", debug=debug_multi) # generate IEEE exception raising only of libm-compliant # mode is enabled enable_raise = self.libm_compliant # managing special cases # x inf and y inf pre_scheme = ConditionBlock( x_inf_or_nan, ConditionBlock( x_inf, ConditionBlock( y_inf_or_nan, Statement( # signaling NaNs raise invalid operation flags ConditionBlock(y_snan, Raise(ML_FPE_Invalid)) if enable_raise else Statement(), Return(FP_QNaN(self.precision)), ), ConditionBlock(comp_sign, Return(FP_MinusInfty(self.precision)), Return(FP_PlusInfty(self.precision)))), Statement( ConditionBlock(x_snan, Raise(ML_FPE_Invalid)) if enable_raise else Statement(), Return(FP_QNaN(self.precision)))), ConditionBlock( x_zero, ConditionBlock( LogicalOr(y_zero, y_nan, precision=ML_Bool), Statement( ConditionBlock(y_snan, Raise(ML_FPE_Invalid)) if enable_raise else Statement(), Return(FP_QNaN(self.precision))), Return(vx)), ConditionBlock( y_inf_or_nan, ConditionBlock( y_inf, Return( Select(comp_sign, FP_MinusZero(self.precision), FP_PlusZero(self.precision))), Statement( ConditionBlock(y_snan, Raise(ML_FPE_Invalid)) if enable_raise else Statement(), Return(FP_QNaN(self.precision)))), ConditionBlock( y_zero, Statement( Raise(ML_FPE_DivideByZero) if enable_raise else Statement(), ConditionBlock( comp_sign, Return(FP_MinusInfty(self.precision)), Return(FP_PlusInfty(self.precision)))), # managing numerical value result cases Statement( recp_approx, reduced_div_approx, ConditionBlock( Test(unscaled_result, specifier=Test.IsSubnormal, likely=False), # result is subnormal Statement( # inexact flag should have been raised when computing yerr_last # ConditionBlock( # Comparison( # yerr_last, 0, # specifier=Comparison.NotEqual, likely=True), # Statement(Raise(ML_FPE_Inexact, ML_FPE_Underflow)) #), Return(subnormal_result), ), # result is normal Statement( # inexact flag should have been raised when computing yerr_last #ConditionBlock( # Comparison( # yerr_last, 0, # specifier=Comparison.NotEqual, likely=True), # Raise(ML_FPE_Inexact) #), Return(unscaled_result))), ))))) # managing rounding mode save and restore # to ensure intermediary computations are performed in round-to-nearest # clearing exception before final computation #rnd_mode = GetRndMode() #scheme = Statement( # rnd_mode, # SetRndMode(ML_RoundToNearest), # yerr_last, # SetRndMode(rnd_mode), # unscaled_result, # ClearException(), # pre_scheme #) scheme = pre_scheme return scheme
def generate_scalar_scheme(self, vx, n): # fixing inputs' node tag vx.set_attributes(tag="x") n.set_attributes(tag="n") int_precision = self.precision.get_integer_format() # assuming x = m.2^e (m in [1, 2[) # n, positive or null integers # # rootn(x, n) = x^(1/n) # = exp(1/n * log(x)) # = 2^(1/n * log2(x)) # = 2^(1/n * (log2(m) + e)) # # approximation log2(m) # retrieving processor inverse approximation table dummy_var = Variable("dummy", precision=self.precision) dummy_div_seed = ReciprocalSeed(dummy_var, precision=self.precision) inv_approx_table = self.processor.get_recursive_implementation( dummy_div_seed, language=None, table_getter=lambda self: self.approx_table_map) log_f = sollya.log(sollya.x) # /sollya.log(self.basis) use_reciprocal = False # non-scaled vx used to compute vx^1 unmodified_vx = vx is_subnormal = Test(vx, specifier=Test.IsSubnormal, tag="is_subnormal") exp_correction_factor = self.precision.get_mantissa_size() mantissa_factor = Constant(2**exp_correction_factor, tag="mantissa_factor") vx = Select(is_subnormal, vx * mantissa_factor, vx, tag="corrected_vx") m = MantissaExtraction(vx, tag="m", precision=self.precision) e = ExponentExtraction(vx, tag="e", precision=int_precision) e = Select(is_subnormal, e - exp_correction_factor, e, tag="corrected_e") ml_log_args = ML_GenericLog.get_default_args(precision=self.precision, basis=2) ml_log = ML_GenericLog(ml_log_args) log_table, log_table_tho, table_index_range = ml_log.generate_log_table( log_f, inv_approx_table) log_approx = ml_log.generate_reduced_log_split( Abs(m, precision=self.precision), log_f, inv_approx_table, log_table) # floating-point version of n n_f = Conversion(n, precision=self.precision, tag="n_f") inv_n = Division(Constant(1, precision=self.precision), n_f) log_approx = Select(Equal(vx, 0), FP_MinusInfty(self.precision), log_approx) log_approx.set_attributes(tag="log_approx", debug=debug_multi) if use_reciprocal: r = Multiplication(log_approx, inv_n, tag="r", debug=debug_multi) else: r = Division(log_approx, n_f, tag="r", debug=debug_multi) # e_n ~ e / n e_f = Conversion(e, precision=self.precision, tag="e_f") if use_reciprocal: e_n = Multiplication(e_f, inv_n, tag="e_n") else: e_n = Division(e_f, n_f, tag="e_n") error_e_n = FMA(e_n, -n_f, e_f, tag="error_e_n") e_n_int = NearestInteger(e_n, precision=self.precision, tag="e_n_int") pre_e_n_frac = e_n - e_n_int pre_e_n_frac.set_attributes(tag="pre_e_n_frac") e_n_frac = pre_e_n_frac + error_e_n * inv_n e_n_frac.set_attributes(tag="e_n_frac") ml_exp2_args = ML_Exp2.get_default_args(precision=self.precision) ml_exp2 = ML_Exp2(ml_exp2_args) exp2_r = ml_exp2.generate_scalar_scheme(r, inline_select=True) exp2_r.set_attributes(tag="exp2_r", debug=debug_multi) exp2_e_n_frac = ml_exp2.generate_scalar_scheme(e_n_frac, inline_select=True) exp2_e_n_frac.set_attributes(tag="exp2_e_n_frac", debug=debug_multi) exp2_e_n_int = ExponentInsertion(Conversion(e_n_int, precision=int_precision), precision=self.precision, tag="exp2_e_n_int") n_is_even = Equal(Modulo(n, 2), 0, tag="n_is_even", debug=debug_multi) n_is_odd = LogicalNot(n_is_even, tag="n_is_odd") result_sign = Select( n_is_odd, CopySign(vx, Constant(1.0, precision=self.precision)), 1) # managing n == -1 if self.expand_div: ml_division_args = ML_Division.get_default_args( precision=self.precision, input_formats=[self.precision] * 2) ml_division = ML_Division(ml_division_args) self.division_implementation = ml_division.implementation self.division_implementation.set_scheme( ml_division.generate_scheme()) ml_division_fct = self.division_implementation.get_function_object( ) else: ml_division_fct = Division # manage n=1 separately to avoid catastrophic propagation of errors # between log2 and exp2 to eventually compute the identity function # test-case #3 result = ConditionBlock( LogicalOr(LogicalOr(Test(vx, specifier=Test.IsNaN), Equal(n, 0)), LogicalAnd(n_is_even, vx < 0)), Return(FP_QNaN(self.precision)), Statement( ConditionBlock( Equal(n, -1, tag="n_is_mone"), #Return(Division(Constant(1, precision=self.precision), unmodified_vx, tag="div_res", precision=self.precision)), Return( ml_division_fct(Constant(1, precision=self.precision), unmodified_vx, tag="div_res", precision=self.precision)), ), ConditionBlock( # rootn( ±inf, n) is +∞ for even n< 0. Test(vx, specifier=Test.IsInfty), Statement( ConditionBlock( n < 0, #LogicalAnd(n_is_odd, n < 0), Return( Select(Test(vx, specifier=Test.IsPositiveInfty), Constant(FP_PlusZero(self.precision), precision=self.precision), Constant(FP_MinusZero(self.precision), precision=self.precision), precision=self.precision)), Return(vx), ), ), ), ConditionBlock( # rootn(±0, n) is ±∞ for odd n < 0. LogicalAnd(LogicalAnd(n_is_odd, n < 0), Equal(vx, 0), tag="n_is_odd_and_neg"), Return( Select(Test(vx, specifier=Test.IsPositiveZero), Constant(FP_PlusInfty(self.precision), precision=self.precision), Constant(FP_MinusInfty(self.precision), precision=self.precision), precision=self.precision)), ), ConditionBlock( # rootn( ±0, n) is +∞ for even n< 0. LogicalAnd(LogicalAnd(n_is_even, n < 0), Equal(vx, 0)), Return(FP_PlusInfty(self.precision))), ConditionBlock( # rootn(±0, n) is +0 for even n > 0. LogicalAnd(n_is_even, Equal(vx, 0)), Return(vx)), ConditionBlock( Equal(n, 1), Return(unmodified_vx), Return(result_sign * exp2_r * exp2_e_n_int * exp2_e_n_frac)))) return result
def standard_test_cases(self): general_list = [ # ERROR: rootn: inf ulp error at {inf, -2}: *0x0p+0 vs. inf (0x7f800000) at index: 1226 (FP_PlusInfty(self.precision), -2, FP_PlusZero(self.precision)), # ERROR: rootn: inf ulp error at {inf, -2147483648}: *0x0.0000000000000p+0 vs. inf (FP_PlusInfty(self.precision), -2147483648, FP_PlusZero(self.precision)), # (FP_PlusZero(self.precision), -1, FP_PlusInfty(self.precision)), (FP_MinusInfty(self.precision), 1, FP_MinusInfty(self.precision)), (FP_MinusInfty(self.precision), -1, FP_MinusZero(self.precision)), # ERROR coucou7: rootn: -inf ulp error at {inf 7f800000, 479638026}: *inf vs. 0x1.000018p+0 (0x3f80000c) at index: 2367 (FP_PlusInfty(self.precision), 479638026, FP_PlusInfty(self.precision)), (FP_MinusInfty(self.precision), 479638026), #(FP_MinusInfty(self.precision), -479638026), #(FP_PlusInfty(self.precision), -479638026), # rootn( ±0, n) is ±∞ for odd n< 0. (FP_PlusZero(self.precision), -1337, FP_PlusInfty(self.precision)), (FP_MinusZero(self.precision), -1337, FP_MinusInfty(self.precision)), # rootn( ±0, n) is +∞ for even n< 0. (FP_PlusZero(self.precision), -1330, FP_PlusInfty(self.precision)), # rootn( ±0, n) is +0 for even n> 0. (FP_PlusZero(self.precision), random.randrange(0, 2**31, 2), FP_PlusZero(self.precision)), (FP_MinusZero(self.precision), random.randrange(0, 2**31, 2), FP_PlusZero(self.precision)), # rootn( ±0, n) is ±0 for odd n> 0. (FP_PlusZero(self.precision), random.randrange(1, 2**31, 2), FP_PlusZero(self.precision)), (FP_MinusZero(self.precision), random.randrange(1, 2**31, 2), FP_MinusZero(self.precision)), # rootn( x, n) returns a NaN for x< 0 and n is even. (-random.random(), 2 * random.randrange(1, 2**30), FP_QNaN(self.precision)), # rootn( x, 0 ) returns a NaN (random.random(), 0, FP_QNaN(self.precision)), # vx=nan (sollya.parse("-nan"), -1811577079, sollya.parse("nan")), (sollya.parse("-nan"), 832501219, sollya.parse("nan")), (sollya.parse("-nan"), -857435762, sollya.parse("nan")), (sollya.parse("-nan"), -1503049611, sollya.parse("nan")), (sollya.parse("-nan"), 2105620996, sollya.parse("nan")), #ERROR: rootn: inf ulp error at {-nan, 832501219}: *-nan vs. -0x1.00000df2bed98p+1 #ERROR: rootn: inf ulp error at {-nan, -857435762}: *-nan vs. 0x1.0000000000000p+1 #ERROR: rootn: inf ulp error at {-nan, -1503049611}: *-nan vs. -0x1.0000000000000p+1 #ERROR: rootn: inf ulp error at {-nan, 2105620996}: *-nan vs. 0x1.00000583c4b7ap+1 (sollya.parse("-0x1.cd150ap-105"), 105297051), (sollya.parse("0x1.ec3bf8p+71"), -1650769017), # test-case #12 (0.1, 17), # test-case #11, fails in OpenCL CTS (sollya.parse("0x0.000000001d600p-1022"), 14), # test-case #10, fails test with dar(2**-23) (sollya.parse("-0x1.20aadp-114"), 17), # test-case #9 (sollya.parse("0x1.a44d8ep+121"), 7), # test-case #8 (sollya.parse("-0x1.3ef124p+103"), 3), # test-case #7 (sollya.parse("-0x1.01047ep-2"), 39), # test-case #6 (sollya.parse("-0x1.0105bp+67"), 23), # test-case #5 (sollya.parse("0x1.c1f72p+51"), 6), # special cases (sollya.parse("0x0p+0"), 1), (sollya.parse("0x0p+0"), 0), # test-case #3, catastrophic error for n=1 (sollya.parse("0x1.fc61a2p-121"), 1.0), # test-case #4 , k=14 < 0 not supported by bigfloat # (sollya.parse("0x1.ad067ap-66"), -14), ] # NOTE: expected value assumed 32-bit precision output fp_32_only = [ # (sollya.parse("0x1.80bb0ep+70"), 377778829, sollya.parse("0x1.000002p+0")), ] # NOTE: the following test-case are only valid if meta-function supports 64-bit integer # 2nd_input fp_64_only = [ (sollya.parse("0x1.fffffffffffffp+1023"), -1, sollya.parse("0x0.4000000000000p-1022")), (sollya.parse("-0x1.fffffffffffffp1023"), -1, sollya.parse("-0x0.4000000000000p-1022")), #(sollya.parse("-0x1.fffffffffffffp+1023"), 1), #(sollya.parse("0x1.fffffffffffffp+1023"), -1), # ERROR coucou8: rootn: inf ulp error at {-inf, 1854324695}: *-inf vs. -0x1.0000066bfdd60p+0 (FP_MinusInfty(self.precision), 1854324695, FP_MinusInfty(self.precision)), # ERROR: rootn: -60.962402 ulp error at {0x0.000000001d600p-1022, 14}: *0x1.67d4ff97d1fd9p-76 vs. 0x1.67d4ff97d1f9cp-76 (sollya.parse("0x0.000000001d600p-1022"), 14, sollya.parse("0x1.67d4ff97d1fd9p-76")), # ERROR: rootn: -430452000.000000 ulp error at {0x1.ffffffff38c00p-306, 384017876}: *0x1.ffffed870ff01p-1 vs. 0x1.ffffebec8d1d2p-1 (sollya.parse("0x1.ffffffff38c00p-306"), 384017876, sollya.parse("0x1.ffffed870ff01p-1")), # vs. 0x1.ffffebec8d1d2p-1 # ERROR: rootn: 92996584.000000 ulp error at {0x1.ffffffffdae80p-858, -888750231}: *0x1.00000b36b1173p+0 vs. 0x1.00000b8f6155ep+0 (sollya.parse("0x1.ffffffffdae80p-858"), -888750231, sollya.parse("0x1.00000b36b1173p+0")), # ERROR: rootn: 379474.906250 ulp error at {0x0.0000000000022p-1022, -1538297900}: *0x1.00000814a68ffp+0 vs. 0x1.0000081503352p+0 (sollya.parse("0x0.00000006abfffp-1022"), -1221802473, sollya.parse("0x1.00000a01818a4p+0")), (sollya.parse("0x1.ffffffffd0a00p-260"), 1108043946, sollya.parse("0x1.fffffa9042997p-1")), (sollya.parse("0x1.3fffffffff1c0p-927"), -1997086266, sollya.parse("0x1.0000056564c5ep+0")), (sollya.parse("0x1.ffffffff38c00p-306"), 384017876, sollya.parse("0x1.ffffed870ff01p-1")), (sollya.parse("0x0.15c000000002ap-1022"), 740015941, sollya.parse("0x1.ffffdfc47b57ep-1")), (sollya.parse("0x0.00000000227ffp-1022"), -1859058847, sollya.parse("0x1.0000069c7a01bp+0")), (sollya.parse("0x0.0568000000012p-1022"), -447352599, sollya.parse("0x1.00001ab640c38p+0")), (sollya.parse("0x0.000000000000dp-1022"), 132283432, sollya.parse("0x1.ffff43d1db82ap-1")), (sollya.parse("-0x1.c80000000026ap+1023"), 275148531, sollya.parse("-0x1.00002b45a7314p+0")), (sollya.parse("0x0.022200000000ep-1022"), -1969769414, sollya.parse("0x1.000006130e858p+0")), (sollya.parse("0x0.0000000000011p-1022"), 851990770, sollya.parse("0x1.ffffe2cafaff6p-1")), (sollya.parse("0x1.8fffffffff348p-1010"), 526938360, sollya.parse("0x1.ffffd372e2b81p-1")), (sollya.parse("0x0.0000000000317p-1022"), -1315106194, sollya.parse("0x1.0000096973ac9p+0")), (sollya.parse("0x1.1ffffffff2d20p-971"), 378658008, sollya.parse("0x1.ffffc45e803b2p-1")), # (sollya.parse("0x0.0568000000012p-1022"), -447352599, sollya.parse("0x1.00001ab640c38p+0")), # (sollya.parse("0x1.ffffffffd0a00p-260"), 1108043946, sollya.parse("0x1.fffffa9042997p-1")), (FP_MinusZero(self.precision), -21015979, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -85403731, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -180488973, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -1365227287, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -1802885579, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -1681209663, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -1152797721, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -1614890585, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -812655517, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -628647891, FP_MinusInfty(self.precision)), (sollya.parse("0x1.ffffffffdae80p-858"), -888750231, sollya.parse("0x1.00000b36b1173p+0")), (sollya.parse("0x0.0568000000012p-1022"), -447352599, sollya.parse("0x1.00001ab640c38p+0")), (sollya.parse("0x0.00000006abfffp-1022"), -1221802473, sollya.parse("0x1.00000a01818a4p+0")), (sollya.parse("0x0.0000000000022p-1022"), -1538297900, sollya.parse("0x1.00000814a68ffp+0")), #ERROR: rootn: inf ulp error at {-0x0.0000000000000p+0, -1889147085}: *-inf vs. inf #ERROR: rootn: inf ulp error at {-0x0.0000000000000p+0, -373548013}: *-inf vs. inf (FP_MinusZero(self.precision), -1889147085, FP_MinusInfty(self.precision)), (FP_MinusZero(self.precision), -373548013, FP_MinusInfty(self.precision)), #ERROR: rootn: inf ulp error at {-0x0.0000000000000p+0, -1889147085}: *-inf vs. inf #ERROR: rootn: inf ulp error at {-0x0.0000000000000p+0, -373548013}: *-inf vs. inf # [email protected]: PE 0: error[84]: ml_rootn(-0x1.b1a6765727e72p-902, -7.734955e+08/-773495525), result is -0x1.00000d8cb5b3cp+0 vs expected [nan;nan] (sollya.parse("-0x1.b1a6765727e72p-902"), -773495525), # ERROR: rootn: -40564819207303340847894502572032.000000 ulp error at {-0x0.fffffffffffffp-1022, 1}: *-0x0.fffffffffffffp-1022 vs. -0x1.ffffffffffffep-970 (sollya.parse("-0x0.fffffffffffffp-1022 "), 1, sollya.parse("-0x0.fffffffffffffp-1022 ")), # ERROR: rootn: 1125899906842624.000000 ulp error at {-0x1.fffffffffffffp+1023, -1}: *-0x0.4000000000000p-1022 vs. -0x0.0000000000000p+0 (sollya.parse("-0x1.fffffffffffffp+1023"), -1, sollya.parse("-0x0.4000000000000p-1022")), (sollya.parse("0x1.fffffffffffffp+1023"), -1, sollya.parse("0x0.4000000000000p-1022")), ] return (fp_64_only if self.precision.get_bit_size() >= 64 else []) \ + (fp_32_only if self.precision.get_bit_size() == 32 else []) \ + general_list
def generate_scheme(self): # declaring target and instantiating optimization engine vx = self.implementation.add_input_variable("x", self.precision) vx.set_attributes(precision=self.precision, tag="vx", debug=debug_multi) Log.set_dump_stdout(True) Log.report(Log.Info, "\033[33;1m Generating implementation scheme \033[0m") if self.debug_flag: Log.report(Log.Info, "\033[31;1m debug has been enabled \033[0;m") C0 = Constant(0, precision=self.precision) C0_plus = Constant(FP_PlusZero(self.precision)) C0_minus = Constant(FP_MinusZero(self.precision)) def local_test(specifier, tag): """ Local wrapper to generate Test operations """ return Test(vx, specifier=specifier, likely=False, debug=debug_multi, tag="is_%s" % tag, precision=ML_Bool) test_NaN = local_test(Test.IsNaN, "is_NaN") test_inf = local_test(Test.IsInfty, "is_Inf") test_NaN_or_Inf = local_test(Test.IsInfOrNaN, "is_Inf_Or_Nan") test_negative = Comparison(vx, C0, specifier=Comparison.Less, debug=debug_multi, tag="is_Negative", precision=ML_Bool, likely=False) test_NaN_or_Neg = LogicalOr(test_NaN, test_negative, precision=ML_Bool) test_std = LogicalNot(LogicalOr(test_NaN_or_Inf, test_negative, precision=ML_Bool, likely=False), precision=ML_Bool, likely=True) test_zero = Comparison(vx, C0, specifier=Comparison.Equal, likely=False, debug=debug_multi, tag="Is_Zero", precision=ML_Bool) return_NaN_or_neg = Statement(Return(FP_QNaN(self.precision))) return_inf = Statement(Return(FP_PlusInfty(self.precision))) return_PosZero = Return(C0_plus) return_NegZero = Return(C0_minus) NR_init = ReciprocalSquareRootSeed(vx, precision=self.precision, tag="sqrt_seed", debug=debug_multi) result = compute_sqrt(vx, NR_init, int(self.num_iter), precision=self.precision) return_non_std = ConditionBlock( test_NaN_or_Neg, return_NaN_or_neg, ConditionBlock( test_inf, return_inf, ConditionBlock(test_zero, return_PosZero, return_NegZero))) return_std = Return(result) scheme = ConditionBlock(test_std, return_std, return_non_std) return scheme