Эффективность арифметики int и float в Java - PullRequest
8 голосов
/ 28 июля 2010

Я пишу приложение, которое использует алгоритм Дейкстры для поиска минимальных путей в графе. Веса узлов и ребер в графе равны float числам, поэтому алгоритм выполняет много арифметических операций над числами с плавающей точкой. Могу ли я улучшить время бега, если перевести весь вес в int с? Являются ли int арифметические операции в Java быстрее, чем плавающие?

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


EDIT:

Проблема, которую я пытаюсь решить, находится в поле поиска информации. Приложение должно показать ответы на запрос, заданный в виде набора ключевых слов.

Моя структура данных представляет собой взвешенный ориентированный граф. Учитывая набор конечных узлов, я должен найти наименьшее дерево, которое соединяет эти узлы и показать ответ пользователю. Веса назначаются весовой функцией, основанной частично на методе tf / idf. Пользователь не знает, какие веса я назначаю узлам и ребрам, он просто хочет видеть ответы, относящиеся к заданному им запросу. Таким образом, точные результаты не требуются, просто возможность перечислить ответы в соответствии с их весами. Просто нативное использование весовой функции (как я уже говорил, она основана на tf / idf) дает веса с плавающей точкой, поэтому я до сих пор использовал числа с плавающей точкой.

Надеюсь, это добавит некоторый фон к вопросу.

Ответы [ 7 ]

2 голосов
/ 28 июля 2010

для простых операций int быстрее, но с int вам, возможно, придется проделать больше работы, чтобы получить тот же результат.например,

как число с плавающей точкой

float f = 15 * 0.987;

как число типа int

int i = 15 * 987 / 1000;

Дополнительное деление означает, что операция int может занять больше времени.

1 голос
/ 11 июня 2014

Целочисленные вычитания на моей машине в ~ 2,5 раза быстрее, чем двойные вычитания. Однако целочисленные умножения только в ~ 1,5 раза быстрее, чем двойные умножения.

Следующий тест работает со случайными данными, что может помешать оптимизации компилятора.

// test whether int subs are faster than double subs
public void compareIntAndFloatSubtraction(){

    int N = 100000;  // input array size
    int k = 100000;  // number of mathematical operations performed on each element

    // generate random data
    int[] ints = new int[N];
    double[] doubles = new double[N];
    Random r = new Random(1l);
    for (int i = 0; i < N; i++) {
        ints[i] = r.nextInt();
        doubles[i] = r.nextDouble();
    }

    // measure integer subtractions
    long before = System.currentTimeMillis();
    for (int i = 1; i < N; i++) {
        for (int j = 0; j < k; j++) {
            ints[i] -= ints[i-1];  // referring to another element might prevent from optimization also
        }
    }
    System.out.println(String.format("time needed for int subs [ms]: %s", System.currentTimeMillis()-before));

    // measure double subtractions
    before = System.currentTimeMillis();
    for (int i = 1; i < N; i++) {
        for (int j = 0; j < k; j++) {
            doubles[i] -= doubles[i-1];
        }
    }
    System.out.println(String.format("time needed for double subs [ms]: %s", System.currentTimeMillis()-before));

}
1 голос
/ 28 июля 2010

Как и в случае с подобными вещами, вы должны установить себе некоторые цели производительности, а затем профилировать приложение, чтобы увидеть, соответствует ли оно им.

Часто вы можете столкнуться с неожиданными результатами;что на затраченное время практически не влияет базовый числовой тип, или что ваш алгоритм неоптимален.

А что касается оптимизации компилятора - это реальная и действительная часть оптимизации производительности.

Если использование типа A теоретически быстрее, чем использование типа B, но ваш компилятор может оптимизировать тип B, чтобы он был быстрее в реальном сценарии, тогда это ценное доказательство, а не источник разочарования.

0 голосов
/ 28 июля 2010

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

Если вы выполняете вычисления матрицы / массива на платформе X86, среда выполнения может оптимизировать ее для использования SSE, представляющего собой расширенный набор команд только с плавающей запятой / двойной точностью.

На других платформах среда выполнения может быть оптимизирована под OpenCL (я не верю, что кто-то сейчас так делает, но это может произойти :). Я понятия не имею, что работает на такой платформе быстрее всего и при каких условиях. Возможно, OpenCL оптимизирован для целочисленной рабочей нагрузки.

В этих условиях я бы пришел к выводу, что на данном этапе нецелесообразно оптимизировать тип данных (float или int), а просто оптимизировать читаемость кода.

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

Но в целом, просто используйте алгоритм, который вы можете понять, сохраняйте код читабельным, и, таким образом, количество ошибок будет низким. Быстрый код не стоит так много, если результаты не верны:)

0 голосов
/ 28 июля 2010

Как правило, вам не следует беспокоиться о выборе между int и float из соображений производительности.

Вот выдержка из приложения Java Puzzlers :

Арифметика с плавающей точкой является неточной.Не используйте с плавающей точкой, где требуются точные результаты;вместо этого используйте целочисленный тип или BigDecimal.Предпочитайте от double до float.

Если у вас нет действительно веской причины, вы обычно предпочитаете от double до float, если вам необходимо использовать операции с плавающей запятой.Если точный результат желателен, тогда продолжайте и используйте BigDecimal;это будет медленнее, поскольку это не примитив, но если профилирование не покажет, что оно неприемлемо, это часто лучший вариант.

Если вам необходимо использовать операцию с плавающей запятой, попробуйте оптимизировать ее с помощью int опрометчивый.Это может быть преждевременной оптимизацией и только усложнит ненужный код.Напишите это самым естественным, наиболее читаемым способом.Не усложняйте ваш код без необходимости ради небольшого прироста производительности.

Если вам на самом деле не нужна операция с плавающей запятой, тогда непременно используйте int или long.

0 голосов
/ 28 июля 2010

Если вы просто хотите сравнить веса, вы должны предпочесть int для float.

0 голосов
/ 28 июля 2010

Не думаю.

Число с плавающей запятой 4 байта. И Int в Java также 4 байта.

Почему бы не использовать Date (java.util.Date) для получения времени выполнения?

Вы можете определить график, который имеет свои 100000 узлов. Тогда посчитай.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...