Brainfuck - Самая Быстрая Сортировка В Brainf***

  • Автор темы Обморок
  • Обновлено
  • 23, Oct 2024
  • #1

После реализации Быстрая сортировка в BrainF***Я понял, что, вероятно, это было не так быстро. Операции, которые в обычных языках имеют размер O(1) (например, индексация массива), в BF значительно длиннее. Большинство правил эффективной сортировки могут быть выброшены за рамки при написании кода. Тьюринговская тряпка.

Итак, вот задача: реализовать «самую быструю процедуру сортировки BrainF***». Я буду измерять время всех записей, используя переводчик ниже. Интерпретатор использует ленту беззнаковых символов размером 16 КБ. И лента, и ячейки переносятся при продвижении/приращении за пределы. Чтение EOF помещает 0 в текущую ячейку. Измеренное время включает в себя как время анализа исходного файла, так и время обработки всех входных файлов. Самый быстрый код побеждает.

Тестовый вектор будет представлять собой набор файлов Ascii, предназначенных для проверки крайних случаев сортировки, включая

  • Уже отсортированный список: «заказано»

     
     
     
     
     
     
      Author    Program      Average Time    Best Set          Worst Set
    
    AShelly   Quicksort    3224.4 ms       reverse (158.6)   onlynine (1622.4) 
    
    K.Randall Counting     3162.9 ms       reverse (320.6)   onlynine  (920.1)
    
    AShelly   Coinsort      517.6 ms       reverse  (54.0)   onlynine  (178.5) 
    
    K.Randall CountingV2    267.8 ms       reverse  (41.6)   random     (70.5)
    
    AShelly   Strandsort    242.3 ms       reverse  (35.2)   random     (81.0)
     
  • Список с обратной сортировкой: «обратный»

    #include <windows.h> #include <stdio.h> #define MS_PER_SEC 1000.0f #define MAXSIZE (0x4000) #define MAXMASK (MAXSIZE-1) typedef __int64 sysTime_t; typedef unsigned char Uint8; typedef unsigned short Uint16; typedef struct instruction_t { Uint8 inst; Uint16 pair; } Instruction; Instruction prog[MAXSIZE] = {0}; Uint8 data[MAXSIZE] = {0}; const Uint8 FEND = EOF; sysTime_t read_time() { __int64 counts; QueryPerformanceCounter((LARGE_INTEGER*)&counts); return counts; } float sysTime_to_ms(sysTime_t timeIn) { __int64 countsPerSec; QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); return (float)timeIn * MS_PER_SEC / (float)countsPerSec; } int main(int argc, char* argv[]) { FILE* fp; Uint8 c; Uint16 i = 0; Uint16 stack = 0; sysTime_t start_time; sysTime_t elapsed=0,delta; if (argc<3) exit(printf("Error: Not Enough Arguments\n")); fp = fopen(argv[1],"r"); if (!fp) exit(printf("Error: Can't Open program File %s\n",argv[1])); start_time=read_time(); while (FEND != (c = fgetc(fp)) && i <MAXSIZE) { switch (c) { case '+': case '-': case ',': case '.': case '>': case '<': prog[++i].inst = c; break; case '[': prog[++i].inst = c; prog[i].pair=stack; stack = i; break; case ']': if (!stack) exit(printf("Unbalanced ']' at %d\n",i)); prog[++i].inst = c; prog[i].pair=stack; stack = prog[stack].pair; prog[prog[i].pair].pair=i; break; } } if (stack) exit(printf("Unbalanced '[' at %d\n",stack)); elapsed = delta = read_time()-start_time; printf("Parse Time: %f ms\n", sysTime_to_ms(delta)); for (stack=2;stack<argc;stack++) { Instruction *ip = prog; fp = fopen(argv[stack],"r"); if (!fp) exit(printf("Can't Open input File %s\n",argv[stack])); printf("Processing %s:\n", argv[stack]); memset(data,i=0,sizeof(data)); start_time=read_time(); //Run the program while (delta) { switch ((++ip)->inst) { case '+': data[i]++; break; case '-': data[i]--; break; case ',': c=getc(fp);data[i]=(FEND==c)?0:c; break; case '.': putchar(data[i]); break; case '>': i=(i+1)&MAXMASK; break; case '<': i=(i-1)&MAXMASK; break; case '[': if (!data[i]) ip = prog+ip->pair; break; case ']': if (data[i]) ip = prog+ip->pair; break; case 0: delta=0; break; } } delta = read_time()-start_time; elapsed+=delta; printf("\nProcessing Time: %f ms\n", sysTime_to_ms(delta)); } printf("\nTotal Time for %d files: %f ms\n", argc-2, sysTime_to_ms(elapsed)); }
  • Файл, состоящий из множества копий нескольких уникальных значений: «onlynine».

    bftime program.bf infile1 [infile2 ...]
  • Совершенно случайный файл ascii: «случайный»

    sysTime_to_ms()
  • Случайный файл в диапазоне 1..255: «весь диапазон».

    read_time()

Каждый входной файл имеет не более 255 байт.

Вот переводчик. Он написан для консольного режима Windows, но его легко портировать: просто замените öè—@œ™S±ü¼ÓuǯŠf΀n‚ZÊ,ˆÖÄC?tÚDý^öhfF†¬I÷xxÖ÷GààuÈ©ÈÑdàu.y×€ôã…ìcÑ–:*‰˜IP¥©9Ä¢¬]Š\3*\®ªZP!YFõ®ÊÖžáîÓ¹PŸ—wNì/S=Ìœ'g°Ì²¬½ÕQ¹ÀpbWÓ³ »y »ïløó„9k–ƒ~ÕfnšÂt|Srvì^%ÛÀâû¯WWDs‰sç2e£+PÆ@½ã”^$f˜¦K?•òâ¨÷ žøÇÖ¼$NƒRMÉE‹G´QO¨©l¬k¦Ó and 'fQ`0R0gssT)70O>tP[2{9' 0.HMyTjW7-!SyJQ3]gsccR'UDrnOEK~ca 'KnqrgA3i4dRR8g.'JbjR;D67sVOPllHe,&VG"HDY_'Wi"ra?n.5nWrQ6Mac;&}~T_AepeUk{:Fwl%0`FI8#h]J/Cty-;qluRwk|S U$^|mI|D0\^- csLp~`VM;cPgIT\m\(jOdRQu#a,aGI?TeyY^*"][E-/S"KdWEQ,P<)$:e[_.`V0:fpI zL"GMhao$C4?*x с эквивалентами для конкретной платформы.
Использование: ibbkninbkrauickabcufrfckbfikfbbakninfaafafbikuccbariauaibiraacbfkfnbbibknkbfankbbunfruarrnrrrbrniaanfbruiicbuiniakuuiubbknanncbuanbcbcfifuiffbcbckikkfcufkkbbakankffikkkbnfnbncbacbfnaauurfrncuckkrfnufkribnfbcfbkbcrkriukncfrcnuirccbbcuaaifiannarcrnfrbarbiuk

~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!

Результаты на данный момент

Вот среднее время 5 запусков полного набора векторов:

&#33;"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

#самый быстрый код #brainfuck

Обморок


Рег
17 Jul, 2014

Тем
66

Постов
170

Баллов
520
  • 26, Oct 2024
  • #2
 
 
 
 
 
 
 
 
 >>+>,[>+>,]<[[<-<]>+>+[>]>[[-<<[[>>+<<-]<]>>]>-.+[>]>]<<]
 

Я не помню, чья идея была в этом алгоритме. Может быть, Бертрам Фельгенгауэр? Это произошло в результате дискуссий вокруг конкурса Brainfuck Golf №2, состоявшегося более десяти лет назад.

Это самый быстрый из примеров входных данных.

Он также не ограничивается входными данными длиной <256, но может обрабатывать входные данные произвольной длины.

Обе эти вещи были верны и в отношении ответов Альберта ниже. Самое приятное в этом то, что время выполнения составляет O(N) от входной длины. Да, эта штука на самом деле работает в линейном времени. Он уже съел постоянный коэффициент 255 в качестве закуски.

 

SeectDogsDoro75


Рег
25 Oct, 2024

Тем
69

Постов
207

Баллов
552
  • 26, Oct 2024
  • #3

Вот сортировка, которая как минимум в 6 раз быстрее моей быстрой сортировки. Этот алгоритм не имел бы особого смысла на традиционном языке, поскольку его размер O(N*m), где m — максимальное входное значение. После сбора входных данных они проходят через массив, подсчитывая ячейки > 0, а затем уменьшая каждую из них. Затем он добавляет 1 к первому >,[>+>,]+[<[<-<]>>[<[>>]>[<->[>>]<.<[<<]]>>]<<<<<+] cells in the result vector. It repeats the passes until the count is 0.
БФ:

,[[-[->>>+<<<]>>>>+<]>>+<[-<<<]<,]>+[>[<-.+>-]<[->>>+<<<]>>>+]

Эквивалентный алгоритм C:

process input ,[ while input is not zero [ decrement input - copy input over to next bucket [->>>+<<<] mark next bucket as not the first >>>>+< repeat until input is zero ] increment count for this bucket >>+ rewind using markers <[-<<<]< process next input ,] generate output >+[>[<-.+>-]<[->>>+<<<]>>>+]

Вот тот, который в 2 раза быстрее. Он основан на "сорт спагетти": он устанавливает строку из единиц длиной каждый вход. Значение в каждой ячейке представляет количество нитей как минимум такой длины. (Итак, [3,2,1,2] становится >,[[-[>>+<<-]>+>]<[<<]>,]+>[>+<-]>[>[>+<<->-]<[<<.>>-]<<[>>+<<-]>>+>>] ). Then it starts 'measuring' the strands and prints out the length every time it finds the end of one.

>,[ [-[>>+<<-]>+>] <[<<]>,] build strand of 1s for each input +>[>+<-]>[ while there are strands >[>+<<->-] do any strands end here? <[<<.>>-] print length of all that do <<[>>+<<-]>>+>>] shift right 1; inc length

Сырой:

|4|0|3|0|1|0|0| ||answer||

Простая реализация сортировки подсчетом. Каждый сегмент имеет ширину 3 ячейки и содержит текущие входные данные, маркер и количество раз, когда счетчик появляется во входных данных.

uchar A[MAX]={0}; uchar R[MAX]={0}; int count,i,n=0; while (A[n++]=getchar()) ; do { count = 0; for (i=0; i<n; i++) count += (A[i]) ? (A[i]-->0) : 0; for (i=0; i<count; i++) R[i]++; } while (count>0); for (i=0; R[i]; i++) ; for (i--; i>=0; i--) putchar(R[i]);

без комментариев:

Get Input >,[>>+>,] Count values GT 0 and decrement each <[<[<<<+>>>-]<[-<<+>>>]>[<]<<] While count: add 1 to results <[[[<<+>>-]<+<-] Seek back to end of input >[>>]>>>[>>>] Repeat counting step <<<[<[<<<+>>>-]<[-<<+>>>]>[<]<<]<] Seek to far end of results and print in reverse order <[<<]>>[.>>]
 

Natalika2004


Рег
01 Sep, 2011

Тем
75

Постов
183

Баллов
578
Тем
403,760
Комментарии
400,028
Опыт
2,418,908

Интересно