(Dis) Доказательство того, что один алгоритм работает быстрее, чем другой из-за внутренних языков - PullRequest
7 голосов
/ 20 декабря 2010

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

Нам было поручено реализовать, среди прочего, алгоритм Union-Find и его оптимизацию (Union by Depth, Size). Случайно (делая то, что мне показалось необходимым для правильности алгоритма), я нашел другой способ оптимизации алгоритма.

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

Проект был на Java, а используемые мной структуры данных основывались на простых массивах целых чисел (объект, а не int) Позже, при оценке проекта мне сказали, что он, вероятно, как-то связан с «кэшированием Java», но я не могу найти в Интернете ничего о том, как кэширование повлияет на это.

Каков наилучший способ, без расчета сложности алгоритма, доказать или опровергнуть, что моя оптимизация такая быстрая из-за способа работы java? Реализовать это на другом, более низком уровне? Но кто скажет, что язык не будет делать то же самое?

Надеюсь, я дал понять,

спасибо

Ответы [ 4 ]

4 голосов
/ 20 декабря 2010

Единственный способ - доказать наихудшую (в среднем и т. Д.) Сложность алгоритма.

Потому что, если вы этого не сделаете, это может быть просто следствием комбинации

  • Особые данные
  • Размер данных
  • Некоторые аспекты аппаратного обеспечения
  • Некоторые аспекты реализации языка
  • и т..
3 голосов
/ 20 декабря 2010

Как правило, очень трудно выполнить такую ​​задачу, учитывая современные виртуальные машины! Как вы намекаете, они выполняют все виды вещей за вашей спиной. Вызовы методов становятся встроенными, объекты используются повторно. И т.д. Ярким примером является то, как тривиальные циклы компилируются, если они явно не выполняют ничего, кроме подсчета. Или как функциональный вызов в функциональном программировании встроен или оптимизирован с помощью хвостового вызова.

Кроме того, вам трудно доказать свою точку зрения в целом на любом наборе данных. O (n ^ 2) может быть намного быстрее, чем, казалось бы, более быстрый, скажем, O (n) алгоритм. Два примера

  1. Пузырьковая сортировка быстрее сортирует почти отсортированный сбор данных, чем быстрая сортировка.
  2. Быстрая сортировка в общем случае, конечно, быстрее.

Обычно нотация big-O преднамеренно игнорирует константы, которые в практической ситуации могут означать жизнь или смерть для вашей реализации. и эти константы, возможно, были тем, что поразило вас. Так на практике 0,00001 * н ^ 2 (скажем, время работы вашего алгоритма) быстрее, чем 1000000 * n log n

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

1 голос
/ 20 декабря 2010

Вероятно, либо компилятор, либо JVM нашли оптимизацию для вашего кода.Вы можете попробовать прочитать байт-код, который выводится компилятором javac, и отключить JIT-компиляцию во время выполнения с параметром -Djava.compiler=NONE.

0 голосов
/ 20 декабря 2010

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

...