mathsupport.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 451 行
JAVA
451 行
/*
* Created on Feb 23, 2003
*
* To change this generated comment go to
* Window>Preferences>Java>Code Generation>Code Template
*/
package org.jnode.vm;
/**
* @author epr
*/
public class MathSupport {
public static boolean ucmp(/*unsigned*/
int a, /*unsigned*/
int b) {
if ((b < 0) && (a >= 0))
return true;
if ((b >= 0) && (a < 0))
return false;
return a < b;
}
public static boolean ulcmp(/*unsigned*/
long a, /*unsigned*/
long b) {
if ((b < 0L) && (a >= 0L))
return true;
if ((b >= 0L) && (a < 0L))
return false;
return a < b;
}
public static /*unsigned*/
int udiv(/*unsigned*/
int a, /*unsigned*/
int b) {
if (b < 0) {
if (a < 0) {
if (a >= b)
return 1;
}
return 0;
}
if (a >= 0)
return a / b;
// hard case
int a2 = a >>> 1;
int d = a2 / b;
int m = ((a2 % b) << 1) + (a & 1);
return (d << 1) + m / b;
}
public static /*unsigned*/
int urem(/*unsigned*/
int a, /*unsigned*/
int b) {
if (b < 0) {
if (a < 0) {
if (a >= b)
return a - b;
}
return a;
}
if (a >= 0)
return a % b;
// hard case
int a2 = a >>> 1;
int m = ((a2 % b) << 1) + (a & 1);
return m % b;
}
public static /*unsigned*/
long umul(/*unsigned*/
int a, /*unsigned*/
int b) {
char a_1 = (char)a;
char a_2 = (char) (a >> 16);
char b_1 = (char)b;
char b_2 = (char) (b >> 16);
int r1;
long result = 0L;
r1 = a_1 * b_1;
if (r1 < 0) {
result += Integer.MAX_VALUE;
r1 -= Integer.MAX_VALUE;
}
result += r1;
r1 = a_2 * b_1;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 16;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 16;
r1 = a_1 * b_2;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 16;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 16;
return result;
}
public static long ulmul(long a, long b) {
char a_1 = (char)a;
char a_2 = (char) (a >> 16);
char a_3 = (char) (a >> 32);
char a_4 = (char) (a >> 48);
char b_1 = (char)b;
char b_2 = (char) (b >> 16);
char b_3 = (char) (b >> 32);
char b_4 = (char) (b >> 48);
int r1;
long result = 0L;
r1 = a_1 * b_1;
if (r1 < 0) {
result += Integer.MAX_VALUE;
r1 -= Integer.MAX_VALUE;
}
result += r1;
r1 = a_2 * b_1;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 16;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 16;
r1 = a_1 * b_2;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 16;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 16;
r1 = a_3 * b_1;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 32;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 32;
r1 = a_2 * b_2;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 32;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 32;
r1 = a_1 * b_3;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 32;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 32;
r1 = a_4 * b_1;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 48;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 48;
r1 = a_3 * b_2;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 48;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 48;
r1 = a_2 * b_3;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 48;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 48;
r1 = a_1 * b_4;
if (r1 < 0) {
result += ((long)Integer.MAX_VALUE) << 48;
r1 -= Integer.MAX_VALUE;
}
result += ((long)r1) << 48;
return result;
}
public static long ldiv(long uq, long vq) {
boolean neg = false;
if (uq < 0L) {
uq = -uq;
neg = !neg;
}
if (vq < 0L) {
vq = -vq;
neg = !neg;
}
uq = uldivrem(uq, vq, false);
if (neg)
uq = -uq;
return uq;
}
public static long lrem(long uq, long vq) {
boolean neg = false;
if (uq < 0L) {
uq = -uq;
neg = !neg;
}
if (vq < 0L) {
vq = -vq; /*neg = !neg;*/
}
uq = uldivrem(uq, vq, true);
if (neg)
uq = -uq;
return uq;
}
private static int HHALFQ(long v) {
return (int) (v >> 32);
}
private static int LHALFQ(long v) {
return (int)v;
}
private static char HHALF(int v) {
return (char) (v >> 16);
}
private static char LHALF(int v) {
return (char)v;
}
/*private static int LHUP(int v) {
return v << 16;
}*/
private static /*unsigned*/
int COMBINE(char hi, char lo) {
return (hi << 16) | lo;
}
private static /*unsigned*/
long COMBINEQ(/*unsigned*/
int hi, /*unsigned*/
int lo) {
final long hiL = hi;
final long loL = lo;
return (hiL << 32) | (loL & 0xFFFFFFFFL);
}
/*
* Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
* section 4.3.1, pp. 257--259.
*
* NOTE: the version here is adapted from NetBSD C source code (author unknown).
*/
private static /*unsigned*/
long uldivrem(/*unsigned*/
long uq, /*unsigned*/
long vq, boolean rem) {
final int HALF_BITS = 16;
final int B = 1 << HALF_BITS;
char u[], v[], q[];
char v1, v2;
/*unsigned*/
int qhat, rhat, t;
int m, n, d, j, i;
int ui = 0, vi = 0, qi = 0;
if (vq == 0)
throw new ArithmeticException();
if (ulcmp(uq, vq)) {
if (rem)
return uq;
return 0L;
}
u = new char[5];
v = new char[5];
q = new char[5];
/*
* Break dividend and divisor into digits in base B, then
* count leading zeros to determine m and n. When done, we
* will have:
* u = (u[1]u[2]...u[m+n]) sub B
* v = (v[1]v[2]...v[n]) sub B
* v[1] != 0
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
* m >= 0 (otherwise u < v, which we already checked)
* m + n = 4
* and thus
* m = 4 - n <= 2
*/
u[0] = 0;
u[1] = HHALF(HHALFQ(uq));
u[2] = LHALF(HHALFQ(uq));
u[3] = HHALF(LHALFQ(uq));
u[4] = LHALF(LHALFQ(uq));
v[1] = HHALF(HHALFQ(vq));
v[2] = LHALF(HHALFQ(vq));
v[3] = HHALF(LHALFQ(vq));
v[4] = LHALF(LHALFQ(vq));
for (n = 4; v[vi + 1] == 0; vi++) {
if (--n == 1) {
/*unsigned*/
int rbj; /* r*B+u[j] (not root boy jim) */
char q1, q2, q3, q4;
/*
* Change of plan, per exercise 16.
* r = 0;
* for j = 1..4:
* q[j] = floor((r*B + u[j]) / v),
* r = (r*B + u[j]) % v;
* We unroll this completely here.
*/
t = v[vi + 2]; /* nonzero, by definition */
q1 = (char)udiv(u[ui + 1], t);
rbj = COMBINE((char)urem(u[ui + 1], t), u[ui + 2]);
q2 = (char)udiv(rbj, t);
rbj = COMBINE((char)urem(rbj, t), u[ui + 3]);
q3 = (char)udiv(rbj, t);
rbj = COMBINE((char)urem(rbj, t), u[ui + 4]);
q4 = (char)udiv(rbj, t);
if (rem)
return urem(rbj, t);
return COMBINEQ(COMBINE(q1, q2), COMBINE(q3, q4));
}
}
/*
* By adjusting q once we determine m, we can guarantee that
* there is a complete four-digit quotient at &qspace[1] when
* we finally stop.
*/
for (m = 4 - n; u[ui + 1] == 0; ++ui)
m--;
for (i = 4 - m; --i >= 0;)
q[qi + i] = 0;
qi += 4 - m;
/*
* Here we run Program D, translated from MIX to C and acquiring
* a few minor changes.
*
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
*/
d = 0;
for (t = v[vi + 1]; ucmp(t, B / 2); t <<= 1)
d++;
if (d > 0) {
shl(u, ui, m + n, d); /* u <<= d */
shl(v, vi + 1, n - 1, d); /* v <<= d */
}
/*
* D2: j = 0.
*/
j = 0;
v1 = v[vi + 1]; /* for D3 -- note that v[1..n] are constant */
v2 = v[vi + 2]; /* for D3 */
do {
char uj0, uj1, uj2;
/*
* D3: Calculate qhat (\^q, in TeX notation).
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
* let rhat = (u[j]*B + u[j+1]) mod v[1].
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
* decrement qhat and increase rhat correspondingly.
* Note that if rhat >= B, v[2]*qhat < rhat*B.
*/
uj0 = u[ui + j + 0]; /* for D3 only -- note that u[j+...] change */
uj1 = u[ui + j + 1]; /* for D3 only */
uj2 = u[ui + j + 2]; /* for D3 only */
boolean sim_goto = false;
if (uj0 == v1) {
qhat = B;
rhat = uj1;
//goto qhat_too_big;
sim_goto = true;
} else {
/*unsigned*/
int n2 = COMBINE(uj0, uj1);
qhat = udiv(n2, v1);
rhat = urem(n2, v1);
} while (
sim_goto
|| (ucmp(COMBINE((char)rhat, uj2), (int)umul(v2, qhat)))) {
//qhat_too_big:
sim_goto = false;
qhat--;
if ((rhat += v1) >= B)
break;
}
/*
* D4: Multiply and subtract.
* The variable `t' holds any borrows across the loop.
* We split this up so that we do not require v[0] = 0,
* and to eliminate a final special case.
*/
for (t = 0, i = n; i > 0; i--) {
t = u[ui + i + j] - (int)umul(v[vi + i], qhat) - t;
u[ui + i + j] = LHALF(t);
t = (B - HHALF(t)) & (B - 1);
}
t = u[ui + j] - t;
u[ui + j] = LHALF(t);
/*
* D5: test remainder.
* There is a borrow if and only if HHALF(t) is nonzero;
* in that (rare) case, qhat was too large (by exactly 1).
* Fix it by adding v[1..n] to u[j..j+n].
*/
if (HHALF(t) != 0) {
qhat--;
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
t += u[ui + i + j] + v[vi + i];
u[ui + i + j] = LHALF(t);
t = HHALF(t);
}
u[ui + j] = LHALF(u[ui + j] + t);
}
q[qi + j] = (char)qhat;
}
while (++j <= m); /* D7: loop on j. */
/*
* If caller wants the remainder, we have to calculate it as
* u[m..m+n] >>> d (this is at most n digits and thus fits in
* u[m+1..m+n], but we may need more source digits).
*/
if (rem) {
if (d != 0) {
for (i = m + n; i > m; --i)
u[ui + i] =
(char) ((u[ui + i] >>> d)
| LHALF(u[ui + i - 1] << (HALF_BITS - d)));
u[ui + i] = 0;
}
return COMBINEQ(COMBINE(u[1], u[2]), COMBINE(u[3], u[4]));
}
return COMBINEQ(COMBINE(q[1], q[2]), COMBINE(q[3], q[4]));
}
private static void shl(char[] p, int off, int len, int sh) {
int i;
final int HALF_BITS = 16;
for (i = 0; i < len; i++)
p[off + i] =
(char) (LHALF(p[off + i] << sh)
| (p[off + i + 1] >>> (HALF_BITS - sh)));
p[off + i] = LHALF(p[off + i] << sh);
}
// greatest double that can be rounded to an int
//public static double maxint = (double)Integer.MAX_VALUE;
// least double that can be rounded to an int
//public static double minint = (double)Integer.MIN_VALUE;
// greatest double that can be rounded to a long
//public static double maxlong = (double)Long.MAX_VALUE;
// least double that can be rounded to a long
//public static double minlong = (double)Long.MIN_VALUE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?