Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.147.73.35] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Надо написать программу которая находит моду в массиве чисел т.е. надо найти число которое встречается больше всего раз в массиве, если таких чисел несколько вывести любое из них, реализовать в связке pas-asm. Нельзя использовать больше 1 массива.
Я по пытался это написать вроде в td всё работает хорошо, но не возвращает значение max обратно в pascal. Не могу найти ошибку. Алгоритм мой заключаетсяв том, что я сравниваю smax и max в которые я записываю значения массива. Т.е. при первом проходе в max - 1 значение элемента массива, если оно встретилось там раз 5, тогда maxn=5; А в smax значение 2 элемента (ну или 1 это не важно), если оно встретилось 4 раза, тогда smaxn=4. Так-как smax встретилось большое количество раз, тогда заменяю max на smax и smax заношу следующие значение элемента массива.. Если нет, тогда лишь в smax заношу следующие значение элемента массива. При следующем проходе у меня в max уже хранится smax, а в smax следующие значение элемента массива, и я снова сравниваю, что чаще встретится в smaxn и maxn хранится сколько раз я его встретил. Я бы его сделал легче, просто мне нельзя использовать 2 массив, только 1. А 30 раз ходит внешний цикл, чтобы двигать smax. А во внутреннем цикле идет подсчет сколько встретилось раз max и smax Пишу на tp 7.0 + tasm. {$L LAB2.obj} uses crt; const n=30; type mas=array[0..n] of integer; var a:mas; i,max: integer; { объявляю процедуру} procedure LAB2(var max:integer;var a:mas ); external; {начало бреда} begin clrscr; randomize; write('Исходный массив:'); for i:=0 to n do begin a[i]:=random(n); write(a[i],', '); end; writeln; lab2(max,a);{вызываем asm} writeln('Чащё всего встречается число ',max); readkey; end. .286 public LAB2 data segment public maxn dw ? max dw ? smax dw ? smaxn dw ? data ends code segment byte public assume cs:code, ds:data ;start LAB2 proc near push bp mov bp,sp pusha ;загружаем массив и максимум lds ax,[bp+8] ;max lds bx,[bp+4] ;массив xor dx, dx xor si, si ;чистим xor di, di ;задаем начальные значения для сравнения mov cx, [bx] mov max, cx mov smax, cx mov dx, bx ;1 цикл mov cx, 1Eh ;заполняем счётчик цикла push bx;сохраняем значение ах до входа в под.цикл mainn: push bx push cx mov cx, 1Eh ;запуск первого под цикла mov bx,dx ;начинаем цикл с 1 элемента addl: mov si,max cmp [bx],si je imax mov di,smax cmp [bx],di je ismax ;ходим по внтуренниму массиву add bx,2 loop addl ;начинаем сравнение iff: mov si,max mov di,smax cmp si,di jl yesmen ;если меньше то идем туда, если нет то mov si,0 mov maxn,si mov smaxn,si mov si,[bx] mov smax,si endd: pop cx ;восстанавливаю внешний счетчик (самый главный) pop bx add bx,2 ;сдвиг на следующий элемент массива loop mainn jmp mainend ;инструментируем счетчики количества повторений цифр s imax: inc maxn loop addl ismax: inc smaxn test cx, cx jz endd loop addl yesmen: mov si,max ;меняю местами max=smax mov di,smax mov si,di mov max,si mov maxn,0 mov smaxn,0 mov si,[bx] mov smax,si jmp endd mainend: ;вывод mov bx, max mov bx, 0Ah lds si, [bp+8] mov [si],bx popa pop bp ret 8 LAB2 endp code ends end LAB2 |
Сообщ.
#2
,
|
|
|
Цитата Maksimall89 @ mov bx, max mov bx, 0Ah lds si, [bp+8] mov [si],bx Ну так что ты написал? Естественно возвращает число 10 |
Сообщ.
#3
,
|
|
|
Цитата ValterG @ Ну так что ты написал? Естественно возвращает число 10 Это было для теста, можно убрать. Даже число 10 не возвращает, просто виснет и всё. |
Сообщ.
#4
,
|
|
|
Maksimall89, я ж написал тебе (угу, это был я ) :
.model large, pascal .code findproc proc far uses es ax bx cx dx, sz:word, max:dword, a:dword public findproc mov bx, 0 ; Здесь будет храниться мода mov cx, sz les di, a outer_loop: push cx les si, a mov ax, word ptr es:[di] xor dx, dx ; счетчик повторений текущего элемента mov cx, sz inner_loop: cmp ax, word ptr es:[si] jne no_good inc dx no_good: add si, 2 loop inner_loop cmp bx, dx jg no_op mov bx, dx les si, max mov word ptr es:[si], ax no_op: add di, 2 pop cx loop outer_loop ret findproc endp end + {$L LAB2.obj} procedure findproc(sz: integer; var max : integer; var a : mas ); far; external; |
Сообщ.
#5
,
|
|
|
volvo877Да, я знаю, но я всё равно хочу найти ошибку в своем коде.
|
Сообщ.
#6
,
|
|
|
Цитата Maksimall89 @ Проверить соответствие PUSH/POP не хочешь?я всё равно хочу найти ошибку в своем коде. Как думаешь, что произойдет, если сейчас попробовать выйти из процедуры? Вот то, что написано в 86-ой строке у тебя, то и произойдет Прикреплённый файлmax_89.PNG (15,53 Кбайт, скачиваний: 514) |
Сообщ.
#7
,
|
|
|
Цитата volvo877 @ Проверить соответствие PUSH/POP +1 Maksimall89 Положил bx в стек перед началом главного цикла и не "вынул" |
Сообщ.
#8
,
|
|
|
Спасибо, разобрался. Теперь осталось понять почему не тот max выдает, но это уже ошибка в алгоритме я так думаю.
|
Сообщ.
#9
,
|
|
|
Мне так же ещё, нужно сделать тоже самое в связке asm-pas и asm-asm(но это позже). Применил алгоритм volvo877 для связки asm-pas (только я использую связку pas-asm-pas, в 1 pas лишь вызов asm).
Моя задача в asm лишь задание массива и передача его на выполнение модулю написанному на pas, и потом в asm вывод результата. Сегодня попытался это реализовать. 1. Pas. {подключаем внешний модуль — modul} uses modul,crt; begin clrscr; labi3;{вызываем модуль — процедуру} readkey; end. 2. Pas. unit modul; {внешнка} interface {объявляем под программу} procedure labi3; {asm} {---------------------------} implementation {описываем} procedure lab3; external; {объявляем процедуру на asm как внешнюю} {$L lab3.obj} procedure tmodul(var a:array[1..10] of integer;var max:integer); {объявляем процедуру обработки} var i,j,maxn,smax,smaxn:integer; begin {обнуляем} smaxn:=0; smax:=0; {считаем} max:=a[1]; smax:=a[1]; for j:=1 to 10 do begin for i:=1 to 10 do begin if a[i]=max then inc(maxn); if a[i]=smax then inc(smaxn); end; if maxn<smaxn then begin max:=smax; maxn:=0; smaxn:=0; smax:=a[j]; end else begin maxn:=0; smax:=a[j]; smaxn:=0; end; end; end; { конец кода процедуры обработки} procedure labi3; {вызываем подпрограмму на asm} begin lab3(var a:array[1..30] of integer;var max:integer); end; end. {конец всего модуля } 3. Asm .286 public lab3 ;Объявляем процедуру как внешнюю stack 256 data segment public max dw ? array db '1,2,3,6,7,9,1,8,1,1' data ends code segment byte public assume cs:code, ds:data ;процедуры паскаля объявляем как внешние и дальнего вызова extrn tmodul:far ;процедура обработки ;start lab3 proc near ;процедура ближнего вызова ; выводим на экран содержимое массива mov cx,1Eh ; сколько элементов в массива mov si,0 mov ah,09h lea dx,array int 21h ;обращаемся к внешней процедуре на pas call far ptr tmodul ;выводим на экран результат работы mov ah,02h lea dx,max int 10h LAB3 endp code ends end LAB3 А теперь вопрос к знатокам, правильно ли я оформил вывод вначале массива на экран, а потом десятичного числа? Или всё же надо число переводить в строку, а потом уже выводить на экран, как тут. Склоняюсь к последнему, но мб. есть ещё варианты, а то слишком много кода получается. И самый главный мой вопрос, как передавать значения массива в модуль на pas и как забирать от туда это значение? Не смог найти в интернете ничего, где это написано понятным языком. Находится в основном лишь связь pas - asm. |
Сообщ.
#10
,
|
|
|
Цитата Maksimall89 @ Не похоже. Много лишних телодвижений Применил алгоритм volvo877 для связки asm-pas Цитата Maksimall89 @ Смотри:И самый главный мой вопрос, как передавать значения массива в модуль на pas и как забирать от туда это значение? 1. Основная программа: { подключаем внешний модуль — modul } uses modul, crt; begin clrscr; labi3; { вызываем модуль — процедуру } readkey; end. 2. Модуль: unit modul; interface procedure labi3; {---------------------------} implementation {$L lab3.obj} procedure lab3; external; { объявляем процедуру на asm как внешнюю } const size = 30; type tarray = array[1 .. size] of integer; procedure print(X : Integer); begin write(X:3); end; { Функция. Ближняя, поэтому Far отсутствует. Принимает указатель на массив, возвращает моду } function tmodul(var a : tarray) : integer; var i, j, max, max_count, curr_max : integer; begin writeln; max := 0; max_count := 0; for j := 1 to size do begin curr_max := 0; for i := 1 to size do if a[i] = a[j] then inc(curr_max); if curr_max > max_count then begin max_count := curr_max; max := a[j]; end; end; tmodul := max; end; { конец кода процедуры обработки} procedure labi3; { вызываем подпрограмму на asm } begin lab3; end; end. { конец модуля } 3. Собственно, ASM-файл: .model large, pascal .stack 256 .data max dw ? arr dw 1,2,3,6,7,9,1,8,1,1, 1,2,3,6,7,9,1,8,1,1, 1,2,3,6,7,9,1,8,1,1 .code ; Процедуры паскаля объявляем как внешние extrn tmodul : near ; Функция обработки extrn Print : near public lab3 ; Объявляем процедуру как доступную извне Lab3 proc near ; Процедура ближнего вызова mov ax, seg @data mov ds, ax mov es, ax xor bx, bx mov cx, 30 print_loop: mov ax, arr[bx] push bx cx ; Паскаль не сохраняет общие регистры, поэтому сделаем это сами ... push ax call Print ; Печатаем элементы массива pop cx bx inc bx inc bx loop print_loop ; Обращаемся к внешней функции на pas ; (результат вернется через AX, переменная max вообще не нужна) ; Функция принимает Var-параметр, а значит - 2 байта => Сегмент:Смещение lea bx, arr ; грузим смещение массива в BX; сегмент известен, это DS push ds push bx call tmodul ; вызов TModul (var arr: TArray); mov max, ax ; просто для проформы, раз есть переменная, ее надо заполнить ... ; Теперь печатаем результат и уходим ... push ax call Print ret Lab3 endp end Lab3 |
Сообщ.
#11
,
|
|
|
Огромное спасибо volvo877!
Я только дописал вывод чисел прямо из asm, может кому пригодиться. Modul unit modul; interface procedure labi3; implementation {$L lab3.obj} procedure print(X : Integer); begin write(X:3); end; procedure lab3; external; { объявляем процедуру на asm как внешнюю } const n = 30; type mas= array[1..n] of integer; { Функция. Ближняя, поэтому Far отсутствует. Принимает указатель на массив, возвращает моду } function tmodul(var a:mas):integer; var i,j,max,maxn,curr_max:integer; begin writeln; max:=0; maxn:=0; for j:=1 to n do begin curr_max:=0; for i:=1 to n do if a[i]=a[j] then inc(curr_max); if curr_max>maxn then begin maxn:=curr_max; max:=a[j]; end; end; tmodul:=max; end; { конец кода процедуры обработки} procedure labi3; { вызываем подпрограмму на asm } begin lab3; end; end. { конец модуля } Asm .model large, pascal .stack 256 .data max dw ? arr dw 9,2,3,5,9,7,9,2,3,9,0,9,1,6,3,7,9,8,1,5,6,7,0,1,9,9,9,1,8,6 .code ; процедуры паскаля объявляем как внешние extrn tmodul : near ; функция обработки public lab3 ; объявляем процедуру как доступную извне Lab3 proc near ; процедура ближнего вызова mov ax, seg @data mov ds, ax mov es, ax ; выводим массив на экран lea si, arr mov cx, 30 out_mass: mov ah, 2h mov dl, [si] add dl, '0' int 21h mov ah, 2h mov dl, ' ' int 21h add si, 2 loop out_mass ; выводим пустоту mov ah, 2h mov dl, ' ' int 21h ; обращаемся к внешней функции на pas ; (результат вернется через AX, переменная max вообще не нужна) ; функция принимает Var-параметр, а значит - 2 байта => Сегмент:Смещение lea bx, arr ; грузим смещение массива в BX; сегмент известен, это DS push ds push bx call tmodul ; вызов TModul (var arr: TArray); mov max, ax; просто для проформы, раз есть переменная, ее надо заполнить ... ; теперь печатаем результат и уходим ... aam ; коррекция числа add ax,3030h mov dl,ah mov dh,al mov ah,02 mov dl,dh int 21h ret Lab3 endp end Lab3 И у меня опять вопрос, надеюсь я ещё не надоел volvo877. Теперь мне нужно сделать связь asm-asm, и у меня тот же вопрос, а как передавать значение в книги Юрова, сказано, что можно через регистры, но там показано только для процедуры которая находится 1 файле с вызовом, а как сделать чтобы я из головного файла передал опять же массив и получил свое значение max? Думаю, что как-то так можно: mov cx, n mov si, offset arr ; В si — адрес первого элемента массива. call Work lea ax, max ;возврат значения max А в под программе уже по умолчанию в si будет массив. И потом в ax перед выходом закинуть значение max. |
Сообщ.
#12
,
|
|
|
Цитата Maksimall89 @ А какая, собственно, разница, передаешь ты адрес массива в Паскаль-программу, или в другой модуль, написанный на ассемблере? Теперь мне нужно сделать связь asm-asm, и у меня тот же вопрос, а как передавать значение ; ... d_seg segment byte public 'data' assume ds:d_seg arr dw 1,2,3,6,7,9,1,8,1,1, 1,2,3,6,7,9,1,8,1,1, 1,2,3,6,7,9,1,8,1,1 d_seg ends ; Объявляем внешнюю процедуру МЕЖДУ сегментами, иначе ; будет FIXUP OVERFLOW при попытке собрать все в один EXE TLINK-ом ; В другом файле описана функция обработки (почти то, что я показывал выше): ; findproc proc far uses es bx cx dx, sz:word, a:dword ; (AX не восстанавливаю, через него возвращается результат) extrn findproc : far c_seg segment word public 'code' assume cs:c_seg Lab3 proc near ; Процедура ближнего вызова ; ... ; данные для findproc lea bx, arr push cx ; кол-во элементов массива push ds ; адрес массива push bx call far ptr findproc ; вызов findproc... Результат вернется через AX ; вот и все, в AX - результат работы функции, можешь с ним делать что надо Lab3 endp ; ... ; а из основного блока вызываешь Lab3 call Lab3 ; ... |
Сообщ.
#13
,
|
|
|
Цитата volvo877 @ А какая, собственно, разница, передаешь ты адрес массива в Паскаль-программу, или в другой модуль, написанный на ассемблере? А разве при передаче в pas запись не идет обратно? По моему это и должно накладывать свои отличия и ограничения. Или я что-то не так понимаю? |
Сообщ.
#14
,
|
|
|
Что куда идет, еще раз сформулируй мысль?
Я еще раз спрашиваю: есть 2 модуля, в одном - вызывающая процедура и данные. В другом - функция, эти данные обрабатывающая. Какая разница, на каких языках написаны эти самые модули? Все, что тебе надо - это передать в обрабатывающую функцию адрес массива. |
Сообщ.
#15
,
|
|
|
Я про данные, вот когда мы их передаем. Паскаль их передает наоборот, а мы должны их считать в правильном порядке. У паскаля адрес возврата наверху стека, а при передаче asm-asm он внизу если я правильно понимаю. Вот и вопрос, разве это не означает, что делается это по другому?
И что-то не могу понять зачем переименовывать сегмент данных? А паблик он же для объединения данного сегмента с модулем? Добавлено Где-то я накосячил... Головная программа .286 d_seg segment byte public arr dw 9,2,3,5,9,7,9,2,3,9,0,9,1,6,3,7,9,8,1,5,6,7,0,1,9,9,9,1,8,6 d_seg ends extrn findproc : far code segment byte public assume cs:code, ds:d_seg Lab3 proc near ; данные для findproc lea bx, arr mov cx, 30d push cx ; кол-во элементов массива push ds ; адрес массива push bx ; смещение call far ptr findproc ; вызов findproc... результат вернется через AX Lab3 endp ; запуск mov ax, seg d_seg mov ds, ax mov es, ax ; выводим массив на экран lea si, arr mov cx, 30 out_mass: mov ah, 2h mov dl, [si] add dl, '0' int 21h mov ah, 2h mov dl, ' ' int 21h add si, 2 loop out_mass ; выводим пустоту mov ah, 2h mov dl, ' ' int 21h ;запуск 2 файла на asm call Lab3 ; теперь печатаем результат и уходим ... aam ; коррекция числа add ax,3030h mov dl,ah mov dh,al mov ah,02 mov dl,dh int 21h ret code ends end Модуль .286 d_seg segment byte public n dw ? max dw ? d_seg ends code segment byte public assume cs:code, ds:d_seg findproc proc far public findproc ; сама работа ; восстанавливаю значения регистров pop bx pop ds pop cx mov n, cx ; сохраняю кол-во элементов mov arr, bx ; сохраняю адрес 1 элемента mov bx, 0 ; здесь будет храниться мода mov cx, n ; заполняем главный цикл les di, arr ; закидываем начальное значение массива outer_loop: push cx ; сохраняем значение внешнего цикла les si, arr ; закидываем начальное значение массива mov ax, word ptr es:[di] ;задаем начальное значение моды xor dx, dx ; чистим счетчик повторений текущего элемента mov cx, n ; загрузка внутреннего цикла inner_loop: cmp ax, word ptr es:[si] ; равно ли значение моды текущему элементу jne no_good ; если не равно inc dx ; если равно увеличиваем счётчик no_good: add si, 2 ; переходим к следующему элементу loop inner_loop ; бегаем по внутреннему циклу cmp bx, dx ; новый счетчик больше старого максимума? jg no_op ; нет mov bx, dx ; значит, у нас есть новый кандидат на моду les si, max mov word ptr es:[si], ax ; сохраняем текущее значение моды в "max" no_op: add di, 2 ; переходим к следующему элементу pop cx ; восстанавливаем внешний счетчик loop outer_loop ; бегаем по внешнему циклу mov ax, max ; записываю на всякий значение моды ret findproc endp code ends end |