Pow для интегральных значений

Мне нужна версия pow для целых чисел. У меня есть 2 проблемы, которые мне нужно решить с pow:

  1. Если результат больше моего целочисленного типа, мне нужно numeric_limits::max()
  2. Я должен быть в состоянии справиться с 41.99999 округления до 42, а не до 41

Предоставляет ли мне C ++ какое-то встроенное решение здесь, или я застрял в написании своей собственной функции:

template <typename T>
enable_if_t<is_integral_v<T>, T> mypow(const T base, unsigned int exp) {
T result = exp == 0U ? base : 1;

while(exp-- > 1U) {
if(numeric_limits<T>::max() / result <= base) return numeric_limits<T>::max();
result *= base;
}
return result;
}

6

Решение

C ++ предоставляет мне какое-то встроенное решение здесь

Нет, нет целого числа pow в стандартной библиотеке.

или я застрял писать свою собственную функцию

Да, вы можете написать свою собственную функцию. Обратите внимание, что показанный цикл умножения может быть медленнее, чем при использовании std::pow реализовать функцию, тем более что у вас также есть ветвление и деление в цикле:

template<class I>
I int_pow_no_overflow(I base, I exp)
{
double max = std::numeric_limits<I>::max();
double result = std::round(std::pow(base, exp));
return result >= max
? max
: result;
}

Для более общего подхода, возможно, вы захотите рассмотреть и недостаток.

Есть и другие, более быстрые алгоритмы (см., Например, Возведение в степень по квадрату) для целочисленного возведения в степень, отличного от показанного вами линейного, но я не уверен, стоит ли их рассматривать, если вы не имеете дело с арифметикой произвольной точности или со встроенной системой без единицы с плавающей запятой.

3

Другие решения

Ваш код не скомпилирован, вы должны, если возможно, сначала проверить код, скомпилировать его, или сначала проверить его в проводнике компилятора.

Также вы забыли учесть отрицательные значения. Это очень важная особенность интегральных сил. Код ниже для обычного типа int. Я позволю вам изучить, как вы могли бы расширить его для других целочисленных типов.

#include <type_traits>
#include <iostream>
#include <cmath>
#include <limits>

using namespace std;

template <typename T>
enable_if_t< is_integral<T>::value, T>
mypow(T base, unsigned int exp)
{
T result = T(1);
bool sign = (base < 0);

if (sign) base = -base;

T temp = result;
while(exp-- != 0)
{
temp *= base;
if (temp < result)
{
return (sign) ? numeric_limits<T>::min()
: numeric_limits<T>::max();
}
result = temp;
}
return (sign && (exp & 1)) ? -result : result;
}

template <typename T>
enable_if_t< !is_integral<T>::value, int>
mypow(const T& base, unsigned int exp)
{
T result = T(1);
int i_base = int(floor(base + .5));
bool sign = (i_base < 0);

if (sign) i_base = -i_base;

int temp = result;
while(exp-- != 0)
{
temp *= i_base;
if (temp < result)
{
return (sign) ? numeric_limits<int>::min() : numeric_limits<int>::max();
}
result = temp;
}
return (sign && (exp & 1)) ? -result : result;
}

В реальной жизни я бы сделал это замечание об использовании пола даже в интегральном случае.

  template<typename T>
enable_if_t< is_integral<T>::value, T>
mypow(T x, unsigned int y) { return T(floor(pow(x, y) + .5)); }

template<typename T>
enable_if_t< !is_integral<T>::value, int>
mypow(T x, unsigned int y) { return int(floor(pow(floor(x + .5), y) + .5)); }
2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector