summaryrefslogtreecommitdiff
path: root/systems/knuth/local/mf-sparc/mf_arith.c
diff options
context:
space:
mode:
Diffstat (limited to 'systems/knuth/local/mf-sparc/mf_arith.c')
-rw-r--r--systems/knuth/local/mf-sparc/mf_arith.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/systems/knuth/local/mf-sparc/mf_arith.c b/systems/knuth/local/mf-sparc/mf_arith.c
new file mode 100644
index 0000000000..5347107e81
--- /dev/null
+++ b/systems/knuth/local/mf-sparc/mf_arith.c
@@ -0,0 +1,142 @@
+/*
+ * mf_arith.c -- optimized arithmetic routines for UNIX METAFONT 84
+ *
+ * These functions account for a significant percentage of the processing
+ * time used by METAFONT, and have been recoded in assembly language for
+ * some classes of machines.
+ *
+ * As yet I don't have code for SPARC, so I'm just using a C version
+ * by richards, in hopes that cc does better than pc on the brute-force
+ * algorithm found in mf.web.
+ *
+ * function makefraction(p, q: integer): fraction;
+ * { Calculate the function floor( (p * 2^28) / q + 0.5 ) }
+ * { if both p and q are positive. If not, then the value }
+ * { of makefraction is calculated as though both *were* }
+ * { positive, then the result sign adjusted. }
+ * { (e.g. makefraction ALWAYS rounds away from zero) }
+ * { In case of an overflow, return the largest possible }
+ * { value (2^32-1) with the correct sign, and set global }
+ * { variable "aritherror" to 1. Note that -2^32 is }
+ * { considered to be an illegal product for this type of }
+ * { arithmetic! }
+ *
+ * function takefraction(f: fraction; q: integer): integer;
+ * { Calculate the function floor( (p * q) / 2^28 + 0.5 ) }
+ * { takefraction() rounds in a similar manner as }
+ * { makefraction() above. }
+ *
+ */
+
+#include "h00vars.h"
+
+extern bool aritherror; /* to be set on overflow */
+
+#define EL_GORDO 0x7fffffff /* 2^31-1 */
+#define FRACTION_ONE 0x10000000 /* 2^28 */
+#define FRACTION_HALF 0x08000000 /* 2^27 */
+#define FRACTION_FOUR 0x40000000 /* 2^30 */
+
+int makefraction(p, q)
+ register int p, q;
+{
+ int negative;
+ register int be_careful;
+ register int f;
+ int n;
+
+ if (p < 0) {
+ negative = 1;
+ p = -p;
+ } else negative = 0;
+
+ if (q < 0) {
+ negative = !negative;
+ q = -q;
+ }
+
+ n = p / q;
+ p = p % q;
+
+ if (n >= 8) {
+ aritherror = TRUE;
+ return (negative? -EL_GORDO : EL_GORDO);
+ }
+
+ n = (n-1)*FRACTION_ONE;
+ f = 1;
+ do {
+ be_careful = p - q;
+ p = be_careful + p;
+ if (p >= 0) {
+ f = f + f + 1;
+ } else {
+ f <<= 1;
+ p += q;
+ }
+ } while (f < FRACTION_ONE);
+
+ be_careful = p - q;
+ if ((be_careful + p) >= 0)
+ f += 1;
+ return (negative? -(f+n) : (f+n));
+
+}
+
+int takefraction(q, f)
+ register int q;
+ register int f;
+{
+ int n, negative;
+ register int p, be_careful;
+
+ if (f < 0) {
+ negative = 1;
+ f = -f;
+ } else negative = 0;
+ if (q < 0) {
+ negative = !negative;
+ q = -q;
+ }
+ if (f < FRACTION_ONE)
+ n = 0;
+ else {
+ n = f / FRACTION_ONE;
+ f = f % FRACTION_ONE;
+ if (q < (EL_GORDO / n))
+ n = n * q;
+ else {
+ aritherror = TRUE;
+ n = EL_GORDO;
+ }
+ }
+
+ f += FRACTION_ONE;
+ p = FRACTION_HALF;
+ if (q < FRACTION_FOUR)
+ do {
+ if (f & 0x1)
+ p = (p+q) >> 1;
+ else
+ p >>= 1;
+ f >>= 1;
+ } while (f > 1);
+ else
+ do {
+ if (f & 0x1)
+ p = p + ((q-p) >> 1);
+ else
+ p >>= 1;
+ f >>= 1;
+ } while (f > 1);
+
+ be_careful = n - EL_GORDO;
+ if ((be_careful + p) > 0) {
+ aritherror = TRUE;
+ n = EL_GORDO - p;
+ }
+
+ return(negative? -(n+p) : (n+p));
+}
+
+