HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Compile time integer square root for large numbers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
compilenumberstimelargerootforsquareinteger

Problem

This computes the integer square root at compile time for any \$0 \le N \le L\$ where \$L\$ is the largest integral representation of template parameter T.

This was motivated by the fact that many of the algorithms I found were not able to handle large values of \$N\$. I also just wanted to practice template meta-programming.

Important: I cannot simply declare the runtime algorithm as a constexpr function because my compiler does not allow it.

The implementation is based on this runtime algorithm:

template 
T rt_square_root( T num )
{
    T bit{ static_cast( 1 )  num )
        bit >>= 2;

    T res{ 0 };
    while ( bit )
    {
        T delta{ res + bit };
        if ( num >= delta )
        {
            num -= delta;
            res = ( res >> 1 ) + bit;
        }
        else
        {
            res >>= 1;
        }
        bit >>= 2;
    }
    return res;
}


Source

square_root.h

Template meta-programming based implementation of the algorithm:

#ifndef CR_SQUARE_ROOT_H
#define CR_SQUARE_ROOT_H

namespace ct
{
    template 
    bool constexpr greater( T a, U b )
    {
        return b 
    class calc_shifted_bit
    {
    private:
        static T constexpr shifted_bit = bit >> 2;

    public:
        static T constexpr result = calc_shifted_bit::result;
    };

    template 
    class calc_shifted_bit
    {
    public:
        static T constexpr result = bit 
    class calc_sqrt
    {
    private:
        static T constexpr delta = res + bit;
        static bool constexpr num_gt_delta = num >= delta;

    public:
        static T constexpr result = calc_sqrt
            > 1 ) + bit : ( res >> 1 ),
            ( bit >> 2 )
            >::result;
    };

    template 
    class calc_sqrt>
    {
    public:
        static T constexpr result = res;
    };

    template 
    struct sqrt
    {
        static T constexpr result =
            calc_sqrt
            ( 1 ) ::result
            >::result;
    };
}


main.cpp

Some tests, compilati

Solution

Since you're on a C++14 compiler, the simplest solution is just to stick constexpr in front of your runtime algorithm:

template 
constexpr T rt_square_root(T num)
{
    /* exact same code as before */
}

static_assert( rt_square_root(N_1 * N_1) == N_1, "bad square root" );


I'm not sure there's a compelling reason to do it any other way.

Code Snippets

template <typename T>
constexpr T rt_square_root(T num)
{
    /* exact same code as before */
}

static_assert( rt_square_root(N_1 * N_1) == N_1, "bad square root" );

Context

StackExchange Code Review Q#109604, answer score: 3

Revisions (0)

No revisions yet.