diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2024-02-06 16:45:04 +0300 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2024-02-06 16:45:04 +0300 |
commit | 21c5be3706f70d573f8d0195760846fce46f6807 (patch) | |
tree | 9240d238d5b183bdaf57ecad69c10595736690e0 | |
parent | 37eef3cf0ab0b0ed3dabc1c96515f4e30011f9db (diff) | |
download | sciteco-21c5be3706f70d573f8d0195760846fce46f6807.tar.gz |
fixed the power (^*) operator: did not handle corner cases and was inefficient
* in fact, with a negative exponent the previous naive implementation would even hang indefinitely!
* Now uses the squaring algorithm.
This is slightly longer but significantly more efficient.
* added test cases
-rw-r--r-- | src/expressions.c | 23 | ||||
-rw-r--r-- | tests/testsuite.at | 9 |
2 files changed, 31 insertions, 1 deletions
diff --git a/src/expressions.c b/src/expressions.c index 93e3fdc..cec3492 100644 --- a/src/expressions.c +++ b/src/expressions.c @@ -184,7 +184,28 @@ teco_expressions_calc(GError **error) switch (op) { case TECO_OP_POW: - for (result = 1; vright--; result *= vleft); + if (!vright) { + result = vleft < 0 ? -1 : 1; + break; + } + if (vright < 0) { + if (!vleft) { + g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, + "Negative power of 0 is not defined"); + return FALSE; + } + result = ABS(vleft) == 1 ? vleft : 0; + break; + } + result = 1; + for (;;) { + if (vright & 1) + result *= vleft; + vright >>= 1; + if (!vright) + break; + vleft *= vleft; + } break; case TECO_OP_MUL: result = vleft * vright; diff --git a/tests/testsuite.at b/tests/testsuite.at index 80e111c..3a8bed8 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,6 +27,15 @@ AT_CHECK([$SCITECO -e "2%a,%a - 3\"N(0/0)'"], 0, ignore, ignore) AT_CHECK([$SCITECO -e "(1,) \"~|(0/0)'"], 0, ignore, ignore) AT_CLEANUP +AT_SETUP([Exponentiation]) +AT_CHECK([$SCITECO -e "-1^*0 - (-1)\"N(0/0)'"], 0, ignore, ignore) +AT_CHECK([$SCITECO -e "-1^*-5 - (-1)\"N(0/0)'"], 0, ignore, ignore) +AT_CHECK([$SCITECO -e "0^*-5="], 1, ignore, ignore) +AT_CHECK([$SCITECO -e "0^*0 - 1\"N(0/0)'"], 0, ignore, ignore) +AT_CHECK([$SCITECO -e "1^*-5 - 1\"N(0/0)'"], 0, ignore, ignore) +AT_CHECK([$SCITECO -e "2^*-5 - 0\"N(0/0)'"], 0, ignore, ignore) +AT_CLEANUP + AT_SETUP([Missing left operand]) AT_CHECK([$SCITECO -e '+23='], 1, ignore, ignore) AT_CLEANUP |