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 number == 0 or isinf(number) or isnan(number): return space.newfloat(number) # 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(number) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.newfloat(0.0 * number) # 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 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 number == 0 or isinf(number) or isnan(number): return space.wrap(number) # 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(number) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.wrap(0.0 * number) # 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.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.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 test_round_half_even(): from rpython.rlib import rfloat func = rfloat.round_double # 2.x behavior assert func(2.5, 0, False) == 3.0 # 3.x behavior assert func(2.5, 0, True) == 2.0 for i in range(-10, 10): assert func(i + 0.5, 0, True) == i + (i & 1) assert func(i * 10 + 5, -1, True) == (i + (i & 1)) * 10 exact_integral = 5e15 + 1 assert round_double(exact_integral, 0, True) == exact_integral assert round_double(exact_integral / 2.0, 0, True) == 5e15 / 2.0 exact_integral = 5e15 - 1 assert round_double(exact_integral, 0, True) == exact_integral assert round_double(exact_integral / 2.0, 0, True) == 5e15 / 2.0
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 method_sleep(self, space, w_duration=None): if w_duration is None: raise space.error(space.w_NotImplementedError) elif space.is_kind_of(w_duration, space.w_string): raise space.error(space.w_TypeError, "can't convert String into time interval") start = time.time() time.sleep(Coerce.float(space, w_duration)) return space.newint(int(round_double(time.time() - start, 0)))
def rpy_round(number, ndigits): # Algorithm copied directly from CPython if number == 0 or rfloat.isinf(number) or rfloat.isnan(number): return number # 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 number elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return 0.0 * number # finite x, and ndigits is not unreasonably large z = rfloat.round_double(number, ndigits) if rfloat.isinf(z): raise OverflowError return z
def _round(ivkbl, rcvr, args, meta_level): int_value = int(round_double(rcvr.get_embedded_double(), 0)) return ivkbl.get_universe().new_integer(int_value)
def method_sleep(self, space, w_duration=None): if w_duration is None: raise space.error(space.w_NotImplementedError) start = time.time() time.sleep(space.float_w(w_duration)) return space.newint(int(round_double(time.time() - start, 0)))
def test_round_double(): def almost_equal(x, y): assert round(abs(x-y), 7) == 0 almost_equal(round_double(0.125, 2), 0.13) almost_equal(round_double(0.375, 2), 0.38) almost_equal(round_double(0.625, 2), 0.63) almost_equal(round_double(0.875, 2), 0.88) almost_equal(round_double(-0.125, 2), -0.13) almost_equal(round_double(-0.375, 2), -0.38) almost_equal(round_double(-0.625, 2), -0.63) almost_equal(round_double(-0.875, 2), -0.88) almost_equal(round_double(0.25, 1), 0.3) almost_equal(round_double(0.75, 1), 0.8) almost_equal(round_double(-0.25, 1), -0.3) almost_equal(round_double(-0.75, 1), -0.8) round_double(-6.5, 0) == -7.0 round_double(-5.5, 0) == -6.0 round_double(-1.5, 0) == -2.0 round_double(-0.5, 0) == -1.0 round_double(0.5, 0) == 1.0 round_double(1.5, 0) == 2.0 round_double(2.5, 0) == 3.0 round_double(3.5, 0) == 4.0 round_double(4.5, 0) == 5.0 round_double(5.5, 0) == 6.0 round_double(6.5, 0) == 7.0 round_double(-25.0, -1) == -30.0 round_double(-15.0, -1) == -20.0 round_double(-5.0, -1) == -10.0 round_double(5.0, -1) == 10.0 round_double(15.0, -1) == 20.0 round_double(25.0, -1) == 30.0 round_double(35.0, -1) == 40.0 round_double(45.0, -1) == 50.0 round_double(55.0, -1) == 60.0 round_double(65.0, -1) == 70.0 round_double(75.0, -1) == 80.0 round_double(85.0, -1) == 90.0 round_double(95.0, -1) == 100.0 round_double(12325.0, -1) == 12330.0 round_double(350.0, -2) == 400.0 round_double(450.0, -2) == 500.0 almost_equal(round_double(0.5e21, -21), 1e21) almost_equal(round_double(1.5e21, -21), 2e21) almost_equal(round_double(2.5e21, -21), 3e21) almost_equal(round_double(5.5e21, -21), 6e21) almost_equal(round_double(8.5e21, -21), 9e21) almost_equal(round_double(-1.5e22, -22), -2e22) almost_equal(round_double(-0.5e22, -22), -1e22) almost_equal(round_double(0.5e22, -22), 1e22) almost_equal(round_double(1.5e22, -22), 2e22)
def _round(ivkbl, frame, interpreter): rcvr = frame.pop() int_value = int(round_double(rcvr.get_embedded_double(), 0)) frame.push(interpreter.get_universe().new_integer(int_value))
def arith_round(self): from rpython.rlib.rfloat import round_double return values.W_Flonum(round_double(self.value, 0, half_even=True))
def test_round_double(): def almost_equal(x, y): assert abs(x - y) < 1e-7 almost_equal(round_double(0.125, 2), 0.13) almost_equal(round_double(0.375, 2), 0.38) almost_equal(round_double(0.625, 2), 0.63) almost_equal(round_double(0.875, 2), 0.88) almost_equal(round_double(-0.125, 2), -0.13) almost_equal(round_double(-0.375, 2), -0.38) almost_equal(round_double(-0.625, 2), -0.63) almost_equal(round_double(-0.875, 2), -0.88) almost_equal(round_double(0.25, 1), 0.3) almost_equal(round_double(0.75, 1), 0.8) almost_equal(round_double(-0.25, 1), -0.3) almost_equal(round_double(-0.75, 1), -0.8) assert round_double(-6.5, 0) == -7.0 assert round_double(-5.5, 0) == -6.0 assert round_double(-1.5, 0) == -2.0 assert round_double(-0.5, 0) == -1.0 assert round_double(0.5, 0) == 1.0 assert round_double(1.5, 0) == 2.0 assert round_double(2.5, 0) == 3.0 assert round_double(3.5, 0) == 4.0 assert round_double(4.5, 0) == 5.0 assert round_double(5.5, 0) == 6.0 assert round_double(6.5, 0) == 7.0 assert round_double(-25.0, -1) == -30.0 assert round_double(-15.0, -1) == -20.0 assert round_double(-5.0, -1) == -10.0 assert round_double(5.0, -1) == 10.0 assert round_double(15.0, -1) == 20.0 assert round_double(25.0, -1) == 30.0 assert round_double(35.0, -1) == 40.0 assert round_double(45.0, -1) == 50.0 assert round_double(55.0, -1) == 60.0 assert round_double(65.0, -1) == 70.0 assert round_double(75.0, -1) == 80.0 assert round_double(85.0, -1) == 90.0 assert round_double(95.0, -1) == 100.0 assert round_double(12325.0, -1) == 12330.0 assert round_double(350.0, -2) == 400.0 assert round_double(450.0, -2) == 500.0 almost_equal(round_double(0.5e21, -21), 1e21) almost_equal(round_double(1.5e21, -21), 2e21) almost_equal(round_double(2.5e21, -21), 3e21) almost_equal(round_double(5.5e21, -21), 6e21) almost_equal(round_double(8.5e21, -21), 9e21) almost_equal(round_double(-1.5e22, -22), -2e22) almost_equal(round_double(-0.5e22, -22), -1e22) almost_equal(round_double(0.5e22, -22), 1e22) almost_equal(round_double(1.5e22, -22), 2e22) exact_integral = 5e15 + 1 assert round_double(exact_integral, 0) == exact_integral assert round_double(exact_integral / 2.0, 0) == 5e15 / 2.0 + 1.0 exact_integral = 5e15 - 1 assert round_double(exact_integral, 0) == exact_integral assert round_double(exact_integral / 2.0, 0) == 5e15 / 2.0
def _round(ivkbl, rcvr, args): int_value = int(round_double(rcvr.get_embedded_double(), 0)) return ivkbl.get_universe().new_integer(int_value)