(lhs: Rational, rhs: Rational)
| 115 | // `a/b < 2^(la - lb + 1)`, so the value can be subnormal only when |
| 116 | // `la - lb + 1 <= -1022`. |
| 117 | if (la - lb <= -1023) { |
| 118 | const num = a << 1074n; |
| 119 | let k = num / b; |
| 120 | const twiceRemainder = 2n * (num - k * b); |
| 121 | if (twiceRemainder > b || (twiceRemainder === b && (k & 1n) === 1n)) |
| 122 | k += 1n; |
| 123 | if (k <= 2n ** 52n) { |
| 124 | const result = Number(k) * Number.MIN_VALUE; |
| 125 | return negative ? -result : result; |
| 126 | } |
| 127 | } |
| 128 | const e = la - lb - 64; |
| 129 | const num = e < 0 ? a << BigInt(-e) : a; |
| 130 | const den = e > 0 ? b << BigInt(e) : b; |
| 131 | let q = num / den; |
| 132 | if (q * den !== num) q |= 1n; |
| 133 | const half = Math.trunc(e / 2); |
| 134 | const result = Number(q) * 2 ** half * 2 ** (e - half); |
| 135 | return negative ? -result : result; |
| 136 | } |
| 137 | |
| 138 | export function isNeg(x: Rational): boolean { |
| 139 | return x[0] < 0; |
| 140 | } |
| 141 | |
| 142 | export function div(lhs: Rational, rhs: Rational): Rational { |
| 143 | return mul(lhs, inverse(rhs)); |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Add a literal numeric value to a rational. |
| 148 | * If the rational is a bigint, this is a hint to do the calculation in bigint |
| 149 | * (no need to check `bignumPreferred()`). |
| 150 | * @param lhs |
| 151 | * @param rhs |
| 152 | * @returns |
| 153 | */ |
| 154 | export function add(lhs: Rational, rhs: Rational): Rational { |
| 155 | if (typeof lhs[0] === 'number' && !Number.isFinite(lhs[0])) return lhs; |
| 156 | |
| 157 | const rhsNum = rhs; |
| 158 | |
| 159 | if (rhsNum === null) return lhs; |
| 160 | |
| 161 | if (isBigRational(rhsNum)) { |
| 162 | lhs = [BigInt(lhs[0]), BigInt(lhs[1])]; |
| 163 | return [rhsNum[1] * lhs[0] + rhsNum[0] * lhs[1], rhsNum[1] * lhs[1]]; |
| 164 | } |
no test coverage detected