2010-07-28 7 views
8

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

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


EDIT:

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

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

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

+0

Каков был результат? – Amarghosh

+0

Я получил, что умножение ints немного быстрее около 13%, но сравнение двух ints медленнее около 22%. – jutky

+0

Я не совсем уверен, но для Dijkstra достаточно просто выполнить операции сложения и сравнения. И для этих операций он не должен сильно отличаться для float или int. Я действительно удивлен тем, что целочисленное сравнение будет на 22% медленнее. Могу ли я узнать, какого рода бенчмаркинг вы провели? – tafa

ответ

1

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

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

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

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

+2

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

2

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

, как поплавок

float f = 15 * 0.987; 

как INT

int i = 15 * 987/1000; 

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

+0

в алгоритме Дейкстры Я просто суммирую и сравниваю вес путей, поэтому операция удаления довольно задняя для меня. Откуда вы знаете, что для простых операций ints быстрее, это общая сцена или вы можете указать мне на литературу по этой теме. – jutky

+1

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

-6

Я так не считаю.

Float - 4 байт. И Int в java также 4 байта.

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

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

+0

Возможно, вы захотите использовать слово «байт» вместо «бит». Целое число 4 * бит * может содержать только 16 различных значений ... –

+0

Извините ... Мой английский плохой. Так что я использовал неправильное слово. (Мой родной язык не английский) На самом деле, я думаю, если скорость быстрее, чем float, это потому, что аппаратное обеспечение. В физике, Int, возможно, легко достичь, чем плавать. – rainisic

0

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

+0

Тот же комментарий, что и для другого ответа: это общая сцена или вы можете указать мне на какую-то литературу по этой теме. – jutky

0

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

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

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

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

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

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

+0

См. Также http://stackoverflow.com/questions/2550281/floating-point-vs-integer-calculations-on-modern-hardware и http://stackoverflow.com/questions/2010252/float-versus-integer-arithmetic -performance-on-modern-chips – polygenelubricants

+0

Я добавил несколько вопросов к вопросу. надеюсь, что прояснит некоторые вещи. Спасибо за ссылки. – jutky

0

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

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

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

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

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

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

1

Целочисленные вычитания в 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

Спасибо за тест. Запуск его для тестов на изъятие на моей машине (Xeon, 64-bit, Windows, Java 1.8) дал: время, необходимое для int subs [ms]: 7704, время, необходимое для двойных subs [ms]: 10869. Меня больше интересовали больше чем и меньше операций, потому что я тестировал его для использования при построении TreeMap. Результат операций сравнения/* if (удваивает [i] <удваивает [i-1]) tmp ++; if (удваивает [i]> удваивает [i-1]) tmp ++; */были: время, необходимое для int cmp [ms]: 8479, время, необходимое для двойного cmp [мс]: 15925. – Henry

+1

FYI, я снова проверил тест для «длинного» типа данных. Результат для вычитания: время, необходимое для длинных субмарок [мс]: 7513, время, необходимое для двойных subs [ms]: 10898. И результат для сравнений: время, необходимое для длинных cmp [мс]: 15768, время, необходимое для двойного cmp [ ms]: 16012. Для «longs» похоже, что производительность аналогична для проверок равенства. – Henry

+0

Вы не можете выполнить тест в одном и том же исполнении для разных типов значений, JVM будет горячим –

Смежные вопросы