Как вы делаете* integer * возведение в степень в C#?
встроенный Math.Pow()
функция в .NET вызывает double
базовый double
экспонента и возвращает double
результат.
как лучше всего сделать то же самое с целыми числами?
добавил: кажется, что можно просто бросить Math.Pow()
result to (int), но всегда ли это приведет к правильному числу и без ошибок округления?
10 ответов
довольно быстро, может быть что-то вроде этого:
int IntPow(int x, uint pow)
{
int ret = 1;
while ( pow != 0 )
{
if ( (pow & 1) == 1 )
ret *= x;
x *= x;
pow >>= 1;
}
return ret;
}
обратите внимание, что это не дает негативных сил. Я оставлю это тебе в качестве упражнения. :)
добавлено: О да, почти забыл - также добавьте проверку переполнения / underflow, или вы можете получить несколько неприятных сюрпризов по дороге.
LINQ кто-нибудь?
public static int Pow(this int bas, int exp)
{
return Enumerable
.Repeat(bas, exp)
.Aggregate(1, (a, b) => a * b);
}
использование в качестве расширения:
var threeToThePowerOfNine = 3.Pow(9);
используя математику в блоге Джона Кука,
public static long IntPower(int x, short power)
{
if (power == 0) return 1;
if (power == 1) return x;
// ----------------------
int n = 15;
while ((power <<= 1) >= 0) n--;
long tmp = x;
while (--n > 0)
tmp = tmp * tmp *
(((power <<= 1) < 0)? x : 1);
return tmp;
}
для решения возражения, что код не будет работать, если вы измените тип питания, хорошо... оставляя в стороне тот момент, что любой, кто меняет код, он не понимает, а затем использует его без тестирования.....
но чтобы решить эту проблему, эта версия защищает глупцов от этой ошибки... (Но не от множества других, которые они могли бы сделать) примечание: не проверено.
public static long IntPower(int x, short power)
{
if (power == 0) return 1;
if (power == 1) return x;
// ----------------------
int n =
power.GetType() == typeof(short)? 15:
power.GetType() == typeof(int)? 31:
power.GetType() == typeof(long)? 63: 0;
long tmp = x;
while (--n > 0)
tmp = tmp * tmp *
(((power <<= 1) < 0)? x : 1);
return tmp;
}
также попробуйте этот рекурсивный эквивалент (медленнее, конечно):
public static long IntPower(long x, int power)
{
return (power == 0) ? x :
((power & 0x1) == 0 ? x : 1) *
IntPower(x, power >> 1);
}
здесь блоге это объясняет самый быстрый способ поднять целые числа до целочисленных степеней. Как указывает один из комментариев, некоторые из этих трюков встроены в чипы.
лолз, как насчет:
public static long IntPow(long a, long b)
{
long result = 1;
for (long i = 0; i < b; i++)
result *= a;
return result;
}
используйте двойную версию, проверите для переполнения (над максимальным инт или максимальным длинным) и бросьте к инт или длиной?
мое любимое решение этой проблемы-классическое рекурсивное решение divide and conquer. На самом деле это быстрее, чем умножение n раз, поскольку оно уменьшает количество умножений в два раза каждый раз.
public static int Power(int x, int n)
{
// Basis
if (n == 0)
return 1;
else if (n == 1)
return x;
// Induction
else if (n % 2 == 1)
return x * Power(x*x, n/2);
return Power(x*x, n/2);
}
Примечание: это не проверяет переполнение или отрицательное n.
больше двух...
public static int FastPower(int x, int pow)
{
switch (pow)
{
case 0: return 1;
case 1: return x;
case 2: return x * x;
case 3: return x * x * x;
case 4: return x * x * x * x;
case 5: return x * x * x * x * x;
case 6: return x * x * x * x * x * x;
case 7: return x * x * x * x * x * x * x;
case 8: return x * x * x * x * x * x * x * x;
case 9: return x * x * x * x * x * x * x * x * x;
case 10: return x * x * x * x * x * x * x * x * x * x;
case 11: return x * x * x * x * x * x * x * x * x * x * x;
// up to 32 can be added
default: // Vilx's solution is used for default
int ret = 1;
while (pow != 0)
{
if ((pow & 1) == 1)
ret *= x;
x *= x;
pow >>= 1;
}
return ret;
}
}
public static int SimplePower(int x, int pow)
{
return (int)Math.Pow(x, pow);
}
Я провел быстрое тестирование производительности
Мини-Я : 32 МС
Sunsetquest (быстро): 37 МС
Vilx: 46 ms
Чарльз Бретана (он же Кук): 166 МС
Sunsetquest(простой): 469 МС
3dGrabber (по LINQ версия): 868 ms
(примечания по тестированию: intel i7 2nd gen, .net 4, Сборка выпуска, запуск выпуска, 1M различных баз, exp от 0-10 только)
вывод: mini-me является лучшим как в производительности, так и в простоте
очень минимальное испытание точности было сделано
Я бросил результат в int, например:
double exp = 3.0;
int result = (int)Math.Pow(2.0, exp);
в этом случае нет ошибок округления, потому что база и Экспонента являются целыми. Результат тоже будет целочисленным.
для короткого быстрого ОДН-вкладыша.
int pow(int i, int exp) => (exp == 0) ? 1 : i * pow(i, exp-1);
нет отрицательных показателей или проверок переполнения.