FreeBasic
Вы хотите отреагировать на этот пост ? Создайте аккаунт всего в несколько кликов или войдите на форум.

Увеличение на единицу

Участников: 3

Перейти вниз

Увеличение на единицу Empty Увеличение на единицу

Сообщение  Vadim Weinberg Пн Окт 06, 2014 2:46 am

Пытался найти быстрый способ увеличения переменной на 1.
Написал программку.
Код:

/'ПОПЫТКА ОПРЕДЕЛИТЬ САМЫЙ БЫСТРЫЙ ИЛИ САМЫЙ МЕДЛЕННЫЙ СПОСОБ УВЕЛИЧЕНИЯ ЦЕЛОГО НА 1.

ЗАДАЧА РАСПРОСТРАНЕННАЯ.
БЫЛО ЖЕЛАНИЕ НАЙТИ БЫСТРЫЙ СПОСОБ УВЕЛИЧЕНИЯ ПЕРЕМЕННОЙ НА 1.
ВРОДЕ КАК УМНОЖЕНИЕ НА 2 ПУТЕМ СДВИГА ВЛЕВО.

ПРОБОВАЛ УВЕЛИЧИВАТЬ ПЕРЕМЕННУЮ НА 1
- ПРИБАВЛЯЛ ЕЙ 1                         (ДВА СПОСОБА ЗАПИСИ intA+=1    И intA=intA+1)
- ПРИБАВЛЯЛ 1 ОПРЕДЕЛЕННУЮ ЧЕРЕЗ #Define (ДВА СПОСОБА ЗАПИСИ intA+=1    И intA=intA+1)
- ПРИБАВЛЯЛ ПЕРЕМЕННУЮ=1                 (ДВА СПОСОБА ЗАПИСИ intA+=iOne И intA=intA+iOne)
- ПРИБАВЛЯЛ КОНСТАНТУ =1                 (ДВА СПОСОБА ЗАПИСИ intA+=iONE И intA=intA+iONE)
- ПРИБАВЛЯЛ С ПОМОЩЮ АССЕМБЛЕРНОЙ ВСТАВКИ(ДВА СПОСОБА        inc eax    И add eax, 1.    ДУМАЛ inc БЫСТРЕЕ)

ПОПРОБОВАЛ ЭТИ МАНИПУЛЯЦИИ С БЕЗЗНАКОВЫМИ ПЕРЕМННЫМИ/КОНСТАНТАМИ.
 
НО, ОБЛОМ, ЛИДЕРСКОГО СПОСОБА НЕТ.
'/
#Include "string.bi" 'БЕЗ НЕГО ФУНКЦИЯ Format() НЕ РАБОТАЕТ.  

Namespace Class1'КЛАСС СПРЯТАЛ ВНУТРЬ Namespace, Т.К. УДОБНЕЕ В РЕДАКТОРЕ (FbEdit) СВОЙСТВА И МЕТОДЫ "ОБЪЕДЕНИНЫ".
  Type Bench 'КЛАСС ЗАСЕКАЕТ НАЧАЛО И КОНЕЦ ТЕСТА, РАСЧИТЫВАЕТ ВРЕМЯ, ПЕЧАТАЕТ СКОРОСТЬ ТЕСТА И ЕГО НАЗВАНИЕ.
    Declare Sub Start(As String,ByRef As Integer)   'ПИШУ НОМЕР ТЕСТА, НАЗВАНИЕ ТЕСТА, ЗАПОМИНАНЮ-ЗАСЕКАЮ ВРЕМЯ НАЧАЛА ТЕСТА.
    Declare Sub Finish()                            'ЗАПОМИНАНЮ-ЗАСЕКАЮ ВРЕМЯ ОКОНЧАНИЯ ТЕСТА, ЗАПИСЫВАЮ СКОРОСТЬ ТЕСТА.
    Declare Sub Record()                            'ВЫВОЖУ МАКСИМАЛЬНОЕ И МИНИМАЛЬНОЕ ЗНАЧЕНИЕ ТЕСТА.
    Private:' ЗАЧЕМ Private? МОЖЕТ И НЕ НАДО? НО ПУСКАЙ БУДЕТ...
    T1 As Double                  'ЗНАЧЕНИЕ ТАЙМЕРА В НАЧАЛЕ ТЕСТА.
    T2 As Double                  'ЗНАЧЕНИЕ ТАЙМЕРА ПОСЛЕ ЗАВЕРШЕНИЯ ТЕСТА.
    Num_Test As UShort=0          'НОМЕР ТЕСТА
    Record_Tmp As String          'ВРЕМЕННАЯ СТРОКА, СОХРАНЯЕТ НАЗВАНИЕ ТЕСТА В Start ДЛЯ Finish ГДЕ МОЖЕТ БЫТЬ ПРИСВОЕНА САМОМУ БЫСТОМУ ИЛИ МЕДЕННОМУ ТЕСТУ.
    Record_MAX_Name As String     'ИМЯ   САМОГО МЕДЛЕННОГО ТЕСТА.
    Record_MAX_Num As Double=0    'ВРЕМЯ САМОГО МЕДЛЕННОГО ТЕСТА.
    Record_MIN_Name As String     'ИМЯ   САМОГО БЫСТОГО    ТЕСТА.
    Record_MIN_Num As Double=1000 'ВРЕМЯ САМОГО БЫСТОГО    ТЕСТА.
  End Type
  Sub Bench.Start(tName As String,ByRef i As Integer)'ПИШУ НОМЕР ТЕСТА, НАЗВАНИЕ ТЕСТА, ЗАПОМИНАНЮ-ЗАСЕКАЮ ВРЕМЯ НАЧАЛА ТЕСТА.
    i=0 'ОБНУЛЯЮ ПЕРЕМЕННУЮ "ДОНОР" (aInt), КОТОРУЮ В ТЕСТЕ "ДОВЕЛИ ДО МАКСИМУМА"(2147483646). ДОСТУП К НЕЙ ЕСТЬ, ПОЛУЧЕНА ПО ByRef.
    Record_Tmp=tName 'СОХРАНЯЮ НАЗВАНИЕ ТЕСТА ДО ИСПОЛЬЗОВАНИЯ В Finish, ГДЕ ОПРЕДЕЛЯЮ САМЫЙ БЫСТРЫЙ И САМЫЙ МЕДЛЕННЫЙ ТЕСТ.
    Num_Test+=1      'УВЕЛИЧИВАЮ НОМЕР ТЕСТА.
    ? Space(4-Len(Str(Num_Test)))&Str(Num_Test)&": "& tName &" "&String(50-Len(tName),45)&" ";'ПЕЧАТАЮ СТРОКУ С НОМЕРОМ ТЕСТА И НАЗВАНИЕМ (СТРОКУ НЕ ПЕРЕНОШУ).
    T1=Timer'ОП !!!! ЗАСЁК ВРЕМЯ. ДАЛЕЕ ТЕСТ.
  End Sub
  Sub Bench.Finish()'ЗАПОМИНАНЮ-ЗАСЕКАЮ ВРЕМЯ ОКОНЧАНИЯ ТЕСТА, ЗАПИСЫВАЮ СКОРОСТЬ ЦИКЛА С ТЕТСОМ.
    T2=Timer-T1'ОП !!! И ВРЕМЯ ЗАСЕК И РАЗНИЦУ ПОДСЧИТАЛ (ДПЛИТЕЛЬНОСТЬ ТЕСТА).
    ? Format(T2 ," ##0.0000 ")'ДОПЕЧАТЫВАЮ ДЛИТЕЛЬНОСТЬ ТЕСТА.
    If T2<Record_MIN_Num Then                           'ИЩУ САМОЕ БЫСТРОЕ ВЫПОЛНЕНИЕ ТЕСТА.
      Record_MIN_Name = Record_Tmp: Record_MIN_Num = T2 'ЗАПОМИНАЮ НАЗВАНИЕ ТЕСТА И ВРЕМЯ ЕГО ВЫПОЛНЕНИЯ.
    EndIf
    If T2>Record_MAX_Num Then                           'ИЩУ САМОЕ МЕДЛЕННОЕ ВЫПОЛНЕНИЕ ТЕСТА.
      Record_MAX_Name = Record_Tmp: Record_MAX_Num = T2 'ЗАПОМИНАЮ НАЗВАНИЕ ТЕСТА И ВРЕМЯ ЕГО ВЫПОЛНЕНИЯ.
    EndIf
  End Sub
  Sub Bench.Record'ПЕЧАТАЮ ИТОГ ВЫПОЛНЕНИЯ ТЕСТОВ.
    ?
    ? "MIN - "; Format(Record_MIN_Num," ##0.0000 "), Record_MIN_Name       'САМОЕ КОРОТКОЕ ВРЕМЯ И НАЗВАНИЕ ТЕСТА.
    ? "DIF - "; Format(100-100*(Record_MIN_Num/Record_MAX_Num),"#0.00");"%"'ОТЛИЧИЕ СКОРОСТИ В ПРОЦЕНТАХ.
    ? "MAX - "; Format(Record_MAX_Num," ##0.0000 "), Record_MAX_Name       'САМОЕ ДЛИННОЕ ВРЕМЯ  И НАЗВАНИЕ ТЕСТА.
    ?
    ? !"END\7":Sleep 'ВСЁ! END-BEEP-SLEEP.
  End Sub
End Namespace' КОНЕЦ Class1

Dim Test As Class1.Bench    'СОЗДАЮ ЭКЗЕМПЛЯР КЛАССА. ДОСТУП ЧУТЬ СЛОЖНЕЕ, ЗАТО МЕТОДЫ-ФУНКЦИИ И ОПИСАНИЕ КЛАССА НЕ БОЛТАЮТСЯ В ПРОГРАММЕ.

Const MaxI=2147483646       'СТОЛЬКО РАЗ БУДУ "ГОНЯТЬ" ТЕСТЫ.
Dim As Integer aInt         '"ДОНОР". ЭТОЙ ПЕРЕМЕННОЙ БУДЕМ ПРИБАВЛЯТЬ 1.
Dim As Integer iOne=1       'ЕДИНИЦА В ПЕРЕМЕННОЙ Integer
Const As Integer C_ONE=1    'ЕДИНИЦА В КОНСТАНТЕ  Integer
#Define dINTEGER 1          'ЕДИНИЦА ОПЕРДЕЛЕННАЯ #Define

'      ПОЧЕМУ ТЕСТЫ В ОДНУ СТРОКУ ЗАПИСАНЫ? РЕШИЛ, ЧТО ТАК ПРОЩЕ И ПОНЯТНЕЕ. ОНИ ОДНОТИПНЫЕ. ИНАЧЕ, НА СОТНЮ СТРОК БОЛЬШЕ.
'ПЕЧАТАЮ НАЗВАНИЕ ТЕСТА И ВКЛЮЧАЮ "ТАЙМЕР":НАЧИНАЮ ЦИКЛ ОТ 0 ДО MaxI  :|==== САМ ТЕСТ ====|:Next:ВЫКЛЮЧАЮ "ТАЙМЕР", ПЕЧАТАЮ РЕЗУЛЬТАТ.
Test.start("Integer+=1",aInt)             :For n As UInteger=0 To MaxI: aInt+=1            :Next:Test.Finish
Test.start("Integer=Integer+1",aInt)      :For n As UInteger=0 To MaxI: aInt=aInt+1        :Next:Test.Finish
Test.start("Integer+=Integer",aInt)       :For n As UInteger=0 To MaxI: aInt+=iOne         :Next:Test.Finish
Test.start("Integer=Integer+Integer",aInt):For n As UInteger=0 To MaxI: aInt=aInt+iOne     :Next:Test.Finish
Test.start("Integer+=Const",aInt)         :For n As UInteger=0 To MaxI: aInt+=C_ONE        :Next:Test.Finish
Test.start("Integer=Integer+Const",aInt)  :For n As UInteger=0 To MaxI: aInt=aInt+C_ONE    :Next:Test.Finish
Test.start("Integer+=#Define",aInt)       :For n As UInteger=0 To MaxI: aInt+=dINTEGER     :Next:Test.Finish
Test.start("Integer=Integer+#Define",aInt):For n As UInteger=0 To MaxI: aInt=aInt+dINTEGER :Next:Test.Finish
Test.start("Asm inc eax (Integer)",aInt)  :For n As UInteger=0 To MaxI:                    :    :
:                                         :                           : Asm mov eax, [aInt]'    :
:                                         :                           : Asm inc eax        '    :  
:                                         :                           : Asm mov [aInt], eax'    :
:                                         :                           :                    :Next:Test.Finish
Test.start("Asm add eax, 1(Integer)",aInt):For n As UInteger=0 To MaxI:                    :    :
:                                         :                           : Asm mov eax, [aInt]'    :
:                                         :                           : Asm add eax, 1     '    :
:                                         :                           : Asm mov [aInt], eax'    :
:                                         :                           :                    :Next:Test.Finish
'ПЕЧАТАЮ НАЗВАНИЕ ТЕСТА И ВКЛЮЧАЮ "ТАЙМЕР":НАЧИНАЮ ЦИКЛ ОТ 0 ДО MaxI  :|==== САМ ТЕСТ ====|:Next:ВЫКЛЮЧАЮ "ТАЙМЕР", ПЕЧАТАЮ РЕЗУЛЬТАТ.

'МОЖЕТ БЫТЬ С БЕЗЗНАКОВЫМИ ЦЕЛЫМИ СКОРОСТЬ ВОЗРАСТЕТ? ПРОВЕРИМ.
Dim As UInteger aUInt     '"ДОНОР". ЭТОЙ ПЕРЕМЕННОЙ БУДЕМ ПРИБАВЛЯТЬ 1.
Dim As UInteger uiOne=1   'ЕДИНИЦА В ПЕРЕМЕННОЙ UInteger
Const As UInteger C_UONE=1'ЕДИНИЦА В КОНСТАНТЕ  Integer

'ЗДЕСЬ НЕМНОГО СТРАННО.  
'МЕТОД Start(As String,ByRef As Integer) ДОЛЖЕН ВО ВТОРОМ ПАРАМЕТРЕ ПОЛУЧАТЬ Integer ByRef,
'НО Я ЕМУ ПОДСОВЫВАЮ UInteger, А ОН КОРРЕКТНО РАБОТАЕТ... НАВЕРНОЕ, ПОТОМУ, ЧТО ByRef?

'ПЕЧАТАЮ НАЗВАНИЕ ТЕСТА И ВКЛЮЧАЮ "ТАЙМЕР"    :НАЧИНАЮ ЦИКЛ ОТ 0 ДО MaxI  :|==== САМ  ТЕСТ ====|:Next:ВЫКЛЮЧАЮ "ТАЙМЕР", ПЕЧАТАЮ РЕЗУЛЬТАТ.
Test.start("UInteger+=1",aUInt)               :For n As UInteger=0 To MaxI: aUInt+=1            :Next:Test.Finish
Test.start("UInteger=UInteger+1",aUInt)       :For n As UInteger=0 To MaxI: aUInt=aUInt+1       :Next:Test.Finish
Test.start("UInteger+=UInteger",aUInt)        :For n As UInteger=0 To MaxI: aUInt+=uiOne        :Next:Test.Finish
Test.start("UInteger=UInteger+UInteger",aUInt):For n As UInteger=0 To MaxI: aUInt=aUInt+uiOne   :Next:Test.Finish
Test.start("UInteger+=UConst",aUInt)          :For n As UInteger=0 To MaxI: aUInt+=C_UONE       :Next:Test.Finish
Test.start("UInteger=UInteger+UConst",aUInt)  :For n As UInteger=0 To MaxI: aUInt=aUInt+C_UONE  :Next:Test.Finish
Test.start("UInteger+=#Define",aUInt)         :For n As UInteger=0 To MaxI: aUInt+=dINTEGER     :Next:Test.Finish
Test.start("UInteger=UInteger+#Define",aUInt) :For n As UInteger=0 To MaxI: aUInt=aUInt+dINTEGER:Next:Test.Finish
Test.start("Asm inc eax (UInteger)",aUInt)    :For n As UInteger=0 To MaxI:                     :    :
:                                             :                           : Asm mov eax, [aUInt]'    :
:                                             :                           : Asm inc eax         '    :
:                                             :                           : Asm mov [aUInt], eax'    :
:                                             :                           :                     :Next:Test.Finish
Test.start("Asm add eax, 1 (UInteger)",aUInt) :For n As UInteger=0 To MaxI:                     :    :
:                                             :                           : Asm mov eax, [aUInt]'    :
:                                             :                           : Asm Add eax, 1      '    :
:                                             :                           : Asm mov [aUInt], eax'    :
:                                             :                           :                     :Next:Test.Finish
'ПЕЧАТАЮ НАЗВАНИЕ ТЕСТА И ВКЛЮЧАЮ "ТАЙМЕР"    :НАЧИНАЮ ЦИКЛ ОТ 0 ДО MaxI  :|==== САМ  ТЕСТ ====|:Next:ВЫКЛЮЧАЮ "ТАЙМЕР", ПЕЧАТАЮ РЕЗУЛЬТАТ.

'ПЕЧАТАЮ ИТОГ ВЫПОЛНЕНИЯ ТЕСТОВ.
Test.Record'ЗДЕСЬ ПРОГРАММЕ КОНЕЦ.

'P.S. ИЗВИНИТЕ ЗА ОШИБКИ В РУССКИХ СЛВАХ. НЕ ДАНО.
Выводы

  1. Среди выполненных тестов нет явного лидера по скорости работы. Чаще самым быстрым оказывался Asm add eax, 1. Тесты с Беззнаковыми целыми самыми быстрыми были очень редко.
  2. Нет и самого медленного. Среди самых медленных часто оказывались тесты с Беззнаковыми целыми.
  3. Скорость выполнения тестов различается на 5-10%.
  4. Скорость работы могут сильно (в 1,5-1,7 раза) замедлять другие программы. Мне пришлось выключать Службу индексирования и Антивирус.
  5. FB версии 1 генерирует бОльший по объёму код, по сравнении с FB v0.91. 59 и 51 Kb соответственно. На скорость работы вроде бы не влияет.

FB оптимизирует ASM код используя inc в тех случаях, когда увеличение на 1 задано явно (Const, #Define или прямо в тексте программы +1).


Dim As Integer aInteger
aInteger+=666

'Задано явно, но не 1.

sub esp, 4
.Lt_0002:
mov dword ptr [ebp-4], 0
add dword ptr [ebp-4], 666

Dim As Integer aInteger
aInteger+=1

'Единица задана в тексте.

sub esp, 4
.Lt_0002:
mov dword ptr [ebp-4], 0
inc dword ptr [ebp-4]

Dim As Integer aInteger
aInteger=aInteger+1

'Единица задана в тексте.

sub esp, 4
.Lt_0002:
mov dword ptr [ebp-4], 0
inc dword ptr [ebp-4]

Dim As Integer aInteger
Dim As Integer bInteger=1
aInteger=aInteger+bInteger

'Единица присвоена переменной.

sub esp, 8
.Lt_0002:
mov dword ptr [ebp-4], 0
mov dword ptr [ebp-8], 1
mov eax, dword ptr [ebp-8]
add dword ptr [ebp-4], eax

Dim As Integer aInteger
Const As Integer cInteger=1
aInteger=aInteger+cInteger

'Единица явно определена в Const.

sub esp, 4
.Lt_0002:
mov dword ptr [ebp-4], 0
inc dword ptr [ebp-4]

Dim As Integer aInteger
#Define dINTEGER 1
aInteger=aInteger+dINTEGER

'Единица явно определена в #Define.

sub esp, 4
.Lt_0002:
mov dword ptr [ebp-4], 0
inc dword ptr [ebp-4]


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


Случайно обнаружил.
Функция декларированная с параметром (..., ByRef As Integer), корректно работала получая UInteger. Предупреждений от компилятора не было. Вроде удобно, но можно нарваться на ошибку выполнения (типа Переполнения), так, что надо внимательно следить, если пользоваться такой халявой.


Последний раз редактировалось: Vadim Weinberg (Чт Окт 16, 2014 6:53 pm), всего редактировалось 1 раз(а)

Vadim Weinberg

Сообщения : 18
Дата регистрации : 2010-07-08
Возраст : 59
Откуда : СПб

Вернуться к началу Перейти вниз

Увеличение на единицу Empty Re: Увеличение на единицу

Сообщение  Замабувараев Ср Окт 15, 2014 7:52 am

Нужно посмотреть, сколько байт занимает команда mov и сколько inc и выбрать что меньше.
Замабувараев
Замабувараев

Сообщения : 99
Дата регистрации : 2008-08-20
Возраст : 40
Откуда : Красноярск

http://www.freebasic.su

Вернуться к началу Перейти вниз

Увеличение на единицу Empty Re: Увеличение на единицу

Сообщение  Vadim Weinberg Чт Окт 16, 2014 6:51 pm

zamabuvaraeu пишет:Нужно посмотреть, сколько байт занимает команда mov и сколько inc и выбрать что меньше.

Уточнил.

inc  eax      
add eax, 1

Делают о дно и то же. Прибавляют единицу.
В современных процессорах (по мануалам от Pentium и новее) add выполняется за 1 такт, как и inc. Но в некоторых случаях за 2. Все зависит от предыдущего кода, а как зависит, я не стал разбираться. Думаю и inc может за 2 такта.
Мне помнилось, что inc 1 такт, а add 2 такта. Но может это память о каких-то очень древних процессорах (возможно вообще Z80?). Не знаю, копать не буду, это уже археология.
Что касаемо скорости увеличения на единицу, скорость примерно одинаковая во всех способах.
Думаю, что тему можно закрыть.

P.S.

В "The microarchitecture of Intel, AMD and VIA CPUs." советуют:

INC and DEC

These instructions have a problem with partial flag access.

Always replace INC EAX with ADD EAX,1, etc.

Чего-то с флагами делают не то, рекомендуют использовать add.

Vadim Weinberg

Сообщения : 18
Дата регистрации : 2010-07-08
Возраст : 59
Откуда : СПб

Вернуться к началу Перейти вниз

Увеличение на единицу Empty Re: Увеличение на единицу

Сообщение  electrik Пн Окт 20, 2014 11:09 pm

поповоду предыдущих команд, есть мануал: оптимизация для процессоров пентиум.
там выравнивается код по границам, вобщем запарная вещь, да и ещё спаривание команд.
если мы не пишем программу, которая за час должна вычислить 1000000 знаков после запятой числа pi, тогда то что предоставляет FreeBasic- сойдёт.
попробуй оптимизировать свой код вот так:
оригинальный кусок кода
Код:

:                                         :                           : Asm mov eax, [aInt]'    :
:                                         :                           : Asm inc eax        '    :  
:                                         :                           : Asm mov [aInt], eax'    

оптимизированный код:
Код:

:                                         :                           : Asm push [aInt]'    :
asm pop eax
:                                         :                           : Asm inc eax        '    :  
asm push eax
:                                         :                           : Asm pop [aInt]'    :
такой код, должен быстрее работать, хоть и команд больше. пуши и попы быстро работают.
а вообще, если серьёзно, то быстрые участки кода, надо сразу на асме проектировать, считать всё в регистрах, и только в самую последнюю очередь записывать в память.
я раньше тоже был фанатом оптимизаций, а щас надоело. микрософт пишет запускной файл ворда на 10 мегабайт, а я извращаюсь, пытаясь всё в 64 кб засунуть. нафиг надо! машины щас мощные, и они для этого и придуманы, чтоб за счет скорости, даже не оптимизированный код быстро обсчитывать.
единственное, где нужна реально злая оптимизация- это графика и синтез псевдоаналогово видео и звука- тут ещё пока машины не могут за долю секунды обсчитать пол вселенной видео.
мы конечно ещё пока молодёж, но будущее уже за той молодёжью, которым лет по 14. учитесь и стройте квантовый компьютер, там уже будет пофиг, как говорят там всё мгновенно. уже есть разработки, но пока информация передаётся с большими потерями. на таком компьютере, можно будет делать всё и сразу.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Вернуться к началу Перейти вниз

Увеличение на единицу Empty Re: Увеличение на единицу

Сообщение  Замабувараев Чт Окт 30, 2014 6:53 pm

Оптимизация не нужна, нужно лишь купить железо помощнее.
Замабувараев
Замабувараев

Сообщения : 99
Дата регистрации : 2008-08-20
Возраст : 40
Откуда : Красноярск

http://www.freebasic.su

Вернуться к началу Перейти вниз

Вернуться к началу

- Похожие темы

 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения