Exemple #1
0
    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
Exemple #2
0
 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
Exemple #3
0
    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 []
Exemple #4
0
    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
Exemple #5
0
    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)
Exemple #6
0
    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
Exemple #7
0
    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
Exemple #8
0
    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
Exemple #9
0
    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