/*vsaud - vector sorting of array unordered data*/
Векторне сортування масиву невпорядкованих даних.

Нехай задано 5-ти гігібайтний масив невпорядкованих данних, який необхідно відсортувати.
Проаналізуємо поставлену задачу...

Основною одиницею вимірювання інформації є байт (з восьми бітів (нулів та одиниць)), який може містити 256-ть значень (від 0 (0x00) до 255 (0xFF - в шістнадцятковій системі числення)). Існує велика ймовірністі того, що у файлі подібного розміру ці значення зустрічатимуться неодноразово (при сталості своїх значень, і змінності своїх положень). Таким чином, впорядкувавши (приміром в порядку зростання) будь-яким з відомих алгоритмів сортування подібний масив невпорядкованих даних, ми отримаємо вихідний файл із значень від 0 до 255 з періодом повторення кожного з них відповідно до їх кількості у вхідному файлі.

Проаналізувавши відповідним чином подібну задачу, ми можемо прийти до висновку про те, що найбільш ефективним методом впорядкування такого масиву, буде створення векторної таблиці із полями (достатнього розміру, щоб описати максимальну кількость елементів масиву) та присвоєння кожному із значень масиву вектора і занесення у відповідне йому поле кількості віднайдених елементів. Оскільки ми сортуємо байтний масив даних, нам знадобиться лише 256 векторів із розміром поля векторної таблиці у вісім байтів (оскільки, адрес поля ми вираховуватимемо простим зсувом в ліво значення його вектора), щоб мати можливість описати максимальну кількість елементів масиву більшу за 4GiB (>2^32). Тож розміром таблиці, буде: 256V * 8B = 2048B (2-ва кілобайти).

Асамблерний джерельний код циклу, алгоритму векторного сортування для даної задачі складається лише з п'яти рядків і на процесорі i486 виконується за 14 тактів, та виглядає наступним чином:

.2:movzx ax, [si]; //отримуємо значення (елемента масиву) вектора
   inc   si; //просуваємо si на наступне значення елемента масиву
   shl   ax, 3; //обчислюємо адрес поля таблиці на яке вказує вектор
es inc   word [eax]; //збільшуємо значення поля таблиці на одиницю
   loop  .2; //переходимо до наступного значення вектора

Даний цикл повинен повторюватися відповідно до кількості елементів масиву і на момент завершення останнього з них, у полях таблиці ми отримаємо кількість усіх значень елементів масиву відповідно до їх векторів. Таким чином, масив невпорядкованих даних буде відсортовано лише за один прохід, що не можливо досягнути при використанні інших алгоритмів сортування невпорядкованих даних.

Як випливає з вище наведеного коду, при використанні si як індекса джерела, ми не можемо адресувати пам'ть вище 64KiB (4GiB при використанні esi). Та оскільки, ми маємо можливість впорядкувати масив за один прохід, фактично не порівнюючи елементи масиву один з одним, то ми можемо розбити файл масиву на зручні для нас фрагменти у 4GiB/64KiB чи навіть розміром в один блок данних 4/2/1KiB або 512B (відповідно до використовуваної файлової системи).

Джерельний код для роботи із 512-ти байтним блоком даних виглядатиме наступним чином:

.1:call  load_next_block; //завантажуємо наступний блок даних
   push  cx; //зберігаємо кількість завантажуваних блоків
      mov   cx, 512; //кількість байтів в блоці даних для проходу
      xor   si, si; //встановлюємо si на початок блоку даних
   .2:movzx ax, [si]; //отримуємо значення (елемента масиву) вектора
      inc   si; //просуваємо si на наступне значення елемента масиву
      shl   ax, 3; //обчислюємо адрес поля таблиці на яке вказує вектор
   es inc   word [eax]; //збільшуємо значення поля таблиці на одиницю
      loop  .2; //переходимо до наступного значення вектора
   pop   cx; //відновлюємо кількість блоків для завантаження
   loop  .1; //зменшуємо її на одиницю та завантажуєм наступний блок даних

Зрозуміло що таким чином ми зможемо опрацювати 64Ki блоків, або 32MiB даних файлу. Тому такий цикл ми будемо вимушені вкласти в інший для опрацювання наступного фрагменту файла і можливо змінити si на esi, якщо захочемо модифікувати його для роботи з більшим об'ємом даних в циклі на один прохід по фрагменту. Та це вже залежить від конкретної програми сортування з роботою по даному алгоритмі і виходить за межі теми. Тому я на цьому завершую і сподіваюсь, що викладене вище є достатньо чітким і зрозумілим для пояснення роботи алгоритму векторного сортування масиву невпорядкованних даних.

p.s. - адміністрації сайту. Помістіть будь ласка мою попередню тему про генератор випадкових чисел з "корзини" принаймні в розділ "інше" (помістив випадково(ось що буває, коли цілу ніч працюєш над чимось:)).

2

(2 відповідей, залишених у Системне програмування)

Цілий день розробки пройшов не даремно. 8)

Прихований текст
;/* ary33s */;Copyright: ******@*****
             ;Licence: free for non commercial education only
             ;Waranty: AS IS
nl equ 0xA

   org 0
   use16

   jmp far 0x7C0:init;
ary:
db '123456789',0
init:
   mov   ax, cs;
   mov   ds, ax;
   push  ds;
   pop   es;
sbc:; / sort by columns
   xor   bx, bx; /1t column
   mov   cx, 3;
 .1:
   push  cx;
      mov   cx, 3;
    .2:
      xor   di, di; /1t row
      mov   si, 3;  /2d row
    .3:
      call  sdec;
      cmp   cx, 2;
       jnz  short .4;
      dec   cx;
      jmp   short .2;
    .4:
      mov   di, si; /look
      add   si, 3;  /forward
      loop  .3;
   inc   bx;
   pop   cx;
   loop  .1;
sbr:; / sort by row
   mov   bx, 3; /2d row
   mov   cx, bx;
 .1:
   xor   di, di; /1t col
   mov   si, 1;
 .2:
   call  sdec;
   cmp   cx, 2;
    jnz  short .3;
   dec   cx;
   jmp   short .1;
 .3:
   cmpsb; /look forward
   loop  .2;
dpy:
   call  sbuf;
   mov   si, buf;
   call  tty;
   mov   bx, 3;
   mov   al, [ary + bx];
   mov   [val], al;
   mov   si, faq;
   call  tty;
   mov   si, msg;
   call  tty;
dly:
   xor   ax, ax;
   int   0x16;
off:
db 0xEA,0,0,0xFF,0xFF;

;/procedures/
sdec:; / sort by decrease
   mov   al, [ary + bx + si];
   cmp   [ary + bx + di], al;
    ja   short .r;
   xchg  al, [ary + bx + di];
   mov   [ary + bx + si], al;
 .r:
retn;

sbuf:
   mov   si, ary;
   mov   di, buf;
   mov   cx, 3;
 .1:
   push  cx;
      mov   cx, 3;
      rep   movsb;
      inc   di;
   pop   cx;
   loop  .1;
retn;


tty:; /teletipe
   mov   ah, 0xE;
   jmp   .gch;
 .nl:; /new line
   int   0x10;
   mov   al, 0xD;
 .rpt:; /repeat
   int   0x10;
 .gch:; /get char
   lodsb;
   cmp  al, 0xA;
    jz  .nl;
   or   al, al;
    jnz .rpt;
retn;

faq:
db 'faq: '
val:
db ' ',nl,0
buf:
db '+++',nl
db '+++',nl
db '+++',nl,0
msg:
db 0x19,'key to reboot',nl,0

Що правда, відносно поставленого завдання є недолік. Програма після сортування стовпців масиву, перед виводом максимального елемента 2-го рядка, сортує в порядку спадання ще й його. Оскільки, я мабуть не вірно зрозумів другу частину завдання. [:}  Та все ж таки, всі хто знайде корисним може висловити подяку, кнопкою в низу справа, а обгрунтовану критику та ваші алодисменти готовий вислухати в хвості поста (тобто з низу). З приводу пожертв, звертайтесь в приват.

Залюбки приєднуюсь до "клубу любителів, шрифту: Courier New" 8)

4

(5 відповідей, залишених у Системне програмування)

Наскільки я можу судити, 0xDADA11C7 ви не скучаєте, на цьому форумі.

З вашого дозволу, почну спочатку. По перше, вже ваше перше запитання до мене у попередньому пості із запитанням про доречність коду (що містило, власне натяк на те що він є недоречним) є образливим для мене. По друге, ваші наступні зауваження (а по суті, повчання), якраз і є не доречними. Хоча б тому, що ви вже виявили свою некомпетентність в цьму питанні. Що випливає хочаб з того, що ви назвали викладений мною код - кодом сектору завантаження. Хоча, як ви можете бачити, він він не працію з дисковими секторами і відповідно нічого не завантажує. Щодо оформлення коду, то вимушений з вами все ж таки погодитись, але прийміть будь ласка до уваги, що це був мій перший пост на цьому форумі і вже у другому я все ж таки виправився. До того ж, хоча я й не помістив його в секцію коду та все ж таки приховав (деякою мірою) недоліки свого коду (написання якого, разом з часом на debuging, зайняло у мене до півтори години часу) помістивши в spoiler. Далі щодо некропостингу, поставлена Taras задача є неважкою і цікавою для мене, як може бути цікавою й для інших форумчан (та й не лише для студентів). Далі, як ви зауважили - не знання платформи, не позбавляє нас можливості вирішити саму задачу змоделювавши її на іншій платформі, що я й зробив на прикладі IBM PC (й насмілюся, знову ж таки з вашого дозволу, запропонувати даний спосіб й вам - якщо захочете комусь допомогти).

p.s. - При вій повазі до вас, сподівайсь я вас жодним чином не образив.

Скомпілюйте код в fasm - Run|Compile (Ctrl+F9), помістіть його починаючи з найпершого сектору гнучкого диску (в цьому допоможе програма HxD) та запустіть його за допомогою Bochs-2.6.6 і ви побачите, що він виконує саме те що потрібно, а для ілюстрації цього ще й самотестується проглядаючи бітову карту (bmap) де 1 - спрацювання променя на вхід, а 0 - відповідно на вихід.

7

(5 відповідей, залишених у Системне програмування)

nam test <p1,p2,p3>
Прихований текст
;/* entrance */;/Copyrigth by ******@*****
               ;/License: free for non commercial education purpose only
               ;/Waranty: AS IS

;/initials ES:SS:CS:DS = 0; SP = 0x400; IP = 0x7C00.

   org 0
   use16

   jmp far 0x7C0:init;

init:; /segment initialisation
   mov   ax, cs;
   mov   ds, ax;
   mov   cx, 16;
 @@:; /loop test
   push  cx;
   call  near gent;
    jnc  short .q;
 .e:
   inc   byte [user];
   jmp   short .dpy;
 .q:
   dec   byte [user];
 .dpy:
   call  near dpy;
 .dly:; /delay
   xor   ax, ax;
   int   0x16;
   pop   cx;
   loop  @b;
reboot:
db 0xEA,0x00,0x00,0xFF,0xFF;

;/procedures

btst  dw 0;
bmap  dw 0x00FF;
gent:; /get entrance
   mov   cx, [btst];
   bt    word [bmap], cx;
    jc   short .se;
 .sq:
   inc   word [btst];
   clc;
retn;
 .se:
   inc   word [btst];
   stc;
retn;

dpy:; /display
   call  tty;
   call  dcl;
   mov   al, 0xD;
   call  pch;
   mov   al, 0xA;
   call  pch;
retn;

cdg:; / convert digit
   add   al, 0x30;
   cmp   al, 0x3A;
    jb   .pch;
   add   al, 0x7;
 .pch:
   call  pch;
retn;

user  db 0;
dcl:; / dacimal
   mov   al, [user];
   mov   bl, 0xA;
   mov   cl, 0x0;
 .rp1:
   mov   ah, 0x0;
   div   bl;
   mov   dl, ah;
   inc   cx;
   push  dx;
   or    al, al;
    jnz  .rp1;
 .rp2:
   pop   ax;
   call  cdg;
   loop  .rp2;
retn;

pch:; / put char
   mov   ah, 0xE;
   int   0x10;
retn;

msg:
db 'users: ',0
tty:; /teletipe
   mov   ah, 0xE;
   mov   si, msg;
   jmp   .gch;
 .rpt:; /repeat
   int   0x10;
 .gch:; /get char
   lodsb;
   or   al, al;
    jnz .rpt;
retn;