Java nanoTime не дает надежных результатов

Я делаю проект, в котором мне нужно реализовать алгоритмы пузырьковой сортировки, шелл-сортировки и быстрой сортировки в массиве из 999 случайных двойников.

Мне нужно измерить время, необходимое для запуска каждого алгоритма.

Я использую System.nanoTime() для измерения времени выполнения каждого алгоритма. У меня есть 3 кнопки, по одной для каждого алгоритма. При нажатии кнопки запускается таймер, вызывается функция, затем вызывается таймер окончания, а продолжительность рассчитывается с учетом конечного времени-начального времени. Затем продолжительность печатается на этикетке в верхней части кнопки.

public double[] randomArray = SortAlg.getArray();

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        long startTimeBubble = System.nanoTime();
        SortAlg.bubble(randomArray);
        long endTimeBubble = System.nanoTime();
        long durationBubble = (endTimeBubble - startTimeBubble) / 1000000;
        bubbleTiempo.setText("bubble took " + durationBubble + " ms");
    }                                        

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        long startTimeShellSort = System.nanoTime();
        SortAlg.shellSort(randomArray);
        long endTimeShellSort = System.nanoTime();
        long durationShellSort = (endTimeShellSort - startTimeShellSort) / 1000000;
        shellSortTime.setText("ShellSort took " + durationShellSort + " ms");
    }                                        

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        long startTimeQuickSort = System.nanoTime();
        SortAlg.quickSort(randomArray, 0, randomArray.length - 1);
        long endTimeQuickSort = System.nanoTime();
        long durationQuickSort = (endTimeQuickSort - startTimeQuickSort) / 1000000;
        quickSortTime.setText("Quicksort took " + durationQuickSort + " ms");
    } 

Общие пояснения: 1-getArray() генерирует случайный массив из 999 действительных (двойных) чисел от 0 до 2000.

2-Ни один из методов алгоритма не возвращает массив, поэтому этот randomArray НЕ сохраняется как отсортированный, поэтому каждый раз, когда нажимается кнопка, случайный массив, который передается в функцию, не сортируется.

3-Каждая кнопка имеет уникальную метку для отображения результатов.

4-То, что вы видите, взято из класса GUI, который я создал с помощью редактора GUI Netbeans, часть кнопок. Main просто создает новый кадр графического интерфейса и устанавливает его как видимый, а SortAlg содержит логику для алгоритмов, которые я уже проверил на работоспособность.

Но у меня есть 2 проблемы: если я нажимаю кнопку более 1 раза, время уменьшается с каждым нажатием, пока в конечном итоге не станет 0, что не имеет смысла.

Кроме того, у меня изначально была ошибка расчета, и я делил время на 100000, а не на 1000000, но, как ни странно, это никогда не давало мне никаких ошибок. Однако, когда я делю его на 1000000 (что должно быть правильной операцией для преобразования ns в ms), я иногда получаю время выполнения 0 мс, что опять же не имеет смысла.

Наконец, и я знаю, что это может быть трудно определить, но у меня сложилось впечатление, что quickSort должен быть самым быстрым алгоритмом? Но время их выполнения сильно различается в пределах сборки. Иногда каждый из них составляет 5 мс, иногда 30, иногда 68. Меня это беспокоит, потому что кажется, что первый щелчок всегда самый быстрый, а другие в конечном итоге медленнее. Я вообще не уверен в этих результатах.


person Dasphillipbrau    schedule 13.03.2020    source источник


Ответы (1)


Однако, когда я делю его на 1000000 (что должно быть правильной операцией для преобразования ns в ms), я иногда получаю время выполнения 0 мс, что опять же не имеет смысла.

Поскольку вы используете целочисленное деление:

long durationBubble = (endTimeBubble - startTimeBubble) / 1000000;
                                                          ^^^^^^^

Просто замените его на double, чтобы включить дробь:

double durationBubble = (endTimeBubble - startTimeBubble) / 1_000_000.0;

Видеть:

person Eng.Fouad    schedule 13.03.2020
comment
@Dasphillipbrau: для этой цели вам не нужна такая точность, но если предупреждение вас беспокоит, вы можете использовать java.math.BigDecimal и точно выполнить математику. - person ruakh; 13.03.2020
comment
Легче, чем подсчитывать нули в таком числе, как 1000000, использовать показатели степени. Использование показателей также избавляет от целочисленной математики. (end-start)*1e-9*1e3; 1e-9 преобразуется в секунды, а 1e3 обратно в миллисекунды. - person markspace; 13.03.2020