реализация pow () в cmath и эффективная замена

Я читал, что cmath вычисляет pow(a,b), выполняя exp(b*log(a)). Это не должно использоваться, когда b является целым числом, так как это сильно замедляет вычисления. Какие есть альтернативы, когда

  1. вычисление множества последовательных pow() с одной и той же константой a
  2. заранее известно, что b определенно будет целым числом?

Я ищу быстрые альтернативы, которые эффективны в этих конкретных сценариях.


person Community    schedule 11.11.2014    source источник
comment
Я не уверен, что вы правы насчет pow. В некоторых реализациях он довольно хорошо оптимизирован.   -  person Basile Starynkevitch    schedule 11.11.2014
comment
В случае степени двойки вы можете просто использовать операции сдвига: 1 ‹* N означает 2 ^ N.   -  person sfrehse    schedule 11.11.2014
comment
1) Является ли b числом double с целым числом или b int? 2) Какого типа должен быть результат: double, int, `unsigned long long и т. Д.?   -  person chux - Reinstate Monica    schedule 11.11.2014
comment
@sfrehse a не является степенью 2 @ legends2k c ++ 11 @chux b is int, и результат используется для выполнения дальнейших вычислений с doubles   -  person    schedule 11.11.2014
comment
Вы читали, что он буквально выполняет эти вызовы функций? Или просто это имело такой же эффект? В любом случае см. en.wikipedia.org/wiki/Exponentiation_by_squaring   -  person Mike Seymour    schedule 11.11.2014


Ответы (3)


Есть несколько более быстрых альтернатив, которые я собрал на протяжении многих лет, которые обычно полагаются на recursive реализацию функции и битовые сдвиги для обработки умножения, когда это оправдано. Ниже представлены функции, адаптированные для integer, float и double. Они поставляются с нормальным disclaimer:, хотя быстрее не были запущены все возможные тесты, и пользователь должен проверять правильность ввода перед вызовом и при возврате ... бла, бла, бла ... Но они чертовски полезны:

Я считаю, что правильная атрибуция принадлежит Компьютерщики для компьютерных фанатов Pow (x, n), как указано синей луной. Давно потерял ссылки .. Вот похоже на них. (за вычетом одной или двух настроек).

/* Function to calculate x raised to the power y

    Time Complexity: O(n)
    Space Complexity: O(1)
    Algorithmic Paradigm: Divide and conquer.
*/
int power1 (int x, unsigned int y)
{
    if (y == 0)
        return 1;
    else if ((y % 2) == 0)
        return power1 (x, y / 2) * power1 (x, y / 2);
    else
        return x * power1 (x, y / 2) * power1 (x, y / 2);

}

/* Function to calculate x raised to the power y in O(logn)
    Time Complexity of optimized solution: O(logn)
*/
int power2 (int x, unsigned int y)
{
    int temp;
    if (y == 0)
        return 1;

    temp = power2 (x, y / 2);
    if ((y % 2) == 0)
        return temp * temp;
    else
        return x * temp * temp;
}

/* Extended version of power function that can work
for float x and negative y
*/
float powerf (float x, int y)
{
    float temp;
    if (y == 0)
    return 1;
    temp = powerf (x, y / 2);
    if ((y % 2) == 0) {
        return temp * temp;
    } else {
        if (y > 0)
            return x * temp * temp;
        else
            return (temp * temp) / x;
    }
}

/* Extended version of power function that can work
for double x and negative y
*/
double powerd (double x, int y)
{
    double temp;
    if (y == 0)
    return 1;
    temp = powerd (x, y / 2);
    if ((y % 2) == 0) {
        return temp * temp;
    } else {
        if (y > 0)
            return x * temp * temp;
        else
            return (temp * temp) / x;
    }
}
person David C. Rankin    schedule 11.11.2014
comment
Если это то место, откуда вы собрали, укажите, что . - person P.P; 11.11.2014
comment
Спасибо за подробный ответ, но я не вижу тех битовых сдвигов, о которых вы говорили ... - person ; 11.11.2014
comment
@BlueMoon Спасибо за ссылку. Похоже, откуда они пришли. На моем ящике они живут по адресу ~/dev/src-c/function/math/fn-power.c, и исходные ссылки были потеряны с течением времени. Я добавил атрибуцию. - person David C. Rankin; 11.11.2014
comment
@Pickle - Должно быть, я думал о другом наборе, где умножение меньше 10 было разбито на соответствующую комбинацию shifts + adds. Не вижу этого в тезисах. - person David C. Rankin; 11.11.2014
comment
power1() не имеет пространственной сложности O(1), но O(log y) (обратите внимание, что глубина рекурсии такая же, как и в случае power2()). И временная сложность power1() намного хуже, чем указано; это скорее O(log^2 y), поэтому его вообще не следует использовать: power2() - это более оптимизированная версия power1(), гарантирующая, что одно и то же не вычисляется дважды (для каждой рекурсии), что делает его O(log y). Для больших y это действительно имеет большое значение. (Верно, что сегодняшние компиляторы могут быть достаточно умны, чтобы сделать оптимизацию за вас, но я бы все еще не полагался на это.) - person mity; 05.03.2018

Нерекурсивный ответ с плавающей запятой

Замени uintmax_t/intmax_t на тип своего желания. Переполнения не обнаружено.

uintmax_t powjuu(unsigned x, unsigned y) {
  uintmax_t z = 1;
  uintmax_t base = x;
  while (y) {
    if (y & 1) {  // or y%2
      z *= base;
    }
    y >>= 1; // or y /= 2
    base *= base;
  }
  return z;
}

intmax_t powjii(int x, int y) {
  if (y < 0) {
    switch (x) {
      case 0:
        return INTMAX_MAX;
      case 1:
        return 1;
      case -1:
        return y % 2 ? -1 : 1;
    }
    return 0;
  }
  intmax_t z = 1;
  intmax_t base = x;
  while (y) {
    if (y & 1) {
      z *= base;
    }
    y >>= 1;
    base *= base;
  }
  return z;
}
person chux - Reinstate Monica    schedule 11.11.2014
comment
это возвращенные результаты pow очень быстро, и я могу настроить его в соответствии с моими требованиями, например, добавить модуль к результату pow - person psaraj12; 07.06.2021
comment
@ psaraj12 Чтобы выполнить pow(a,b) mod c полный диапазон, см. Модульное возведение в степень без ограничения диапазона. - person chux - Reinstate Monica; 07.06.2021

Вы можете проверить это. Это быстрый алгоритм замены функции pow.

person Iulian Popescu    schedule 11.11.2014