def _round_float(space, w_float, w_ndigits=None): # Algorithm copied directly from CPython x = w_float.floatval if w_ndigits is None: # single-argument round: round to nearest integer rounded = rfloat.round_away(x) if math.fabs(x - rounded) == 0.5: # halfway case: round to even rounded = 2.0 * rfloat.round_away(x / 2.0) return newlong_from_float(space, rounded) # interpret 2nd argument as a Py_ssize_t; clip on overflow ndigits = space.getindex_w(w_ndigits, None) # nans and infinities round to themselves if not rfloat.isfinite(x): return space.wrap(x) # Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x # always rounds to itself. For ndigits < NDIGITS_MIN, x always # rounds to +-0.0 if ndigits > NDIGITS_MAX: return space.wrap(x) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.wrap(0.0 * x) # finite x, and ndigits is not unreasonably large z = rfloat.round_double(x, ndigits, half_even=True) if rfloat.isinf(z): raise oefmt(space.w_OverflowError, "overflow occurred during round") return space.wrap(z)
def _round_float(space, w_float, w_ndigits=None): # Algorithm copied directly from CPython x = w_float.floatval if w_ndigits is None: # single-argument round: round to nearest integer rounded = rfloat.round_away(x) if math.fabs(x - rounded) == 0.5: # halfway case: round to even rounded = 2.0 * rfloat.round_away(x / 2.0) return newlong_from_float(space, rounded) # interpret 2nd argument as a Py_ssize_t; clip on overflow ndigits = space.getindex_w(w_ndigits, None) # nans and infinities round to themselves if not rfloat.isfinite(x): return space.newfloat(x) # Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x # always rounds to itself. For ndigits < NDIGITS_MIN, x always # rounds to +-0.0 if ndigits > NDIGITS_MAX: return space.newfloat(x) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.newfloat(0.0 * x) # finite x, and ndigits is not unreasonably large z = rfloat.round_double(x, ndigits, half_even=True) if math.isinf(z): raise oefmt(space.w_OverflowError, "overflow occurred during round") return space.newfloat(z)
def round(space, number, w_ndigits): """round(number[, ndigits]) -> floating point number Round a number to a given precision in decimal digits (default 0 digits). This always returns a floating point number. Precision may be negative.""" # Algorithm copied directly from CPython # interpret 2nd argument as a Py_ssize_t; clip on overflow ndigits = space.getindex_w(w_ndigits, None) # nans, infinities and zeros round to themselves if not isfinite(number): z = number elif ndigits == 0: # common case z = round_away(number) # no need to check for an infinite 'z' here else: # Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x # always rounds to itself. For ndigits < NDIGITS_MIN, x always # rounds to +-0.0. if ndigits > NDIGITS_MAX: z = number elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x z = 0.0 * number else: # finite x, and ndigits is not unreasonably large z = round_double(number, ndigits) if isinf(z): raise oefmt(space.w_OverflowError, "rounded value too large to represent") return space.newfloat(z)
def test_round_away(): assert round_away(.1) == 0. assert round_away(.5) == 1. assert round_away(.7) == 1. assert round_away(1.) == 1. assert round_away(-.5) == -1. assert round_away(-.1) == 0. assert round_away(-.7) == -1. assert round_away(0.) == 0.
def method_divmod(self, space, w_other): if math.isnan(self.floatvalue) or math.isinf(self.floatvalue): raise space.error( space.w_FloatDomainError, space.obj_to_s(space.getclass(w_other)) ) if (space.is_kind_of(w_other, space.w_fixnum) or space.is_kind_of(w_other, space.w_bignum) or space.is_kind_of(w_other, space.w_float)): y = space.float_w(w_other) if math.isnan(y): raise space.error( space.w_FloatDomainError, space.obj_to_s(space.getclass(w_other)) ) x = self.floatvalue mod = space.float_w(self.method_mod_float_impl(space, y)) # TAKEN FROM: pypy/module/cpytext/floatobject.py div = (x - mod) / y if (mod): # ensure the remainder has the same sign as the denominator if ((y < 0.0) != (mod < 0.0)): mod += y div -= 1.0 else: mod *= mod # hide "mod = +0" from optimizer if y < 0.0: mod = -mod # snap quotient to nearest integral value if div: floordiv = math.floor(div) if (div - floordiv > 0.5): floordiv += 1.0 else: # div is zero - get the same sign as the true quotient div *= div # hide "div = +0" from optimizers floordiv = div * x / y # zero w/ sign of vx/wx try: return space.newarray([self.float_to_w_int(space, round_away(div)), space.newfloat(mod)]) except OverflowError: return space.newarray([space.newbigint_fromfloat(div), space.newfloat(mod)]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Float" % ( space.obj_to_s(space.getclass(w_other)) ) )
def method_divmod(self, space, w_other): if space.is_kind_of(w_other, space.w_float): return space.send(self.method_to_f(space), "divmod", [w_other]) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), "divmod", [w_other]) elif space.is_kind_of(w_other, space.w_fixnum): y = space.int_w(w_other) if y == 0: raise space.error(space.w_ZeroDivisionError, "divided by 0") mod = space.int_w(self.method_mod_int_impl(space, y)) div = (self.intvalue - mod) / y return space.newarray( [space.newint(int(round_away(div))), space.newfloat(mod)]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Fixnum" % (space.obj_to_s(space.getclass(w_other))))
def method_divmod(self, space, w_other): if space.is_kind_of(w_other, space.w_float): return space.send(self.method_to_f(space), "divmod", [w_other]) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), "divmod", [w_other]) elif space.is_kind_of(w_other, space.w_fixnum): y = space.int_w(w_other) if y == 0: raise space.error( space.w_ZeroDivisionError, "divided by 0" ) mod = space.int_w(self.method_mod_int_impl(space, y)) div = (self.intvalue - mod) / y return space.newarray([space.newint(int(round_away(div))), space.newfloat(mod)]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Fixnum" % ( space.obj_to_s(space.getclass(w_other)) ) )
def method_round(self, space): return space.newint(int(round_away(Coerce.float(space, self))))
def method_round(self, space): return space.newint(int(round_away(self.floatvalue)))