2017-06-15 66 views
6

我需要整数的pow版本。我有2个问题,我需要pow解决:pow for Integral Values

  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; 
} 
+0

你不能使用['std :: pow'](http://en.cppreference.com/w/cpp/numeric/math/pow)并截断结果,如果需要? – NathanOliver

+0

@NathanOliver是啊...如果有一种方法可以保证** 1 **和** 2 **不会被违反。有没有办法做到这一点? –

+0

您可以使用尾递归和某些数字欺骗来提高运行时性能。此外,你可以使这个方法constexpr。 https://stackoverflow.com/questions/9348933/using-recursion-to-raise-a-base-to-its-exponent-c – Andrew

回答

3

不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; 
} 

对于一个更通用的方法,你可能要考虑下溢好。

有以及其他,更快的算法(参见例如通过平方幂)为整数的指数比线性的,你表现,但我不能确定,除非你处理任意精度是否会是值得考虑他们算术或者没有浮点单元的嵌入式系统。

+0

如果你有更好的方法来避免截断并使用'pow'进行钳位都在耳边。我得到的是我能想到的最好,而且非常昂贵。 –

+0

为什么你需要通用编程? –

+1

@JonathanMee作为线索,N^8 = N^4 * N^4所以你不需要两次计算N^4。 –

2

你的代码没有编译,你应该尽可能先检查你的代码编译,使用你的编译器,或者先在编译器资源管理器上检查它。

此外,你忘了考虑负值。这是整体力量的一个非常重要的特征。下面的代码是针对普通的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)); } 
+0

我只是以此为例,但是,这是另一个我不想写自己的功能的原因:( –

+0

在支持浮点操作的CPU上使用浮点数pow通常会更快一些。现代的CPU有一个浮点pow指令。 –

+1

@JonathanMee:也许你应该检查这个主题的有趣的讨论:https://stackoverflow.com/questions/101439/the-most-efficient-way-to-implement-an -integer-based-power-function-powint-int –