Явное умножение Java - программирование

Явное умножение Java

Посмотрите на код ниже:

class Test
{
    public static void main(String abc[])
    {
        for( int N=1; N <= 1_000_000_000; N=N*10)
        {
            long t1 = System.nanoTime();

            start(N);

            long t2 = System.nanoTime() - t1;
            System.out.println("Time taken for " + N + " : " + t2);
        }
    }

    public static void start( int N )
    {
        int j=1;
        for(int i=0; i<=N; i++)
            j=j*i;
    }
}

Результат, полученный по вышеуказанному вопросу:

Time taken for 1 : 7267
Time taken for 10 : 3312
Time taken for 100 : 7908
Time taken for 1000 : 51181
Time taken for 10000 : 432124
Time taken for 100000 : 4313696
Time taken for 1000000 : 9347132
Time taken for 10000000 : 858
Time taken for 100000000 : 658
Time taken for 1000000000 : 750

Вопросы:

1.) Почему время N = 1 необычно больше N = 10? (иногда он даже превышает N = 100)

2.) Почему время для N = 10M и далее необычно ниже?

Образец, указанный в вышеуказанных вопросах, является глубоким и остается даже после многих итераций. Есть ли связь с memoization здесь?

EDIT:

Спасибо за ваши ответы. Я думал о замене вызова метода фактическим циклом. Но теперь нет оптимизации JIT. Почему нет? Является ли размещение утверждений способом, облегчающим процесс оптимизации? Измененный код ниже:

class test
{
    public static void main(String abc[])
    {
        for( int k=1; k<=3; k++)
        {
            for( int N=1; N<=1_000_000_000; N=N*10)
            {
                long t1 = System.nanoTime();

                int j=1;
                for(int i=0; i<=N; i++)
                    j=j*i;

                long t2 = System.nanoTime() - t1;
                System.out.println("Time taken for "+ N + " : "+ t2);
            }
        }
    }
}

ИЗМЕНИТЬ 2: Вывод модифицированного выше кода:

Time taken for 1 : 2160
Time taken for 10 : 1142
Time taken for 100 : 2651
Time taken for 1000 : 19453
Time taken for 10000 : 407754
Time taken for 100000 : 4648124
Time taken for 1000000 : 12859417
Time taken for 10000000 : 13706643
Time taken for 100000000 : 136928177
Time taken for 1000000000 : 1368847843
Time taken for 1 : 264
Time taken for 10 : 233
Time taken for 100 : 332
Time taken for 1000 : 1562
Time taken for 10000 : 17341
Time taken for 100000 : 136869
Time taken for 1000000 : 1366934
Time taken for 10000000 : 13689017
Time taken for 100000000 : 136887869
Time taken for 1000000000 : 1368178175
Time taken for 1 : 231
Time taken for 10 : 242
Time taken for 100 : 328
Time taken for 1000 : 1551
Time taken for 10000 : 13854
Time taken for 100000 : 136850
Time taken for 1000000 : 1366919
Time taken for 10000000 : 13692465
Time taken for 100000000 : 136833634
Time taken for 1000000000 : 1368862705
4b9b3361

Ответ 1

1.) Почему время N = 1 необычно больше, чем N = 10

Поскольку это первый раз, когда виртуальная машина увидела этот код, он может решить просто интерпретировать его, или потребуется немного времени, чтобы JIT файл был привязан к собственному коду, но, вероятно, без оптимизации. Это одна из "ошибок" тестирования Java.

2.) Почему время для N = 10M и далее необычно ниже?

В этот момент JIT усложнил оптимизацию кода, уменьшив его почти до нуля.

В частности, если вы запустите этот код несколько раз (только в цикле), вы увидите эффект оптимизации компилятора JIT:

Time taken for 1 : 3732
Time taken for 10 : 1399
Time taken for 100 : 3266
Time taken for 1000 : 26591
Time taken for 10000 : 278508
Time taken for 100000 : 2496773
Time taken for 1000000 : 4745361
Time taken for 10000000 : 933
Time taken for 100000000 : 466
Time taken for 1000000000 : 933
Time taken for 1 : 933
Time taken for 10 : 467
Time taken for 100 : 466
Time taken for 1000 : 466
Time taken for 10000 : 933
Time taken for 100000 : 466
Time taken for 1000000 : 933
Time taken for 10000000 : 467
Time taken for 100000000 : 467
Time taken for 1000000000 : 466
Time taken for 1 : 467
Time taken for 10 : 467
Time taken for 100 : 466
Time taken for 1000 : 466
Time taken for 10000 : 466
Time taken for 100000 : 467
Time taken for 1000000 : 466
Time taken for 10000000 : 466
Time taken for 100000000 : 466
Time taken for 1000000000 : 466

Как вы можете видеть, после первого цикла цикл занимает одинаковое количество времени независимо от ввода (шум модуля - в основном он всегда равен ~ 460ns или ~ 933ns, непредсказуемо), что означает, что JIT оптимизировал цикл.

Если вы действительно вернули j и изменили начальное значение i на 1 вместо 0, вы увидите ожидаемые результаты. Изменение начального значения i на 1 происходит потому, что в противном случае JIT может заметить, что вы всегда будете возвращать 0.

Ответ 2

youre фактически сравнивает java JIT. если я немного изменил код yout:

class Test
{
    public static void main(String abc[])
    {
        for( int N=1; N <= 1_000_000_000; N=N*10)
        {
            long t1 = System.nanoTime();

            start(N);

            long t2 = System.nanoTime() - t1;
            System.out.println("Time taken for " + N + " : " + t2);
        }

        for( int N=1; N <= 1_000_000_000; N=N*10)
        {
            long t1 = System.nanoTime();

            start(N);

            long t2 = System.nanoTime() - t1;
            System.out.println("Time taken for " + N + " : " + t2);
        }
    }

    public static void start( int N )
    {
        int j=1;
        for(int i=0; i<=N; i++)
            j=j*i;
    }
}

я получаю следующее:

Time taken for 1 : 1811
Time taken for 10 : 604
Time taken for 100 : 1510
Time taken for 1000 : 10565
Time taken for 10000 : 104439
Time taken for 100000 : 829173
Time taken for 1000000 : 604
Time taken for 10000000 : 302
Time taken for 100000000 : 0
Time taken for 1000000000 : 0
Time taken for 1 : 0
Time taken for 10 : 302
Time taken for 100 : 0
Time taken for 1000 : 302
Time taken for 10000 : 301
Time taken for 100000 : 302
Time taken for 1000000 : 0
Time taken for 10000000 : 0
Time taken for 100000000 : 0
Time taken for 1000000000 : 302

никогда не тестирует "холодную" систему. всегда повторяйте каждое измерение несколько раз и отбрасывайте 1-е несколько, потому что оптимизация еще не нажата

Ответ 3

Причина в том, что 1) вы не возвращаете значение и 2) результат вычисления всегда равен 0. В конечном счете JIT просто скомпилирует цикл.

Вы получите ожидаемое поведение, если вы измените свой цикл на:

public static int start(int N) {
    int j = 1;
    for (int i = 1; i <= N; i++)
        j = j * i;
    return j;
}

Обратите внимание, что я изменил цикл init на int i = 1 и добавил return j. Если я сделаю только один из них, цикл (в конце концов) все еще будет скомпилирован.

Это приведет к следующим сериям (если выполняется дважды):

Time taken for 1 : 2934
Time taken for 10 : 1466
Time taken for 100 : 3422
Time taken for 1000 : 20534
Time taken for 10000 : 191644
Time taken for 100000 : 1898845
Time taken for 1000000 : 1210489
Time taken for 10000000 : 11884401
Time taken for 100000000 : 115257525
Time taken for 1000000000 : 1061254223
Time taken for 1 : 978
Time taken for 10 : 978
Time taken for 100 : 978
Time taken for 1000 : 2444
Time taken for 10000 : 11244
Time taken for 100000 : 103644
Time taken for 1000000 : 1030089
Time taken for 10000000 : 10448535
Time taken for 100000000 : 107299391
Time taken for 1000000000 : 1072580803