From 30c673b8752bae431da86500f8fda1f4e9419199 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 18 Feb 2023 20:26:58 +0800 Subject: [PATCH] use qpow algo for int to fix precision loss --- src/pocketpy.h | 13 ++++++++++++- tests/_basic.py | 9 +++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/pocketpy.h b/src/pocketpy.h index 9ec18e8a..08880a3b 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -171,7 +171,18 @@ void init_builtins(VM* _vm) { _vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, pkpy::Args& args) { if(args[0]->is_type(vm->tp_int) && args[1]->is_type(vm->tp_int)){ - return vm->PyInt((i64)round(pow(vm->PyInt_AS_C(args[0]), vm->PyInt_AS_C(args[1])))); + i64 lhs = vm->PyInt_AS_C(args[0]); + i64 rhs = vm->PyInt_AS_C(args[1]); + bool flag = false; + if(rhs < 0) {flag = true; rhs = -rhs;} + i64 ret = 1; + while(rhs){ + if(rhs & 1) ret *= lhs; + lhs *= lhs; + rhs >>= 1; + } + if(flag) return vm->PyFloat((f64)(1.0 / ret)); + return vm->PyInt(ret); }else{ return vm->PyFloat((f64)pow(vm->num_to_float(args[0]), vm->num_to_float(args[1]))); } diff --git a/tests/_basic.py b/tests/_basic.py index be06473a..e0aa4d4f 100644 --- a/tests/_basic.py +++ b/tests/_basic.py @@ -117,3 +117,12 @@ assert round(23.2) == 23 assert round(23.8) == 24 assert round(-23.2) == -23 assert round(-23.8) == -24 + + +assert 7**21 == 558545864083284007 +assert 7**22 == 3909821048582988049 +assert 2**62 == 4611686018427387904 +assert eq(2**-2, 0.25) +assert 0**0 == 1 +assert 0**1 == 0 +assert 1**0 == 1 \ No newline at end of file