Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > что работает быстрее?


Автор: polosatij 26.11.2004, 16:38
и всё с ней связанное:
народ! нужна информация по оптимизации smile

например, кто скажет, что работает быстрее:

Vector() или ArrayList() smile
может есть что-то другое, побыстрее?

например, на

http://forum.vingrad.ru/index.php?showtopic=24799&st=90

нашёл очень полезную для меня инфо.

Еще цитируя Domestic Cat:

Цитата(Domestic @ 8.7.2004, 17:33)
Не претендую на абсолютную истину, но попробую.

Не оптимизируйте! Пишите программы, которые понятны, легко дебагить и модифицировать.

На самом деле конечно оптимизировать нужно. Чтобы понять что оптимизировать, помните,
что в основном нагрузка приходится на 10-20% кода. Узнать какой метод наиболее задействован
мозжно, запустив с флагом -Xprof.

На самом деле HotSpot и JIT (Just-In-Time Compiler) делают большую работу по оптимизации. Можно легко найти инфо по этому вопросу. В целом же оптимизация программы программистом сводится к:

1. Использованию оптимальных алгоритмов. Например, для быстрого поиска используйте
HashMap, он быстрее чем, скажем TreeMap.

2. Старайтесь использоват побитовые операции. Вместо х/32 луче использоват х >> 5; вместо
х % 32 - х & 31 (31 = 32 - 1). Работает только для степеней 2.

3. Заменяйте умножение на суммирование, возведение в степень - на умножение.

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

5.Заменяйте операции с float, double на операции с int и делайте кастинг назад в float (тут на предыдущей странице пример есть )

6. Используйте Buffered{}Stream

7. Если нужен рандом -доступ к большим файлам (несколько мб), используйте memory-mapped files (см MappedByteBuffer в Java API). Программа может читать из MappedByteBuffer почти так же быстро, как из памяти.

http://forum.vingrad.ru/index.php?showtopic=24799&st=105



может еще кто что подскажет на это тему smile

Domestic Cat, я не совсем понял, что ты подразумеваешь под:

6. Используйте Buffered{}Stream

не объяснишь?

ещё на эту тему:

Код

MyDialog dial= new MyDialog(new Frame(), "title", true);

....

class MyDialog extens Dialog{
 ...
}


млин! у меня большая проблема с передачей Диалогу: new Frame(). У меня такое ощушение, что new Frame() ест очень много памяти! из за этого похоже.. если я быстро вызываю новый Диалог (скажим, 2 раза подряд), всё моё приложение зависает на вечность smile

если я передаю в Диалог -> null, то получаю исключение: nullOwnerException.
есть ли другие методы smile


заранее БОЛЬШОЕ паси smile

Автор: redrick 26.11.2004, 17:06
Buffered{}Stream = BufferedInputStream || BufferedOutputStream

ну буффер у них там есть - что тут еще скажешь :

...an application can write bytes to the underlying output stream without necessarily causing a call to the underlying system for each byte written.

Автор: Domestic Cat 26.11.2004, 17:12
Цитата
Vector() или ArrayList() 
может есть что-то другое, побыстрее?


ArrayList почти тo ж самоe что i Vector, только несинхронизованный. Следовательно, он быстрее.

Цитата
6. Используйте Buffered{}Stream

не объяснишь?


Буффированный стрим пишет(читает) сначала в буфер, когдa буфер заполняется, sодержимое передается системе. это быстрее, чем передавать системе каждый байт. все этo в апи ест:
Цитата
The class implements a buffered output stream. By setting up such an output stream, an application can write bytes to the underlying output stream without necessarily causing a call to the underlying system for each byte written.


Цитата
млин! у меня большая проблема с передачей Диалогу: new Frame(). У меня такое ощушение, что new Frame() ест очень много памяти! из за этого похоже.. если я быстро вызываю новый Диалог (скажим, 2 раза подряд), всё моё приложение зависает на вечность 


U диалогa должен быть владелец - другой диалог или фрейm. Передавaй ему ссылку на уже имеющийся фрейм / диалоg или пользуйся чем либо другим JOptionPane, JWindow

Автор: polosatij 26.11.2004, 17:22
Цитата(Domestic @ 26.11.2004, 17:12)
U диалогa должен быть владелец - другой диалог или фрейm. Передавaй ему ссылку на уже имеющийся фрейм / диалоg или пользуйся чем либо другим JOptionPane, JWindow


я javax.swing.*; не могу использовать..

у меня нет имеюшегося Фрэйма -> Applett.
А Аплет не может выступить "прородичем" smile

Автор: Domestic Cat 26.11.2004, 17:28
Значит, передавай всем диалогам ссылку нa один и тот же фрейм:

Код

Frame frame = new Frame();
MyDialog dial= new MyDialog(frame, "title", true);
MyDialog dial2= new MyDialog(frame, "title", true);

Автор: Sleepy_PIP 26.11.2004, 19:49
Цитата(polosatij @ 26.11.2004, 16:38)
и всё с ней связанное:
народ! нужна информация по оптимизации smile

например, кто скажет, что работает быстрее:

Vector() или ArrayList() smile
может есть что-то другое, побыстрее?

например, на

http://forum.vingrad.ru/index.php?showtopic=24799&st=90

нашёл очень полезную для меня инфо.

Еще цитируя Domestic Cat:

Цитата(Domestic @ 8.7.2004, 17:33)
Не претендую на абсолютную истину, но попробую.

Не оптимизируйте! Пишите программы, которые понятны, легко дебагить и модифицировать.

На самом деле конечно оптимизировать нужно. Чтобы понять что оптимизировать, помните,
что в основном нагрузка приходится на 10-20% кода. Узнать какой метод наиболее задействован
мозжно, запустив с флагом -Xprof.

На самом деле HotSpot и JIT (Just-In-Time Compiler) делают большую работу по оптимизации. Можно легко найти инфо по этому вопросу. В целом же оптимизация программы программистом сводится к:

1. Использованию оптимальных алгоритмов. Например, для быстрого поиска используйте
HashMap, он быстрее чем, скажем TreeMap.

2. Старайтесь использоват побитовые операции. Вместо х/32 луче использоват х >> 5; вместо
х % 32 - х & 31 (31 = 32 - 1). Работает только для степеней 2.

3. Заменяйте умножение на суммирование, возведение в степень - на умножение.

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

5.Заменяйте операции с float, double на операции с int и делайте кастинг назад в float (тут на предыдущей странице пример есть )

6. Используйте Buffered{}Stream

7. Если нужен рандом -доступ к большим файлам (несколько мб), используйте memory-mapped files (см MappedByteBuffer в Java API). Программа может читать из MappedByteBuffer почти так же быстро, как из памяти.

http://forum.vingrad.ru/index.php?showtopic=24799&st=105



может еще кто что подскажет на это тему smile

Domestic Cat, я не совсем понял, что ты подразумеваешь под:

6. Используйте Buffered{}Stream

не объяснишь?

ещё на эту тему:

Код

MyDialog dial= new MyDialog(new Frame(), "title", true);

....

class MyDialog extens Dialog{
 ...
}


млин! у меня большая проблема с передачей Диалогу: new Frame(). У меня такое ощушение, что new Frame() ест очень много памяти! из за этого похоже.. если я быстро вызываю новый Диалог (скажим, 2 раза подряд), всё моё приложение зависает на вечность smile

если я передаю в Диалог -> null, то получаю исключение: nullOwnerException.
есть ли другие методы smile


заранее БОЛЬШОЕ паси smile

я несколько не понял цитаты DomestikCat - по поводу арифметики. - я всегда считал и считаю что мат. сопроцессор, который теперь есть везде, в любом ядре любого процессора на ПС будет гораздо лучше меня вычислять умножения (нет, не степени 2-ки - хотя и там оптимизация есть!), деления, и тем паче синусы и пр. тригонометрию. На самом деле мат. сопр - если разбираться в его кишках - в основном через таблицы и действует, редко когда через алгоритмы. но даже если через алгоритмы - это все равно будет быстрее доступа до элемента массива на J ИМХО конечно.
т.е. эту цитату можно воспринимать как - "JVM не использует мат сопроцессор"?????
Не, правда - для меня это будет открытием.

Автор: Domestic Cat 26.11.2004, 19:57
Цитата
На самом деле мат. сопр - если разбираться в его кишках - в основном через таблицы и действует, редко когда через алгоритмы. но даже если через алгоритмы - это все равно будет быстрее доступа до элемента массива на J ИМХО конечно.


Дело здесь в том, что если считаешь sin/cos в Java, тo обрашется она к нативным функциям. Просмотреть значние в "своем" массиве будет быстрее, тем более еслi не нужна большая точн ость.

Автор: Sleepy_PIP 26.11.2004, 20:16
Цитата(Domestic @ 26.11.2004, 19:57)
Цитата
На самом деле мат. сопр - если разбираться в его кишках - в основном через таблицы и действует, редко когда через алгоритмы. но даже если через алгоритмы - это все равно будет быстрее доступа до элемента массива на J ИМХО конечно.


Дело здесь в том, что если считаешь sin/cos в Java, тo обрашется она к нативным функциям. Просмотреть значние в "своем" массиве будет быстрее, тем более еслi не нужна большая точн ость.

эээ ... разве 4-5 тактов процессора быстрее доступа к элементу массива в J (нет, я правда не знаю - но сопр за 4-5 тактов любую операцию сделает).
Добавлено @ 20:21
Цитата(Sleepy_PIP @ 26.11.2004, 20:16)
Цитата(Domestic @ 26.11.2004, 19:57)
Цитата
На самом деле мат. сопр - если разбираться в его кишках - в основном через таблицы и действует, редко когда через алгоритмы. но даже если через алгоритмы - это все равно будет быстрее доступа до элемента массива на J ИМХО конечно.


Дело здесь в том, что если считаешь sin/cos в Java, тo обрашется она к нативным функциям. Просмотреть значние в "своем" массиве будет быстрее, тем более еслi не нужна большая точн ость.

эээ ... разве 4-5 тактов процессора быстрее доступа к элементу массива в J (нет, я правда не знаю - но сопр за 4-5 тактов любую операцию сделает).

тоесть я хотел сказать - это реально проверяли? и доступ к массиву быстрее сопроцессора?
если действительно так - может JVM просто сопроцессор не использует?
Я правда не знаю и интересуюсь ...

Автор: Domestic Cat 26.11.2004, 20:22
Цитата
эээ ... разве 4-5 тактов процессора быстрее доступа к элементу массива в J (нет, я правда не знаю - но сопр за 4-5 тактов любую операцию сделает).


сaм ВЫЗОВ нативноgo метоda медленнее smile
Добавлено @ 20:23
Цитата
тоесть я хотел сказать - это реально проверяли? и доступ к массиву быстрее сопроцессора?
если действительно так - может JVM просто сопроцессор не использует?
Я правда не знаю и интересуюсь ...


могем и бенчмарк забацать ... после перекурa =)

Автор: Sleepy_PIP 26.11.2004, 20:26
Цитата(Domestic @ 26.11.2004, 20:22)
Цитата
эээ ... разве 4-5 тактов процессора быстрее доступа к элементу массива в J (нет, я правда не знаю - но сопр за 4-5 тактов любую операцию сделает).


сaм ВЫЗОВ нативноgo метоda медленнее smile

нее, погоди. я опять не понял. Если байт-код синуса не транслируется JVM в непосредственную команду сопроцессора - то так и будет.
Дело в том, что речь насколько я надеюсь не о найтивных методах - а о ASM командах сопроцессору.
Если JVM действительно транслирует вызовы скажем тригонометрии в вызовы какой-либо библиотеки - то да, но если напрямую в команду сопроцессора - то сопроцессор должен быть быстрее всех ...
Вообщем пошел проверять smile ... Спасибо!

Автор: Domestic Cat 26.11.2004, 20:50
Вот такоj тест:

Код

// B.java
public class B
{  
   public static void main(String[] args)    
   {
       long t1 = System.currentTimeMillis();
       for (int i = 0; i < 10000000; i++)
       {
           GameMath.cos(0.54231f);
       }
       long t2 = System.currentTimeMillis();
       System.out.println("First took " + (t2-t1) + " milliseconds");
       t1 = System.currentTimeMillis();
       for (int i = 0; i < 10000000; i++)
       {
           Math.cos(0.54231f);
       }
       t2 = System.currentTimeMillis();
       System.out.println("Second took " + (t2-t1) + " milliseconds");
   }
}

Код

// GameMath.java
public class GameMath
{

   private static final int TABLE_SIZE_BITS = 12;
   private static final int TABLE_SIZE = 1 << TABLE_SIZE_BITS;
   private static final int TABLE_SIZE_MASK = TABLE_SIZE - 1;
   private static final int HALF_PI = TABLE_SIZE / 4;
   private static final float CONVERSION_FACTOR =
       (float)(TABLE_SIZE / (2 * Math.PI));

   private static float[] sinTable;

   static
   {
       init();
   }

   private static void init()
   {
       sinTable = new float[TABLE_SIZE];
       for (int i=0; i<TABLE_SIZE; i++)
       {
           sinTable[i] = (float)Math.sin(i / CONVERSION_FACTOR);
       }
   }
   
   public static float cos(float angleInRadians)
   {
       return cos(angleConvert(angleInRadians));
   }
   
   public static float cos(int angle)
   {
       return sinTable[(HALF_PI-angle) & TABLE_SIZE_MASK];
   }
   
   public static float cos(float dy, float hypo)
   {
       return dy / hypo;
   }

   public static float sin(float dx, float hypo)
   {
       return dx / hypo;
   }
   
   public static float sin(float angleInRadians)
   {
       return sin(angleConvert(angleInRadians));
   }
   
   public static float sin(int angle)
   {
       return sinTable[angle & TABLE_SIZE_MASK];
   }

   public static int angleConvert(float angleInRadians)
   {
       return  (int)(angleInRadians * CONVERSION_FACTOR);
   }
}




Результаты 3x запусков:

Цитата
cat> java B
First took 669 milliseconds
Second took 3037 milliseconds
cat> java B
First took 672 milliseconds
Second took 3048 milliseconds
cat> java B
First took 761 milliseconds
Second took 3121 milliseconds

Автор: Sleepy_PIP 26.11.2004, 20:57
Цитата(Domestic @ 26.11.2004, 20:50)
Вот такоj тест:

Код

// B.java
public class B
{  
   public static void main(String[] args)    
   {
       long t1 = System.currentTimeMillis();
       for (int i = 0; i < 10000000; i++)
       {
           GameMath.cos(0.54231f);
       }
       long t2 = System.currentTimeMillis();
       System.out.println("First took " + (t2-t1) + " milliseconds");
       t1 = System.currentTimeMillis();
       for (int i = 0; i < 10000000; i++)
       {
           Math.cos(0.54231f);
       }
       t2 = System.currentTimeMillis();
       System.out.println("Second took " + (t2-t1) + " milliseconds");
   }
}

Код

// GameMath.java
public class GameMath
{

   private static final int TABLE_SIZE_BITS = 12;
   private static final int TABLE_SIZE = 1 << TABLE_SIZE_BITS;
   private static final int TABLE_SIZE_MASK = TABLE_SIZE - 1;
   private static final int HALF_PI = TABLE_SIZE / 4;
   private static final float CONVERSION_FACTOR =
       (float)(TABLE_SIZE / (2 * Math.PI));

   private static float[] sinTable;

   static
   {
       init();
   }

   private static void init()
   {
       sinTable = new float[TABLE_SIZE];
       for (int i=0; i<TABLE_SIZE; i++)
       {
           sinTable[i] = (float)Math.sin(i / CONVERSION_FACTOR);
       }
   }
   
   public static float cos(float angleInRadians)
   {
       return cos(angleConvert(angleInRadians));
   }
   
   public static float cos(int angle)
   {
       return sinTable[(HALF_PI-angle) & TABLE_SIZE_MASK];
   }
   
   public static float cos(float dy, float hypo)
   {
       return dy / hypo;
   }

   public static float sin(float dx, float hypo)
   {
       return dx / hypo;
   }
   
   public static float sin(float angleInRadians)
   {
       return sin(angleConvert(angleInRadians));
   }
   
   public static float sin(int angle)
   {
       return sinTable[angle & TABLE_SIZE_MASK];
   }

   public static int angleConvert(float angleInRadians)
   {
       return  (int)(angleInRadians * CONVERSION_FACTOR);
   }
}




Результаты 3x запусков:

Цитата
cat> java B
First took 669 milliseconds
Second took 3037 milliseconds
cat> java B
First took 672 milliseconds
Second took 3048 milliseconds
cat> java B
First took 761 milliseconds
Second took 3121 milliseconds

ничего себе.
тоесть
Math.cos(0.54231f);
не транслируется в прямые вызовы сопроцессора. Так понять это?
как-же так ... обидно ужас ... сопр. есть, но не используется smile(. нет?
Добавлено @ 21:02
жаль что не прошли времена когда о математике надо было заботиться. и жаль что это теперь в J ... теперь надо быть осторожнее в 10 крат.
Спасибо!

Автор: Domestic Cat 26.11.2004, 21:09
Цитата
не транслируется в прямые вызовы сопроцессора. Так понять это?


JVM - это "надстройка " над ОС, напрямую она ничего не вызывает. smile

Автор: Sleepy_PIP 26.11.2004, 21:15
Цитата(Domestic @ 26.11.2004, 21:09)
Цитата
не транслируется в прямые вызовы сопроцессора. Так понять это?


JVM - это "надстройка " над ОС, напрямую она ничего не вызывает. smile

да. мои заблуждения глубоки. учимся далше. ....

Автор: polosatij 26.11.2004, 21:51
ещё один линк на тему оптимизации: smile

http://lib.juga.ru/article/articleview/164/1/68
Добавлено @ 21:59
вот, откопал то, что, наверно, не только мне одному интересно будет прочитать ( и не один раз )

Объекты

1. уменьшайте число временных объектов (в том числе внутри циклов);
2. по возможности используйте старые объекты, не создавайте новых;
3. контролируйте процесс создания объектов

* пишите простые конструкторы;
* используйте метод clone();
* используйте методы для создания объектов:
* public MyObject getInstance() { return new MyObject();}

String

1. используйте метод append() класса StringBuffer взамен конкантации строк;
2. используйте массив char[] array для создания строки, а не класс StringBuffer;
3. используйте запись String myString = "Hello!"; вместо String myString = new String("Hello!");
4. метод equalsIgnoreCase() работает быстрее, чем equals(), если длины строк не равны.

Поля классов и экземпляров классов

1. используйте ключевое слово final для создания неизменных объектов;
2. избегайте повторной инициализации полей экземпляра класса;
3. делайте методы static/private;
4. время, затраченное на вызов метода, оценивается примерно по следующей схеме: static < final < instance < interface метод < synchronized метод.

Память

1. используйте WeakReference для хранения элементов в больших таблицах;
2. используйте SoftReference для кэширования элементов;
3. используйте SoftReference для повторного использования памяти;
4. для замера времени исполнения фрагмента кода вызывайте System.gc();

Методы

1. не используйте без причины приведение типов;
2. не пишите громоздких методов;
3. операторы "n+=4" быстрее, чем "n=n+4";
4. оператор int++ быстрее, чем short++ or byte++;
5. избегайте деления переменных типа long;
6. используйте итерацию, а не рекурсию.

Синхронизация

1. по возможности избегайте синхронизации;
2. синхронизируйте блок, а не метод;
3. не используйте синхронизацию в циклах;
4. создавайте/используйте мониторы (Monitors) и мютексы (Mutex) взамен обыкновенной синхронизации.

Класс Doubles

1. Double.toString(double) метод – очень медленный;
2. не создавайте Double-объект из строки;

Общие советы

1. выполнение System.currentTimeMillis может занимать около 0.5ms;
2. научитесь понимать байт-код.

Автор: Sleepy_PIP 27.11.2004, 13:48
кстати я был не прав. в большинстве прямо компилирующихся языков под любой платформой sin(cos, tg, и так далее) будет превращаться в первую очередь в вызов библиотечной. ф., а та уже в свою очередь задействует сопроцессор. что явно больше времени доступа к массиву даже с предвычислением индекса. да.

Автор: Sleepy_PIP 27.11.2004, 19:04
объясните пожалуста. почему деление путем вычитания быстрее натурального деления?
вот код:
Код

public void TestS()
 {
   long ll=45000;
   long ts = System.currentTimeMillis();
   for(int i=0;i<1000000;i++)
   {
     for (; ll > 1; )
     {
       ll -= 5000;
     }
   }
   long te = System.currentTimeMillis();    
   System.out.println("del by minus " + (te-ts) + " milliseconds");
   ts = System.currentTimeMillis();
   for(int i=0;i<1000000;i++)
   {
     ll/=5000;
   }
   te = System.currentTimeMillis();    
   System.out.println("del by del " + (te-ts) + " milliseconds");

 }


вот результат:
del by minus 16 milliseconds
del by del 62 milliseconds

все-ж - от чего так происходит?
само деление - уже не вызов метода - это оператор, который вполне может быть выполнен на сопроцессоре, как в прочем и приведение типа.
Однако как сказад DomesticCat - так оно и получается, деление путем вычитания быстрее
Спасибо!
PS: что еще интересно - результат в ll для ll/=5000; всегда будет 0. ...

Автор: Domestic Cat 27.11.2004, 20:21
Цитата(Sleepy_PIP @ 27.11.2004, 10:04)
del by minus 16 milliseconds
del by del 62 milliseconds


Ну не настолько же быстрее smile
Просто у тебя ошибка: после первого прохода цикла
Код

for (; ll > 1; )
{
       ll -= 5000;
}


ll становится равным 0. Тогда все оставшиеся 999999 раз этот цикл пропускается. Во втором с,лучае ноль получается из-за того, что ты делишь 45000 на 5000 1000000 раз. После девятого деления ll становится равным 1, а 1/5000 дает 0, т.к. оба числа целые и выполняется целочисленное деление (остаток = 1, результат = 0) .
Я сделал так:

Код

public class Test1
{
public static void main(String [] args)
 {
   long ll=45000;
   long ts = System.currentTimeMillis();
   for(int i=0;i<1000000;i++)
   {
ll=45000;
     for (; ll > 1; )
     {
       ll -= 5000;
     }
   }
   long te = System.currentTimeMillis();
   System.out.println("del by minus " + (te-ts) + " milliseconds");
ts = System.currentTimeMillis();
   for(int i=0;i<1000000;i++)
   {
ll=45000;
     ll/=5000;
   }
   te = System.currentTimeMillis();
   System.out.println("del by del " + (te-ts) + " milliseconds");

 }
}


и получил:
Цитата
del by minus 330 milliseconds
del by del 320 milliseconds

то есть скорость приблизительно одинакова.

Автор: Sleepy_PIP 27.11.2004, 20:25
Спасибо. ошибку я проглядел smile.

а вот дельфевый код
Код

procedure TForm1.Button1Click(Sender: TObject);
var
i: longint;
ll: longint;
ds, de: TDateTime;
dd: double;
begin
    ll:=45000;
    ds:=now;
    for i:=0 to 1000000000 do
    begin
      ll:=45000;
      while ll>1 do
         ll:=ll-5000;
    end;
    de:=Now;
    ShowMessage(TimeToStr(ds-de));
    ds:=now;
    for i:=0 to 1000000000 do
    begin
         ll:=45000;
         dd:=ll/5000;
    end;
    de:=Now;
    ShowMessage(TimeToStr(ds-de));

end;



выполняется в более чем 10 раз быстрее для деления. Правда тут есть одна тонкость - результат деления засовывается в вещественную переменную ...

Автор: Domestic Cat 27.11.2004, 20:33
Цитата(Sleepy_PIP @ 27.11.2004, 11:25)

выполняется в более чем 10 раз быстрее для деления. Правда тут есть одна тонкость - результат деления засовывается в вещественную переменную ...


Ну, Делфи я не знаю, так что сказать не могу ничего. Если изменить так в Java коде:

Код

ll=45000;
double d = ll/5000;


то замедление незначительное: 330 мс против 390 мс.

Автор: Sleepy_PIP 27.11.2004, 20:37
сделал аналог дельфевому коду, с исправлением ошибок smile
Код

public void TestS()
 {
   long ll=45000;
   double dd;
   long ts = System.currentTimeMillis();
   for(int i=0;i<1000000;i++)
   {
     ll=45000;      
     for (; ll > 1; )
     {

       ll -= 5000;
     }
   }
   long te = System.currentTimeMillis();
   System.out.println("del by minus " + (te-ts) + " milliseconds");
   ts = System.currentTimeMillis();
   ll=45000;
   for(int i=0;i<1000000;i++)
   {
     ll=45000;
     dd=ll/5000;
   }
   te = System.currentTimeMillis();
   System.out.println("del by del " + (te-ts) + " milliseconds");

 }



но результаты все равно я не понимаю:
del by minus 47 milliseconds
del by del 93 milliseconds
правда тут может влиять ll=45000; в цикле. неужели из-а этого?
нет, не из-а этого.
закоментаринивание в цикле ll=45000;
дает все равно:

del by minus 47 milliseconds

del by del 94 milliseconds

учусь! и еще на долго ...




Автор: Domestic Cat 27.11.2004, 20:40
Ну деление-то остается делением, оно все-таки медленнее smile К тому же тут ты используешь (неявно) еще один оператор - конвертации лонга в дабл :
Код

dd = ll/5000;

эквивалентно:

dd = (double) (ll / 5000);


а конвертация - медленная штука.

Автор: Sleepy_PIP 27.11.2004, 20:44
Цитата(Domestic @ 27.11.2004, 20:40)
Ну деление-то остается делением, оно все-таки медленнее smile

сории, я еще не освоил дизасм (или как там в яве?) - не мог-бы ты привести во что выражается в байткоде вычитание и деление? случаем не в вызовы методов?
Сильно похоже что jvm действительно не использует сопроцессор вообще ... только догадки ...

Добавлено @ 20:46
Цитата(Domestic @ 27.11.2004, 20:40)
Ну деление-то остается делением, оно все-таки медленнее smile К тому же тут ты используешь (неявно) еще один оператор - конвертации интежера в дабл :
Код

dd = ll/5000;

эквивалентно:

dd = (double) (ll / 5000);


а конвертация - медленная штука.

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

Автор: Domestic Cat 27.11.2004, 20:50
Цитата
дело в том, что конвертацией так-же может заведовать сопроцессор ... но увы и ах, я так и не понимаю на чем теряется время ....


конвертацией занимается JVM, опкод l2d (в данном случае)

Цитата
не мог-бы ты привести во что выражается в байткоде вычитание и деление?


опкоды lsub и ldiv (для лонгов).

Все это ни о чем не говорит, т.к. JVM всегда вызывает методы ОС, она не работает с процессором напрямую.

Автор: Sleepy_PIP 27.11.2004, 20:55
Цитата(Domestic @ 27.11.2004, 20:50)
Цитата
дело в том, что конвертацией так-же может заведовать сопроцессор ... но увы и ах, я так и не понимаю на чем теряется время ....


конвертацией занимается JVM, опкод l2d (в данном случае)

Цитата
не мог-бы ты привести во что выражается в байткоде вычитание и деление?


опкоды lsub и ldiv (для лонгов).

Все это ни о чем не говорит, т.к. JVM всегда вызывает методы ОС, она не работает с процессором напрямую.

ааа. вот тыт понятно. Спасибо! а жаль между прочим! JVM все одно на всех платформах своя - могли-б и сопр. задействовать на прямую ...

Добавлено @ 20:59
Цитата(Sleepy_PIP @ 27.11.2004, 20:55)
Цитата(Domestic @ 27.11.2004, 20:50)
Цитата
дело в том, что конвертацией так-же может заведовать сопроцессор ... но увы и ах, я так и не понимаю на чем теряется время ....


конвертацией занимается JVM, опкод l2d (в данном случае)

Цитата
не мог-бы ты привести во что выражается в байткоде вычитание и деление?


опкоды lsub и ldiv (для лонгов).

Все это ни о чем не говорит, т.к. JVM всегда вызывает методы ОС, она не работает с процессором напрямую.

ааа. вот тыт понятно. Спасибо! а жаль между прочим! JVM все одно на всех платформах своя - могли-б и сопр. задействовать на прямую ...

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

Автор: Zandr 17.3.2005, 08:09
Ребята, зачем деление вычитанием? Причем просто вот так в цикле! smile
Вчера вечером вспомнил, что можно делить столбиком, и что битовые операции очень быстрые. В общем вот что получилось:
Код
    static int div( int a, int b) {
        if (b == 0) {
            throw new ArithmeticException( "divide by zero");
        }
        int r = 0, t = 1;
        boolean plus = (a ^ b) >= 0;

//        if (a < 0) {
// alternative to 'a = -a;' (but probably less efficient) is 
//            a = ~a;
//            a++;
//        }
        if (a < 0) a = -a;
        if (b < 0) b = -b;

        while ( a > b) {
            b <<= 1;
            t <<= 1;
        }

        while ( t > 0) {
            if (a >= b) {
                a -= b;
                r += t;
            }
            b >>= 1;
            t >>= 1;
        }
        return plus ? r : -r;
    }

Кому не лень, сравните сскорости с делением методом вычитания в случаях, когда
а) число делится на бОльшее (т.е. нуль в результате)
б) очень большое число делится на единицу, например.
в) что-нибудь на что-нибудь, когда ответ - первые единицы (1, 2, 3, ...)
Вот случай (б) должен оказаться показательным smile

Автор: Zandr 17.3.2005, 10:28
Ой, жалко - то как...... Тута ошибочка есть неразрешимая почти...
может вылазить при |a| > 0x40000000. Эх.

Автор: NotGonnaGetUs 17.3.2005, 18:20
прикольно, запустил тест "деление путём вычитания" c ключом -server (взят выше)

del by minus 31 milliseconds
del by del 0 milliseconds

без него, что-то порядка

del by minus 47 milliseconds
del by del 78 milliseconds

%)
Оптимизации это великолепно.


Хотя вполне возможно, это следствие оптимизации цикла, в режиме -server.

Так и есть.

Если заменить 5000, на рандомный делитель int by = r.nextInt(4000)+1000;
то обычное деление выигрывает в обычном и сервер моде.
Короче говоря то, что делить вычитанием быстрее - тоже заблуждение.
В случае -server / выигрывает в 2 раза, -client / выигрывает на 15-20% (1782 vs 1468 ms).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)