From 47daaf555f8bd4172a3c54d3e249199700076a49 Mon Sep 17 00:00:00 2001 From: Adolfo Gonzalez III Date: Fri, 8 Nov 2019 16:13:11 -0600 Subject: [PATCH] Rebasing branch --- tests/snippets/math_module.py | 125 ++++++++++++++++++++++++++++++++++ vm/src/stdlib/math.rs | 30 +++++++- 2 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 tests/snippets/math_module.py diff --git a/tests/snippets/math_module.py b/tests/snippets/math_module.py new file mode 100644 index 000000000..42ae6b955 --- /dev/null +++ b/tests/snippets/math_module.py @@ -0,0 +1,125 @@ +import math +from testutils import assert_raises + +# assert(math.exp(2) == math.exp(2.0)) +# assert(math.exp(True) == math.exp(1.0)) +# +# class Conversible(): +# def __float__(self): +# print("Converting to float now!") +# return 1.1111 +# +# assert math.log(1.1111) == math.log(Conversible()) + +# roundings +assert int.__trunc__ +assert int.__floor__ +assert int.__ceil__ + +# assert float.__trunc__ +with assert_raises(AttributeError): + assert float.__floor__ +with assert_raises(AttributeError): + assert float.__ceil__ + +assert math.trunc(2) == 2 +assert math.ceil(3) == 3 +assert math.floor(4) == 4 + +assert math.trunc(2.2) == 2 +assert math.ceil(3.3) == 4 +assert math.floor(4.4) == 4 + +# Check if the type of the resulting number is correct +assert type(math.trunc(2.2)) == int +assert type(math.ceil(3.3)) == int +assert type(math.floor(4.4)) == int + +class A(object): + def __trunc__(self): + return 2 + + def __ceil__(self): + return 3 + + def __floor__(self): + return 4 + +assert math.trunc(A()) == 2 +assert math.ceil(A()) == 3 +assert math.floor(A()) == 4 + +class A(object): + def __trunc__(self): + return 2.2 + + def __ceil__(self): + return 3.3 + + def __floor__(self): + return 4.4 + +assert math.trunc(A()) == 2.2 +assert math.ceil(A()) == 3.3 +assert math.floor(A()) == 4.4 + +class A(object): + def __trunc__(self): + return 'trunc' + + def __ceil__(self): + return 'ceil' + + def __floor__(self): + return 'floor' + +assert math.trunc(A()) == 'trunc' +assert math.ceil(A()) == 'ceil' +assert math.floor(A()) == 'floor' + +with assert_raises(TypeError): + math.trunc(object()) +with assert_raises(TypeError): + math.ceil(object()) +with assert_raises(TypeError): + math.floor(object()) + +assert str(math.frexp(0.0)) == str((+0.0, 0)) +assert str(math.frexp(-0.0)) == str((-0.0, 0)) +assert math.frexp(1) == (0.5, 1) +assert math.frexp(1.5) == (0.75, 1) +assert_raises(TypeError, lambda: math.frexp(None)) + +assert str(math.ldexp(+0.0, 0)) == str(0.0) +assert str(math.ldexp(-0.0, 0)) == str(-0.0) +assert math.ldexp(0.5, 1) == 1 +assert math.ldexp(0.75, 1) == 1.5 +assert_raises(TypeError, lambda: math.ldexp(None, None)) + +assert math.frexp(float('inf')) == (float('inf'), 0) +assert str(math.frexp(float('nan'))) == str((float('nan'), 0)) +assert_raises(TypeError, lambda: math.frexp(None)) + +assert math.gcd(0, 0) == 0 +assert math.gcd(1, 0) == 1 +assert math.gcd(0, 1) == 1 +assert math.gcd(1, 1) == 1 +assert math.gcd(-1, 1) == 1 +assert math.gcd(1, -1) == 1 +assert math.gcd(-1, -1) == 1 +assert math.gcd(125, -255) == 5 +assert_raises(TypeError, lambda: math.gcd(1.1, 2)) + +assert math.factorial(0) == 1 +assert math.factorial(1) == 1 +assert math.factorial(2) == 2 +assert math.factorial(3) == 6 +assert math.factorial(10) == 3628800 +assert math.factorial(20) == 2432902008176640000 +assert_raises(ValueError, lambda: math.factorial(-1)) + +assert math.modf(1.25) == (0.25, 1.0) +assert math.modf(-1.25) == (-0.25, -1.0) +assert math.modf(2.56) == (0.56, 2.0) +assert math.modf(-2.56) == (-0.56, -2.0) +assert math.modf(1) == (0.0, 1.0) diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index d548ab8ae..9627ce6cc 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -214,19 +214,45 @@ fn math_trunc(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { try_magic_method("__trunc__", vm, &value) } +/// Applies ceiling to a float, returning an Integral. +/// +/// # Arguments +/// +/// * `value` - Either a float or a python object which implements __ceil__ +/// * `vm` - Represents the python state. +/// +/// # Remarks +/// +/// Currently the code is applying ceil to the float using rust's builtin +/// method and then converts to integral using python float's __int__ method. +/// fn math_ceil(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { if objtype::isinstance(&value, &vm.ctx.float_type()) { let v = objfloat::get_value(&value); - Ok(vm.ctx.new_float(v.ceil())) + let v = vm.ctx.new_float(v.ceil()); + try_magic_method("__int__", vm, &v) } else { try_magic_method("__ceil__", vm, &value) } } +/// Applies floor to a float, returning an Integral. +/// +/// # Arguments +/// +/// * `value` - Either a float or a python object which implements __ceil__ +/// * `vm` - Represents the python state. +/// +/// # Remarks +/// +/// Currently the code is applying floor to the float using rust's builtin +/// method and then converts to integral using python float's __int__ method. +/// fn math_floor(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { if objtype::isinstance(&value, &vm.ctx.float_type()) { let v = objfloat::get_value(&value); - Ok(vm.ctx.new_float(v.floor())) + let v = vm.ctx.new_float(v.floor()); + try_magic_method("__int__", vm, &v) } else { try_magic_method("__floor__", vm, &value) }