class RR {
constructor(approx) {
this.value = null;
this.cf = '';
this.cfrac = [];
this.approx = (N) => {
if (N < this.N_min) N = this.N_min;
let [a, b] = approx(N*2n);
const delta = new QQ(1n, N).subtract(b.subtract(a));
if (delta.p > 0n) {
const max = (delta.q * 2n) / delta.p;
a = a.relax(-max);
b = b.relax(max);
}
let cfrac = [], i = 0;
while (i < a.cfrac.length && i < b.cfrac.length) {
if (a.cfrac[i] != b.cfrac[i]) break;
cfrac.push(a.cfrac[i]);
i++;
}
if (cfrac.length > this.cfrac.length) {
this.cf = `[${cfrac[0]};${cfrac.slice(1).join(',')},...]`;
this.cfrac = cfrac;
}
return [a, b];
};
this.N_min = 1n;
this.sign = this.sign();
}
static toRR(q) {
q = QQ.toQQ(q);
return new RR((N) => [q, q]);
}
sign() {
let N = 1n;
while (true) {
const [a, b] = this.approx(N);
this.N_min = N;
if (a.p > 0) return 1n;
if (b.p < 0) return -1n;
N *= 2n;
}
}
add(other) {
return new RR((N) => {
if (other instanceof QQ || typeof other === 'bigint') {
// Approximate this with precision N and add the QQ directly
const [a1, b1] = this.approx(N);
return [a1.add(other), b1.add(other)];
} else if (other instanceof RR) {
// Use 2N to approximate both numbers and add them
const [a1, b1] = this.approx(N * 2n);
const [a2, b2] = other.approx(N * 2n);
return [a1.add(a2), b1.add(b2)];
} else {
throw new TypeError("Unsupported type for addition");
}
});
}
subtract(other) {
return new RR((N) => {
if (other instanceof QQ || typeof other === 'bigint') {
// Approximate this with precision N and add the QQ directly
const [a1, b1] = this.approx(N);
return [a1.subtract(other), b1.subtract(other)];
} else if (other instanceof RR) {
// Use 2N to approximate both numbers and add them
const [a1, b1] = this.approx(N * 2n);
const [a2, b2] = other.approx(N * 2n);
return [a1.subtract(b2), b1.subtract(a2)];
} else {
throw new TypeError("Unsupported type for addition");
}
});
}
multiply(other) {
return new RR((N) => {
if (other instanceof QQ || typeof other === 'bigint') {
// Multiply with a QQ directly
other = QQ.toQQ(other);
if (other.p >= 0n) {
const [a, b] = this.approx(N * other.p / other.q + 1n);
return [a.multiply(other), b.multiply(other)];
} else {
const [a, b] = this.approx(N * (-other.p) / other.q + 1n);
return [b.multiply(other), a.multiply(other)];
}
} else if (other instanceof RR) {
const eps = new QQ(1n, N);
while (true) {
const [a1, b1] = this.approx(N);
const [a2, b2] = other.approx(N);
let [a, b] = [a1.multiply(a2), b1.multiply(b2)];
if (this.sign * other.sign === -1n) [a, b] = [b, a];
if (b.subtract(a).lessThan(eps)) return [a, b];
N *= 2n;
}
} else {
throw new TypeError("Unsupported type for multiplication");
}
});
}
divide(other) {
if (other instanceof QQ || typeof other === 'bigint') {
return this.multiply(QQ.toQQ(other).inverse());
} else if (other instanceof RR) {
return this.multiply(other.inverse());
} else {
throw new TypeError(`Unsupported type for division (${typeof other})`);
}
}
power(k) {
k = BigInt(k);
if (k === 0n) return new QQ(1n);
return new RR((N) => {
const eps = new QQ(1n, N);
const est = this.approx(1n)[1];
while (true) {
const est_k = est.power(k-1n)
let N_prime = N * (k * est_k.p) / est_k.q;
if (N_prime < 0n) N_prime = -N_prime;
let [a, b] = this.approx(N_prime);
let [a_k, b_k] = [a.power(k), b.power(k)];
a_k = a_k.relax(-N*4n);
b_k = b_k.relax(N*4n);
if (a_k.greaterThan(b_k)) [a_k, b_k] = [b_k, a_k];
if (b_k.subtract(a_k).lessThan(eps)) return [a_k, b_k];
N *= 2n;
}
});
}
inverse() {
return new RR((N) => {
const eps = new QQ(1n, N);
const sgn = this.sign();
while (true) {
let [a, b] = this.approx(N);
if (a.p * b.p > 0n) {
[a, b] = [b.inverse(), a.inverse()];
if (b.subtract(a).lessThan(eps)) return [a, b];
}
N *= 2n;
}
});
}
}