Блог пользователя removed1

Автор removed1, 15 лет назад, По-русски

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

Каждый код прогонялся три раза в topcoder practice room 461 easy. Результаты и код можно посмотреть здесь: http://advgreat.narod.ru/matrices.rar

Если кто-то думает, что я что-то делаю не так -- код в студию.

Мои извинения любителям Java. В прошлый раз я забыл указать ключевое слово final, теперь добавил. 

Для C# я попробовал замерить вариант, когда значение size не задается литералом, а берется из входных данных -- в таком случае у компилятора не будет шансов догадаться, что будет это такое при работе программы. Правда, влияние на скорость это оказывает только для С/С++.

Для C# и Java вывод такой:

если нужен двухмерный массив или его аналог, то индексация в 

int[,] будет работать медленнее всего

int[][] будет работать немного быстрее

int[] с индексацией вида arr[y*cols + x] будет работать еще быстрее

Для C++, как и ожидалось, индексация в массиве массивов (int **) оказалась медленее, чем в двухмерном массиве (int [][]), никакого преимущества переход с адресации int[][] на развернутое int[] не дает.

Также хочу рассказать тем, кто не знает, что GCC поддерживает VLA. То есть там работает такой код:

int foo(int n) { int arr[n][n]; // все, массив готов и в него можно писать

p.s. Почему я писал этот пост

меня удивила фраза Федора в http://codeforces.me/blog/entry/254#comment-3033 про двухмерные массивы в C#

в результате прогона его кода выяснилось, что он прав, а я ошибался

я заинтересовался другими способами использования массива, а потом немного решил погонять и другие языки, заодно проверив фразу Петра о том, что Java медленнее C#

теперь решил сделать измерение корректным и выложить исходники 

p.p.s.любители Java ухитрилось заминусовать даже мой коммент со ссылкой на бенчмарк, где Java быстрее C/C++. Очевидно, что Java коррелирует с биполярностью мышления и скудостью ума. Для вас еще есть замечательный пост о гибкой Java: http://codeforces.me/blog/entry/312

  • Проголосовать: нравится
  • -15
  • Проголосовать: не нравится

15 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится

Вообще, скорость java, в отличие от c/c++ сильно зависит от проверяющего сервера. Например (на основании моего небольшого опыта) на uva она довольно тормозная, а на timus и codeforces - быстрая. Например, вот мои результаты для ресурсоемкой задачи C с 8 беты http://codeforces.me/contest/8/problem/C

MS C++ - 140 мс     132644 Кб

GNU C++ - 200 мс     132636 Кб

Java  - 330 мс     208880 Кб

Медленнее MS в 2.35 раза, а GCC в 1.65 раза

Если не влом, прогони plz свои тесты на codeforces :)

  • 15 лет назад, # ^ |
      Проголосовать: нравится -9 Проголосовать: не нравится

    >Например, вот мои результаты

    Неинтересно. Нету исходников.

    >Если не влом, прогони plz свои тесты на codeforces :)

    Прогони сам. Исходники я выложил.

    • 15 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Итак, тестирование умножения матриц (Java 1.6, G++ 4) на codeforces.ru.

      Для каждого языка тестировалось следующее:

      1) Наивное умножение на 2d массивах

      2) Оптимизированное умножение на 2d массивах

      3) Наивное умножение на 1d массивах (ручной подсчет индесов)

      4) Оптимизированное умножение на 1d массивах

      Под словом "оптимизированное" я понимаю следующую очевидную оптимизацию тройного цикла: вместо с[i][j] += ... сначала сделать int v = c[i][j], далее v += ..., потом с[i][j] = v

      Теперь к результатам (по пунктам 1 - 4)

      Java: 1250 ms, 670 ms, 800 ms, 550 ms

      C++ 190 ms, 170 ms, 170 ms, 170 ms

      Видно, что "оптимизация" практически не влияет на С++, но ускоряет Яву в 2 раза

      Вывод: в С++ можно использовать 2d массивы не  задумываясь о производительности. В Java тоже можно спокойно работать с 2d массивами, но при этом необходимо помнить об их природе - это массив массивов.

      Автору поста плюсег - затавил критически взглянуть на используемый инструмент :)

      P.S. Исходники здесь http://ifolder.ru/17347525

      P.P.S Задача C CF #8 - тут 2d массивов нет, но до кучи дам ссылки на исходники

      http://paste.ubuntu.com/416628/

      http://paste.ubuntu.com/416630/

      • 15 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Неплохо бы добавить сишарп
        • 15 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          http://ifolder.ru/17349840

          Добавил шарп, поправил java_plain_opt

          В отдельном зачете выступают 2d массивы в C# (Mono)

          Naive: 2280 ms

          Opt: 1130 ms

          Они проигрывают всем, в том числе и массиву массивов в C# (Mono)

          Результаты (в том же порядке, что и в предыдущем посте)

          C++              190 ms, 170 ms, 170 ms, 170 ms

          Java              1250 ms, 670 ms, 800 ms, 530 ms

          C# (Mono)   1260 ms, 830 ms, 780 ms, 480 ms

          В общем, результаты C# (Mono) практически совпадают с результатами Java  

15 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Не совсем удачный пример для сравнения быстродействия языков, в С++ статические двухмерные массивы по типу A[500][500] на самом деле являются одномернымы, поэтому С++ так здорово удается прооптимизировать операции обращения к индексам, в Java так сделать не получится. Хотелось бы увидеть побольше примеров, где в программе есть не только математические вычисления, но и активно используется память (чтобы еще и garbage collector подключался в Java), стандартные библиотеки -- то, что чаще всего используется.
  • 15 лет назад, # ^ |
      Проголосовать: нравится -13 Проголосовать: не нравится

    А я не сравниваю быстродействие языков. Это тестирование пошло от того, КАК ЛУЧШЕ использовать массивы в C#.

    >в С++ статические двухмерные массивы по типу A[500][500] на самом деле являются одномернымы

    Во-первых, неправильная терминология. Во-вторых, для C# как ни странно, двухмерный массив оказался медленее массива массивов. В-третьих, см. предыдущий пост: умножение через vector<vector<int>> оказалось все равно быстрее, тем таковое в Java.

    > стандартные библиотеки

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

  • 15 лет назад, # ^ |
      Проголосовать: нравится -7 Проголосовать: не нравится

    А я не сравниваю быстродействие языков. Это тестирование пошло от того, КАК ЛУЧШЕ использовать массивы в C#.

    >в С++ статические двухмерные массивы по типу A[500][500] на самом деле являются одномернымы

    Во-первых, неправильная терминология. Во-вторых, для C# как ни странно, двухмерный массив оказался медленее массива массивов. В-третьих, см. предыдущий пост: умножение через vector<vector<int>> оказалось все равно быстрее, тем таковое в Java.

    > стандартные библиотеки

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

    • 15 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Если вы не сравниваете быстродействие, тогда к чему эти фразы

       "В результате наивный код на Java проигрывает наивному сишному в скорости не 8, а 6 раз. Это, конечно, существенное ускорение. Но все равно существенно отставание от C#, и намерение любителей Java меряться с С++ довольно забавно."

      Как правильно подметил dev_il С++ будет всегда быстрее Java и высмеивание скорости неуместно.

      С другой стороны мне интересно где по сравнению с C++ у Java узкие места, чтобы в нужный момент сделать правильный выбор и сразу написать код на С++, а не получив вердикт ТЛ еще к тому же 10 мин тратить на переделывание кода на другой язык.
  • 15 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Между прочим, в Topcoder Hard задачи на с умножением матриц встречаются довольно часто.
    • 15 лет назад, # ^ |
        Проголосовать: нравится +6 Проголосовать: не нравится
      хорошо..в таком случае покажи задачу с TopCoder'a, которая пишется на С++ но не на Java!? ... 
      я вот не могу понять. Вполне ясно, что С++ всегда будет быстрее джава.. всегда. Но вопрос в том, зачем постоянно заводить об этом дискуссии!?. Или вам легче от того, что ваш С++ на каком-то тесте будет работать не в 7, а в 8 раз быстрее?? ИМХО всё равно в итоге скорее всего все останутся при своём мнении и будут писать на том, на чём писали.
      • 15 лет назад, # ^ |
          Проголосовать: нравится +3 Проголосовать: не нравится

        >Вполне ясно, что С++ всегда будет быстрее джава.. всегда

        Нет, не всегда. Если постараться, то можно найти случай, когда Java будет быстрее.

        >зачем

        прочитай постскриптум к посту

  • 15 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    > в С++ статические двухмерные массивы по типу A[500][500] на самом деле являются одномернымы,
    Пример того, как Java повреждает мозг. int A[500][500] это массив массивов, потому что каждый его элемент является массивом типа int[500]. В Java int[][] это не просто массив массивов, а массив ссылок/указателей (вставить нужное слово по желанию) на массивы.
15 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
хех.. а вот это интересно =) . благодаря вашей ссылке я кое-что интересное обнаружил... написал прогу, которая суммирует числа в двумерном массиве... запустил её как обычно - пишет 2.726 sec.. а потом запустил с опцией компилятора -server (java -server file) и что же вы думаете? выигрыш по скорости более чем в 2 раза =) .. попробуйте-ка сами
15 лет назад, # |
  Проголосовать: нравится +10 Проголосовать: не нравится
"Очевидно, что Java коррелирует с биполярностью мышления и скудостью ума."
Уважаемый alliumnsk, неужели ради того, чтобы доказать свою точку зрения вы запросто переходите на оскорбления. У всех есть своё мнение, которое можно поменять если адекватно обьяснить почему оно неправильное, ваши высказывания этому не способствуют. Проявляйте больше уважения...


dev_il могли бы вы поподробнее рассказать, что это за опция -server и почему она дает ускорение аж в 2 раза, возможно все дело в неправильном измерении времени выполнения?

  • 15 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится
    даже и не знаю ... ничего не нашёл по этому поводу :-( .. ну а вообще в опциях написано что это позволяет использовать серверную виртуальную машину, а не клиентскую, которая стоит по умолчанию .. только непонятно всё же что это означает
    • 15 лет назад, # ^ |
        Проголосовать: нравится +5 Проголосовать: не нравится
      Все дело в том, что есть 2 виртуалные Java-машины от Sun. Одна серверная, другая клиентская. Причем серверная делает больше JIT-оптимизаций, соответственно увеличивается время загрузки, но код становится более эффективным.
  • 15 лет назад, # ^ |
      Проголосовать: нравится +11 Проголосовать: не нравится
    Согласен с Xazker. Уже не первый раз я вижу едкие высказывания про Java и тех, кто её использует, от alliumnsk Очевидно, что на нормальных соревнованиях, где есть Java, у жюри будут решения на ней, причём вряд ли с какими-то извратными оптимизациями. И участники смогут использовать все преимущества Java и при этом не думать, как нужно переставить местами форики, чтобы это быстрее работало. Я бы с удовольствием поизучал тесты и сравнения с программами на других языках, но за такой пост могу поставить только минус.
    • 15 лет назад, # ^ |
        Проголосовать: нравится -10 Проголосовать: не нравится

      А чем в этом аспекте Java лучше Python или Ruby? Только тем, что на ней больше народу пишет?

      Не забываем нажать на красный треугольничек!

      • 15 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Не знаю, какой именно аспект имелся ввиду, но преимущество джавы для олимпиад перед python/ruby - статическая типизация.
      • 15 лет назад, # ^ |
          Проголосовать: нравится +9 Проголосовать: не нравится
        Сравнить сами языки не могу - не писал ни на Python, ни на Ruby. Но одно точно очевидно - на Java можно писать на всех престижных соревнованиях, в отличие от Python и Ruby, упоминания ACM ICPC, на котором даже на C# писать нельзя, или TopCoder, думаю, достаточно. Конечно, круто знать несколько языков и в тот момент, когда на одном из них код явно будет проще и короче, использовать именно его. Но если есть элегантный язык, имеющий как минимум те преимущества, которые перечислил Petr здесь, на котором я могу писать во всех контестах, в которых мне хочется участвовать, и, в конце концов, на котором мне просто нравится писать, то я не понимаю, почему нужно говорить, что я обладаю скудостью ума.
        • 15 лет назад, # ^ |
            Проголосовать: нравится +6 Проголосовать: не нравится
          Хочу отметить, что господин alliumnsk - представитель славного вуза НГТУ, где поддержка Java во время четвертьфинала просто великолепна. Или уже что-то изменилось?
          • 15 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            К проведению соревнований там я никакого отношения не имел и не имею.
            Тестирующая система полностью переписана from scratch, так что о нынешнем состоянии я ничего не могу сказать.
          • 15 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Кстати я там агитировал за PCMS2. Но ее там никогда не будет, ибо NIH. Когда я сам настраивал поддержку для решений на Java в системе PCMS2, написанной на Java же -- могу сказать только одно: самый неудобный язык для поддержки на контестах.
    • 15 лет назад, # ^ |
        Проголосовать: нравится -6 Проголосовать: не нравится
      А почему вы не потребуете таких контестов, чтобы читать можно было через Scanner, это же удобнее?
      • 15 лет назад, # ^ |
          Проголосовать: нравится +19 Проголосовать: не нравится
        Ну вот, опять:( Думаете, если будете пытаться меня опустить, кто-то будет больше уважать С++ или вас? Вряд ли. Я, разумеется, считаю, что Java удобна для контестов, а не наоборот. Да, для поддержки Java нужно приложить некоторые усилия, в том числе спроектировать защиту для тестирующей системы. Но это нужно сделать один раз, и дальше можно только получать удовольствие от красивого языка от контеста к контесту. А недостатки или преимущества самих языков будут сопровождать постоянно при написании каждой новой программы, и чем лучше пользоваться в данный момент, неплохо бы решать самому, а не под давлением жюри, которое, к примеру, не может обеспечить поддержку какому-то из них.
        • 15 лет назад, # ^ |
            Проголосовать: нравится -13 Проголосовать: не нравится
          Что, неужели ответ на мой вопрос слишком сложен? Я вот не до конца понимаю, почему на олимпиадах часть участников предпочитает писать boilerplate код для ввода-вывода.
          >будет больше уважать С++
          а я где-то сказал, что С++ хороший?

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

          клинический случай, апелляции к разуму бесполезны *FACEPALM*
          • 15 лет назад, # ^ |
              Проголосовать: нравится +4 Проголосовать: не нравится
            Вопрос? Апелляции к разуму? Может ли считаться предложение требовать от контестов, чтобы проходило чтение через Scanner, чем-то из этого? По-моему, это просто стёб над Java.
            Зачем забивать темплэйт для чтения - очевидно, чтобы дальше было удобней писать на соответствующем языке. Обычно несколько минут, потраченные на это, не являются очень большой жертвой.
            >а я где-то сказал, что С++ хороший?
            Нет. Но из заявлений о корреляции Java со скудостью ума можно сделать вывод, что вы не в восторге от Java. А обо всех языках вы вряд ли так думаете - иначе ВСЕ программисты обладают скудостью ума, что сомнительно. Значит, есть какие-то не очень плохие языки. А будет ли стоять в процитированной вами фразе C++, C# или другой язык, её сути не меняет.
            • 15 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              Вы вообще понимаете разницу между понятиями "коррелирует" и "равно"? Уверен, что да, только позволяете иногда себе ее забыть.

              И не надо делать выводы о том, что мне нравится и что не нравится, я в отличие от, биполярностью мышления не страдаю.

              Вы мне лучше скажите, как увидеть в Topcoder Arena тот шрифт, который мне нужен, тогда я тоже может быть начну получать удовольствие от Java.
15 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
Не читайте этот пост, если вам не интересны оптимизации а-ля "попереставлять форики".

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

На С++ удалось достичь времени около 0.138 (код без оптимизаций давал 0.236). Вот отрывок:
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
{
    int* ai = a[i];
    int* bj = b[j];
    int s = 0;
    for (int k = 0; k < N; k++)
        s += ai[k] * bj[k];
    c[i][j] = s;
}
То есть за скобки (за цикл) вынесены два указателя и счетчик суммы.

На С# время вышло 0.360 (код без оптимизаций на одномерном массиве - 0.703). Отрывок:
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
{
    int isz = i * size;
    int jsz = j * size;
    int s = 0;
    for (int k = 0; k < size; k++)
        s += a[isz+k] * b[jsz+k];
    c[i*size+j] = s;
}
За скобки пришлось вынести два произведения. Удивительно, но компилятор до этого сам не додумался.

Но самый враждебный код получился на Java. Время его работы - тоже 0.360 (код без оптимизаций на одномерном массиве давал 1.121 - в 3 раза больше). Выглядит это как-то так:
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
{
    int isz = i * size;
    int jsz = j * size;
    int s = 0;
    for (int t = size / 16; t > 0; t--)
    {
        s += a[isz++] * b[jsz++];
        ...
        // еще 15 раз эта же строчка
    }
    for (int t = size % 16; t > 0; t--)
        s += a[isz++] * b[jsz++];
    c[i*size+j] = s;
}
Тут пришлось вручную раскручивать цикл. Жаль, что на Java нельзя написать девайс Даффа...

Конечно, никакому врагу не пожелаешь оказаться на контесте в ситуации, когда возникает необходимость делать вещи, которые должен бы делать компилятор - раскручивать циклы, вручную инлайнить функции и т. д. Тем не менее полезно держать в голове и такие расклады.
  • 15 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А почему на C++ и на С# не развёрнуты циклы? Это не помогло?

    Вообще, я помню, как у нас на Всесибирской олимпиаде после разворачивания цикла от 1 до n, где n <= 6, решение стало работать в полтора раза быстрее и сдалось. Решение было на VS C++.