Vanya1529
Интересующийся
Offline
|
|
« : 10-04-2014 16:49 » |
|
Привет. Помогите с задачей: Условия задачи: Задано целое беззнаковое число Х<65536. Определить, есть ли в записи числа цифра, равная среднему арифметическому остальных цифр? Полученное значение вывести на экран. Дела такие, введенное число н. п. 50433 я разбиваю на числа 5, 0, 4, 3, 3 делением на 10 и записываю в стэк, как дальше делать - никак не пойму. Вот код: ... mov ax,62002 mov number,ax mov bx,10 mov cx,0
a: div bx push dx mov dx,0 inc cx cmp ax,0 jne a
mov bx,cx ...
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #1 : 10-04-2014 16:58 » |
|
Vanya1529, а если среднее - не целое, то что будешь делать? введенное число н. п. 50433 я разбиваю на числа 5, 0, 4, 3, 3 делением на 10 и записываю в стэк, как дальше делать - никак не пойму. Ну как что? ты ж сам написал: посчитать среднее, затем поискать число. Как считается среднее?
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #2 : 10-04-2014 17:11 » |
|
Vanya1529, а если среднее - не целое, то что будешь делать?
Об этом не думал как-то Ну как что? ты ж сам написал: посчитать среднее, затем поискать число.
Как считается среднее?
Складываются все и делятся на количество, но я все-равно не понимаю, стопр какой-то
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #3 : 10-04-2014 17:23 » |
|
Vanya1529, чего не понимаешь? Ты ж написал цикл получения цифр. Ну напиши цикл сложения цифр, а потом подели. Подсказка: складывать можно прям в том же цикле, где и цифры "добываешь".
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #4 : 10-04-2014 17:38 » |
|
Vanya1529, чего не понимаешь? Ты ж написал цикл получения цифр. Ну напиши цикл сложения цифр, а потом подели. Подсказка: складывать можно прям в том же цикле, где и цифры "добываешь".
Всмысле прямо в стеке складывать?Это как?
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #5 : 10-04-2014 19:18 » |
|
Vanya1529, что значит прямо в стеке? Ты же число сперва получаешь в регистре, прежде чем в стек положить.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #6 : 10-04-2014 19:21 » |
|
Вот что-то получилось, только там где вопросы я не знаю как на экран вывести число если оно есть и если нет. .MODEL small .STACK 100h .DATA mas dw 5 dup(0) .CODE begin: xor ax,ax xor bx,bx xor cx,cx xor dx,dx xor si,si xor di,di
mov ax,62002 mov bx,10 mov cx,0 mov si,4
a: div bx sub si, 1 mov mas[si],dx add di,dx mov dx,0 inc cx cmp ax,0 jne a
mov bx,cx xor ax,ax mov ax,di div bx xor cx,cx mov cx,5
b: cmp ax, mas[si] je c inc si LOOP b ????????
c: ????????????? mov ax, 4c00h int 21h end start
Добавлено через 20 секунд:Правильно так?
|
|
« Последнее редактирование: 10-04-2014 19:21 от Vanya1529 »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #7 : 10-04-2014 22:40 » |
|
Vanya1529, а ты словами каждую строчку опиши. mov mas[si],dx Это как-то странно выглядит. Кругом регистры, а тут бац и массив. Вообще для работы с массивом сперва его адрес нужно загрузить в регистр базы (BX), делается это инструкцией LEA. В общем-то никто тебе не мешал работать и со стеком, как в предыдущих вариантах. Но массив так массив. Ещё обрати внимание, что массив у тебя содержит левые нули - в тех случаях, когда числа короче 5 цифр. И ты эти нули считаешь полноправными цифрами, хотя это по условию задачи не задано. В итоге у тебя и среднее получается с влиянием этих нулей, и поиск ты делаешь тоже с учётом нулей. Что-то мне кажется, что так не должно быть. И для поиска в массиве слов в есть специальные инструкции SCASW REPE и т.п. Т.е. цикл для задачи поиска писать не обязательно - процессор умеет её делать аппаратно. Но это для 286 и выше.
|
|
« Последнее редактирование: 10-04-2014 22:42 от Dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #8 : 11-04-2014 05:30 » |
|
Vanya1529, а ты словами каждую строчку опиши. mov mas[si],dx Это как-то странно выглядит. Кругом регистры, а тут бац и массив. Вообще для работы с массивом сперва его адрес нужно загрузить в регистр базы (BX), делается это инструкцией LEA. В данном случае это не обязательно. И для поиска в массиве слов в есть специальные инструкции SCASW REPE и т.п. Т.е. цикл для задачи поиска писать не обязательно - процессор умеет её делать аппаратно. Но это для 286 и выше.
По-моему эта команда есть начиная с 86, да и в любом случае - на всех современных процессорах она уже есть.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #9 : 11-04-2014 06:20 » |
|
По-моему эта команда есть начиная с 86, да и в любом случае - на всех современных процессорах она уже есть. Ну человек пишет код для TASM под DOS 16 бит. Тут дело не в том, что процессоры поддерживают, а в том, как сам ассемблер обрабатывает исходный код. Для 286 и других нужно указать соответствующую директиву. Так что по умолчанию код 8086.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #10 : 06-05-2014 16:22 » |
|
.MODEL small .STACK 100h .DATA stroka1 db "Chisla ravnogo srednemu arifmeticheskomu ostalnih cifr net: $" stroka2 db "Nashlos chislo ravnoe srednemu arifmeticheskomu ostalnih cifr: $" mas dw 5 dup(0) .CODE begin: xor dx,dx xor di,di mov ah,0ah int 21h mov ax,dx xor dx,dx mov bx,10 mov cx,0 mov si,4
a: div bx mov mas[si],dx dec si add di,dx mov dx,0 inc cx cmp ax,0 jne a
mov bx,cx xor ax,ax mov ax,di div bx xor cx,cx mov cx,5
b: cmp ax,mas[si] je c inc si LOOP b Вот подскажите где ошибка, программа всегда выдает Stroka1 на экран, даже если в записи числа есть нужная цифра. я запутался Добавлено через 1 минуту и 8 секунд:.MODEL small .STACK 100h .DATA stroka1 db "Chisla ravnogo srednemu arifmeticheskomu ostalnih cifr net: $" stroka2 db "Nashlos chislo ravnoe srednemu arifmeticheskomu ostalnih cifr: $" mas dw 5 dup(0) .CODE begin: xor dx,dx xor di,di mov ah,0ah int 21h mov ax,dx xor dx,dx mov bx,10 mov cx,0 mov si,4
a: div bx mov mas[si],dx dec si add di,dx mov dx,0 inc cx cmp ax,0 jne a
mov bx,cx xor ax,ax mov ax,di div bx xor cx,cx mov cx,5
b: cmp ax,mas[si] je c inc si LOOP b
lea dx,stroka1 mov ah,09h int 21h jmp d
c: lea dx,stroka2 mov ah,09h int 21h
d: mov ax, 4c00h int 21h end
Упс, не весь код кинул
|
|
« Последнее редактирование: 06-05-2014 16:23 от Vanya1529 »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #11 : 06-05-2014 17:44 » |
|
Vanya1529, а что ты хочешь? Ты выводишь строку и всё. А где превращение числа в строку из цифр? Где вывод этой строки или печать в цикле по одной цифре?
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #12 : 06-05-2014 18:16 » |
|
Я имею ввиду то что даже если в записи числа есть цифра, равная среднему арифметическому всех остальных цифр то программа все равно выдает мне строку 1. А нужна строка 2.
|
|
|
Записан
|
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #13 : 06-05-2014 18:17 » |
|
Вот например число 44444 среднее арифм. 4. В числе есть такая цифра, а оно мне вот ... Да еще и тттттт какие-то
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #14 : 06-05-2014 18:51 » |
|
Vanya1529, так ты не инициализировал правильным образом сегментный регистр DS, и при вызове функции происходит ерунда. .model small
.data
s db "Test", 0Dh, 0Ah, "$"
.code
.8086
entry:
; Вот эта инициализация регистра DS обязательна для модели памяти small mov ax, @data mov ds, ax
lea dx, s mov ah, 09h int 21h
mov ah, 4Ch int 21h
end entry
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #15 : 06-05-2014 19:02 » |
|
Другой вариант: вовсе не использовать разные сегменты. .model tiny
.code
; Задаёт смещение начала кода - нужно для DOS. org 100h
.8086
entry:
; Перепрыгиваем область данных jmp main
s db "Test", 0Dh, 0Ah, "$"
; Область кода main:
lea dx, s mov ah, 09h int 21h
; Выход в DOS другим способом - для COM-программы. int 20h
end entry Собирать нужно, вызывая tlink с ключом /t. Получится com-файл. Модель памяти tiny (крошечная) - это когда данные, код и стек находятся в одном общем сегменте размером 64 Кб. Модель памяти small (маленькая) - это когда код и стек находятся в одном общем сегменте 64 Кб, а данные в другом отдельном сегменте тоже размером 64 Кб. Итого может использоваться до 128 Кб.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #16 : 09-05-2014 12:52 » |
|
Вот сделал, все работает. Но программа дает правильный результат только с 5-значными числами. Например ввести 44444, оно выдаст что число такое есть, но стоит ввести 234 например и все.. хотя (2+3+4):3 = 3 Вроде эта строчка(mas dw 5 dup(0)) где я задаю массив не влияет на это, так в чем проблема тогда? .MODEL small .STACK 100h .DATA stroka1 db 10,13,"Chisla ravnogo srednemu arifmeticheskomu ostalnih cifr net: $" stroka2 db 10,13,"Nashlos chislo ravnoe srednemu arifmeticheskomu ostalnih cifr: $" s db "Vvedite chislo: $" mas dw 5 dup(0) .CODE include 'emu8086.inc' begin: ; mov ax, @data mov ds, ax
xor dx,dx xor di,di
lea dx, s mov ah,09h int 21h CALL scan_num mov ax,cx xor dx,dx mov bx,10 mov cx,0 xor si,si
a: div bx mov mas[si],dx inc si add di,dx mov dx,0 cmp ax,0 jne a
mov bx,si xor ax,ax mov ax,di div bx mov cx,si
b: cmp ax,mas[si] je c dec si LOOP b
lea dx,stroka1 mov ah,09h int 21h jmp d
c: lea dx,stroka2 mov ah,09h int 21h
d: mov ax, 4c00h int 21h DEFINE_SCAN_NUM end begin
Добавлено через 1 минуту и 18 секунд:И еще как мне вывести "это" число, если оно есть. У меня выводит просто сообщение, а нужно чтоб еще и его выводило на экран.
|
|
« Последнее редактирование: 09-05-2014 12:53 от Vanya1529 »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #17 : 09-05-2014 13:19 » |
|
Vanya1529, я не знаю, что ты там за макросы нагородил, и структура кода вообще отсутствует. Поэтому разбираться за тебя, почему эта каша не работает, как-то не весело.
Напиши русским языком шаги алгоритма решения задачи. Затем распиши по блокам кода эти шаги алгоритма. Не используй лишних регистров как попало. Тогда может и сам поймёшь, что не так. Если не поймёшь, по меньшей мере код будет читабельным, чтобы разобраться.
А то так фактически предлагаешь, чтобы за тебя кто-то эту программу запустил (что невозможно из-за отсутствия используемых inc-файлов), прошёлся по ней отладчиком и нашёл баг. Это работа программиста, причём не какая-то там интеллектуальная, а черновая. С какой радости её за тебя делать?
Что касается вывода числа. Число на экране изображается символами-цифрами. Десятичными. Соответственно, тебе нужно число разложить на десятичные цифры, каждую цифру вывести на экран (или записать в строчку, которую потом вывести на экран). Причём делать это в правильном порядке следования цифр. Для этого опиши алгоритм. В твоём случае цифра всё равно одна, так что это будет алгоритм вывода цифры. Если задача расширится до многознаковых чисел, то вывод одной цифры будет вспомогательным алгоритмом для вывода длинных чисел. Вывод отдельного символа в телетайпном режиме обеспечивает int 10h, функция AH=0eh, ASCII-код символ нужно записать в регистр AL, в регистре BL может быть указан цвет символа.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #18 : 12-05-2014 17:22 » |
|
.MODEL small .STACK 100h .DATA stroka1 db 10,13,"Chisla ravnogo srednemu arifmeticheskomu ostalnih cifr net: $" ;заносим в переменную строку stroka2 db 10,13,"Nashlos chislo ravnoe srednemu arifmeticheskomu ostalnih cifr: $" ;заносим в переменную строку s db "Vvedite chislo: $" ;заносим в переменную строку mas dw 5 dup(0) ;создаем массив из 5-ти элементов, заполняем нулями .CODE include 'emu8086.inc' ;подключаем файлы библиотек begin: ;начало программы mov ax, @data mov ds, ax
xor dx,dx ;обнуляем регистры dx и di xor di,di
lea dx, s ;Выводим на экран строку, содержащуюся в переменной s mov ah,09h int 21h CALL scan_num ;с клавиатуры вводится число ( Х<65536 ) (заносится в регистр сх) mov ax,cx ;переносим число из регистра сх в ах (для дальнейшего деления) xor dx,dx ;обнуляем регистр dx mov bx,10 ;заносим в регистр bx число 10 ( в дальнейшем делением на 10 будем заносить цифры числа в массив) mov cx,0 ;обнуляем регистр сх xor si,si ;обнуляем регистр si
БЛОК 1 (занос цифр числа в массив)
a: div bx ; Делим содержимое регистра ах на содержимое регистра bx (т.е на 10) и тем самым получаем 1 цифру числа в регистре dx mov mas[si],dx ;затем эту первую цифру заносим в 1 элемент массива (т.е в нулевой). затем это будет 2,3 и т.д inc si ;инкрементрируем регистр si, что бы сл. цифру занести уже в сл. элемент массива add di,dx ;В регистре di мы накапливаем сумму всех этих цифр ( для дальнейшего деления их суммы на количества) mov dx,0 ;обнуляем регистр dx cmp ax,0 ;сравниваем регистр ах( в котором изначально находится число) с 0 jne a ;если он равен нулю то все цифры числа перенесены в массив и можно продолжать работу, иначе, переход снов ана метку а
БЛОК 2 (Нахождение среднего арифметического цифр числа)
xor ax,ax ;обнуляем регистр ах mov cx,si ;заносим содержимое регистра si(в si сейчас кол-во проходов цикла из блока 1, т.е количество цифр в числе) в регистр сх(нужно для цикла в блоке 3 mov ax,di ;заносим содержимое регистра di (сумма отдельных цифр числа) в регистр ах div bx ;делим содержимое регистра ах на содержимое регистра si ( результат в ах)
БЛОК 3 (поиск цифры в числе, равной среднему арифметическому остальных цифр)
b: cmp ax,mas[si] ;сравниваем то самое среднее арифметическое со всеми цифрами по очереди je c ;если равная цифра нашлась то переход на метку с dec si ;уменьшение регистра si на единицу ( чтобы с начала цикла уже сравнивалось число с другим элементов массива) LOOP b ;переход на следующую команду по завершению цикла
lea dx,stroka1 ;вывод на экран содержимого переменной stroka1 ( т.е сообщения о том что таких цифр нет) mov ah,09h int 21h jmp d ;безусловный переход на конец программы
c: lea dx,stroka2 ;вывод на экран содержимого переменной stroka2 ( т.е сообщения о том что нашлась такая цифра) mov ah,09h int 21h
d: mov ax, 4c00h int 21h DEFINE_SCAN_NUM end begin ;конец программы
|
|
« Последнее редактирование: 12-05-2014 17:29 от Vanya1529 »
|
Записан
|
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #19 : 12-05-2014 17:30 » |
|
Ну вот. Все равно не понимаю из-за чего она только 5-ти значные берет. Было одно лишнее действие, я его убрал.
|
|
|
Записан
|
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #20 : 12-05-2014 20:56 » |
|
Число как вывести я уже разобрался - через PRINT_NUM_UNS. Но все равно почему программа правильно работает только с 5-ти значными числами??
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #21 : 12-05-2014 22:09 » |
|
Ну давай разбираться. Я лично не знаю, что вот эти строки делают и как include 'emu8086.inc' ;подключаем файлы библиотек
CALL scan_num ;с клавиатуры вводится число ( Х<65536 ) (заносится в регистр сх)
DEFINE_SCAN_NUM
У меня нет файла emu8086.inc, процедуры scan_num и макроса DEFINE_SCAN_NUM. Они нестандартные. И не очень-то понятно, зачем они тебе. Потому что если б ты сам написал чтение цифр в массив, ты бы понял, как записывать число на экран. Это одинаковые задачи, просто в разном направлении работают: одна читает символы, вторая печатает. ;заносим в переменную строку Это не совсем так. Это не операция присваивания переменной. Это метка на адрес куска памяти, где записана строка. Ближе всего будет понятие "константа" в языках высокого уровня. Но всё же строчки по адресу можно перезаписывать - нужно лишь помнить об их размерах. xor dx,dx ;обнуляем регистры dx и di xor di,di
Прекрасно. Только непонятно, зачем? Ниже ты регистр DX благополучно перезаписываешь в инструкции LEA. Регистр DI вовсе не используется для ввода. Лишние бесполезные строчки - мусор в программе. Больше мусора, меньше понятно, что к чему. mov ax,cx ;переносим число из регистра сх в ах (для дальнейшего деления) xor dx,dx ;обнуляем регистр dx mov bx,10 ;заносим в регистр bx число 10 ( в дальнейшем делением на 10 будем заносить цифры числа в массив) mov cx,0 ;обнуляем регистр сх xor si,si ;обнуляем регистр si
БЛОК 1 (занос цифр числа в массив)
a: div bx ; Делим содержимое регистра ах на содержимое регистра bx (т.е на 10) и тем самым получаем 1 цифру числа в регистре dx mov mas[si],dx ;затем эту первую цифру заносим в 1 элемент массива (т.е в нулевой). затем это будет 2,3 и т.д inc si ;инкрементрируем регистр si, что бы сл. цифру занести уже в сл. элемент массива add di,dx ;В регистре di мы накапливаем сумму всех этих цифр ( для дальнейшего деления их суммы на количества) mov dx,0 ;обнуляем регистр dx cmp ax,0 ;сравниваем регистр ах( в котором изначально находится число) с 0 jne a Итак, ты используешь алгоритм циклического деления на 10 и размещение остатков внутри массива (заодно подумай, так ли уж сильно это отличается от вывода числа на экран). Здесь полезно заранее планировать, какие регистры для чего используются. Инструкции деления DIV/IDIV использует регистры AX,DX таким образом, что делимое 32 бита располагается в двух 16-битных регистрах DX (старшие разряды) и AX (младшие разряды). Это делимое делится (с учётом бита отрицательного числа в IDIV и без учёта в DIV) на аргумент инструкции. Результат оказывается тоже в регистрах: AX - целая часть результата, DX - остаток. AX - это аккумуляторный регистр, DX - регистр данных. Эта инструкция ключевая, и по определению видно, что регистр AX должен получить входное значение, а затем никак не использоваться до конца алгоритма. Алгоритм заканчивается, когда AX обращается в ноль. Для работы с массивами используются специальные индексные регистры: BX - регистр адреса базы, BP - регистр указателя относительно базы, SI, DI - регистры индекса данных. Достаточно лишь использовать один регистр указателя, который последовательно будет указывать на элементы массива. Аргументом деления может быть либо другой регистр, либо значение в ячейке памяти, но, к сожалению, не константа. Поэтому воспользуемся каким-либо регистром. У нас из основных регистров остаётся свободным CX - регистр счётчика. В итоге получаем такой код: mov ax, <1> ; подготовительная операция: в аккумуляторный регистр AX записывается исходное число lea bx, mas ; подготовительная операция: в регистр базы BX записывается указатель на начало массива mov cx, 10 ; подготовительная операция: в регистр счётчика записывается делитель r1: ; начало цикла cwd ; обнуляется DX, который содержит старшие разряды делимого div cx ; деление, в результате в AX оказывается частное, а в DX остаток от деления mov byte ptr [bx], dl ; запись остатка от деления в массив: записывается 1 байт, ; и поэтому используется младшая половина регистра DX - регистр DL размером 8 бит inc bx ; указатель сдвигается к следующему элементу массива cmp ax, 0 ; частное сравнивается с нулём для определения конца алгоритма jnz r1 ; условный переход: если частное не равно 0, переход на метку r1 Здесь вместо <1> нужно использовать то место, где лежит исходное число. У тебя это регистр CX. То, что потом CX "испортится", не имеет значения. Посмотрим на этот алгоритм. Во-первых, он "стрёмный" с точки зрения размера массива: если массив окажется короче количества цифр в исходном числе, произойдёт выход за пределы массива, и значения соседних переменных могут быть испорчены. Более безопасный вариант - делать цикл по длине массива. Во-вторых, массив заполняется цифрами задом наперёд. Т.е. число "12345" в массиве будет записано как "5 4 3 2 1". Чтобы исправить оба этих "косяка", будет разумно использовать не цикл while ax>0, а цикл for cx с уменьшением регистра счётчика - инструкцию LOOP. Она уменьшает CX на единицу, и если CX ещё не 0, переходит на метку. Но для этой схемы нужно переместить делитель в другой регистр. Из свободных у нас остались лишь разные счётчики и указатели: DI, SI, BP. Ну, допустим, тот же DI. Получается: ; подготовительные к циклу операции mov ax, <1> ; в аккумуляторный регистр AX записывается исходное число mov cx, 5 ; в регистр счётчика CX записывает размер массива lea bx, mas ; в регистр базы BX записывается указатель на начало массива add bx, cx ; указатель сдвигается за край массива dec bx ; указатель сдвигается на последний элемент массива (на 1 меньше размер массива) mov di, 10 ; в регистр индекса DI записывается делитель r1: ; тело цикла cwd ; обнуляется DX, который содержит старшие разряды делимого div di ; деление, в результате в AX оказывается частное, а в DX остаток от деления mov byte ptr [bx], dl ; запись остатка от деления в массив: записывается 1 байт, ; и поэтому используется младшая половина регистра DX - регистр DL размером 8 бит dec bx ; указатель сдвигается к предыдущем элементу массива loop r1 ; циклический переход по регистру счётчика: если CX>0, переход на метку r1 Этот цикл работает до начала массива, даже если последние цифры и регистр AX давно уже равны нулю. Но он работает лишь до начала массива, даже если не все цифры исходного числа разобраны. Теперь к этому хозяйству нужно приделать подсчёт среднего арифметического: т.е. нужны регистр для накопления суммы и счётчик цифр (их ведь может быть меньше, чем размер массива). Выбор тут небогатый: остались два свободные регистра. Пусть счётчик будет в SI, а сумма в BP. Их нужно в начале обнулить, потом внутри цикла правильно обрабатывать. Кроме того, внутри цикла нужно сделать break на тот случай, если количество цифр в числе окажется меньше размера массива - и чтобы счётчик цифр дальше не увеличивался, и чтобы "лишние" итерации не крутились. ; подготовительные к циклу операции mov ax, <1> ; в аккумуляторный регистр AX откуда-то вводится исходное число mov cx, 5 ; в регистр счётчика CX записывает размер массива lea bx, mas ; в регистр базы BX записывается указатель на начало массива add bx, cx ; указатель сдвигается за край массива dec bx ; указатель сдвигается на последний элемент массива (на 1 меньше размер массива) mov di, 10 ; в регистр индекса DI записывается делитель mov si, 0 ; в регистр индекса SI записывается начальное значение счётчика цифр mov bp, 0 ; в регистр указателя BP записывается начальное значение сумм цифр r1: ; тело цикла cwd ; обнуляется DX, который содержит старшие разряды делимого div di ; деление, в результате в AX оказывается частное, а в DX остаток от деления mov byte ptr [bx], dl ; запись остатка от деления - цифры числа - в массив: записывается 1 байт, ; и поэтому используется младшая половина регистра DX - регистр DL размером 8 бит add bp, dx ; добавление цифры числа к сумме цифр (тут DX вместо DL потому, ; что инструкция ADD в данном случае требует аргумент 16 бит) inc si ; увеличение счётчика цифр dec bx ; указатель сдвигается к предыдущем элементу массива (важно сделать до выхода из цикла) cmp ax, 0 ; сравнение частного с 0 loopne r1 ; циклический переход по регистру счётчика: если CX>0 и результат предыдущего сравнения не равен 0, переход на метку r1 - начало цикла a: ; вычисление среднего mov ax, bp ; в аккумуляторный регистр записывается делимое - сумма цифр cwd ; обнуляется DX, который содержит старшие разряды делимого div si ; деление, в результате в AX оказывается частное mov <2>, ax ; из аккумуляторного регистра AX куда-то выводится результат - округлённое до целого среднее всех цифр Дальше требуется найти в массиве такую цифру, которая получилась как значение среднего. Исходными данными для этой задачи являются: - аккумуляторный регистр AX, в котором содержится среднее; - массив, в котором содержатся цифры, причём они "прижаты" к правому краю массива - массив хранит число в десятичной записи с левыми незначащими нулями, например, 00123; - регистр индекса SI, в котором содержится количество цифр в массиве. - регистр базы BX, который указывает на элемент массива левее последней цифры числа (или за левый край массива, если весь массив заполнен) ; поиск среднего среди цифр mov cx, si ; регистр счётчика CX становится равен количеству цифр. add bx, si ; регистр базы BX, остановившийся левее последней цифры числа, сдвигается опять на последний элемент массива r2: ; тело цикла cmp byte ptr [bx], al ; сравниваем цифру в массиве с цифрой среднего в младшей половине регистра AX - регистре AL. je f ; условный переход: если результат сравнения - равенство, выход за пределы цикла - на метку f dec bx ; указатель сдвигается к предыдущем элементу массива loop r2 ; циклический переход по регистру счётчика: если CX>0, переход на метку r1 ; если не найдена цифра в числе, равная среднему nop ; холостой ход процессора, тут нужны другие некие действия jmp e ; перепрыгивание через другую ветвь условия - безусловный переход на метку e. f: ; если найдена цифра в числе, равная среднему nop ; холостой ход процессора, тут нужны другие некие действия e: ; завершение программы nop ; холостой ход процессора, тут нужны другие некие действия Ну вот как-то так, и это работает правильно c количеством цифр от 1 до 5. Сверяй со своим. Примечание: у меня описана работа с массивом по байтам (тип массива db dup(5)), а не по словам, как у тебя (тип массива dw dup(5)). Чтобы мой код работал с dw, нужно изменить арифметику указателей: все операции с bx умножать на 2, и вместо byte ptr использовать word ptr.
|
|
« Последнее редактирование: 12-05-2014 22:14 от Dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #22 : 12-05-2014 22:30 » |
|
Наконец, вариант, в котором ограничения на размер массива не играют роли - это работа со стеком. Массив вообще не используется. В этом случае количество цифр не ограничивается даже 5, а теоретически может быть равно свободному месту в стеке - это многие тысячи цифр, но в этом случае нужно смотреть за регистром, накапливающим сумму, чтобы он не переполнился. ; подготовительные к циклу операции mov ax, <1> ; в аккумуляторный регистр AX откуда-то вводится исходное число mov di, 10 ; в регистр индекса DI записывается делитель mov cx, 0 ; в регистр счётчика CX записывается начальное значение счётчика цифр mov si, 0 ; в регистр индекса SI записывается начальное значение сумм цифр r1: ; тело цикла cwd ; расширяем значение AX до пары DX,AX, помещая в DX старшие разряды делимого div di ; деление, в результате в AX оказывается частное, а в DX остаток от деления push dx ; полученная как остаток деления цифра числа сохраняется в стеке add si, dx ; добавление цифры числа к сумме цифр inc cx ; увеличение счётчика цифр cmp ax, 0 ; сравнение частного с 0 jnz r1 ; условный переход: если частное ещё не равно нулю, переход на метку r1 - начало цикла a: ; вычисление среднего mov ax, si ; в аккумуляторный регистр записывается делимое - сумма цифр cwd ; расширяем значение AX до пары DX,AX, помещая в DX старшие разряды делимого div cx ; деление на количество цифр, в результате в AX оказывается частное - среднее цифр ; поиск среднего среди цифр r2: ; тело цикла pop dx ; из стека извлекается очередная цифра cmp dx, ax ; сравниваем цифру из стека с цифрой среднего. je f ; условный переход: если результат сравнения - равенство, выход за пределы цикла - на метку f loop r2 ; циклический переход по регистру счётчика: если CX>0, переход на метку r2 ; если не найдена цифра в числе, равная среднему nop ; холостой ход процессора, тут нужны другие некие действия jmp e ; перепрыгивание через другую ветвь условия - безусловный переход на метку e. f: ; если найдена цифра в числе, равная среднему nop ; холостой ход процессора, тут нужны другие некие действия e: ; завершение программы nop ; холостой ход процессора, тут нужны другие некие действия
|
|
« Последнее редактирование: 13-05-2014 15:46 от Dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #23 : 13-05-2014 20:24 » |
|
Спасибо большое за помощь. Вот я составил 2 финальные программы: с помощью массива и с помощью стека: Способ 1 (с помощью массива):.MODEL small .STACK 100h .DATA stroka1 db 10,13,"Chisla ravnogo srednemu arifmeticheskomu ostalnih cifr net: $" ;заносим в переменную константу stroka2 db 10,13,"Nashlos chislo ravnoe srednemu arifmeticheskomu ostalnih cifr: $" ;заносим в переменную константу s db "Vvedite chislo: $" ;заносим в переменную константу mas db 5 dup(0) ;создаем массив из 5-ти элементов, заполняем нулями .CODE include 'emu8086.inc' ;подключаем файлы библиотек begin: ; ;начало программы mov ax, @data mov ds, ax
lea dx, s ;Выводим на экран константу, содержащуюся в переменной s mov ah,09h int 21h CALL scan_num ;с клавиатуры вводится число ( Х<65536 ) (заносится в регистр сх) ; подготовительные к циклу операции mov ax, cx ; в аккумуляторный регистр AX из регистра СХ вводится исходное число mov cx, 5 ; в регистр счётчика CX записывает размер массива lea bx, mas ; в регистр базы BX записывается указатель на начало массива add bx, cx ; указатель сдвигается за край массива dec bx ; указатель сдвигается на последний элемент массива (на 1 меньше размер массива) mov di, 10 ; в регистр индекса DI записывается делитель mov si, 0 ; в регистр индекса SI записывается начальное значение счётчика цифр mov bp, 0 ; в регистр указателя BP записывается начальное значение сумм цифр
r1: ; тело цикла xor dx, dx ; обнуляется DX, который содержит старшие разряды делимого div di ; деление, в результате в AX оказывается частное, а в DX остаток от деления mov byte ptr [bx], dl ; запись остатка от деления - цифры числа - в массив: записывается 1 байт, ; и поэтому используется младшая половина регистра DX - регистр DL размером 8 бит add bp, dx ; добавление цифры числа к сумме цифр (тут DX вместо DL потому, ; что инструкция ADD в данном случае требует аргумент 16 бит) inc si ; увеличение счётчика цифр dec bx ; указатель сдвигается к предыдущем элементу массива (важно сделать до выхода из цикла) cmp ax, 0 ; сравнение частного с 0 loopne r1 ; циклический переход по регистру счётчика: если CX>0 и результат предыдущего сравнения не равен 0, переход на метку r1 - начало цикла
a: ; вычисление среднего mov ax, bp ; в аккумуляторный регистр записывается делимое - сумма цифр xor dx, dx ; обнуляется DX, который содержит старшие разряды делимого div si ; деление, в результате в AX оказывается частное cmp dx, 0 ;сравнение регистра dx (в котором находится остаток от деления) с нулем. Если регистр dx не равен нулю, значит число получилось дробное и его не будет среди цифр массива. Значит переход на метку с jne c ; поиск среднего среди цифр mov cx, si ; регистр счётчика CX становится равен количеству цифр. add bx, si ; регистр базы BX, остановившийся левее последней цифры числа, сдвигается опять на последний элемент массива
r2: ; тело цикла cmp byte ptr [bx], al ; сравниваем цифру в массиве с цифрой среднего в младшей половине регистра AX - регистре AL. je f ; условный переход: если результат сравнения - равенство, выход за пределы цикла - на метку f dec bx ; указатель сдвигается к предыдущем элементу массива loop r2 ; циклический переход по регистру счётчика: если CX>0, переход на метку r2 ; если не найдена цифра в числе, равная среднему c: lea dx,stroka1 ;вывод на экран содержимого переменной stroka1 ( т.е сообщения о том что таких цифр нет) mov ah,09h int 21h jmp e ;безусловный переход на конец программы f: ;если найдена цифра в числе, равная среднему mov bp, ax lea dx, stroka2 ;вывод на экран содержимого переменной stroka2 ( т.е сообщения о том что нашлась такая цифра) mov ah, 09h int 21h mov ax, bp CALL PRINT_NUM_UNS e: ; завершение программы mov ax, 4c00h int 21h DEFINE_SCAN_NUM DEFINE_PRINT_NUM_UNS end begin Оставил я уже работу с массивом по байтам, только изменил mas dw 5 dup(0) на mas db 5 dup(0) и заменил команды "cwd" на xor dx, dx. Иначе выдавало ошибку деления - переполнение если вводилось число больше 32768. Теперь число больше 65536 просто не вводится, как и надо по условиюСпособ 2 (с помощью стека):.MODEL small .STACK 100h .DATA stroka1 db 10,13,"Chisla ravnogo srednemu arifmeticheskomu ostalnih cifr net: $" ;заносим в переменную константу stroka2 db 10,13,"Nashlos chislo ravnoe srednemu arifmeticheskomu ostalnih cifr: $" ;заносим в переменную константу s db "Vvedite chislo: $" ;заносим в переменную константу mas db 5 dup(0) ;создаем массив из 5-ти элементов, заполняем нулями .CODE include 'emu8086.inc' ;подключаем файлы библиотек begin: ; ;начало программы mov ax, @data mov ds, ax
lea dx, s ;Выводим на экран константу, содержащуюся в переменной s mov ah,09h int 21h CALL scan_num ;с клавиатуры вводится число ( Х<65536 ) (заносится в регистр сх) ; подготовительные к циклу операции mov ax, cx ; в аккумуляторный регистр AX откуда-то вводится исходное число mov di, 10 ; в регистр индекса DI записывается делитель mov cx, 0 ; в регистр счётчика CX записывается начальное значение счётчика цифр mov si, 0 ; в регистр индекса SI записывается начальное значение сумм цифр r1: ; тело цикла xor dx, dx ; расширяем значение AX до пары DX,AX, помещая в DX старшие разряды делимого div di ; деление, в результате в AX оказывается частное, а в DX остаток от деления push dx ; полученная как остаток деления цифра числа сохраняется в стеке add si, dx ; добавление цифры числа к сумме цифр inc cx ; увеличение счётчика цифр cmp ax, 0 ; сравнение частного с 0 jnz r1 ; условный переход: если частное ещё не равно нулю, переход на метку r1 - начало цикла a: ; вычисление среднего mov ax, si ; в аккумуляторный регистр записывается делимое - сумма цифр xor dx, dx ; расширяем значение AX до пары DX,AX, помещая в DX старшие разряды делимого div cx ; деление на количество цифр, в результате в AX оказывается частное - среднее цифр cmp dx, 0 ;сравнение регистра dx (в котором находится остаток от деления) с нулем. Если регистр dx не равен нулю, значит число получилось дробное и его не будет среди цифр массива. Значит переход на метку с jne c ; поиск среднего среди цифр r2: ; тело цикла pop dx ; из стека извлекается очередная цифра cmp dx, ax ; сравниваем цифру из стека с цифрой среднего. je f ; условный переход: если результат сравнения - равенство, выход за пределы цикла - на метку f loop r2 ; циклический переход по регистру счётчика: если CX>0, переход на метку r2 ; если не найдена цифра в числе, равная среднему c: lea dx,stroka1 ;вывод на экран содержимого переменной stroka1 ( т.е сообщения о том что таких цифр нет) mov ah,09h int 21h jmp e ;безусловный переход на конец программы f: ;если найдена цифра в числе, равная среднему mov bp, ax lea dx, stroka2 ;вывод на экран содержимого переменной stroka2 ( т.е сообщения о том что нашлась такая цифра) mov ah, 09h int 21h mov ax, bp CALL PRINT_NUM_UNS e: ; завершение программы mov ax, 4c00h int 21h DEFINE_SCAN_NUM DEFINE_PRINT_NUM_UNS end begin Тоже самое, пришлось поменять команды "cwd" на xor dx, dx. Иначе выдавало ту же ошибку деления - переполнение. Также в обоих программах я добавил в метку "а" строки кода: cmp dx, 0 jne c чтобы избежать принятия программой дробного среднего как целого. Как я понял файл с библиотеками находится у меня в папке с программой по пути emu8086/inc. Вот я прикрепил архив, в нем эта самая папка и русский хелп, в котором я и на нашел эти макросы по пути уроки/Библиотека общих функций - emu8086.inc
|
|
« Последнее редактирование: 13-05-2014 21:03 от Vanya1529 »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #24 : 13-05-2014 21:40 » |
|
и заменил команды "cwd" на xor dx, dx. Иначе выдавало ошибку деления - переполнение если вводилось число больше 32768. Ну инструкция CWD расширяет число с учётом знака. Т.е. если в AX старший бит 1 (знак минус), то DX заполняется единицами, а если 0 (знак плюс), то нулями. Вот я составил 2 финальные программы Увы, ты не "составил", а "передрал" с косметическими изменениями. Это грустно. Лучше б разобрался и сам нашёл, где у тебя были ошибки. Например, стек ты вставил, а всё остальное не поменял: и массив в программе остался ненужный, и размер стека какой-то куцый - 256 байт. Халтура.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Vanya1529
Интересующийся
Offline
|
|
« Ответ #25 : 13-05-2014 21:57 » |
|
Ошибки я свои видел, и основная заключалась именно в этом Кроме того, внутри цикла нужно сделать break на тот случай, если количество цифр в числе окажется меньше размера массива - и чтобы счётчик цифр дальше не увеличивался, и чтобы "лишние" итерации не крутились. А на счет стека. Да забыл как-то. Делал на этой же программе и забыл убрать
|
|
|
Записан
|
|
|
|
|