From dd8509fb3fb8f5df6f86d99df354c29c013d2e25 Mon Sep 17 00:00:00 2001 From: Rose <83477269+AtariDreams@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:32:34 -0400 Subject: [PATCH] Simplify calculations of the nearest power of 2 Use compiler intrinsics to find the nearest power of 2 as quickly as possible. In addition, handle the 0 case, so that the program does not become stuck in an infinite loop if iNum is 0. --- src/CalcManager/CEngine/sciset.cpp | 31 ++++++----------------- src/CalcManager/Header Files/CalcEngine.h | 4 +-- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/CalcManager/CEngine/sciset.cpp b/src/CalcManager/CEngine/sciset.cpp index 57aeda3bd..7d7e5cc3a 100644 --- a/src/CalcManager/CEngine/sciset.cpp +++ b/src/CalcManager/CEngine/sciset.cpp @@ -50,7 +50,7 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidt DisplayNum(); } -int32_t CCalcEngine::DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth) +uint32_t CCalcEngine::DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth) { switch (numwidth) { @@ -103,30 +103,15 @@ bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno) } // Returns the nearest power of two -int CCalcEngine::QuickLog2(int iNum) +unsigned int CCalcEngine::QuickLog2(unsigned int iNum) { - int iRes = 0; + // Nearest power of 2 to 0 is 1 + if (!iNum) + return 1; - // while first digit is a zero - while (!(iNum & 1)) - { - iRes++; - iNum >>= 1; - } - - // if our number isn't a perfect square - iNum = iNum >> 1; - if (iNum) - { - // find the largest digit - for (iNum = iNum >> 1; iNum; iNum = iNum >> 1) - ++iRes; - - // and then add two - iRes += 2; - } - - return iRes; + // Count the number of leading 0's of iNum - 1, + // and then shift 1 by that amount + return 1U << (32 - __builtin_clz(iNum - 1)); } //////////////////////////////////////////////////////////////////////// diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/Header Files/CalcEngine.h index f387c020a..9c012be45 100644 --- a/src/CalcManager/Header Files/CalcEngine.h +++ b/src/CalcManager/Header Files/CalcEngine.h @@ -179,7 +179,7 @@ class CCalcEngine CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op); CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs); void SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidth); - int32_t DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth); + uint32_t DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth); uint32_t NRadixFromRadixType(RadixType radixtype); double GenerateRandomNumber(); @@ -199,7 +199,7 @@ class CCalcEngine static std::vector DigitGroupingStringToGroupingVector(std::wstring_view groupingString); std::wstring GroupDigits(std::wstring_view delimiter, std::vector const& grouping, std::wstring_view displayString, bool isNumNegative = false); - static int QuickLog2(int iNum); + static unsigned int QuickLog2(unsigned int iNum); static void ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision); void BaseOrPrecisionChanged();