Я сделал некоторые тесты на голове (экспонента) метод. К сожалению, мои математические навыки не достаточно сильны для решения следующей проблемы.
Я использую этот код:
BigInteger.valueOf(2).pow(var);
Результаты:
Видеть? 2 500 000 экспонент вычисляются почти с такой скоростью, как 2,000,000. 4,500,000 вычисляется намного быстрее затем 4,000,000.
Почему это?
Чтобы дать Вам некоторую справку, вот, исходная реализация BigInteger.pow (экспонента):
public BigInteger pow(int exponent) {
if (exponent < 0)
throw new ArithmeticException("Negative exponent");
if (signum==0)
return (exponent==0 ? ONE : this);
// Perform exponentiation using repeated squaring trick
int newSign = (signum<0 && (exponent&1)==1 ? -1 : 1);
int[] baseToPow2 = this.mag;
int[] result = {1};
while (exponent != 0) {
if ((exponent & 1)==1) {
result = multiplyToLen(result, result.length,
baseToPow2, baseToPow2.length, null);
result = trustedStripLeadingZeroInts(result);
}
if ((exponent >>>= 1) != 0) {
baseToPow2 = squareToLen(baseToPow2, baseToPow2.length, null);
baseToPow2 = trustedStripLeadingZeroInts(baseToPow2);
}
}
return new BigInteger(result, newSign);
}
Алгоритм использует повторное возведение в квадрат ( squareToLen
) и умножение ( multiplyToLen
). Время выполнения этих операций зависит от размера задействованных чисел. Умножение больших чисел в конце вычисления намного дороже, чем в начале.
Умножение выполняется только при выполнении этого условия: ((экспонента & 1) == 1)
. Количество операций возведения в квадрат зависит от количества бит в числе (исключая ведущие нули), но умножение требуется только для битов, для которых установлено значение 1. Легче увидеть требуемые операции, посмотрев на двоичный файл. представление числа:
2000000: 0000111101000010010000000 2500000: 0001001100010010110100000 3000000: 0001011011100011011000000 3500000: 0001101010110011111100000 4000000: 0001111010000100100000000 4500000: 0010001001010101000100000 5000000: 0010011000100101101000000
Обратите внимание, что 2,5M и 4,5M повезло в том, что у них установлено меньше старших битов, чем в числах, окружающих их. В следующий раз это произойдет на 8,5M:
8000000: 0011110100001001000000000 8500000: 0100000011011001100100000 9000000: 0100010010101010001000000
Сладкие точки - это точные степени 2.
1048575: 0001111111111111111111111 // 16408 ms 1048576: 0010000000000000000000000 // 6209 ms
Только предположение:
экспонента обрабатывается побитно, и если младший бит равен 1, выполняется дополнительная работа.
Если L - количество бит в экспоненте и A количество бит, равное 1 и t1 время обработки общей части и t2 - дополнительная обработка времени, когда LSbit равен 1
, тогда время выполнения будет
L t1 + A t2
или время зависит от количества единиц в двоичном формате. представление.
сейчас пишу небольшую программу для проверки моей теории ...
Я не уверен, сколько раз вы проводили тайминги. Как отметили некоторые из комментаторов, для получения хороших результатов (и они все равно могут быть неверными) вам придется выполнять операции много-много раз.
Предполагая, что вы хорошо засекли время, помните, что в математике есть много коротких путей, которые можно использовать. Вам не нужно выполнять операции 5*5*5*5*5*5*5, чтобы вычислить 5^6.
Вот один из способов сделать это гораздо быстрее. http://en.wikipedia.org/wiki/Exponentiation_by_squaring