#Compile-time exponentiation

10 messages · Page 1 of 1 (latest)

cyan nest
#

Sorry for the wall of text, but I am looking for potential improvements on this code. I don't like how difficult it is to read, I can only imagine it's worse if you didn't write it :/

#include <limits>
#include <stdexcept>

template<typename T>
class Number
{
private:
    T value;

    constexpr T check_overflow(const T x, const T y) const
    {
        if (std::numeric_limits<T>::is_signed)
            if ((x > 0 && (y > std::numeric_limits<T>::max() / x || y < std::numeric_limits<T>::min() / x)) ||
                (x < 0 && (y > 0 && x < std::numeric_limits<T>::min() / y) ||
                (y < 0 && x > std::numeric_limits<T>::max() / y)))
                    throw std::overflow_error("Overflow during multiplication");

        if (x > std::numeric_limits<T>::max() / y)
            throw std::overflow_error("Overflow during multiplication");
    
        return x * y;
    }
    
public:
    consteval Number(const T n) : value(n) {}

    constexpr T operator^(const T exp) const
    {
        if (exp < 0)
        {
            return (exp == 0)
                ? 1
                : 1.0 / (*this ^ -exp);
        }

        return (exp == 0)
            ? 1
            : check_overflow(this->value, ((*this) ^ (exp - 1)));
    }
};```
It's essentially a class that aids in simpler exponential calculation, all done in the compilation process to avoid runtime overhead.
#

I am also open to people pointing out potential bugs, especially with the check_overflow function, which is very confusing to read and debug

snow tartan
#

you can throw at compile time?

#
constexpr T operator^(const T exp) const {
        if (exp < 0)
                return 1.0 / (*this ^ -exp);

        return (exp == 0)
            ? 1
            : check_overflow(this->value, ((*this) ^ (exp - 1)));
    }
#

isn't this cleaner?

#

also, do you really need to pass a member variable to a member function? seems redudant...

cyan nest
cyan nest
cyan nest
#
#include <limits>
#include <stdexcept>
#include <iostream>

template<typename T>
class Number
{
private:
    T value;

    consteval T check_overflow(const T x, const T y) const
    {
        if (std::numeric_limits<T>::is_signed)
            if ((x > 0 && (y > std::numeric_limits<T>::max() / x || y < std::numeric_limits<T>::min() / x)) ||
                (x < 0 && (y > 0 && x < std::numeric_limits<T>::min() / y) ||
                (y < 0 && x > std::numeric_limits<T>::max() / y)))
                    throw std::overflow_error("Overflow during multiplication");

        if (x > std::numeric_limits<T>::max() / y)
            throw std::overflow_error("Overflow during multiplication");
    
        return x * y;
    }
    
public:
    consteval Number(const T n) : value(n) {}

    consteval T operator^(const T exp) const
    {
        if (exp < 0)
            return 1.0 / (*this ^ -exp);

        return (exp == 0)
            ? 1
            : check_overflow(this->value, ((*this) ^ (exp - 1)));
    }
};

int main()
{
    constexpr Number<long> d(2);
    std::cout << "32 bit signed integer limit: " << (d ^ 31) - 1 << '\n';
}```
#

This is probably as good as it's going to get, as long as it's me writing the code