+#define IPOW(ret, x, y) do { \
+ int ipow_limit = (y); \
+ if ((x) == 1 || (x) == 0) ipow_limit = 1; \
+ else if ((x) == -1) ipow_limit &= 1; \
+ (ret) = 1; \
+ while (ipow_limit-- > 0) { \
+ int tmp; \
+ MUL(tmp, ret, x); \
+ ret = tmp; \
+ } \
+} while (0)
+
+static int perform_exp(int *a, int *b, int *output)
+{
+ int an, ad, xn, xd, limit, t, i;
+
+ /*
+ * Exponentiation is permitted if the result is rational. This
+ * means that:
+ *
+ * - first we see whether we can take the (denominator-of-b)th
+ * root of a and get a rational; if not, we give up.
+ *
+ * - then we do take that root of a
+ *
+ * - then we multiply by itself (numerator-of-b) times.
+ */
+ if (b[1] > 1) {
+ an = 0.5 + pow(a[0], 1.0/b[1]);
+ ad = 0.5 + pow(a[1], 1.0/b[1]);
+ IPOW(xn, an, b[1]);
+ IPOW(xd, ad, b[1]);
+ if (xn != a[0] || xd != a[1])
+ return FALSE;
+ } else {
+ an = a[0];
+ ad = a[1];
+ }
+ if (b[0] >= 0) {
+ IPOW(xn, an, b[0]);
+ IPOW(xd, ad, b[0]);
+ } else {
+ IPOW(xd, an, -b[0]);
+ IPOW(xn, ad, -b[0]);
+ }
+ if (xd == 0)
+ return FALSE;
+
+ OUT(output, xn, xd);
+ return TRUE;
+}
+
+static int perform_factorial(int *a, int *b, int *output)
+{
+ int ret, t, i;
+
+ /*
+ * Factorials of non-negative integers are permitted.
+ */
+ if (a[1] != 1 || a[0] < 0)
+ return FALSE;
+
+ ret = 1;
+ for (i = 1; i <= a[0]; i++) {
+ MUL(t, ret, i);
+ ret = t;
+ }
+
+ OUT(output, ret, 1);
+ return TRUE;
+}
+