Instead of O(n) in the value of the exponent, we can compute exponents
in O(log n), with exponentiation by squaring. With this patch, "time
echo 'eval(3**2000000000)' | m4" drops from 2 seconds to under 10
milliseconds.
* src/eval.c (parse_expr): Use exponentiation by squaring.
* doc/m4.texi (Eval): Test it.
---
doc/m4.texi | 16 ++++++++++++++++
src/eval.c | 17 +++++++++++++----
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/doc/m4.texi b/doc/m4.texi
index 81476bc8..612ed945 100644
--- a/doc/m4.texi
+++ b/doc/m4.texi
@@ -7235,6 +7235,22 @@ Eval
@result{}
@end example
+@ignore
+@comment This test makes sure the algorithm is fast, but does not
+@comment need to be displayed as-is in the manual.
+
+@example
+eval(`3**2000000000')
+@result{}632360961
+define(`loop', `ifelse(`$1', `1000', `pass',
+`loop(eval($1+!!(3**2000000000)))')')loop(0)
+@result{}pass
+define(`check', `ifelse(`$1', `100', `pass', `$2', eval(-3**$1),
+`check(incr($1), eval(-3*$2))', `oops')')check(0, 1)
+@result{}pass
+@end example
+@end ignore
+
Within @var{expression}, (but not @var{radix} or @var{width}), numbers
without a special prefix are decimal. A simple @samp{0} prefix
introduces an octal number. @samp{0x} introduces a hexadecimal number.
diff --git a/src/eval.c b/src/eval.c
index 163e2634..69cd5e41 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -389,6 +389,8 @@ parse_expr (int32_t *v1, eval_error er, unsigned min_prec)
int32_t v2;
int32_t v3;
uint32_t u1;
+ uint32_t u2;
+ uint32_t u3;
if (er >= SYNTAX_ERROR)
return er;
@@ -429,17 +431,24 @@ parse_expr (int32_t *v1, eval_error er, unsigned min_prec)
that the implementation-defined overflow when casting
unsigned to signed is a silent twos-complement
wrap-around. */
- u1 = 1;
if (v2 < 0)
er = NEGATIVE_EXPONENT;
else if (*v1 == 0 && v2 == 0)
er = DIVIDE_ZERO;
else
{
- while (v2-- > 0)
- u1 *= (uint32_t) *v1;
+ u1 = *v1;
+ u2 = v2;
+ u3 = 1;
+ while (u2)
+ {
+ if (u2 & 1)
+ u3 *= u1;
+ u1 *= u1;
+ u2 >>= 1;
+ }
}
- *v1 = u1;
+ *v1 = u3;
break;
case TIMES:
--
2.49.0
_______________________________________________
M4-patches mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/m4-patches