(x: Decimal, p: number)
| 10 | |
| 11 | //IMPL: Helper function to find n1, e1, and r1 using direct calculation |
| 12 | function findN1E1R1(x: Decimal, p: number) { |
| 13 | const maxN1 = getPowerOf10(p) |
| 14 | const minN1 = getPowerOf10(p - 1) |
| 15 | |
| 16 | // Direct calculation: compute e1 from logarithm |
| 17 | // e1 is the exponent such that n1 * 10^(e1-p+1) <= x |
| 18 | // Taking log: log(n1) + (e1-p+1)*log(10) <= log(x) |
| 19 | // Since n1 is between 10^(p-1) and 10^p, we have: |
| 20 | // (p-1) + (e1-p+1) <= log10(x) < p + (e1-p+1) |
| 21 | // Simplifying: e1 <= log10(x) < e1 + 1 |
| 22 | // Therefore: e1 = floor(log10(x)) |
| 23 | const log10x = x.log(10) |
| 24 | let e1 = log10x.floor() |
| 25 | |
| 26 | // Calculate n1 and r1 from e1 |
| 27 | const divisor = getPowerOf10(e1.minus(p).plus(1)) |
| 28 | let n1 = x.div(divisor).floor() |
| 29 | let r1 = n1.times(divisor) |
| 30 | |
| 31 | // Verify and adjust if n1 is out of bounds |
| 32 | // This handles edge cases near powers of 10 |
| 33 | if (n1.greaterThanOrEqualTo(maxN1)) { |
| 34 | e1 = e1.plus(1) |
| 35 | const newDivisor = getPowerOf10(e1.minus(p).plus(1)) |
| 36 | n1 = x.div(newDivisor).floor() |
| 37 | r1 = n1.times(newDivisor) |
| 38 | } else if (n1.lessThan(minN1)) { |
| 39 | e1 = e1.minus(1) |
| 40 | const newDivisor = getPowerOf10(e1.minus(p).plus(1)) |
| 41 | n1 = x.div(newDivisor).floor() |
| 42 | r1 = n1.times(newDivisor) |
| 43 | } |
| 44 | |
| 45 | // Final verification with fallback to iterative search if needed |
| 46 | if ( |
| 47 | r1.lessThanOrEqualTo(x) && |
| 48 | n1.lessThan(maxN1) && |
| 49 | n1.greaterThanOrEqualTo(minN1) |
| 50 | ) { |
| 51 | return {n1, e1, r1} |
| 52 | } |
| 53 | |
| 54 | // Fallback: iterative search (should rarely be needed) |
| 55 | const maxE1 = x.div(minN1).log(10).plus(p).minus(1).ceil() |
| 56 | let currentE1 = maxE1 |
| 57 | while (true) { |
| 58 | const currentDivisor = getPowerOf10(currentE1.minus(p).plus(1)) |
| 59 | let currentN1 = x.div(currentDivisor).floor() |
| 60 | if (currentN1.lessThan(maxN1) && currentN1.greaterThanOrEqualTo(minN1)) { |
| 61 | const currentR1 = currentN1.times(currentDivisor) |
| 62 | if (currentR1.lessThanOrEqualTo(x)) { |
| 63 | return { |
| 64 | n1: currentN1, |
| 65 | e1: currentE1, |
| 66 | r1: currentR1, |
| 67 | } |
| 68 | } |
| 69 | } |
no test coverage detected