|
1 | 1 | /*
|
2 |
| - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
4 | 4 | *
|
5 | 5 | * This code is free software; you can redistribute it and/or modify it
|
@@ -1892,6 +1892,204 @@ private boolean unsignedLongCompare(long one, long two) {
|
1892 | 1892 | return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE);
|
1893 | 1893 | }
|
1894 | 1894 |
|
| 1895 | + /** |
| 1896 | + * Calculate the integer {@code n}th root {@code floor(nthRoot(this, n))} and the remainder, |
| 1897 | + * where {@code nthRoot(., n)} denotes the mathematical {@code n}th root. |
| 1898 | + * The contents of {@code this} are <em>not</em> changed. The value of {@code this} |
| 1899 | + * is assumed to be non-negative and the root degree {@code n >= 3}. |
| 1900 | + * Assumes {@code bitLength() <= Integer.MAX_VALUE}. |
| 1901 | + * |
| 1902 | + * @implNote The implementation is based on the material in Richard P. Brent |
| 1903 | + * and Paul Zimmermann, <a href="https://maths-people.anu.edu.au/~brent/pd/mca-cup-0.5.9.pdf"> |
| 1904 | + * Modern Computer Arithmetic</a>, p. 27-28. |
| 1905 | + * |
| 1906 | + * @param n the root degree |
| 1907 | + * @return the integer {@code n}th root of {@code this} and the remainder |
| 1908 | + */ |
| 1909 | + MutableBigInteger[] nthRootRem(int n) { |
| 1910 | + // Special cases. |
| 1911 | + if (this.isZero() || this.isOne()) |
| 1912 | + return new MutableBigInteger[] { this, new MutableBigInteger() }; |
| 1913 | + |
| 1914 | + final int bitLength = (int) this.bitLength(); |
| 1915 | + // if this < 2^n, result is unity |
| 1916 | + if (bitLength <= n) { |
| 1917 | + MutableBigInteger rem = new MutableBigInteger(this); |
| 1918 | + rem.subtract(ONE); |
| 1919 | + return new MutableBigInteger[] { new MutableBigInteger(1), rem }; |
| 1920 | + } |
| 1921 | + |
| 1922 | + MutableBigInteger s; |
| 1923 | + if (bitLength <= Long.SIZE) { |
| 1924 | + // Initial estimate is the root of the unsigned long value. |
| 1925 | + final long x = this.toLong(); |
| 1926 | + long sLong = (long) nthRootApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L; |
| 1927 | + /* The integer-valued recurrence formula in the algorithm of Brent&Zimmermann |
| 1928 | + * simply discards the fraction part of the real-valued Newton recurrence |
| 1929 | + * on the function f discussed in the referenced work. |
| 1930 | + * Indeed, for real x and integer n > 0, the equality ⌊x/n⌋ == ⌊⌊x⌋/n⌋ holds, |
| 1931 | + * from which the claim follows. |
| 1932 | + * As a consequence, an initial underestimate (not discussed in BZ) |
| 1933 | + * will immediately lead to a (weak) overestimate during the 1st iteration, |
| 1934 | + * thus meeting BZ requirements for termination and correctness. |
| 1935 | + */ |
| 1936 | + if (BigInteger.bitLengthForLong(sLong) * (n - 1) <= Long.SIZE) { |
| 1937 | + // Do the 1st iteration outside the loop to ensure an overestimate |
| 1938 | + long sToN1 = BigInteger.unsignedLongPow(sLong, n - 1); |
| 1939 | + sLong = ((n - 1) * sLong + Long.divideUnsigned(x, sToN1)) / n; |
| 1940 | + |
| 1941 | + if (BigInteger.bitLengthForLong(sLong) * (n - 1) <= Long.SIZE) { |
| 1942 | + // Refine the estimate. |
| 1943 | + long u = sLong; |
| 1944 | + do { |
| 1945 | + sLong = u; |
| 1946 | + sToN1 = BigInteger.unsignedLongPow(sLong, n - 1); |
| 1947 | + u = ((n - 1) * sLong + Long.divideUnsigned(x, sToN1)) / n; |
| 1948 | + } while (u < sLong); // Terminate when non-decreasing. |
| 1949 | + |
| 1950 | + return new MutableBigInteger[] { |
| 1951 | + new MutableBigInteger(sLong), new MutableBigInteger(x - sToN1 * sLong) |
| 1952 | + }; |
| 1953 | + } |
| 1954 | + } |
| 1955 | + // s^(n - 1) could overflow long range, use MutableBigInteger loop instead |
| 1956 | + s = new MutableBigInteger(sLong); |
| 1957 | + } else { |
| 1958 | + final int rootLen = (bitLength - 1) / n + 1; // ⌈bitLength / n⌉ |
| 1959 | + int rootSh; |
| 1960 | + double rad = 0.0, approx = 0.0; |
| 1961 | + if (n < Double.PRECISION) { |
| 1962 | + // Set up the initial estimate of the iteration. |
| 1963 | + /* Since the following equality holds: |
| 1964 | + * nthRoot(x, n) == nthRoot(x/2^sh, n) * 2^(sh/n), |
| 1965 | + * |
| 1966 | + * to get an upper bound of the root of x, it suffices to find an integer sh |
| 1967 | + * and a real s such that s >= nthRoot(x/2^sh, n) and sh % n == 0. |
| 1968 | + * The upper bound will be s * 2^(sh/n), indeed: |
| 1969 | + * s * 2^(sh/n) >= nthRoot(x/2^sh, n) * 2^(sh/n) == nthRoot(x, n). |
| 1970 | + * To achieve this, we right shift the input of sh bits into finite double range, |
| 1971 | + * rounding up the result. |
| 1972 | + * |
| 1973 | + * The value of the shift sh is chosen in order to have the smallest number of |
| 1974 | + * trailing zeros in the double value of s after the significand (minimizing |
| 1975 | + * non-significant bits), to avoid losing bits in the significand. |
| 1976 | + */ |
| 1977 | + // Determine a right shift that is a multiple of n into finite double range. |
| 1978 | + rootSh = (bitLength - Double.PRECISION) / n; // rootSh < rootLen |
| 1979 | + /* Let x = this, P = Double.PRECISION, ME = Double.MAX_EXPONENT, |
| 1980 | + * bl = bitLength, sh = rootSh * n, ex = (bl - P) % n |
| 1981 | + * |
| 1982 | + * We have bl-sh = bl-((bl-P)-ex) = P + ex |
| 1983 | + * Since ex < n < P, we get P + ex ≤ ME, and so bl-sh ≤ ME. |
| 1984 | + * |
| 1985 | + * Recalling x < 2^bl: |
| 1986 | + * x >> sh < 2^(bl-sh) ≤ 2^ME < Double.MAX_VALUE |
| 1987 | + * Thus, rad ≤ 2^ME is in the range of finite doubles. |
| 1988 | + * |
| 1989 | + * Noting that ex ≥ 0, we get bl-sh = P + ex ≥ P |
| 1990 | + * which shows that x >> sh has at least P bits of precision, |
| 1991 | + * since bl-sh is its bit length. |
| 1992 | + */ |
| 1993 | + // Shift the value into finite double range |
| 1994 | + rad = this.toBigInteger().shiftRight(rootSh * n).doubleValue(); |
| 1995 | + |
| 1996 | + // Use the root of the shifted value as an estimate. |
| 1997 | + // rad ≤ 2^ME, so Math.nextUp(rad) < Double.MAX_VALUE |
| 1998 | + rad = Math.nextUp(rad); |
| 1999 | + approx = nthRootApprox(rad, n); |
| 2000 | + } else { // fp arithmetic gives too few correct bits |
| 2001 | + // Set the root shift to the root's bit length minus 1 |
| 2002 | + // The initial estimate will be 2^rootLen == 2 << (rootLen - 1) |
| 2003 | + rootSh = rootLen - 1; |
| 2004 | + } |
| 2005 | + |
| 2006 | + if (rootSh == 0) { |
| 2007 | + // approx has at most ⌈Double.PRECISION / n⌉ + 1 ≤ 19 integer bits |
| 2008 | + s = new MutableBigInteger((int) approx + 1); |
| 2009 | + } else { |
| 2010 | + // Allocate ⌈intLen / n⌉ ints to store the final root |
| 2011 | + s = new MutableBigInteger(new int[(intLen - 1) / n + 1]); |
| 2012 | + |
| 2013 | + if (n >= Double.PRECISION) { // fp arithmetic gives too few correct bits |
| 2014 | + // Set the initial estimate to 2 << (rootLen - 1) |
| 2015 | + s.value[0] = 2; |
| 2016 | + s.intLen = 1; |
| 2017 | + } else { |
| 2018 | + // Discard wrong integer bits from the initial estimate |
| 2019 | + // The reduced radicand rad has Math.getExponent(rad)+1 integer bits, but only |
| 2020 | + // the first Double.PRECISION leftmost bits are correct |
| 2021 | + // We scale the corresponding wrong bits of approx in the fraction part. |
| 2022 | + int wrongBits = ((Math.getExponent(rad) + 1) - Double.PRECISION) / n; |
| 2023 | + // Since rad <= 2^(bitLength - sh), then |
| 2024 | + // wrongBits <= ((bitLength - sh + 1) - Double.PRECISION) / n, |
| 2025 | + // so wrongBits is less than ⌈(bitLength - sh) / n⌉, |
| 2026 | + // the bit length of the exact shifted root, |
| 2027 | + // hence wrongBits + rootSh < ⌈(bitLength - sh) / n⌉ + rootSh == rootLen |
| 2028 | + rootSh += wrongBits; |
| 2029 | + approx = Math.scalb(approx, -wrongBits); |
| 2030 | + |
| 2031 | + // now approx has at most ⌈Double.PRECISION / n⌉ + 1 ≤ 19 integer bits |
| 2032 | + s.value[0] = (int) approx + 1; |
| 2033 | + s.intLen = 1; |
| 2034 | + } |
| 2035 | + |
| 2036 | + /* The Newton's recurrence roughly doubles the correct bits at each iteration. |
| 2037 | + * Instead of shifting the approximate root into the original range right now, |
| 2038 | + * we only double its bit length and then refine it with Newton's recurrence, |
| 2039 | + * using a suitable shifted radicand, in order to avoid computing and |
| 2040 | + * carrying trash bits in the approximate root. |
| 2041 | + * The shifted radicand is determined by the same reasoning used to get the |
| 2042 | + * initial estimate. |
| 2043 | + */ |
| 2044 | + // Refine the estimate to avoid computing non-significant bits |
| 2045 | + // rootSh is always less than rootLen, so correctBits >= 1 |
| 2046 | + for (int correctBits = rootLen - rootSh; correctBits < rootSh; correctBits <<= 1) { |
| 2047 | + s.leftShift(correctBits); |
| 2048 | + rootSh -= correctBits; |
| 2049 | + // Remove useless bits from the radicand |
| 2050 | + MutableBigInteger x = new MutableBigInteger(this); |
| 2051 | + x.rightShift(rootSh * n); |
| 2052 | + |
| 2053 | + newtonRecurrenceNthRoot(x, s, n, s.toBigInteger().pow(n - 1)); |
| 2054 | + s.add(ONE); // round up to ensure s is an upper bound of the root |
| 2055 | + } |
| 2056 | + |
| 2057 | + // Shift the approximate root back into the original range. |
| 2058 | + s.leftShift(rootSh); // Here rootSh > 0 always |
| 2059 | + } |
| 2060 | + } |
| 2061 | + |
| 2062 | + // Do the 1st iteration outside the loop to ensure an overestimate |
| 2063 | + newtonRecurrenceNthRoot(this, s, n, s.toBigInteger().pow(n - 1)); |
| 2064 | + // Refine the estimate. |
| 2065 | + do { |
| 2066 | + BigInteger sBig = s.toBigInteger(); |
| 2067 | + BigInteger sToN1 = sBig.pow(n - 1); |
| 2068 | + MutableBigInteger rem = new MutableBigInteger(sToN1.multiply(sBig).mag); |
| 2069 | + if (rem.subtract(this) <= 0) |
| 2070 | + return new MutableBigInteger[] { s, rem }; |
| 2071 | + |
| 2072 | + newtonRecurrenceNthRoot(this, s, n, sToN1); |
| 2073 | + } while (true); |
| 2074 | + } |
| 2075 | + |
| 2076 | + private static double nthRootApprox(double x, int n) { |
| 2077 | + return Math.nextUp(n == 3 ? Math.cbrt(x) : Math.pow(x, Math.nextUp(1.0 / n))); |
| 2078 | + } |
| 2079 | + |
| 2080 | + /** |
| 2081 | + * Computes {@code ((n-1)*s + x/sToN1)/n} and places the result in {@code s}. |
| 2082 | + */ |
| 2083 | + private static void newtonRecurrenceNthRoot( |
| 2084 | + MutableBigInteger x, MutableBigInteger s, int n, BigInteger sToN1) { |
| 2085 | + MutableBigInteger dividend = new MutableBigInteger(); |
| 2086 | + s.mul(n - 1, dividend); |
| 2087 | + MutableBigInteger xDivSToN1 = new MutableBigInteger(); |
| 2088 | + x.divide(new MutableBigInteger(sToN1.mag), xDivSToN1, false); |
| 2089 | + dividend.add(xDivSToN1); |
| 2090 | + dividend.divideOneWord(n, s); |
| 2091 | + } |
| 2092 | + |
1895 | 2093 | /**
|
1896 | 2094 | * Calculate the integer square root {@code floor(sqrt(this))} and the remainder
|
1897 | 2095 | * if needed, where {@code sqrt(.)} denotes the mathematical square root.
|
|
0 commit comments