// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // IntSqrt.hpp // Integer square root, n-th root, and perfect-power detection // // Algorithms: // - sqrt: mpn-level Newton method (double precision for small values) // - sqrtRem: compute square root and remainder simultaneously // - nthRoot: n-th root computation via precision-doubling Newton method // - nthRootRem: compute n-th root and remainder simultaneously // - isSquare: GMP-style 3-layer filter (mod 256 + mod_34lsub1 + sqrtRem) // // References: // - Brent & Zimmermann, "Modern Computer Arithmetic", section 1.5.2 // - GMP: mpz_sqrt, mpz_sqrtrem, mpz_root, mpz_rootrem, mpz_perfect_square_p #ifndef SANGI_INT_SQRT_HPP #define SANGI_INT_SQRT_HPP #include "IntBase.hpp" #include namespace sangi { class IntSqrt { public: // Integer square root (floor(sqrt(value))) // Special states: NaN -> NaN, negative -> NaN (NegativeSqrt), +inf -> +inf, 0 -> 0 // Algorithm: chosen automatically by size // - MSB < 52: computed in double precision (exact) // - otherwise: mpn-level Newton method static Int sqrt(const Int& value); // Return square root and remainder: value = sqrt^2 + remainder // remainder always satisfies 0 <= remainder < 2*sqrt + 1 // GMP compatible: mpz_sqrtrem static Int sqrtRem(const Int& value, Int& remainder); // Perfect-square check. // If pSqrt != nullptr, the square root is stored in *pSqrt. // Acceleration: GMP-style 3-layer filter (mod 256, mod_34lsub1, sqrtRem) // GMP compatible: mpz_perfect_square_p static bool isSquare(const Int& value, Int* pSqrt = nullptr); // N-th root (floor(value^(1/n))) // Special states: NaN -> NaN, n<=0 -> NaN, negative with even n -> NaN, +inf -> +inf, 0 -> 0 // Algorithm: precision-doubling Newton + remainder tracking // x_{k+1} = ((n-1)*x_k + value/x_k^(n-1)) / n // GMP compatible: mpz_root static Int nthRoot(const Int& value, uint32_t n); // Return n-th root and remainder: value = root^n + remainder // remainder always satisfies 0 <= remainder // GMP compatible: mpz_rootrem static Int nthRootRem(const Int& value, uint32_t n, Int& remainder); // Perfect-power check: does there exist k such that value = b^k (k >= 2)? // Returns true if it exists, and stores b in pBase if pBase != nullptr. // Algorithm: try k = 2..bitLength, verify with nthRoot. static bool isPerfectPower(const Int& value, Int* pBase = nullptr, uint32_t* pExp = nullptr); private: // Compute square root in double precision (for MSB < 52 bits) static Int sqrt_small(const Int& value); // Unified implementation of n-th root + optional remainder. // If pRemainder != nullptr, stores value - root^n into *pRemainder. // Since the verification block already computes R = value - x^n, this // eliminates the duplicate pow(root, n) call that nthRootRem would otherwise // perform (PLAN_NTHROOT_FOLLOWUP candidate A, follow-up to commit 4f86e68). static Int nthRoot_internal(const Int& value, uint32_t n, Int* pRemainder); }; } // namespace sangi #endif // SANGI_INT_SQRT_HPP