Как возвести число в степень в C#
В C# нет оператора степени: символ ^ здесь означает побитовое исключающее ИЛИ, поэтому 2 ^ 3 даёт 1, а не 8. Возвести число в степень можно через Math.Pow, обычный цикл, быстрое бинарное возведение или BigInteger.Pow для больших чисел. Ниже разобраны все способы, их точность, скорость и типичные ошибки.

Содержание
Почему ^ не работает как степень
Выходцы из математики и Excel привыкли писать 2^10, но в C# этот символ обозначает XOR. Компилятор не выдаст ошибку, программа просто посчитает другое число, и баг найти сложно. Для степени в языке нет специального оператора, вместо него используются методы библиотеки и собственные функции.
Console.WriteLine(2 ^ 3); // 1, это XOR двоичных чисел 010 и 011
Console.WriteLine(Math.Pow(2, 3)); // 8Для самых частых случаев вроде квадрата и куба методы не нужны: x * x и x * x * x короче, быстрее и не требуют преобразования типов. Метод имеет смысл, когда показатель степени задан переменной, дробный или отрицательный.
Метод Math.Pow
Основной инструмент находится в классе System.Math. Сигнатура: double Math.Pow(double x, double y), где x - основание, а y - показатель. Оба аргумента и результат имеют тип double, поэтому целые числа подставляются без явного приведения, а вот результат в int нужно приводить вручную.
double baseNumber = 2;
double exponent = 10;
double result = Math.Pow(baseNumber, exponent);
Console.WriteLine(result); // 1024
int squared = (int)Math.Pow(7, 2); // 49
Console.WriteLine(squared);
Console.WriteLine(Math.Pow(2, -2)); // 0.25
Console.WriteLine(Math.Pow(9, 0.5)); // 3, то же, что квадратный корень
Console.WriteLine(Math.Pow(27, 1.0 / 3)); // около 3, кубический кореньМетод умеет работать с отрицательными и дробными показателями, поэтому им же извлекают корни. Для квадратного корня удобнее Math.Sqrt, для кубического есть Math.Cbrt. Подробнее об остальных функциях класса рассказано в статье про математические функции в C#.
Особые значения и граничные случаи
Метод не бросает исключений, а возвращает специальные значения double. Это важно помнить, если степень вычисляется по данным пользователя: ошибка проявится не падением программы, а странным числом в отчёте.
| Вызов | Результат | Пояснение |
|---|---|---|
Math.Pow(0, 0) | 1 | по соглашению любое число в нулевой степени равно 1 |
Math.Pow(0, -1) | Infinity | деление на ноль в вещественной арифметике |
Math.Pow(-8, 1.0 / 3) | NaN | дробная степень отрицательного числа не определена |
Math.Pow(10, 400) | Infinity | переполнение диапазона double |
Math.Pow(double.NaN, 0) | 1 | нулевая степень даёт 1 даже для NaN |
Проверять результат можно через double.IsNaN и double.IsInfinity. Если вы получаете NaN там, где ждали число, сначала посмотрите на знак основания и на дробность показателя.
Точность и целые результаты
Результат Math.Pow вычисляется в двоичной арифметике с плавающей точкой, поэтому для небольших целых степеней он обычно точен, а для больших значений начинаются погрешности. Тип double хранит целые числа без потерь только до 2 в 53-й степени, то есть примерно до 9 квадриллионов. Всё, что больше, будет округлено. Причины такого поведения разобраны в материале про неточность вещественной арифметики.
double big = Math.Pow(3, 40);
Console.WriteLine(big); // 1.2157665459056929E+19, значение уже приблизительное
Console.WriteLine((long)Math.Round(Math.Pow(10, 15))); // 1000000000000000Если нужно целое число, не обрезайте результат приведением сразу: значение вроде 24.999999999 превратится в 24. Сначала округлите через Math.Round, затем приводите к long. А если результат может выйти за 2 в 53-й степени, лучше вовсе уйти от double и использовать целочисленные алгоритмы или BigInteger.
Возведение в степень циклом
Самый наглядный способ для целых чисел - перемножать основание нужное число раз. Он не использует вещественную арифметику, поэтому результат точен, пока не случится переполнение. Чтобы переполнение не осталось незамеченным, оберните умножение в checked, тогда вместо молчаливо искажённого числа вы получите OverflowException.
static long PowLoop(long value, int exponent)
{
if (exponent < 0)
throw new ArgumentOutOfRangeException(nameof(exponent), "Показатель должен быть неотрицательным");
long result = 1;
for (int i = 0; i < exponent; i++)
{
result = checked(result * value);
}
return result;
}
Console.WriteLine(PowLoop(2, 10)); // 1024
Console.WriteLine(PowLoop(5, 3)); // 125Недостаток очевиден: число операций равно показателю. Для степени 10 это мелочь, для миллиарда - вечность. Здесь помогает приём, который сокращает количество умножений до логарифма.
Бинарное возведение в степень
Идея в том, что любую степень можно разложить по двоичным разрядам показателя. Например, x в 13-й равно x в 8-й, умноженному на x в 4-й и на x в первой, ведь 13 = 8 + 4 + 1. Алгоритм по очереди возводит основание в квадрат и перемножает те квадраты, которым соответствует единичный бит показателя. Вместо 13 умножений получается около шести.
static long BinaryPow(long value, long exponent)
{
long result = 1;
while (exponent > 0)
{
if ((exponent & 1) == 1)
result = checked(result * value);
exponent >>= 1;
if (exponent > 0)
value = checked(value * value);
}
return result;
}
Console.WriteLine(BinaryPow(2, 30)); // 1073741824
Console.WriteLine(BinaryPow(3, 13)); // 1594323Проверка exponent > 0 перед последним возведением основания в квадрат нужна, чтобы не получить ложное переполнение на ненужном шаге. Без неё BinaryPow(3, 39) упадёт, хотя результат в long помещается.
Степень по модулю
В олимпиадных задачах и криптографии часто требуется остаток от деления степени на число, например 7 в 1000000-й по модулю 1000000007. Считать саму степень бессмысленно, она огромна. Достаточно брать остаток после каждого умножения. Все промежуточные значения остаются меньше модуля, поэтому произведение двух таких чисел помещается в long, пока модуль не превышает примерно 3 миллиарда.
static long ModPow(long value, long exponent, long modulus)
{
long result = 1;
value %= modulus;
while (exponent > 0)
{
if ((exponent & 1) == 1)
result = result * value % modulus;
value = value * value % modulus;
exponent >>= 1;
}
return result;
}
Console.WriteLine(ModPow(7, 1_000_000, 1_000_000_007));BigInteger.Pow для больших чисел
Когда результат не влезает в long, подключайте пространство имён System.Numerics. Структура BigInteger хранит целое произвольной длины, а статический метод BigInteger.Pow(BigInteger, int) возводит его в степень без потери точности. Показатель здесь типа int. Для степени по модулю есть готовый BigInteger.ModPow, и писать собственную реализацию обычно не нужно.
using System.Numerics;
BigInteger big = BigInteger.Pow(2, 200);
Console.WriteLine(big);
// 1606938044258990275541962092341162602522202993782792835301376
BigInteger mod = BigInteger.ModPow(7, 1_000_000, 1_000_000_007);
Console.WriteLine(mod);
BigInteger huge = BigInteger.Pow(new BigInteger(12345), 20);
Console.WriteLine(huge.ToString().Length); // количество цифр результатаЦена - скорость и память: операции с BigInteger заметно медленнее аппаратных. Использовать его стоит там, где точность важнее, например в криптографии, факториалах или задачах на длинную арифметику.
Степень для decimal и других типов
Для decimal метода Math.Pow нет: перегрузки принимают только double. Если показатель целый и небольшой, пишите цикл или бинарный алгоритм на decimal, так вы сохраните десятичную точность, нужную в финансах. Например, сложный процент считается как сумма, умноженная на коэффициент в степени числа периодов. О выборе между типами подробно рассказано в статье decimal против double.
static decimal PowDecimal(decimal value, int exponent)
{
decimal result = 1m;
for (int i = 0; i < Math.Abs(exponent); i++)
result *= value;
return exponent >= 0 ? result : 1m / result;
}
decimal deposit = 100_000m;
decimal rate = 1.07m;
Console.WriteLine(deposit * PowDecimal(rate, 5)); // сумма через 5 лет при 7% годовыхНачиная с .NET 7 у типов с плавающей точкой появились статические методы обобщённой математики, например double.Pow(x, y) и float.Pow(x, y). Они работают так же, как Math.Pow, но позволяют писать универсальный код через интерфейс IPowerFunctions<T>. Для одиночных вычислений разницы нет, выбирайте привычный Math.Pow.
Какой способ выбрать
| Способ | Типы | Точность | Когда применять |
|---|---|---|---|
x * x | любые числовые | полная до переполнения | квадрат и куб |
Math.Pow | double | около 15-16 значащих цифр | дробные и отрицательные показатели, корни, инженерные расчёты |
| Цикл | int, long, decimal | полная до переполнения | небольшие целые показатели |
| Бинарный алгоритм | int, long | полная до переполнения | большие показатели, степень по модулю |
BigInteger.Pow | BigInteger | точная при любой длине | очень большие целые результаты |
Частые ошибки
Первая ошибка - всё тот же ^. Вторая - целочисленное деление в показателе: выражение Math.Pow(8, 1 / 3) даёт 1, потому что 1 / 3 для целых равно нулю, и получается 8 в нулевой степени. Нужно писать 1.0 / 3, на эту ловушку отдельно указано в материале о целочисленном делении.
Третья ошибка - приведение результата к int без проверки диапазона. При значении больше int.MaxValue в контексте без checked вы получите случайное число. Четвёртая - сравнение результата Math.Pow с целым через ==: для надёжности используйте допуск, например Math.Abs(a - b) < 1e-9.
Частые вопросы
Как в C# написать x в квадрате?
Самый простой вариант - x * x. Он быстрее вызова метода и сохраняет тип переменной. Запись Math.Pow(x, 2) тоже работает, но вернёт double, и для целых чисел придётся приводить тип.
Есть ли в C# оператор степени?
Нет. Символ ^ выполняет побитовое XOR, а не возведение в степень. Используйте Math.Pow или собственную функцию.
Как возвести число в степень и получить int?
Вычислите Math.Round(Math.Pow(a, b)) и приведите к int, либо воспользуйтесь циклом на целых числах. Последний вариант надёжнее, потому что исключает вещественные погрешности, а с checked ещё и сообщит о переполнении.
Как возвести в отрицательную степень?
Передайте отрицательный показатель в Math.Pow: Math.Pow(2, -3) вернёт 0.125. В собственных целочисленных реализациях считайте степень по модулю показателя и берите обратное значение, как в примере для decimal.
Чем заменить Math.Pow для очень больших чисел?
Типом BigInteger и методом BigInteger.Pow. Он считает точно, но медленнее. Для остатка от деления на модуль используйте BigInteger.ModPow.
Почему результат Math.Pow иногда неточен?
Метод работает с двоичными дробями типа double. Для малых целых степеней результат точен, но при больших значениях и дробных показателях появляются погрешности. Поэтому перед приведением к целому результат округляют через Math.Round.





