def c_cosh(x, y): if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = copysign(INF, math.cos(y)) imag = -copysign(INF, math.sin(y)) r = (real, imag) else: r = cosh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN if isinf(y) and not isnan(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: # deal correctly with cases where cosh(x) overflows but # cosh(z) does not. x_minus_one = x - copysign(1., x) real = math.cos(y) * math.cosh(x_minus_one) * math.e imag = math.sin(y) * math.sinh(x_minus_one) * math.e else: real = math.cos(y) * math.cosh(x) imag = math.sin(y) * math.sinh(x) if isinf(real) or isinf(imag): raise OverflowError("math range error") return real, imag
def c_atanh(x, y): if not isfinite(x) or not isfinite(y): return atanh_special_values[special_type(x)][special_type(y)] # Reduce to case where x >= 0., using atanh(z) = -atanh(-z). if x < 0.: return c_neg(*c_atanh(*c_neg(x, y))) ay = fabs(y) if x > CM_SQRT_LARGE_DOUBLE or ay > CM_SQRT_LARGE_DOUBLE: # if abs(z) is large then we use the approximation # atanh(z) ~ 1/z +/- i*pi/2 (+/- depending on the sign # of y h = math.hypot(x / 2., y / 2.) # safe from overflow real = x / 4. / h / h # the two negations in the next line cancel each other out # except when working with unsigned zeros: they're there to # ensure that the branch cut has the correct continuity on # systems that don't support signed zeros imag = -copysign(math.pi / 2., -y) elif x == 1. and ay < CM_SQRT_DBL_MIN: # C99 standard says: atanh(1+/-0.) should be inf +/- 0i if ay == 0.: raise ValueError("math domain error") #real = INF #imag = y else: real = -math.log(math.sqrt(ay) / math.sqrt(math.hypot(ay, 2.))) imag = copysign(math.atan2(2., -ay) / 2, y) else: real = log1p(4. * x / ((1 - x) * (1 - x) + ay * ay)) / 4. imag = -math.atan2(-2. * y, (1 - x) * (1 + x) - ay * ay) / 2. return (real, imag)
def c_exp(x, y): if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = copysign(0., math.cos(y)) imag = copysign(0., math.sin(y)) r = (real, imag) else: r = exp_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN and not -infinity if isinf(y) and (isfinite(x) or (isinf(x) and x > 0)): raise ValueError("math domain error") return r if x > CM_LOG_LARGE_DOUBLE: l = math.exp(x - 1.) real = l * math.cos(y) * math.e imag = l * math.sin(y) * math.e else: l = math.exp(x) real = l * math.cos(y) imag = l * math.sin(y) if isinf(real) or isinf(imag): raise OverflowError("math range error") return real, imag
def c_exp(x, y): if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = copysign(0., math.cos(y)) imag = copysign(0., math.sin(y)) r = (real, imag) else: r = exp_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN and not -infinity if isinf(y) and (isfinite(x) or (isinf(x) and x > 0)): raise ValueError("math domain error") return r if x > CM_LOG_LARGE_DOUBLE: l = math.exp(x-1.) real = l * math.cos(y) * math.e imag = l * math.sin(y) * math.e else: l = math.exp(x) real = l * math.cos(y) imag = l * math.sin(y) if isinf(real) or isinf(imag): raise OverflowError("math range error") return real, imag
def c_sinh(x, y): # special treatment for sinh(+/-inf + iy) if y is finite and nonzero if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = -copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) r = (real, imag) else: r = sinh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN if isinf(y) and not isnan(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: x_minus_one = x - copysign(1., x) real = math.cos(y) * math.sinh(x_minus_one) * math.e imag = math.sin(y) * math.cosh(x_minus_one) * math.e else: real = math.cos(y) * math.sinh(x) imag = math.sin(y) * math.cosh(x) if isinf(real) or isinf(imag): raise OverflowError("math range error") return real, imag
def c_rect(r, phi): if not isfinite(r) or not isfinite(phi): # if r is +/-infinity and phi is finite but nonzero then # result is (+-INF +-INF i), but we need to compute cos(phi) # and sin(phi) to figure out the signs. if isinf(r) and isfinite(phi) and phi != 0.: if r > 0: real = copysign(INF, math.cos(phi)) imag = copysign(INF, math.sin(phi)) else: real = -copysign(INF, math.cos(phi)) imag = -copysign(INF, math.sin(phi)) z = (real, imag) else: z = rect_special_values[special_type(r)][special_type(phi)] # need to raise ValueError if r is a nonzero number and phi # is infinite if r != 0. and not isnan(r) and isinf(phi): raise ValueError("math domain error") return z real = r * math.cos(phi) imag = r * math.sin(phi) return real, imag
def str__Complex(space, w_complex): if w_complex.realval == 0 and copysign(1., w_complex.realval) == 1.: return space.wrap(str_format(w_complex.imagval) + 'j') sign = (copysign(1., w_complex.imagval) == 1. or isnan(w_complex.imagval)) and '+' or '' return space.wrap('(' + str_format(w_complex.realval) + sign + str_format(w_complex.imagval) + 'j)')
def test_nan_and_special_values(): from pypy.rlib.rfloat import isnan, isinf, isfinite, copysign inf = 1e300 * 1e300 assert isinf(inf) nan = inf/inf assert isnan(nan) for value, checker in [ (inf, lambda x: isinf(x) and x > 0.0), (-inf, lambda x: isinf(x) and x < 0.0), (nan, isnan), (42.0, isfinite), (0.0, lambda x: not x and copysign(1., x) == 1.), (-0.0, lambda x: not x and copysign(1., x) == -1.), ]: def f(): return value f1 = compile(f, []) res = f1() assert checker(res) l = [value] def g(x): return l[x] g2 = compile(g, [int]) res = g2(0) assert checker(res) l2 = [(-value, -value), (value, value)] def h(x): return l2[x][1] h3 = compile(h, [int]) res = h3(1) assert checker(res)
def c_atanh(x, y): if not isfinite(x) or not isfinite(y): return atanh_special_values[special_type(x)][special_type(y)] # Reduce to case where x >= 0., using atanh(z) = -atanh(-z). if x < 0.: return c_neg(*c_atanh(*c_neg(x, y))) ay = fabs(y) if x > CM_SQRT_LARGE_DOUBLE or ay > CM_SQRT_LARGE_DOUBLE: # if abs(z) is large then we use the approximation # atanh(z) ~ 1/z +/- i*pi/2 (+/- depending on the sign # of y h = math.hypot(x/2., y/2.) # safe from overflow real = x/4./h/h # the two negations in the next line cancel each other out # except when working with unsigned zeros: they're there to # ensure that the branch cut has the correct continuity on # systems that don't support signed zeros imag = -copysign(math.pi/2., -y) elif x == 1. and ay < CM_SQRT_DBL_MIN: # C99 standard says: atanh(1+/-0.) should be inf +/- 0i if ay == 0.: raise ValueError("math domain error") #real = INF #imag = y else: real = -math.log(math.sqrt(ay)/math.sqrt(math.hypot(ay, 2.))) imag = copysign(math.atan2(2., -ay) / 2, y) else: real = log1p(4.*x/((1-x)*(1-x) + ay*ay))/4. imag = -math.atan2(-2.*y, (1-x)*(1+x) - ay*ay) / 2. return (real, imag)
def __eq__(self, other): if (type(self) is SomeFloat and type(other) is SomeFloat and self.is_constant() and other.is_constant()): from pypy.rlib.rfloat import isnan, copysign # NaN unpleasantness. if isnan(self.const) and isnan(other.const): return True # 0.0 vs -0.0 unpleasantness. if not self.const and not other.const: return copysign(1., self.const) == copysign(1., other.const) # return super(SomeFloat, self).__eq__(other)
def c_sqrt(x, y): # Method: use symmetries to reduce to the case when x = z.real and y # = z.imag are nonnegative. Then the real part of the result is # given by # # s = sqrt((x + hypot(x, y))/2) # # and the imaginary part is # # d = (y/2)/s # # If either x or y is very large then there's a risk of overflow in # computation of the expression x + hypot(x, y). We can avoid this # by rewriting the formula for s as: # # s = 2*sqrt(x/8 + hypot(x/8, y/8)) # # This costs us two extra multiplications/divisions, but avoids the # overhead of checking for x and y large. # # If both x and y are subnormal then hypot(x, y) may also be # subnormal, so will lack full precision. We solve this by rescaling # x and y by a sufficiently large power of 2 to ensure that x and y # are normal. if not isfinite(x) or not isfinite(y): return sqrt_special_values[special_type(x)][special_type(y)] if x == 0. and y == 0.: return (0., y) ax = fabs(x) ay = fabs(y) if ax < DBL_MIN and ay < DBL_MIN and (ax > 0. or ay > 0.): # here we catch cases where hypot(ax, ay) is subnormal ax = math.ldexp(ax, CM_SCALE_UP) ay1= math.ldexp(ay, CM_SCALE_UP) s = math.ldexp(math.sqrt(ax + math.hypot(ax, ay1)), CM_SCALE_DOWN) else: ax /= 8. s = 2.*math.sqrt(ax + math.hypot(ax, ay/8.)) d = ay/(2.*s) if x >= 0.: return (s, copysign(d, y)) else: return (d, copysign(s, y))
def rAssertAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg=''): """Fail if the two floating-point numbers are not almost equal. Determine whether floating-point values a and b are equal to within a (small) rounding error. The default values for rel_err and abs_err are chosen to be suitable for platforms where a float is represented by an IEEE 754 double. They allow an error of between 9 and 19 ulps. """ # special values testing if isnan(a): if isnan(b): return raise AssertionError(msg + '%r should be nan' % (b,)) if isinf(a): if a == b: return raise AssertionError(msg + 'finite result where infinity expected: ' 'expected %r, got %r' % (a, b)) # if both a and b are zero, check whether they have the same sign # (in theory there are examples where it would be legitimate for a # and b to have opposite signs; in practice these hardly ever # occur). if not a and not b: # only check it if we are running on top of CPython >= 2.6 if sys.version_info >= (2, 6) and copysign(1., a) != copysign(1., b): raise AssertionError(msg + 'zero has wrong sign: expected %r, ' 'got %r' % (a, b)) # if a-b overflows, or b is infinite, return False. Again, in # theory there are examples where a is within a few ulps of the # max representable float, and then b could legitimately be # infinite. In practice these examples are rare. try: absolute_error = abs(b-a) except OverflowError: pass else: # test passes if either the absolute error or the relative # error is sufficiently small. The defaults amount to an # error of between 9 ulps and 19 ulps on an IEEE-754 compliant # machine. if absolute_error <= max(abs_err, rel_err * abs(a)): return raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
def rAssertAlmostEqual(a, b, rel_err=2e-15, abs_err=5e-323, msg=''): """Fail if the two floating-point numbers are not almost equal. Determine whether floating-point values a and b are equal to within a (small) rounding error. The default values for rel_err and abs_err are chosen to be suitable for platforms where a float is represented by an IEEE 754 double. They allow an error of between 9 and 19 ulps. """ # special values testing if isnan(a): if isnan(b): return raise AssertionError(msg + '%r should be nan' % (b, )) if isinf(a): if a == b: return raise AssertionError(msg + 'finite result where infinity expected: ' 'expected %r, got %r' % (a, b)) # if both a and b are zero, check whether they have the same sign # (in theory there are examples where it would be legitimate for a # and b to have opposite signs; in practice these hardly ever # occur). if not a and not b: # only check it if we are running on top of CPython >= 2.6 if sys.version_info >= (2, 6) and copysign(1., a) != copysign(1., b): raise AssertionError(msg + 'zero has wrong sign: expected %r, ' 'got %r' % (a, b)) # if a-b overflows, or b is infinite, return False. Again, in # theory there are examples where a is within a few ulps of the # max representable float, and then b could legitimately be # infinite. In practice these examples are rare. try: absolute_error = abs(b - a) except OverflowError: pass else: # test passes if either the absolute error or the relative # error is sufficiently small. The defaults amount to an # error of between 9 ulps and 19 ulps on an IEEE-754 compliant # machine. if absolute_error <= max(abs_err, rel_err * abs(a)): return raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
def float_hex__Float(space, w_float): value = w_float.floatval if not isfinite(value): return str__Float(space, w_float) if value == 0.0: if copysign(1., value) == -1.: return space.wrap("-0x0.0p+0") else: return space.wrap("0x0.0p+0") mant, exp = math.frexp(value) shift = 1 - max(rfloat.DBL_MIN_EXP - exp, 0) mant = math.ldexp(mant, shift) mant = abs(mant) exp -= shift result = ['\0'] * ((TOHEX_NBITS - 1) // 4 + 2) result[0] = _char_from_hex(int(mant)) mant -= int(mant) result[1] = "." for i in range((TOHEX_NBITS - 1) // 4): mant *= 16.0 result[i + 2] = _char_from_hex(int(mant)) mant -= int(mant) if exp < 0: sign = "-" else: sign = "+" exp = abs(exp) s = ''.join(result) if value < 0.0: return space.wrap("-0x%sp%s%d" % (s, sign, exp)) else: return space.wrap("0x%sp%s%d" % (s, sign, exp))
def div(self, v1, v2): try: return v1 / v2 except ZeroDivisionError: if v1 == v2 == 0.0: return rfloat.NAN return rfloat.copysign(rfloat.INFINITY, v1 * v2)
def div(self, v1, v2): # XXX this won't work after translation, probably requires ovfcheck try: return v1 / v2 except ZeroDivisionError: if v1 == v2 == 0.0: return rfloat.NAN return rfloat.copysign(rfloat.INFINITY, v1 * v2)
def test_special_values(): from pypy.module.cmath.special_value import sqrt_special_values assert len(sqrt_special_values) == 7 assert len(sqrt_special_values[4]) == 7 assert isinstance(sqrt_special_values[5][1], tuple) assert sqrt_special_values[5][1][0] == 1e200 * 1e200 assert sqrt_special_values[5][1][1] == -0. assert copysign(1., sqrt_special_values[5][1][1]) == -1.
def c_asinh(x, y): if not isfinite(x) or not isfinite(y): return asinh_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: if y >= 0.: real = copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., x) else: real = -copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., -x) imag = math.atan2(y, fabs(x)) else: s1x, s1y = c_sqrt(1. + y, -x) s2x, s2y = c_sqrt(1. - y, x) real = asinh(s1x * s2y - s2x * s1y) imag = math.atan2(y, s1x * s2x - s1y * s2y) return (real, imag)
def c_asinh(x, y): if not isfinite(x) or not isfinite(y): return asinh_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: if y >= 0.: real = copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., x) else: real = -copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., -x) imag = math.atan2(y, fabs(x)) else: s1x, s1y = c_sqrt(1.+y, -x) s2x, s2y = c_sqrt(1.-y, x) real = asinh(s1x*s2y - s2x*s1y) imag = math.atan2(y, s1x*s2x - s1y*s2y) return (real, imag)
def pow(self, v1, v2): try: return math.pow(v1, v2) except ValueError: return rfloat.NAN except OverflowError: if math.modf(v2)[0] == 0 and math.modf(v2 / 2)[0] != 0: # Odd integer powers result in the same sign as the base return rfloat.copysign(rfloat.INFINITY, v1) return rfloat.INFINITY
def c_acos(x, y): if not isfinite(x) or not isfinite(y): return acos_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: # avoid unnecessary overflow for large arguments real = math.atan2(fabs(y), x) # split into cases to make sure that the branch cut has the # correct continuity on systems with unsigned zeros if x < 0.: imag = -copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., y) else: imag = copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., -y) else: s1x, s1y = c_sqrt(1.-x, -y) s2x, s2y = c_sqrt(1.+x, y) real = 2.*math.atan2(s1x, s2x) imag = asinh(s2x*s1y - s2y*s1x) return (real, imag)
def c_acos(x, y): if not isfinite(x) or not isfinite(y): return acos_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: # avoid unnecessary overflow for large arguments real = math.atan2(fabs(y), x) # split into cases to make sure that the branch cut has the # correct continuity on systems with unsigned zeros if x < 0.: imag = -copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., y) else: imag = copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., -y) else: s1x, s1y = c_sqrt(1. - x, -y) s2x, s2y = c_sqrt(1. + x, y) real = 2. * math.atan2(s1x, s2x) imag = asinh(s2x * s1y - s2y * s1x) return (real, imag)
def c_tanh(x, y): # Formula: # # tanh(x+iy) = (tanh(x)(1+tan(y)^2) + i tan(y)(1-tanh(x))^2) / # (1+tan(y)^2 tanh(x)^2) # # To avoid excessive roundoff error, 1-tanh(x)^2 is better computed # as 1/cosh(x)^2. When abs(x) is large, we approximate 1-tanh(x)^2 # by 4 exp(-2*x) instead, to avoid possible overflow in the # computation of cosh(x). if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = 1.0 # vv XXX why is the 2. there? imag = copysign(0., 2. * math.sin(y) * math.cos(y)) else: real = -1.0 imag = copysign(0., 2. * math.sin(y) * math.cos(y)) r = (real, imag) else: r = tanh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/-infinity and x is finite if isinf(y) and isfinite(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: real = copysign(1., x) imag = 4. * math.sin(y) * math.cos(y) * math.exp(-2.*fabs(x)) else: tx = math.tanh(x) ty = math.tan(y) cx = 1. / math.cosh(x) txty = tx * ty denom = 1. + txty * txty real = tx * (1. + ty*ty) / denom imag = ((ty / denom) * cx) * cx return real, imag
def _make_key(self, obj): # see the tests 'test_zeros_not_mixed*' in ../test/test_compiler.py space = self.space w_type = space.type(obj) if space.is_w(w_type, space.w_float): val = space.float_w(obj) if val == 0.0 and rfloat.copysign(1., val) < 0: w_key = space.newtuple([obj, space.w_float, space.w_None]) else: w_key = space.newtuple([obj, space.w_float]) elif space.is_w(w_type, space.w_complex): w_real = space.getattr(obj, space.wrap("real")) w_imag = space.getattr(obj, space.wrap("imag")) real = space.float_w(w_real) imag = space.float_w(w_imag) real_negzero = (real == 0.0 and rfloat.copysign(1., real) < 0) imag_negzero = (imag == 0.0 and rfloat.copysign(1., imag) < 0) if real_negzero and imag_negzero: tup = [obj, space.w_complex, space.w_None, space.w_None, space.w_None] elif imag_negzero: tup = [obj, space.w_complex, space.w_None, space.w_None] elif real_negzero: tup = [obj, space.w_complex, space.w_None] else: tup = [obj, space.w_complex] w_key = space.newtuple(tup) elif space.is_w(w_type, space.w_tuple): result_w = [obj, w_type] for w_item in space.fixedview(obj): result_w.append(self._make_key(w_item)) w_key = space.newtuple(result_w[:]) else: w_key = space.newtuple([obj, w_type]) return w_key
def _sinpi(x): y = math.fmod(abs(x), 2.) n = int(rfloat.round_away(2. * y)) if n == 0: r = math.sin(math.pi * y) elif n == 1: r = math.cos(math.pi * (y - .5)) elif n == 2: r = math.sin(math.pi * (1. - y)) elif n == 3: r = -math.cos(math.pi * (y - 1.5)) elif n == 4: r = math.sin(math.pi * (y - 2.)) else: raise AssertionError("should not reach") return rfloat.copysign(1., x) * r
def __init__(self, value): self.value = value # a concrete value # try to be smart about constant mutable or immutable values key = type(self.value), self.value # to avoid confusing e.g. 0 and 0.0 # # we also have to avoid confusing 0.0 and -0.0 (needed e.g. for # translating the cmath module) if key[0] is float and not self.value: from pypy.rlib.rfloat import copysign if copysign(1., self.value) == -1.: # -0.0 key = (float, "-0.0") # try: hash(key) except TypeError: key = id(self.value) self.key = key
def special_type(d): if isnan(d): return ST_NAN elif isinf(d): if d > 0.0: return ST_PINF else: return ST_NINF else: if d != 0.0: if d > 0.0: return ST_POS else: return ST_NEG else: if copysign(1., d) == 1.: return ST_PZERO else: return ST_NZERO
def mod__Float_Float(space, w_float1, w_float2): x = w_float1.floatval y = w_float2.floatval if y == 0.0: raise FailedToImplementArgs(space.w_ZeroDivisionError, space.wrap("float modulo")) try: mod = math.fmod(x, y) except ValueError: mod = rfloat.NAN else: if mod: # ensure the remainder has the same sign as the denominator if (y < 0.0) != (mod < 0.0): mod += y else: # the remainder is zero, and in the presence of signed zeroes # fmod returns different results across platforms; ensure # it has the same sign as the denominator; we'd like to do # "mod = y * 0.0", but that may get optimized away mod = copysign(0.0, y) return W_FloatObject(mod)
def c_phase(x, y): # Windows screws up atan2 for inf and nan, and alpha Tru64 5.1 doesn't # follow C99 for atan2(0., 0.). if isnan(x) or isnan(y): return NAN if isinf(y): if isinf(x): if copysign(1., x) == 1.: # atan2(+-inf, +inf) == +-pi/4 return copysign(0.25 * math.pi, y) else: # atan2(+-inf, -inf) == +-pi*3/4 return copysign(0.75 * math.pi, y) # atan2(+-inf, x) == +-pi/2 for finite x return copysign(0.5 * math.pi, y) if isinf(x) or y == 0.: if copysign(1., x) == 1.: # atan2(+-y, +inf) = atan2(+-0, +x) = +-0. return copysign(0., y) else: # atan2(+-y, -inf) = atan2(+-0., -x) = +-pi. return copysign(math.pi, y) return math.atan2(y, x)
def sign(value): if value == 0.0: return 0.0 return rfloat.copysign(1.0, value)
def _format_complex(self, w_complex): space = self.space tp = self._type self._get_locale(tp) default_precision = 6 if self._align == "=": # '=' alignment is invalid msg = ("'=' alignment flag is not allowed in" " complex format specifier") raise OperationError(space.w_ValueError, space.wrap(msg)) if self._fill_char == "0": #zero padding is invalid msg = "Zero padding is not allowed in complex format specifier" raise OperationError(space.w_ValueError, space.wrap(msg)) if self._alternate: #alternate is invalid msg = "Alternate form %s not allowed in complex format specifier" raise OperationError(space.w_ValueError, space.wrap(msg % (self._alternate))) skip_re = 0 add_parens = 0 if tp == "\0": #should mirror str() output tp = "g" default_precision = 12 #test if real part is non-zero if (w_complex.realval == 0 and copysign(1., w_complex.realval) == 1.): skip_re = 1 else: add_parens = 1 if tp == "n": #same as 'g' except for locale, taken care of later tp = "g" #check if precision not set if self._precision == -1: self._precision = default_precision #might want to switch to double_to_string from formatd #in CPython it's named 're' - clashes with re module re_num = formatd(w_complex.realval, tp, self._precision) im_num = formatd(w_complex.imagval, tp, self._precision) n_re_digits = len(re_num) n_im_digits = len(im_num) to_real_number = 0 to_imag_number = 0 re_sign = im_sign = '' #if a sign character is in the output, remember it and skip if re_num[0] == "-": re_sign = "-" to_real_number = 1 n_re_digits -= 1 if im_num[0] == "-": im_sign = "-" to_imag_number = 1 n_im_digits -= 1 #turn off padding - do it after number composition #calc_num_width uses self._width, so assign to temporary variable, #calculate width of real and imag parts, then reassign padding, align tmp_fill_char = self._fill_char tmp_align = self._align tmp_width = self._width self._fill_char = "\0" self._align = "<" self._width = -1 #determine if we have remainder, might include dec or exponent or both re_have_dec, re_remainder_ptr = self._parse_number(re_num, to_real_number) im_have_dec, im_remainder_ptr = self._parse_number(im_num, to_imag_number) if self.is_unicode: re_num = re_num.decode("ascii") im_num = im_num.decode("ascii") #set remainder, in CPython _parse_number sets this #using n_re_digits causes tests to fail re_n_remainder = len(re_num) - re_remainder_ptr im_n_remainder = len(im_num) - im_remainder_ptr re_spec = self._calc_num_width(0, re_sign, to_real_number, n_re_digits, re_n_remainder, re_have_dec, re_num) #capture grouped digits b/c _fill_number reads from self._grouped_digits #self._grouped_digits will get overwritten in imaginary calc_num_width re_grouped_digits = self._grouped_digits if not skip_re: self._sign = "+" im_spec = self._calc_num_width(0, im_sign, to_imag_number, n_im_digits, im_n_remainder, im_have_dec, im_num) im_grouped_digits = self._grouped_digits if skip_re: re_spec.n_total = 0 #reassign width, alignment, fill character self._align = tmp_align self._width = tmp_width self._fill_char = tmp_fill_char #compute L and R padding - stored in self._left_pad and self._right_pad self._calc_padding(self.empty, re_spec.n_total + im_spec.n_total + 1 + add_parens * 2) out = self._builder() fill = self._fill_char if fill == "\0": fill = self._lit(" ")[0] #compose the string #add left padding out.append_multiple_char(fill, self._left_pad) if add_parens: out.append(self._lit('(')[0]) #if the no. has a real component, add it if not skip_re: out.append(self._fill_number(re_spec, re_num, to_real_number, 0, fill, re_remainder_ptr, False, re_grouped_digits)) #add imaginary component out.append(self._fill_number(im_spec, im_num, to_imag_number, 0, fill, im_remainder_ptr, False, im_grouped_digits)) #add 'j' character out.append(self._lit('j')[0]) if add_parens: out.append(self._lit(')')[0]) #add right padding out.append_multiple_char(fill, self._right_pad) return self.space.wrap(out.build())
def pow__Float_Float_ANY(space, w_float1, w_float2, thirdArg): # This raises FailedToImplement in cases like overflow where a # (purely theoretical) big-precision float implementation would have # a chance to give a result, and directly OperationError for errors # that we want to force to be reported to the user. if not space.is_w(thirdArg, space.w_None): raise OperationError(space.w_TypeError, space.wrap( "pow() 3rd argument not allowed unless all arguments are integers")) x = w_float1.floatval y = w_float2.floatval # Sort out special cases here instead of relying on pow() if y == 0.0: # x**0 is 1, even 0**0 return W_FloatObject(1.0) if isnan(x): # nan**y = nan, unless y == 0 return W_FloatObject(x) if isnan(y): # x**nan = nan, unless x == 1; x**nan = x if x == 1.0: return W_FloatObject(1.0) else: return W_FloatObject(y) if isinf(y): # x**inf is: 0.0 if abs(x) < 1; 1.0 if abs(x) == 1; inf if # abs(x) > 1 (including case where x infinite) # # x**-inf is: inf if abs(x) < 1; 1.0 if abs(x) == 1; 0.0 if # abs(x) > 1 (including case where v infinite) x = abs(x) if x == 1.0: return W_FloatObject(1.0) elif (y > 0.0) == (x > 1.0): return W_FloatObject(INFINITY) else: return W_FloatObject(0.0) if isinf(x): # (+-inf)**w is: inf for w positive, 0 for w negative; in oth # cases, we need to add the appropriate sign if w is an odd # integer. y_is_odd = math.fmod(abs(y), 2.0) == 1.0 if y > 0.0: if y_is_odd: return W_FloatObject(x) else: return W_FloatObject(abs(x)) else: if y_is_odd: return W_FloatObject(copysign(0.0, x)) else: return W_FloatObject(0.0) if x == 0.0: if y < 0.0: raise OperationError(space.w_ZeroDivisionError, space.wrap("0.0 cannot be raised to " "a negative power")) negate_result = False # special case: "(-1.0) ** bignum" should not raise ValueError, # unlike "math.pow(-1.0, bignum)". See http://mail.python.org/ # - pipermail/python-bugs-list/2003-March/016795.html if x < 0.0: if isnan(y): return W_FloatObject(NAN) if math.floor(y) != y: raise OperationError(space.w_ValueError, space.wrap("negative number cannot be " "raised to a fractional power")) # y is an exact integer, albeit perhaps a very large one. # Replace x by its absolute value and remember to negate the # pow result if y is odd. x = -x negate_result = math.fmod(abs(y), 2.0) == 1.0 if x == 1.0: # (-1) ** large_integer also ends up here if negate_result: return W_FloatObject(-1.0) else: return W_FloatObject(1.0) try: # We delegate to our implementation of math.pow() the error detection. z = math.pow(x,y) except OverflowError: raise FailedToImplementArgs(space.w_OverflowError, space.wrap("float power")) except ValueError: raise OperationError(space.w_ValueError, space.wrap("float power")) if negate_result: z = -z return W_FloatObject(z)
def reciprocal(self, v): if v == 0.0: return rfloat.copysign(rfloat.INFINITY, v) return 1.0 / v
def sign(self, v): if v == 0.0: return 0.0 return rfloat.copysign(1.0, v)
def signbit(self, v): return rfloat.copysign(1.0, v) < 0.0