Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты по данной тематике

Асмик Гаряка
Статус: Советник
Рейтинг: 10973
∙ повысить рейтинг »
Коцюрбенко Алексей aka Жерар
Статус: Советник
Рейтинг: 4360
∙ повысить рейтинг »
Boriss
Статус: Академик
Рейтинг: 2257
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / Assembler (Ассемблер)

Номер выпуска:1528
Дата выхода:26.06.2012, 16:00
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:91 / 34
Вопросов / ответов:1 / 1

Консультация # 186409: Уважаемые эксперты! Пожалуйста, ответьте на вопрос: требуется написать программу для ТАSM для вычисления данных выражений. Каждую функцию реализовать в виде отдельной подпрограммы, используя наиболее подходящий спос...


Консультация # 186409:

Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
требуется написать программу для ТАSM для вычисления данных выражений.

Каждую функцию реализовать в виде отдельной подпрограммы, используя наиболее подходящий способ передачи аргументов.
Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд.
Организовать ввод значений исходных переменных с клавиатуры и вывод результатов на экран. Обработать возможные ошибки при вводе чисел с клавиатуры.
Все числа считать вещественными, которые могут представляться в форме с фиксированной и плавающей точкой.

Когда то я уже задавал подобрый вопрос и он есть у меня в истории. Требуется написать так программу, чтобы она была весьма простой и максимально откоментированной.
В прошлой программе громоздким считать нужно таблицы для вывода степеней(окончание программы).Буду очень рад если сможете написать все это в максимально возможные сроки.
Спасибо! smile

Дата отправки: 23.06.2012, 15:28
Вопрос задал: Юдин Евгений Сергеевич (Студент)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Лысков Игорь Витальевич (Старший модератор):

Здравствуйте, Юдин Евгений Сергеевич!
Работу с вещественными числами, в любом случае, простой не назовешь...
Раз Вам не понравилось, как сделано в masm-е, я сделал по-другому smile
Надеюсь, что такое решение Вас устроит... smile
Имейте в виду, что при вводе переменных необходимо следить, чтобы выражение под корнем было >= 0

Код :
	.model	small, stdcall
	.386					;необходимо для команды fcos

;макро для вычисления y^x
;в st должно находиться xlog[2]y
POWER	MACRO
	fld	st				;x*log[2]y->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					;y^x = st * (2 в степени st(1))
	fstp	st(1)				;чтобы убрать значение из st(1)
	ENDM

;e^st
;st = z
EXP	MACRO
	fldl2e					;log(осн 2)e->st
	fmulp					;st(1)*log(осн 2)e->st
	POWER					;st=e^(st)
	ENDM

;log[3](st)
LOG3	MACRO
	fld1					;1
	fxch					;st(1)<->st
	fyl2x					;st=1*log[2]st=log[2]y
	fld1					;1
	fld	c3				;3
	fyl2x					;st=1*log[2]3=log[2]3
	fdiv					;st=st(1)/st=log[2]x/log[2]3=log[3]y
	ENDM

;((log[3](y))^2-z)^(1/5)
CALC_YZ	MACRO	yoff,zoff
	lea	bx,y				;address y
	fld	dword ptr [bx]			;y->st
	LOG3					;st=log[3]y
	fld	st				;st=st(1)
	fmulp					;st=log[3]y^2
	lea	bx,z				;address z
	fsub	dword ptr [bx]			;st=log[3]y^2-z
;возведем в степень 1/5
	fld1					;1
	fdiv	c5				;1/5
	fxch					;st(1)<->st
	fyl2x					;st=st(1)*log[2]st
	POWER					;находим (log[3](y)^2-z)^(1/5)
	ENDM	

	.code
start:
	mov	ax, @data
	mov	ds, ax				;настроим сегментные регистры
	mov	es, ax				;на сегмент @data
	mov	ss, ax
	mov	sp, 0fffeh			;стек в вершине
						;введем данные
x_loop:
	lea	si, sEnterX			;строка приглашения
	call	GetFloat			;вводим вещественное, результат в st
	jc	x_loop				;С=1 - ошибка формата! На повтор ввода!
	fstp	x				;сохраним в x
y_loop:
	lea	si, sEnterY
	call	GetFloat
	jc	y_loop
	fstp	y				;y
z_loop:
	lea	si, sEnterZ
	call	GetFloat
	jc	z_loop
	fstp	z				;z

	call	calc_a				;получаем в st расчет a
	fst	a				;сохраним в a и оставим в st(0)
	push	offset sNum			;адрес буфера для числовой строки
	call	float2str			;преобразовываем вещественное число из st(0)
	lea	si, sA				;строка пояснения 'a='
	lea	bx, sNum			;числовая строка
	call	prStr				;выводим две строки [si]+[bx]

	call	calc_b				;получаем в st расчет b
	fst	b				;сохраним в b и оставим в st(0)
	push	offset sNum			;адрес буфера для числовой строки
	call	float2str			;преобразовываем вещественное число из st(0)
	lea	si, sB				;строка пояснения 'b='
	lea	bx, sNum			;числовая строка
	call	prStr				;выводим две строки [si]+[bx]

	lea	si, sAny			;Press any key
	call	prsz				;выводим строку из si

	mov	ah, 0				;ждем any key
	int	16h

	mov	ax,4c00h
	int	21h				;выход в ДОС

GetFloat	proc				;ввод вещественного числа
	call	prsz				;выводим приглашение из si
	lea	dx, sBuf
	mov	ah, 0ah
	int	21h				;вводим строку
	lea	ax, string			;адрес строки
	push	ax				;параметр в стек
	call	str2float			;преобразовываем в вещественное
	ret					;число в st(0)
GetFloat	endp

prsz	proc					;вывод стоки ASCIIZ [si]
	lodsb
	cmp	al, 0
	je	prret
	int	29h
	jmp	prsz
prret:
	ret
prsz	endp

prStr	proc	near				;вывод двух строк ASCIIZ
	call	prsz				;первая [si]
	mov	si, bx
	call	prsz				;вторая [bx]
	ret
prStr	endp

;расчет a
;результат в st
calc_a	proc
	fld	x				;st = x
	fmul	c3				;st = 3*x
	fcos					;st = cos(3x)
	fld	st				;st(1) = st
	fmulp					;st = cos(3x)^2
	fmul	c008				;st = 0.08*cos(3x)^2
	fld	z				;st = z
	EXP					;st = e^z
	fsubp	st(1),st			;st = 0.08*cos(3x)^2 - e^z
	CALC_YZ					;st = (log[3](y)^2 - z)^(1/5)
	fld	z				;st = z
	fmul	C7				;st = 7z
	faddp					;st = (log[3](y)^2 - z)^(1/5) + 7z
	fdivp					;st = (0.08*cos(3x)^2 - e^z)/
	ret					;     ((log[3](y)^2 - z)^(1/5) + 7z)
calc_a	endp

;расчет b
;результат в st
calc_b	proc
	CALC_YZ					;st = (log[3](y)^2 - z)^(1/5)
	fld	y				;st = y
	fmul	C5				;st = 5y
	fsubp					;st = (log[3](y)^2 - z)^(1/5) - 5y
	fadd	C00006				;st = (log[3](y)^2 - z)^(1/5) - 5y + 0.00006
	ret
calc_b	endp

;-----------------------------------------
;П/п конвертации float <-> ASCII
;-----------------------------------------

;преобразование вещественного числа-строки во float
;если строка некорректна, то возвращается C=1
str2float	proc	uses si di, numstr:word
local	numfloat:dword, c10num:word, nextnum:word, order:word

;будем накапивать число в регистре сопроцессора, начинаем с нуля
	fldz
;будем умножать/делить на 10
	mov	c10num, 10
;порядок = 0
	mov	order, 0
;dl=0/1 - положительное/отрицательное число, dh=1 - знак задан
	xor	dx, dx
;cl=0/1 - целая/дробная часть, ch=1 - точка задана
	xor	cx, cx
;bl=0/1 - положительная/отрицательная степень после Е, bh=1 - степень задана
	xor	bx, bx
;адрес строки
	mov	si, numstr
sym_loop:
	xor	ax, ax
	lodsb
	cmp	al, 0dh
	je	set_order	;строка кончилась
	cmp	al, 0
	je	set_order	;строка кончилась
	cmp	al, '+'
	je	plus_sign	;+
	cmp	al, '-'
	je	minus_sign	;-
	cmp	al, '.'
	je	point_sign	;.
	cmp	al, 'e'
	je	order_sign	;e
	cmp	al, 'E'
	je	order_sign	;E
	cmp	al, '0'
	jb	num_err		;ошибка - не цифра
	cmp	al, '9'
	ja	num_err
	sub	al, '0'		;'0'-'9' -> 0-9
	mov	nextnum, ax	;сохраним слово в памяти
	mov	dh, 1		;после цифры задавать знак числа нельзя!
	cmp	bh, 0		;вводим порядок?
	jne	num_order
				;нет, вводим мантиссу
	jcxz	part_integer	;точки еще не было - целая часть числа
part_broken:			;дробная часть
	fld	numfloat	;вес цифры: 0.1, 0.001, 0.0001,...
	fimul	nextnum	 	;умножаем на цифру
	faddp			;и добавляем до числа
	fld	numfloat	;формируем вес следующей цифры
	fidiv	c10num
	fstp	numfloat
	jmp	sym_loop
num_order:			;вводим порядок
	mov	ax, 10		;вводим до конца строки двоичное число
	mul	order
	add	ax, nextnum
	mov	order, ax
	jmp	sym_loop

num_err:			;ошибка (любая)
	fstp	numfloat	;уберем из сопроцессора число
	stc			;признак ошибки
	jmp	str2float_ret	;на общий выход (чтобы подправить стек)

part_integer:			;целая часть
	fimul	c10num		;умножаем на 10
	fiadd	nextnum		;и добавляем цифру
	jmp	sym_loop

plus_sign:			;+
	cmp	bh, 0		;вводим порядок?
	jne	plus_order	
				;нет, вводим мантиссу
	cmp	dh, 0		;проверим на повтор
	jne	num_err		;знак задан! Ошибка! 
	mov	edx, 0100h	;помечаем, что знак задан и остался +
	jmp	sym_loop
plus_order:			;знак в порядке
	cmp	bh, 2		;задан?
	je	num_err		;повтор! Ошибка!
	mov	bx, 0200h	;помечаем, что знак задан и остался +
	jmp	sym_loop

minus_sign:			;-
	cmp	bh, 0		;вводим порядок?
	jne	minus_order	
	cmp	dh, 0		;проверим на повтор
	jne	num_err
	mov	edx, 0101h	;помечаем, что знак задан и стал -
	jmp	sym_loop
minus_order:
	cmp	bh, 2		;задан?
	je	num_err
	mov	bx, 0201h	;помечаем, что знак задан и он -
	jmp	sym_loop

point_sign:			;.
	cmp	bh, 0
	jne	num_err		;точка в порядке запрещена
	cmp	ch, 0		;проверим на повтор
	jne	num_err
	mov	ecx, 0101h	;помечаем, что точка задана
	fld1
	fidiv	c10num		;1/10
	fstp	numfloat	;зададим вес первой дробной цифры (0.1)
	jmp	sym_loop

order_sign:			;символ порядка (e или E)
	ftst			;проверим  на 0
	fstsw	ax		;флаги в ax
	sahf			;флаги в регистре флагов
	jz	num_err		;при задании порядка должна быть ненулевая мантисса
	cmp	bh, 0
	jne	num_err		;и только раз задано e(E)
	mov	bh, 1		;помечаем, что задан порядок
	jmp	sym_loop

set_order:			;строка обработана, учтем порядок
	cmp	bh, 0		;порядок есть?
	je	set_sign	;нет - на установку знака
	mov	cx, order	;порядок
	jcxz	set_sign	;порядок = 0 - ничего менять не надо
	cmp	bl, 0		;+ или -
	je	positive_loop
negative_loop:			;-
	fidiv	c10num		;делим cx раз на 10
	loop	negative_loop		
	jmp	set_sign
positive_loop:			;+
	fimul	c10num		;умножаем cx раз на 10
	loop	positive_loop		
set_sign:			;учтем знак
	cmp	dl, 0		;+ или -
	je	str2float_ok	;+ выходим
	fchs			;меняем на -
str2float_ok:
	clc			;все ок
str2float_ret:
	ret
	endp

;преобразование float из sp в строку по адресу pStr
float2str	proc uses di, pStr:word
local	dig:word, c10:word
	
	mov	c10, 10		;будем делить на 10
	mov	di, pStr	;здесь будем формировать строку
	ftst			;Проверяем число
	fstsw	ax		;флаги в ax
	sahf			;флаги в регистре флагов
	jnz	float2str_notZero	;не 0
	mov	ax, '0' 	;если 0, то рисуем 0 и выводим
	stosw
	jmp	float2str_Ret 	;на выход

float2str_notZero:		;не 0
	jnc	f2s_1		;проверим знак
	mov	al, '-' 	;для отрицательного выведем знак минус
	stosb
	fchs			;и меняем знак числа.

; Пояснение далее пойдёт на примере.	; ST(0) ST(1) ST(2) ST(3) ...
; Отделим целую часть от дробной.	; 73.25 ... что-то не наше
f2s_1:
	fld1				;  1	 73.25 ...
	fld	st(1)			; 73.25  1	 73.25 ...
; Остаток от деления на единицу даст дробную часть.
	fprem				;  0.25  1	 73.25 ...
; Если вычесть её из исходного числа, получится целая часть.
	fsub	st(2), st 		;  0.25  1	 73	 ...
	fxch	st(2)			; 73	 1	  0.25 ...
; Сначала поработаем с целой частью. Считать количество цифр будем в CX.
	xor	cx, cx
; Поделим целую часть на десять,
f2s_2:	fidiv	c10			;  7.3	 1     0.25 ...
	fxch	st(1)			;  1     7.3   0.25 ...
	fld	st(1)			;  7.3   1     7.3  0.25 ...
; отделим дробную часть - очередную справа цифру целой части исходного числа,-
	fprem				;  0.3   1     7.3  0.25 ...
; от частного оставим только целую часть
	fsub	st(2), st 		;  0.3   1     7    0.25 ...
; и сохраним цифру
	fimul	c10			;  3     1     7    0.25 ...
	fistp	dig			;  1     7     0.25 ...
; считаем цифры
	inc	cx
; сохраняем в стеке.
	push	dig
	fxch	st(1)			;  7     1     0.25 ...
; Так будем повторять, пока от целой части не останется ноль.
	ftst
	fstsw	ax
	sahf
	jnz	f2s_2
; Теперь выведем цифры целой части.
f2s_3:	pop	ax
; Вытаскиваем очередную цифру, переводим её в символ и выводим.
	add	al, 30h
	stosb
; И так, пока не выведем все цифры.
	loop	f2s_3			;  0     1     0.25 ...

; Итак, теперь возьмёмся за дробную часть, для начала проверив её существование.
	fstp	st(0)			;  1     0.25 ...
	fxch	st(1)			;  0.25  1    ...
	ftst
	fstsw	ax
	sahf
	jz	f2s_5			;дробной части нет - выходим
; Если она всё-таки ненулевая, выведем точку и 6 знаков после точки
	mov	al, '.'			;рисуем точку
	stosb
	mov	cx, 6			;6 знаков после запятой
; Помножим дробную часть на десять
f2s_4:	fimul	c10			;  2.5   1    ...
	fxch	st(1)			;  1     2.5  ...
	fld	st(1)			;  2.5   1     2.5  ...
; отделим целую часть - очередную слева цифру дробной части исходного числа,-
	fprem				;  0.5   1     2.5  ...
; оставим от произведения лишь дробную часть
	fsub	st(2), st 		;  0.5   1     2    ...
	fxch	st(2)			;  2     1     0.5  ...
; сохраним полученную цифру во временной ячейке
	fistp	dig			;  1     0.5  ...
; и сразу выведем.
	mov	ax, dig
	add	al, 30h
	stosb
; Теперь, если остаток дробной части ненулевой
	fxch	st(1)			;  0.5   1    ...
	ftst
	fstsw	ax
	sahf
; и мы вывели менее cx цифр, продолжим
	loopnz	f2s_4			;  0     1    ...
; Итак, число выведено. Осталось убрать мусор из стека.
f2s_5:	fstp	st(0)			;  1    ...
	fstp	st(0)			;  ...
	mov	byte ptr [di], 0	;закрываем строку
float2str_ret:
	ret
	endp

	.data
x	dd	0
y	dd	0
z	dd	0
a	dd	?
b	dd	?
;константы
c008	dd	0.08
c3	dd	3.
c0005	dd	0.005
c7	dd	7.
c5	dd	5.
c00006	dd	0.00006

sAny	db	0dh,0ah,'Press any key',0
sEnterX	db	0dh,0ah,'Enter x: ',0
sEnterY	db	0dh,0ah,'Enter y: ',0
sEnterZ	db	0dh,0ah,'Enter z: ',0
sA	db	0dh,0ah,'a = ',0
sB	db	0dh,0ah,'b = ',0
sBuf	db	32
cnt	db	?
string	db	32 dup (?)
sNum	db	32 dup (?)

	end	start

Консультировал: Лысков Игорь Витальевич (Старший модератор)
Дата отправки: 25.06.2012, 02:39

5
нет комментария
-----
Дата оценки: 25.06.2012, 08:24

Рейтинг ответа:

НЕ одобряю +1 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка  |  восстановить логин/пароль

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!



В избранное