From f99d5a8356b4762b13397a5a796626d0ddb71566 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Thu, 9 Nov 2023 00:38:01 -0800 Subject: [PATCH] Add integer square root to SCMP. --- CMakeLists.txt | 2 +- include/scmp/Math.h | 7 +++++++ src/scmp/Math.cc | 32 ++++++++++++++++++++++++++++++++ test/math.cc | 30 ++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 427d0a0..a1b973d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.22) project(scsl LANGUAGES CXX - VERSION 1.1.3 + VERSION 1.1.4 DESCRIPTION "Shimmering Clarity Standard Library") set(CMAKE_CXX_STANDARD 14) diff --git a/include/scmp/Math.h b/include/scmp/Math.h index 72f9cba..34f2115 100644 --- a/include/scmp/Math.h +++ b/include/scmp/Math.h @@ -115,6 +115,13 @@ WithinTolerance(T a, T b, T epsilon) } +/// \brief Integer square-root. +/// +/// \param n A max-value integer whose square root should be returned. +/// \return The square root of $n$. +size_t ISqrt(size_t n); + + } // namespace scmp diff --git a/src/scmp/Math.cc b/src/scmp/Math.cc index 738cf16..15318b6 100644 --- a/src/scmp/Math.cc +++ b/src/scmp/Math.cc @@ -151,5 +151,37 @@ DefaultEpsilon(int& epsilon) } +size_t +ISqrt(size_t n) +{ + if (n < 2) { + return n; + } + + size_t start = 0; + size_t end = n / 2; + size_t result = 0; + + while (start <= end) { + auto middle = (start + end) >> 1; + result = middle * middle; + if (result == n) { + return middle; + } + + if (result < n) { + start = middle + 1; + result = middle; + } else { + end = middle - 1; + result = middle; + } + } + + return result; +} + + + } // namespace scmp diff --git a/test/math.cc b/test/math.cc index 44710e2..70df65b 100644 --- a/test/math.cc +++ b/test/math.cc @@ -116,6 +116,35 @@ RotateRadians() } +bool +IntegerSquareRoot() +{ + static std::vector ns{ + // standard integer roots + 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, + + // a few float cases + 42, 90, 92 + }; + static std::vector expected{ + // standard integer roots + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + + // a few float cases + 6, 9, 10 + }; + + SCTEST_CHECK_EQ(ns.size(), expected.size()); + + for (size_t i = 0; i < ns.size(); i++) { + auto root = scmp::ISqrt(ns.at(i)); + SCTEST_CHECK_EQ(root, expected.at(i)); + } + + return true; +} + + } // anonymous namespace @@ -148,6 +177,7 @@ main(int argc, char *argv[]) suite.AddTest("WithinToleranceFloat", WithinToleranceFloat); suite.AddTest("WithinToleranceDouble", WithinToleranceDouble); suite.AddTest("RotateRadians", RotateRadians); + suite.AddTest("IntegerSquareRoot", IntegerSquareRoot); delete flags; auto result = suite.Run();