Тест "Счастливые билеты"

Тема в разделе "WASM.A&O", создана пользователем Intro, 7 сен 2021.

  1. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Оптимизация задачи.
    https://yadi.sk/d/zFoikkKNw2hDQw
    Можно выбрать от 0 до 8 изменив дефайн OPTIMIZATION.
    Время выполнения уменьшилось от 5 млн тактов и до 500-700, т.е. в 10 тысяч раз. Теперь задачу можно решить на любом утюге т.е. калькуляторе хоть на Б3-21.
    --- Сообщение объединено, 8 сен 2021 ---
    Базовый вариант, самый тупой, но зато понятный.
    Код (C):
    1.  
    2.     for(l3=0; l3<10; l3++)
    3.         for(l2=0; l2<10; l2++)
    4.             for(l1=0; l1<10; l1++)
    5.                 for(r3=0; r3<10; r3++)
    6.                     for(r2=0; r2<10; r2++)
    7.                         for(r1=0; r1<10; r1++)
    8.                             if (l1+l2+l3==r1+r2+r3)
    9.                                 count++;
    10.  
    Решил что сумму цифр надо вычислять там, где они меняются.
    Код (C):
    1.  
    2.    for(l3=0, sum_l=0; l3<10; l3++, sum_l-=9)
    3.         for(l2=0; l2<10; l2++, sum_l-=9)
    4.             for(l1=0; l1<10; l1++, sum_l++)
    5.                 for(r3=0, sum_r=0; r3<10; r3++, sum_r-=9)
    6.                     for(r2=0; r2<10; r2++, sum_r-=9)
    7.                         for(r1=0; r1<10; r1++, sum_r++)
    8.                             if (sum_l==sum_r)
    9.                                 count++;
    10.  
    Потом подумал что 686+ очень не любят условные переходы ака if'ы.
    Код (C):
    1.  
    2.     for(l3=0, sum_l=0; l3<10; l3++, sum_l-=9)
    3.         for(l2=0; l2<10; l2++, sum_l-=9)
    4.             for(l1=0; l1<10; l1++, sum_l++)
    5.                 for(r3=0, sum_r=0; r3<10; r3++, sum_r-=9)
    6.                     for(r2=0; r2<10; r2++, sum_r-=9)
    7.                         for(r1=0; r1<10; r1++, sum_r++)
    8.                             count += sum_l==sum_r;
    9.  
    Стало быстрей. Но это всё ерунда. Оптимизируем вариант 1.
    Можно легко доказать что условия count++ в цикле срабатывает только один раз или не разу, если сумма чисел в определённом диапазоне.
    Вот следующий вариант.
    Код (C):
    1.  
    2.     for(l3=0, sum_l=0; l3<10; l3++, sum_l-=9)
    3.         for(l2=0; l2<10; l2++, sum_l-=9)
    4.             for(l1=0; l1<10; l1++, sum_l++)
    5.                 for(r3=0, sum_r=0; r3<10; r3++, sum_r-=9)
    6.                     for(r2=0; r2<10; r2++, sum_r++)
    7.                         if (sum_l>=sum_r && sum_l<sum_r+10)
    8.                             count++;
    9.  
    Скорость заметно возросла. Но идём дальше, там уже по сложней.
    Далее такой вариант. Смотрим на эти ступеньки, и мысленно обваливаем её в пирамиду.
    Код (Text):
    1.  
    2. 0000000001111111111
    3. 000000001111111111
    4. 00000001111111111
    5. 0000001111111111
    6. 000001111111111
    7. 00001111111111
    8. 0001111111111
    9. 001111111111
    10. 01111111111
    11. 1111111111
    12.  
    Вертикальные столбики - это количество вариантов в этих диапазонах. А значит легко делаем следующий код.
    Код (C):
    1.  
    2.     for(l3=0, sum_l=0; l3<10; l3++, sum_l-=9)
    3.         for(l2=0; l2<10; l2++, sum_l-=9)
    4.             for(l1=0; l1<10; l1++, sum_l++)
    5.                 for(r3=0, sum_r=0; r3<10; r3++, sum_r++){
    6.                     int sum = sum_l - sum_r + 1;
    7.                     if (sum>0 && sum<20){
    8.                         count += sum;
    9.                         sum -= 10;
    10.                         if (sum>0)
    11.                             count -= 2*sum;
    12.                     }
    13.                 }
    14.  
    Ещё быстрей! И результат правильный. Но идём дальше.
    Теперь общая сумма вариантов равно не отдельному столбику, а суммы от левого края. Сумма половины пирамиды определяется так: (sum*sum+sum)/2. И по той же формуле отсекает в пирамиде лишние варианты.
    Получается код.
    Код (C):
    1.  
    2.     for(l3=0, sum_l=0; l3<10; l3++, sum_l-=9)
    3.         for(l2=0; l2<10; l2++, sum_l-=9)
    4.             for(l1=0; l1<10; l1++, sum_l++){
    5.                 int sum = sum_l + 1;
    6.                 count += (sum*sum+sum)/2;
    7.                 if (sum>10){
    8.                     sum -= 10;
    9.                     count -= ((sum*sum+sum)/2)*3;
    10.                     if (sum>10){
    11.                         sum -= 10;
    12.                         count += ((sum*sum+sum)/2)*3;
    13.                     }
    14.                 }
    15.             }
    16.  
    Стало ещё быстрей. Что дальше? Можно так.
    Код (C):
    1.  
    2.     for(sum_l=0; sum_l<=9*3; sum_l++){
    3.         int             sum = sum_l + 1;
    4.         unsigned int    count_l = (sum*sum+sum)/2;
    5.         if (sum>10){
    6.             sum -= 10;
    7.             count_l -= ((sum*sum+sum)/2)*3;
    8.             if (sum>10){
    9.                 sum -= 10;
    10.                 count_l += ((sum*sum+sum)/2)*3;
    11.             }
    12.         }
    13.         CountVar3[sum_l] = count_l;
    14.     }
    15.     for(l3=0, sum_l=0; l3<10; l3++, sum_l-=9)
    16.         for(l2=0; l2<10; l2++, sum_l-=9)
    17.             for(l1=0; l1<10; l1++, sum_l++)
    18.                 count += CountVar3[sum_l];
    19.  
    Быстрей, но что то не то. Может так.
    Код (C):
    1.  
    2.     for(sum_l=0; sum_l<=9*3; sum_l++){
    3.         int             sum = sum_l + 1;
    4.         unsigned int    count_l = (sum*sum+sum)/2;
    5.         if (sum>10){
    6.             sum -= 10;
    7.             count_l -= ((sum*sum+sum)/2)*3;
    8.             if (sum>10){
    9.                 sum -= 10;
    10.                 count_l += ((sum*sum+sum)/2)*3;
    11.             }
    12.         }
    13.         CountVar3[sum_l] = count_l;
    14.     }
    15.     for(sum_l=0; sum_l<=9*2; sum_l++){
    16.         int i;
    17.         unsigned int    count_l = CountVar3[sum_l];
    18.         for(i=1; i<10; i++)
    19.             count_l += CountVar3[sum_l+i];
    20.         CountVar2[sum_l] = count_l;
    21.     }
    22.     for(sum_l=0; sum_l<=9*1; sum_l++){
    23.         int i;
    24.         unsigned int    count_l = CountVar2[sum_l];
    25.         for(i=1; i<10; i++)
    26.             count_l += CountVar2[sum_l+i];
    27.         CountVar1[sum_l] = count_l;
    28.     }
    29.     for(l1=0; l1<10; l1++)
    30.         count += CountVar1[l1];
    31.  
    Не! Быстрей, но тоже не то.
    Ах да. Как же я упустил, задача то симметричная, мы вычислили вариант для одной стороны, а значит и для другой стороны такое количество вариантов. Значит надо просто возвести в квадрат.
    Вот вариант.
    Код (C):
    1.  
    2.     for(sum_l=0; sum_l<=9*3; sum_l++){
    3.         int             sum = sum_l + 1;
    4.         unsigned int    count_l = (sum*sum+sum)/2;
    5.         if (sum>10){
    6.             sum -= 10;
    7.             count_l -= ((sum*sum+sum)/2)*3;
    8.             if (sum>10){
    9.                 sum -= 10;
    10.                 count_l += ((sum*sum+sum)/2)*3;
    11.             }
    12.         }
    13.         count += count_l*count_l;
    14.     }
    15.  
    Так, да тут ещё можно в два раза уменьшить вариантов в цикле, а потом умножить на два. Но и так стало очень быстро. Теперь можно и для МК-61 программу составить, и он на своих 100 килогерцах решит достаточно быстро.
    Вот, как то так. Потом может лучше рисунками статью дополнить, чтобы попонятней было и выложить на хабре.
     
    Последнее редактирование: 8 сен 2021
  2. algent

    algent Member

    Публикаций:
    0
    Регистрация:
    11 апр 2018
    Сообщения:
    101
    У меня год назад, сильно зудело - хотелось переписать свой старый FFT алгоритм - пришла пара классных идей. Но увы, нет времени, пришлось включить волю и взять себя в руки. Отложил на потом. Иногда закрыв глаза, мечтаю о том, как переписываю алгоритм. :lol:
    А вам вот сейчас очень завидую. :mda:
     
  3. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Кто-то спрашивал, а что такое пессемизация кода. А вот она, питухонцы, вперёд! Мир на вас надеяться.
    Код (Python):
    1. n = 0
    2. for num in range(1000000):
    3.     st = str(num)
    4.     st = '0'*(6-len(st)) + st;
    5.     if int(st[0]) + int(st[1]) + int(st[2]) == int(st[3]) + int(st[4]) + int(st[5]):
    6.         n = n+1
    7.     #end
    8. #end
    9. print n
    Сейчас попробуют скомпилировать этот код в ассемблер, и без существенной оптимизации. Питухон это ЯП для замены С/С++ и прочих сложных ЯП. У вас не хватает быстродействия для переваривания тонн кода на питухоне, купите мощный ПК хотя бы iшак5 13600, лучше i9 14900 с 64 ГБ ОЗУ, иначе наш питухон будет тормозить.
     
  4. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    110
    Не хватает в нем возможности создавать свои структуры как в си/паскале, без всяких извращений типа классов, так что, такая себе замена

    [​IMG]
     
  5. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Короче, результат компиляции питухон --> ассемблер UASM
    Код (ASM):
    1.     mov     sum, 0
    2.     .for (esi=0: sdword ptr esi<1000000: esi++)
    3.         ASSUME  ebx:ptr byte, edi:ptr byte
    4.         mov     ebx, GlobalAlloc(GMEM_FIXED, 256)   ;;st_ = new char[256];
    5.         mov     edi, GlobalAlloc(GMEM_FIXED, 256)   ;;st = new char[256];
    6.         sprintf(ebx, "%d", esi)                     ;;st_ = str(num)
    7.         strlen(ebx)
    8.         mov     ecx, 6
    9.         sub     ecx, eax                            ;;(6-len(st_))
    10.         .for (edx=0: sdword ptr ecx>0: edx++, ecx--);;st = '0'*(6-len(st))
    11.             mov     [edi][edx], '0'
    12.         .endfor
    13.         .for (ecx=0: [ebx][ecx]: edx++, ecx++)
    14.             mrm     [edi][edx], [ebx][ecx]
    15.         .endfor
    16.         mov     [edi][edx], 0                       ;;st = '0'*(6-len(st)) + st;
    17.         ;;if int(st[0]) + int(st[1]) + int(st[2]) == int(st[3]) + int(st[4]) + int(st[5]):
    18.         mrm     [ebx][0], [edi][0]
    19.         mov     [ebx][1], 0
    20.         mov     tempA, atoi(ebx)
    21.         mrm     [ebx][0], [edi][1]
    22.         mov     [ebx][1], 0
    23.         add     tempA, atoi(ebx)
    24.         mrm     [ebx][0], [edi][2]
    25.         mov     [ebx][1], 0
    26.         add     tempA, atoi(ebx)
    27.         mrm     [ebx][0], [edi][3]
    28.         mov     [ebx][1], 0
    29.         mov     tempB, atoi(ebx)
    30.         mrm     [ebx][0], [edi][4]
    31.         mov     [ebx][1], 0
    32.         add     tempB, atoi(ebx)
    33.         mrm     [ebx][0], [edi][5]
    34.         mov     [ebx][1], 0
    35.         add     tempB, atoi(ebx)
    36.         mov     eax, tempB
    37.         .if (tempA==eax)
    38.             add     sum, 1
    39.         .endif
    40.         GlobalFree(edi)                             ;;delete []st_;
    41.         GlobalFree(ebx)                             ;;delete []st;
    42.         ASSUME  ebx:nothing, edi:nothing
    43.     .endfor
    Время выполнения 1137810458 тактов, а код оптимизации - 0: 10738795 тактов. Это получается 1137810458 / 10738795 = 106 раз медленней. Так что пессимизаторам есть куда стремиться, сделаем код ещё медленней, не надо задрачивать код, и так сойдёт.

    А то денег сотни тысяч не получите.
     
  6. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    441
    Да ладно, не так давно питоний код одного известного в узких кругах ютубера ускорили на 40,832,277,770% (да да, на 40+ миллиардов процентов)
    Пруф (англ):
     
  7. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    aa_dav, есть разные ЯПы. И есть такие которые провоцируют пограмистов писать хреновый код, т.е. если есть вариант плохого кода, то пограмист обязательно его выберет. Собственно вот.
    st = str(num)
    st = '0'*(6-len(st)) + st;
    Так сделал питухонец, а на С/С++ без std можно:
    sprintf(st, "%06d", sum);
    Но тут важно погромист постарался вообще написать самый тупую реализацию насколько это возможно, а всё это из-за особенностей питухона. Код на ассме получается эффективней потому-что там нет всяких автоматических преобразований, в результате такой на вид простой код усложняется, и заставляет идти пограмиста по более оптимальному пути. А вот так.
    Код (ASM):
    1.     xor     ebp, ebp
    2.     mov     dh, 10
    3.     .repeat
    4.         mov     bh, 10
    5.         .repeat
    6.             mov     ch, 10
    7.             .repeat
    8.                 mov     dl, 10
    9.                 .repeat
    10.                     mov     bl, 10
    11.                     .repeat
    12.                         mov     cl, 10
    13.                         align 16
    14.                         .repeat
    15.                             mov     al, cl
    16.                             add     al, bl
    17.                             add     al, dl
    18.                             mov     ah, ch
    19.                             add     ah, bh
    20.                             add     ah, dh
    21.                             .if (al==ah)
    22.                                 inc     ebp
    23.                             .endif
    24.                             dec     cl
    25.                         .until (zero?)
    26.                         dec     bl
    27.                     .until (zero?)
    28.                     dec     dl
    29.                 .until (zero?)
    30.                 dec     ch
    31.             .until (zero?)
    32.             dec     bh
    33.         .until (zero?)
    34.         dec     dh
    35.     .until (zero?)
    хотя при желании можно сделать, и так, как сделал питухонер. Самое интересное, в таком стиле можно программировать и на С/С++, да именно С++ но обязательно БЕЗ std! Тогда код получается максимально эффективный.
    --- Сообщение объединено, 30 окт 2023 ---
    Короче так. Код питухона немного доделал, вместо print n, надо print ("n = ", n)
    Потом нашёл онлайн транслятор питух в С++, код почему-то на 2010 С++ не пошёл, но после танцев с бубном получилось вот.
    Код (C++):
    1. #include <iostream>
    2. #include <string>
    3. #include <sstream>
    4. #include <time.h>
    5. using namespace std;
    6. int main()
    7. {
    8.     clock_t tm = clock();
    9.     int n = 0;
    10.     for (int num = 0; num < 1000000; num++){
    11.         ostringstream tmp;
    12.         tmp << num;
    13.         string  st = tmp.str();
    14.         st = string(6 - st.length(), '0') + st;
    15.         if (st[0]-'0' + st[1]-'0' + st[2]-'0' == st[3]-'0' + st[4]-'0' + st[5]-'0')//тут транслятор сам сделал оптимизацию!!!
    16.             n++;
    17.     }
    18.     double  time = (double)(clock() - tm)/CLOCKS_PER_SEC;
    19.     cout << "n = " << n << ", time = " << time << " sec" << endl;
    20.     return 0;
    21. }
    И можно было подумать что С++ будет быстрей моего варианта компиляции питухон-->ассемблер. Но нет.
    TEST: Happy tickets. OPTIMIZATION = -1
    Count tickets = 55252, tics = 5380653243, time = 287 ms
    А наш любимый С++, настоящий С++ кстати, только немного старый.
    n = 55252, time = 0.819 sec
    Разница почти в три раза! И кстати, сам питухон по сравнению с С++ ненамного медленней. Вот почему говорят: да ладно, питон почти такой же быстрый как С++, и таки не врут собаки. А я думал брешуть, а оно воно как, просто сравнивают говноС++. А С++ может быть быстрей ассемблера(за счёт мощной оптимизации) и даже С(за счёт лучше конструкции), ну чуть чуть совсем, но как я сказал, только при условии низкого уровня, при этом забудьте о std, и прочей шаблонной ереси.
    --- Сообщение объединено, 30 окт 2023 ---
    Вот питухон версии 3.*
    Код (Python):
    1. import time
    2. tm = time.time()
    3. n = 0
    4. for num in range(1000000):
    5.     st = str(num)
    6.     st = '0'*(6-len(st)) + st;
    7.     if int(st[0]) + int(st[1]) + int(st[2]) == int(st[3]) + int(st[4]) + int(st[5]):
    8.         n = n+1
    9.     #end
    10. #end
    11. print ("n = ", n, " time = ", time.clock() - tm, " sec")
    Тест тут запустил, что там за машина не знаю.
    https://www.onlinegdb.com/online_python_compiler
    Но выдала:
    n = 55252 time = 2.5153164863586426 sec
    Как видно, несильно медленней С++, всего в 3 раза. И это компиляция, иначе намного медленней вышло.
    --- Сообщение объединено, 30 окт 2023 ---
    И ещё важно, надо сравнить вариант оптимизация=0
    Код (Python):
    1. tm = time.time()
    2. cnt = 0
    3. for L1 in range(10):
    4.     for L2 in range(10):
    5.         for L3 in range(10):
    6.             for R1 in range(10):
    7.                 for R2 in range(10):
    8.                     for R3 in range(10):
    9.                         if L1+L2+L3==R1+R2+R3:
    10.                             cnt = cnt+1
    11.                         #end
    12.                     #end
    13.                 #end
    14.             #end
    15.         #end
    16.     #end
    17. #end
    18. print ("cnt = ", cnt, " time = ", time.time() - tm, " sec")
    Результат на той же машине:
    cnt = 55252 time = 0.13225150108337402 sec
    Быстрей в 19 раз, ну да код немного больше, но это же копипаста, шлёп, шлёп, готово. Но питухонцы не идут простыми путями, прога должна тормозить по определению.
     
  8. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.087
    Intro, Ты, конечно, мощно задвигаешь :) нужна скорость на питохе - пиши сишный модуль и вызывай его питохой :grin: сила скриптовых япов не в скорости, а в гибкой работе с типами данных, то бишь можно делать само-адаптируемые коды. для компилируемых яп-ов это тоже возможно, но там процесс получается более затратным.
     
  9. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Intro, а в чём твой посыл? В чём прикол сравнивать производительность совершенно полярных языков?
    Питон никогда не целился в нишу High-Performance Computing - это же скриптовый язык.
    Его используют для автоматизации и прототипирования: быстро проверить теорию, что-то распарсить или сконвертировать - лучше питона ничего нет.

    Но писать на нём надо без пошлости.

    Вот смотри, ты говоришь:
    Никто так делать не будет.

    А вот как это делается правильно:
    Код (Python):
    1.  
    2. import time
    3.  
    4. def number_sum(val: int) -> int:
    5.     hundreds = val // 100
    6.     without_hundreds = val - hundreds * 100
    7.     decimals = without_hundreds // 10
    8.     ones = without_hundreds - (decimals * 10)
    9.     return hundreds + decimals + ones
    10.  
    11.  
    12. begin_time = time.time()
    13.  
    14. total_sum = 0
    15. for i in range(1000):
    16.     left_sum = number_sum(i)
    17.     for j in range(1000):
    18.         right_sum = number_sum(j)
    19.         if left_sum == right_sum:
    20.             total_sum += 1
    21.  
    22. end_time = time.time()
    23.  
    24. print("Matches", total_sum)
    25. print("Elapsed time:", end_time - begin_time)
    26.  
    Однако, этот вариант в 2.5 раза медленнее, чем 6 вложенных циклов для каждой цифры - видимо, из-за потерь на вызов функции и из-за делений.

    Но кого это волнует, когда я могу сделать так:
    upload_2023-10-31_0-42-27.png

    А теперь нарисуй мне то же самое на ассемблере или плюсах.
     
    Marylin нравится это.
  10. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.087
    HoShiMin, ну - графики питоха рисует всё-таки не скриптянкой, а вызывает для этого модули на тех же плюсах.. а в остальном поддерживаю твою точку зрения :)
     
  11. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Кстати, если переписать на плюсах с -O3, компилятор посчитает результат в компайлтайме, и получится примерно это:
    Код (ASM):
    1. mov eax, 55252
    2. ret
     
  12. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    110
    Нарисовать такой график на канве, не сложно, если речь о c++/компилируемых яп
    Отдельно нарсовать систему координат, отдельно данные.

    И еще надо масштаб правильно подсчитать, чтобы за границы велосипеда не заходило )

    [​IMG]
     
    Последнее редактирование: 31 окт 2023
  13. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Нарисовать-то можно что угодно, но жизнь коротка)
     
  14. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    110
    И что? Главное не победа, главное участие
     
  15. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    441
    Код (Text):
    1.  
    2.         int             sum = sum_l + 1;
    3.         unsigned int    count_l = (sum*sum+sum)/2;
    4.         if (sum>10){
    5.             sum -= 10;
    6.             count_l -= ((sum*sum+sum)/2)*3;
    7.             if (sum>10){
    8.                 sum -= 10;
    9.                 count_l += ((sum*sum+sum)/2)*3;
    10.             }
    11.         }
    12.  
    Вот эту вот магию я не понял. :lol: Смысл понял - считаем количество комбинаций каждой суммы по отдельности и суммируем их квадраты, но как этот код правильно считает количество комбинаций суммы sum_l для трёх разрядов глубоко непонятно. :)
     
  16. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Да ладно, я этот код взял с хабра, с ходу ссылку не найду, надо в истории браузера копаться. Сам бы до такого, просто не додумался.
    Вот возьмём ваш любимый MASM, наш любимый ассемблер. Я давненько пытался реверсить, надо было найти максимальную длину строки и имени переменной. Да к я не нашёл, код был очень странный, я так понял это именно С++, с толи boost, толи ещё какие-то фреймворки, шаблоны шаблонов, шаблонами шаблонируют. Ну ладно, потом мне тут подсказали UASM, я его немного изучил, есть доступные исходники, нашёл нужные параметры(строка 2048, и длина переменной 247)... Ну в общем решил его использовать, и первым делом перевести на его свой XRayExtensions, это у меня не сразу получилось, оказалось про 100% совместимости не совсем так, но потом у меня получилось, и.... И оказалось что UASM работает раз 30-40 раз быстрей, мой проект буквально за доли секунд компилировался, кода там достаточно много, и сам MASM компилировал секунд 20-25 что ли, уже не помню, ну на старом моём атлоне !! х4 640 3ГГц.
    Так что получается, именно так делают очень многие, причём такие крупные фирмы как микрософт. Более того, эти засранцы говорят, я знаю что на С++ можно программировать как на С, но это плохо, ни в коем случае не делайте так. Блин, если бы мне он сказал в лицо, и у меня был АК, я бы в него весь магаз...
    Тут надо найти свои наброски, там получается типа пирамида, и надо найти формулу которая вычисляет объём пирамиды. Тут я плохо объяснил как точно оптимизировал, т.к. делал это довольно давно, немного подзабыл тонкости хода мысли.
    PS
    Вот нашёл где этот питухонокод.
    https://habr.com/ru/articles/42682/
    А вот афтыр.
    https://habr.com/ru/users/A2K/
     
  17. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    441
    Да, для двух цифр я на бумажке прикинул и получилась чистейшая линейная пирамида 1,2...9,10,9...2,1.
    Но для трёх цифр первые члены ряда уже 1,3,6,10..., т.е. не линейно растут, а инкремент сам увеличивается на 1 каждый шаг, т.е. это уже не пирамида, а что-то изогнутое, и есть подозрение, что к вершине будет сглаженность, по типу графика нормального распределения, тут уже я опух и продолжать не стал. :lol:
     
  18. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Так а вон же я выше скинул график распределения совпадений.
    Они идут по принципу:
    000: 1 вариант
    001: 1 + 2 = 3 вариантов совпадений
    002: 1 + 2 + 3 = 6 вариантов

    Потом доходит до какого-то числа и начинается со сдвигом на 1:
    1 + 2
    1 + 2 + 3
    1 + 2 + 3 + 4

    Потом снова доходит до какого-то числа, и следующее уже
    1 + 2 + 3


    и так до номера 500. А от 501 до 999 - зеркальная копия (та же последовательность, только в обратную сторону).
    --- Сообщение объединено, 31 окт 2023 ---
    А раскрой мысль: что ты подразумеваешь под "программировать на C++ как на С"? От каких концепций в C++ следует отказаться, чтобы код был быстрым, и почему?
     
    Последнее редактирование: 31 окт 2023
  19. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    441
    Мы говлрим про другой график.
    Надо чтобы сумма трех первых цифр совпала с суммой последних трех.
    А какие суммы бывают? От 3*0 до 3*9.
    От 0 до 27.
    Задачу можно свести к тому чтобы понять для каждой такой суммы сколькими комбинациями трех цифр ее можно выложить.
    А полное решение это сумма квадратов этих величин, т.к. каждой комбинации слева соответствуют такие же комбинации справа.
    Например 0 можно выложить только одной комбинацией 000, и 27 тоже только одной 999. Они дадут в ответ вклад по единичке в квадрате. А 1 уже выкладывается тремя комбинациями и 26 тоже. Они дадут в ответ вклад по 3 в квадрате каждый.
    Т.е. по горизонтальной оси числа от 0 до 27. И будет не пила, а симметричная плавно нарастающая и ниспадающая горка.

    И вот тот код который я процитировал топикастера умудряется каждый такой член считать за три непонятных для меня присяда.
     
    Последнее редактирование: 31 окт 2023
  20. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Но ведь твоя претензия не к языку, а к коду конкретного человека. Он просто не сообразил, как из десятичного числа вытащить цифры разрядов.
    Дай ему хоть си, хоть ассемблер - он напишет примерно то же самое, с такой же низкой производительностью.
    И наоборот, даже на медленном питоне можно писать код, производительности которого будет достаточно для решения задач, которые ты на нём решаешь. Да, можно даже делать игры и писать веб-сервера.
    Проще говоря, если человек не умеет писать производительный код и не понимает, почему его код медленный, смена языка ему не поможет.
    --- Сообщение объединено, 31 окт 2023 ---
    Так я про это и говорю. Считаем количество комбинаций, которыми можно получить каждое число - от 000 до 999. Получится такая интересная последовательность, как в том графике.
    Например, число 000 можно получить только одной комбинацией - таким же числом 000.
    Сумму 001 можно получить уже тремя способами: 001, 010, 100.
    Сумму 002 - уже шестью способами.
    Получается последовательность 1, 3, 6, 10, 15, и т.д.
    Проще говоря:
    1
    1 + 2
    1 + 2 + 3
    1 + 2 + 3 + 4
    1 + 2 + 3 + 4 + 5
    1 + ... + N
    1 + 2
    1 + 2 + 3
    1 + ... + M
    1 + 2 + 3
    1 + 2 + 3 + 4
    1 + ...
    И получается такая пила до 499го числа. А с 500 до 999го эта пила идёт в обратную сторону.

    Если сумеешь описать эту пилу общей формулой - тогда подсчёт всех счастливых билетиков сведётся к линейной сложности: пройти от 000 до 499 и подставить каждое число в эту формулу, получить число совпадений, и просто приплюсовать к общему счётчику. А затем умножить счётчик на 2 (т.к. от 500 до 999 будет столько же).
     
    Последнее редактирование: 31 окт 2023