java.math. Голова BigInteger (экспонента) вопрос

Я сделал некоторые тесты на голове (экспонента) метод. К сожалению, мои математические навыки не достаточно сильны для решения следующей проблемы.

Я использую этот код:

BigInteger.valueOf(2).pow(var);

Результаты:

  • var | время в мс
  • 2000000 | 11450
  • 2500000 | 12471
  • 3000000 | 22379
  • 3500000 | 32147
  • 4000000 | 46270
  • 4500000 | 31459
  • 5000000 | 49922

Видеть? 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);
    }
6
задан Jan Kraus 28 May 2010 в 22:17
поделиться

3 ответа

Алгоритм использует повторное возведение в квадрат ( 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
9
ответ дан 9 December 2019 в 22:30
поделиться

Только предположение:

экспонента обрабатывается побитно, и если младший бит равен 1, выполняется дополнительная работа.

Если L - количество бит в экспоненте и A количество бит, равное 1 и t1 время обработки общей части и t2 - дополнительная обработка времени, когда LSbit равен 1

, тогда время выполнения будет

L t1 + A t2

или время зависит от количества единиц в двоичном формате. представление.

сейчас пишу небольшую программу для проверки моей теории ...

1
ответ дан 9 December 2019 в 22:30
поделиться

Я не уверен, сколько раз вы проводили тайминги. Как отметили некоторые из комментаторов, для получения хороших результатов (и они все равно могут быть неверными) вам придется выполнять операции много-много раз.

Предполагая, что вы хорошо засекли время, помните, что в математике есть много коротких путей, которые можно использовать. Вам не нужно выполнять операции 5*5*5*5*5*5*5, чтобы вычислить 5^6.

Вот один из способов сделать это гораздо быстрее. http://en.wikipedia.org/wiki/Exponentiation_by_squaring

1
ответ дан 9 December 2019 в 22:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: