Консультация № 177048
04.03.2010, 05:46
0.00 руб.
04.03.2010, 09:16
0 9 1
Здравствуйте, уважаемые эксперты!
Помогите пожалуйста решить следующую задачу:
Вычислить значения заданных функций с помощью TASM, используя стандартные директивы сегментации. Все переменные описать в разных сегментах данных, каждую функцию — в виде отдельной подпрограммы, используя разные способы передачи параметров. Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд.
Вот данные функции:

Обсуждение

давно
Посетитель
7438
7205
04.03.2010, 09:20
общий
Даниил Цветков:
Правильно писать ссылку на графический файл так - https://rfpro.ru/d/1745.gif
Когда загружали файлик на сервер, то, наверно, видели три ссылки: одна для HTML, одна в BBCode для просто ссылки на файл (Вы так сделали) и одна в BBCode для ссылки на графический файл, чтобы он "нарисовался"
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
04.03.2010, 11:20
общий
Уточните:
"каждую функцию — в виде отдельной подпрограммы" - пишем всего две подпрограммы, одну для a, вторую - для b;
"используя разные способы передачи параметров" - допустим, для вычисления a, параметры передаем в стек по одному. Для b - через регистры. А можно еще записать в структуру и передать адрес структуры...Как Вам хочется?
"Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд" - я вижу только одного претендента: 1/8 + ex+y
Ну и сколько делаем сегментов данных? По одному на число? Предложите свой вариант.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
05.03.2010, 02:26
общий
"каждую функцию — в виде отдельной подпрограммы" - пишем всего две подпрограммы, одну для a, вторую - для b

Совершенно верно.
"используя разные способы передачи параметров" - допустим, для вычисления a, параметры передаем в стек по одному. Для b - через регистры.

Да. Так. Можно ещё через общую память. Думаю лучше будет передавать для а через память, а для b - через регистры.
"Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд" - я вижу только одного претендента: 1/8 + ex+y

Да. Так и есть. Просто в оригинальном задании были и другие функции - но они уже решены.
Ну и сколько делаем сегментов данных? По одному на число? Предложите свой вариант.

Да. По одному на число. Неизвестные а и b хранятся в одном сегменте. Итого должно получиться 4 сегмента.
давно
Посетитель
7438
7205
05.03.2010, 09:29
общий
Даниил Цветков:
Да. Так. Можно ещё через общую память. Думаю лучше будет передавать для а через память
Опять же можно разными путями:
1) вообще не передавать, просто из подпрограммы обращаться к памяти;
2) передавать адреса каждой переменной;
2) оформить в виде структуры, передавать адрес структуры;
3) или подразумевается еще что-то другое...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
05.03.2010, 11:27
общий
Даниил Цветков:
И еще вопрос:
32-битные регистры используем?
Дело в том, что у нас действительные числа, которые по минимуму 4 байта, а то и 8, 10
Передавать в 16-битных регистрах не совсем удобно. В 32-битных еще куда не шло: 4 байтные можно и передать...
Можно еще передавать в регистрах сопроцессора...
Как делать?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
05.03.2010, 16:54
общий
это ответ
Здравствуйте, Даниил Цветков.
Примерчик не из простых: активно используется сопроцессор, если он Вам не знаком, то придется туго.
Еще момент: в сопроцессоре нет команды возведения в степень, поэтому при вычислениях ex+y и cos5/3(x)
приходится прибегать сначала к логарифмированию, затем строить число масштабированием...
Параметры для нахождения b передаются через регистры, но только сопроцессора.
Рекомендую совместно с просмотром в отладчике того, как работает программа, считать на калькуляторе - помогает видеть, как идут вычисления


Приложение:
.386 ;необходимо для команды fcos
sseg segment stack "stack"
db 1024 dup (0)
sseg ends

dsegX segment use16 para public 'data'
x dd 1.5
dsegX ends

dsegY segment use16 para public 'data'
y dd 0.5
dsegY ends

dsegZ segment use16 para public 'data'
z dd 1.1
dsegZ ends

dseg segment use16 para public 'data'
a dd ?
b dd ?
;константы
c8 dd 8.
c85 dd 8.5e-3
c4 dd 0.0004
c5 dd 5.
c3 dd 3.
dseg ends

;в st должно находиться xlog[2]y
POWER MACRO
fld st ;x*log[2]e->st(1)
frndint ;округляем st до целого
fsub st(1),st ;st(1)-=st
fxch ;st(1)<->st
f2xm1 ;st=(2 в степени st) - 1
fld1 ;1->st
fadd ;st+=1
fscale ;exp = st * (2 в степени st(1))
fstp st(1) ;чтобы убрать значение из st(1)
ENDM

;в st cos(x), который возводим в степень 5/3
POWERST MACRO
fld c5
fdiv c3 ;5/3
fxch
fyl2x ;st=st(1)*log[2]st
POWER ;находим cos(x)^(5/3)
ENDM

;e^st + 1/8
;st = x + y
EXP18 MACRO
fldl2e ;log(осн 2)e->st
fmulp ;st(1)*log(осн 2)e->st
POWER ;находим e^(x+y)
fld1 ;1
fdiv c8 ;1/8
faddp ;st = 1/8 + exp(x+y)
ENDM

;берем x и y из памяти, ищем x+y и вычисляем 1/8 + exp(x+y)
EXY18M MACRO xoff,yoff
les bx,xoff
fld dword ptr es:[bx] ;x->st
les bx,yoff
fadd dword ptr es:[bx] ;x+y->st
EXP18
ENDM

cseg segment para use16 public 'code'
assume cs:cseg, ss:sseg, ds:dseg
start:
mov ax,sseg
mov ss,ax
mov ax,dseg
mov ds,ax

push dsegZ ;в стек длинные адреса z
push offset z
push dsegY
push offset y ;y
push dsegX
push offset x ;x
call calc_a ;получаем в st ответ
fstp a ; и сохраняем его в переменной

;загружаем переменные в стек сопроцессора
mov ax,dsegZ ;сегмент для z
mov es,ax
fld dword ptr es:[z] ;z->st(2)
mov ax,dsegY ;сегмент для y
mov es,ax
fld dword ptr es:[y] ;y->st(1)
mov ax,dsegX ;сегмент для x
mov es,ax
fld dword ptr es:[x] ;x->st
call calc_b ;получаем в st ответ
fstp b ; и сохраняем его в переменной

mov ax,3c00h
int 21h

par_x equ [bp+4] ;для адресации в стеке
par_y equ [bp+8]
par_z equ [bp+12]

calc_a proc
push bp
mov bp,sp

les bx, dword ptr par_x ;длинный указатель на x
fld dword ptr es:[bx] ;st = x
fcos ;st = cos(x)
POWERST ;st = cos(x)^(5/3)
fmul c4 ;st = 0.0004 * cos(x)^(5/3)
les bx, dword ptr par_z ;длинный указатель на z
fld dword ptr es:[bx] ;st = z
fmul c85 ;st = z * 8.5*10^-3
fsubp ;st = 0.0004 * cos(x)^(5/3) - z * 8.5*10^-3
EXY18M par_x,par_y ;st = exp(x+y) + 1/8
fdivp ;st = st(1) / st
pop bp
ret 12
calc_a endp

calc_b proc
fld st ;x
fadd st,st(2) ;x+y
EXP18 ;exp(x+y)+1/8
fld st(3) ;z
fmul st,st(4) ;z*z
fld st(3) ;y
fsub c5 ;y-5
fdivp ;z*z/(y-5)
fsubp ;exp(x+y)+1/8 - z*z/(y-5)
faddp st(1) ;exp(x+y)+1/8 - z*z/(y-5) + x
fstp st(1) ;уберем из стека y и z
fstp st(1)
ret
calc_b endp

cseg ends
end start
5
Содержательный и полный ответ. Спасибо большое
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
05.03.2010, 20:15
общий
Опять же можно разными путями:
1) вообще не передавать, просто из подпрограммы обращаться к памяти;
2) передавать адреса каждой переменной;
2) оформить в виде структуры, передавать адрес структуры;
3) или подразумевается еще что-то другое...

Подходит первый вариант.
32-битные регистры используем?

Да. Также как с памятью. Просто брать в подпрограмме из регистра нужное выражение.
Код:
push	dsegZ				;в стек длинные адреса z
push offset z

Не понимаю что происходит в этих командах. Можно обойтись без них или нет?
Ассемблер знаю на минимальном уровне Поэтому прошу прощение за просьбы "упростить" программу.
Код:
	les	bx, dword ptr par_x		;длинный указатель на x

Возможно ли также не использовать подобные команды?
"Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд" - я вижу только одного претендента: 1/8 + ex+y

Возможно ли использовать для этого лишь одну макрокоманду? Или без расписания её на 4 не обойтись?
давно
Посетитель
7438
7205
05.03.2010, 22:02
общий
Подходит первый вариант.
В таком случае, у нас не будет никакой передачи параметров ...
Да. Также как с памятью. Просто брать в подпрограмме из регистра нужное выражение.
Я обошелся 16-битными регистрами.
К Вашему сведению, сопроцессор не может работать напрямую с регистрами (типа AX), только из памяти...
push dsegZ ;в стек длинные адреса z
push offset z
Не понимаю что происходит в этих командах. Можно обойтись без них или нет?
Уважаемый, Ваше задание предполагает работу с разными сегментами. Этими командами мы передаем параметром адрес переменной, что включает сегмент и смещение. Поэтому обойтись никак нельзя.
Ассемблер знаю на минимальном уровне. Поэтому прошу прощение за просьбы "упростить" программу.
Никогда не поздно научиться... Надо просто понять, как работает.
les bx, dword ptr par_x ;длинный указатель на x
Данная команда загружает первое слово из стека (переданный параметр) в BX по адресу par_x=[bp+4] и в ES слово по следующему адресу par_x+2=[bp+6]. В результате получаем в ES:BX длинный указатель на данные. Очень удобная команда
Возможно ли использовать для этого лишь одну макрокоманду? Или без расписания её на 4 не обойтись?
Да можно, конечно...Но было же сказано
Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд.
Вот и оформил повторяющиеся вычисления как макро
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
06.03.2010, 00:27
общий
Лысков Игорь Витальевич:
Cпасибо большое за помощь!
Форма ответа