Консультация № 184029
15.09.2011, 15:56
80.00 руб.
0 8 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
Надеюсь последняя моя проблема с Ассемблером.

Данные задания уже были выполнены, как вставка в паскаль, но теперь те же программы должны быть реализована на языке ассемблера TASM.

1. Представить обыкновенную дробь как запись с полями «Числитель» и «Знаменатель» и реализовать арифметические операции с дробями. (Под записью подразумевается структура с упакованными данными)

2. Реализуйте подпрограмму, которая возвращает символы имеющиеся в данной строке с указанием числа вхождений каждого символа.

3. Дано натуральное число n. Вычислить: (1-1/2!)(1-1/3!)(1-1/4!)…(1-1/n!) (Все повторяющиеся фрагменты должны быть выполнены в виде макросов, вычисления проводятся до пятого знака после запятой)

Ссылки на прошлые ответы: первая, вторая

Благодарю.

Обсуждение

давно
Посетитель
7438
7205
15.09.2011, 18:23
общий
Сразу встречные вопросы:
1) Tasm 16-битный досовский или 32-битный под Wndows?
2) Если досовский, то можно ли использовать 32-битные регистры?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
15.09.2011, 19:04
общий
Про это ничего не сказано. Пусть будет 32-битный под Wndows.
давно
Посетитель
7438
7205
15.09.2011, 20:37
общий
Строка во второй задаче какая?
1) Как в С, заканчивается 0
2) Как в Паскале, первый байт - длина строки (< 256 символов)
3) Как в Делфи, первые 4 байт - длина строки
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
15.09.2011, 21:04
общий
Не принципиально. В условиях ничего про это не сказано, я огласил все условия.
давно
Посетитель
7438
7205
16.09.2011, 01:50
общий
это ответ
Здравствуйте, Посетитель - 380267!
1) Дроби

Сама программа 184029_1.asm
[code h=207]
.386
.model flat,STDCALL

o equ offset
d equ dword ptr
STD_INPUT_HANDLE equ (-10)
STD_OUTPUT_HANDLE equ (-11)
NULL equ 0

;дробь - запись из двух полей: числитель (x) и знаменатель(y)
fraction struct
x dd ?
y dd ?
fraction ends

extrn wsprintfA:PROC
extrn AllocConsole:PROC
extrn GetStdHandle:PROC
extrn lstrlen:PROC
extrn WriteConsoleA:PROC
extrn ReadConsoleA:PROC
extrn GetLastError:PROC
extrn ExitProcess:PROC

.code

;ввод строки с консоли
;используется только для ожидания нажатия на Enter
StdIn proc lpszText:DWORD, dwLen:DWORD
LOCAL bRead :DWORD
call GetStdHandle,STD_INPUT_HANDLE
lea ecx, bRead
call ReadConsoleA, eax, lpszText, dwLen, ecx, 0
ret
StdIn endp

;вывод строки на консоль
StdOut proc lpszText:DWORD
LOCAL hOutPut :DWORD
LOCAL bWritten :DWORD

call GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut, eax

call lstrlen, lpszText ;EAX = длина строки
lea ecx, bWritten ;ECX = адресу переменной, куда запишется длина
; реально выведенного сообщения
call WriteConsoleA,hOutPut,lpszText,eax,ecx,NULL
mov eax, bWritten ;вернем длину
ret
StdOut endp

;функция вычисления наибольшего общего делителя чисел A и B
;числа A в EAX и B в EDX, результат НОД в EAX
GCD proc
push ecx ;сохраним регистр ECX
mov ecx,edx ;число В в регистре EDX, при делении
; будет портиться, пусть будет в ECX
test eax,eax ;возьмем модуль обоих чисел
jns @test_neg_B
neg eax
@test_neg_B:
test ecx, ecx
jns @GCD_continue
neg ecx
@GCD_continue: ;цикл расчета НОД-а
test eax,eax ;пока одно из чисел не станет равным 0
jz @GCD_ret
jcxz @GCD_ret
cmp eax,ecx ;будем искать остаток от деления большего на меньшее
jb @GCD_A_lt_B ;A < B
;A >= B
xor edx,edx ;числа положительные, можно смело обнулять
div ecx ;A / B
mov eax,edx ;EAX = A = A mod B, ECX = B
jmp @GCD_continue
@GCD_A_lt_B: ;A < B
xchg eax,ecx ;EAX = B, ECX = A
xor edx,edx
div ecx ;B / A
mov eax,edx ;EAX = B mod A
xchg eax,ecx ;ECX = B mod A, EAX = A
jmp @GCD_continue
@GCD_ret:
add eax,ecx ;EAX = A + B, или то, или другое,
;т.к. второе будет равно 0}
pop ecx
ret
GCD endp

;процедура деления дроби на НОД
;EAX - НОД, EBX - знаменатель, EDI - числитель, ECX - адрес дроби-результата}

Cut_f proc
XCHG EAX,EBX ;EAX = знаменатель, EBX = НОД
CDQ ;знаковое расширение до DX:AX
IDIV EBX ;EAX = знаменатель / НОД
XCHG EAX,EDI ;EAX = числитель, EDI = знаменатель / НОД
CDQ ;знаковое расширение до DX:AX
IDIV EBX ;EAX = числитель / НОД
;пусть отрицательное число будет только в числителе
TEST EDI,EDI ;знак знаменателя
jns @SET_NUMS
NEG EAX ;умножим на -1
NEG EDI
@SET_NUMS: ;сохраним результат
MOV [ECX].x,EAX
MOV [ECX].y,EDI
ret
Cut_f endp

;процедура складывания двух дробей
;параметры: EAX и EDX - адреса складаемых, ECX - результата
;правило вычисления для x1/y1 + x2/y2
;(первая строка - числитель, вторая - знаменатель):
;(x1*y2+x2*y1) div GCD(x1*y2+x2*y1, y1*y2)
;(y1*y2) div GCD(x1*y2+x2*y1, y1*y2)
Add_f proc
PUSH EBX ;сохраним регистры
PUSH ESI
PUSH EDI

MOV ESI,EAX ;адрес первой дроби
MOV EDI,EDX ;второй

MOV EAX,[ESI].y
IMUL [EDI].y
MOV EBX,EAX ;EBX = y1*y2}

MOV EAX,[ESI].x
IMUL [EDI].y
XCHG EAX,EDI ;EDI = x1*y2, EAX = адресу второй дроби
MOV EAX,[EAX].x
MUL [ESI].y
ADD EDI,EAX ;EDI = x1*y2 + x2*y1

MOV EAX,EDI ;числитель
MOV EDX,EBX ;знаменатель
call GCD ;EAX = НОД

call Cut_f ;делим на НОД и сохраняем

POP EDI
POP ESI
POP EBX
ret
Add_f endp

;процедура вычитания двух дробей
;параметры: EAX - адрес уменьшаемого, EDX - вычитаемого и ECX - результата
;правило вычисления для x1/y1 - x2/y2
;(первая строка - числитель, вторая - знаменатель):
;(x1*y2-x2*y1) div GCD(x1*y2-x2*y1, y1*y2)
;(y1*y2) div GCD(x1*y2-x2*y1, y1*y2)
Sub_f proc
PUSH EBX
PUSH ESI
PUSH EDI

MOV ESI,EAX
MOV EDI,EDX

MOV EAX,[ESI].y
IMUL [EDI].y
MOV EBX,EAX

MOV EAX,[ESI].x
IMUL [EDI].y
XCHG EAX,EDI
MOV EAX,[EAX].x
IMUL [ESI].y
SUB EDI,EAX ;аналогично сумме, отличие только здесь!

MOV EAX,EDI
MOV EDX,EBX
call GCD

call Cut_f

POP EDI
POP ESI
POP EBX
ret
Sub_f endp

;процедура умножения двух дробей
;параметры: EAX, EDX - адреса множителей и ECX - результата}
;правило вычисления для x1/y1 * x2/y2
;(первая строка - числитель, вторая - знаменатель):
;(x1*x2) div GCD(x1*x2, y1*y2)
;(y1*y2) div GCD(x1*x2, y1*y2)
Mul_f proc
PUSH EBX
PUSH ESI
PUSH EDI

MOV ESI,EAX
MOV EDI,EDX

MOV EAX,[ESI].y
IMUL [EDI].y
MOV EBX,EAX ;EBX = y1*y2
MOV EAX,[ESI].x
IMUL [EDI].x
MOV EDI,EAX ;EAX = EDI = x1*x2

MOV EDX, EBX ;второй множитель, первый уже в EAX
call GCD ;НОД

call Cut_f ;делим на НОД и сохраняем

POP EDI
POP ESI
POP EBX
ret
Mul_f endp

;процедура деления двух дробей
;параметры: EAX - адрес делимого, EDX - делителя и ECX - результата
;правило вычисления для x1/y1 * x2/y2
;(первая строка - числитель, вторая - знаменатель):
;(x1*y2) div GCD(x1*y2, y1*x2)
;(y1*x2) div GCD(x1*y2, y1*x2)
Div_f proc
PUSH EBX
PUSH ESI
PUSH EDI

MOV ESI,EAX
MOV EDI,EDX

MOV EAX,[ESI].y
IMUL [EDI].x
MOV EBX,EAX ;EBX = y1*x2
MOV EAX,[ESI].x
IMUL [EDI].y
MOV EDI,EAX ;EDI = x1*y2

MOV EDX,EBX ;делитель, делимое уже в EAX

call GCD ;НОД

call Cut_f ;делим на НОД и сохраняем

POP EDI
POP ESI
POP EBX
ret
Div_f endp

;вывод сообщения
;параметры: три дроби и знак операции
print proc fr1:dword,fr2:dword,fr3:dword,oper:dword
mov eax,fr1
mov edx,fr2
mov ecx,fr3
call wsprintfA C,o buffer,o format,\
d[eax].x,d[eax].y,oper,d[edx].x,d[edx].y,d[ecx].x,d[ecx].y

call StdOut, o buffer
ret
print endp

start:
call AllocConsole ;создадим консоль
test ax, ax
jz exit ;если ошибка, то просто выйдем

mov f1.x,3 ;проинициируем исходные дроби 3/4 и -9/16
mov f1.y,4
mov f2.x,-9
mov f2.y,16

;деление
lea eax,f1 ;делимое
lea edx,f2 ;делитель
lea ecx,f3 ;частное
call Div_f
call print,o f1,o f2,o f3,'/';выведем результат

;умножение
lea eax, f1
lea edx, f2
lea ecx, f3
call Mul_f
call print,o f1,o f2,o f3,'*'

;сумма
lea eax, f1
lea edx, f2
lea ecx, f3
call Add_f
call print,o f1,o f2,o f3,'+'

;разность
lea eax, f1
lea edx, f2
lea ecx, f3
call Sub_f
call print,o f1,o f2,o f3,'-'

;подождем ввода чего-либо или просто нажатия на Enter,
;чтобы не консоль не сразу закрылась
call StdIn,o buffer,256
exit:
call ExitProcess STDCALL, 0

.data
;формат для вывода сообщения
format db '%d/%d %c %d/%d = %d/%d',0dh,0ah,0
;дроби
f1 fraction <>
f2 fraction <>
f3 fraction <>
;буфер
buffer db 256 dup (?)
end start
[/code]

Файл 184029_1.def, в котором, в частности, задаем импорт функции wsprintfA из User32.dll
[code h=207]NAME 184029_1

DESCRIPTION 'Assembly Win32 Program'

CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE

EXETYPE WINDOWS

HEAPSIZE 65536
STACKSIZE 65536

IMPORTS USER32.wsprintfA

[/code]

Для создания EXE удобно пользоваться утилитой MAKE.EXE, которая вызывает все нужные команды

Makefile.mak
[code h=207]# Make file for Turbo Assembler 184029_1.

# make -B Will build the release version of 184029_1.exe
# make -B -DDEBUG Will build the debug version of 184029_1.exe


MAKEDIR = c:\TASM\BIN
NAME = 184029_1
OBJS = $(NAME).obj
DEF = $(NAME).def

!if $d(DEBUG)
TASMDEBUG=/zi
LINKDEBUG=/v
!else
TASMDEBUG=
LINKDEBUG=
!endif

!if $d(MAKEDIR)
IMPORT=$(MAKEDIR)\..\lib\import32
THEINCLUDE=/i$(MAKEDIR)\..\include
!else
IMPORT=..\..\..\lib\import32
THEINCLUDE=
!endif

$(NAME).EXE: $(OBJS) $(DEF)
$(MAKEDIR)\tlink32 /c /m /s /M /aa /Tpe $(LINKDEBUG) $(OBJS),$(NAME),$(NAME),$(IMPORT),$(DEF)

.asm.obj:
$(MAKEDIR)\tasm32 $(TASMDEBUG) /ml $(THEINCLUDE) $&.asm,,$&
[/code]

Ну и, наконец, вызываем этот самый MAKE.EXE с помощью вот такого BAT-файла:
Код:
@c:\TASM\BIN\make -b %1

----------------------------------------------------------------------------------------------------------
2) Строки
Программа работает со строками формата языка С, т.е. заканчивающимися нулем
Программа предполагает, что длина строки не больше 254 байт,
поэтому и счетчики разных букв состоят из одного байта

184029_2.asm
[code h=207]
.386
.model flat,STDCALL

o equ offset
d equ dword ptr
STD_INPUT_HANDLE equ (-10)
STD_OUTPUT_HANDLE equ (-11)
NULL equ 0

extrn wsprintfA:PROC
extrn AllocConsole:PROC
extrn GetStdHandle:PROC
extrn lstrlen:PROC
extrn WriteConsoleA:PROC
extrn ReadConsoleA:PROC
extrn ExitProcess:PROC

.code

;ввод строки с консоли
StdIn proc lpszText:DWORD, dwLen:DWORD
LOCAL bRead :DWORD
call GetStdHandle,STD_INPUT_HANDLE
lea ecx, bRead
call ReadConsoleA, eax, lpszText, dwLen, ecx, 0
ret
StdIn endp

;вывод строки на консоль
StdOut proc lpszText:DWORD
LOCAL hOutPut :DWORD
LOCAL bWritten :DWORD

call GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut, eax

call lstrlen, lpszText ;EAX = длина строки
lea ecx, bWritten ;ECX = адресу переменной, куда запишется длина
; реально выведенного сообщения
call WriteConsoleA,hOutPut,lpszText,eax,ecx,NULL
mov eax, bWritten ;вернем длину
ret
StdOut endp

;процедура формирует строку из разных символов и массив из количеств символов
CharsCount proc Src:dword,Dst:dword,Counts:dword
push edi ;сохраним регистры
push esi
push ebx
mov edx,Dst ;адрес буфера разных символов
mov esi,Src ;адрес исходной строки
mov edi,Counts ;адрес счетчиков
mov ecx,256 ;предполагаем,что там 256 байт
xor eax,eax ;0
rep stosb ;обнуляем
mov edi,Counts ;адрес счетчиков
@CalcCharsLoop: ;цикл по символам строки
lodsb ;очередной символ
cmp al,0dh
je @FormString
cmp al,0
je @FormString
inc byte ptr [edi+eax] ;считаем в массиве счетчиков
loop @CalcCharsLoop ;по всем символам
@FormString: ;формируем результат
xor ebx,ebx ;индекс для 256 значений счетчиков
xor esi,esi ;счетчик разных значений
mov ecx,256 ;счетчик в буфере
@FormStringLoop: ;цикл формирования результата
mov al,[edi+ebx] ;читаем счетчик
test al,al ;проверяем на 0
jz @FormStringNext;если 0,то обходим
mov [edx+esi],bl ;для ненулевого сохраняем индекс,как код символа
mov [edi+esi],al ;и количество,сохраняем с начала массива счетчиков
inc esi ;считаем разные значения
@FormStringNext: ;на следующий счетчик
inc ebx ;индекс следующего счетчика
loop @FormStringLoop ;по всем
mov eax,esi ;вернем длину строки разных символов
mov byte ptr [edx+esi],0;закроем строку нулем
pop ebx ;восстанавливаем регистры
pop esi
pop edi
ret
CharsCount endp

start:
call AllocConsole ;создадим консоль
test ax,ax
jz exit ;если ошибка,то просто выйдем

call StdOut,o sEnter ;пригласим ввести строку
call StdIn,o buffer,256 ;вводим строку длины максимум 256,
; в конце коды 0dh,0ah
;обработаем строку
call CharsCount,o buffer,o Tgt,o Cnt

;сформируем результат
call StdOut,o sTarget ;выведем 'Target ='
xor esi,esi ;индекс в массиве разных символов и количеств
PrCountsLoop: ;по разнам символам
mov al,Tgt[esi] ;очередной символ
cmp al,0 ;конец строки?
je finish
movsx ecx,Cnt[esi] ;считываем количество, 1 байт в dword
inc esi ;индекс следующего
;сформирум информацию о символе в виде "'sym':N," (символ 'sym' N раз)
call wsprintfA,o buffer,o frm_cd,eax,ecx
cmp byte ptr Tgt[esi],0 ;если последний
jne PrNum
call lstrlen,o buffer ;то последнюю запятую
mov dword ptr buffer[eax-1],0a0dh ;меняем на 0d0ah с нулем в конце
PrNum:
call StdOut,o buffer ;выводим
jmp PrCountsLoop ;на следующий
finish:
;подождем ввода чего-либо или просто нажатия на Enter,
;чтобы консоль не сразу закрылась
call StdIn,o buffer,256
exit:
call ExitProcess STDCALL,0

.data
sEnter db 'Enter string: ',0
sTarget db 'Target: ',0
sCounts db 0dh,0ah,'Counts = ',0
frm_cd db "'%c':%d,",0
;буфер
buffer db 256 dup (?) ;буфер для ввода, для формирования строк
Tgt db 256 dup (?) ;буфер для строки разных символов
Cnt db 256 dup (?) ;буфер для количеств разных символов

end start
[/code]

184029_2.def аналогичен
Код:
NAME	     184029_2

DESCRIPTION 'Assembly Win32 Program'

CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE

EXETYPE WINDOWS

HEAPSIZE 65536
STACKSIZE 65536

IMPORTS USER32.wsprintfA


Как и makefile.mak
[code h=207]# Make file for Turbo Assembler 184029_2.

# make -B Will build the release version of 184029_2.exe
# make -B -DDEBUG Will build the debug version of 184029_2.exe


MAKEDIR = c:\TASM\BIN
NAME = 184029_2
OBJS = $(NAME).obj
DEF = $(NAME).def

!if $d(DEBUG)
TASMDEBUG=/zi
LINKDEBUG=/v
!else
TASMDEBUG=
LINKDEBUG=
!endif

!if $d(MAKEDIR)
IMPORT=$(MAKEDIR)\..\lib\import32
THEINCLUDE=/i$(MAKEDIR)\..\include
!else
IMPORT=..\..\..\lib\import32
THEINCLUDE=
!endif

$(NAME).EXE: $(OBJS) $(DEF)
$(MAKEDIR)\tlink32 /c /m /s /M /aa /Tpe $(LINKDEBUG) $(OBJS),$(NAME),$(NAME),$(IMPORT),$(DEF)

.asm.obj:
$(MAKEDIR)\tasm32 $(TASMDEBUG) /ml $(THEINCLUDE) $&.asm,,$&
[/code]

184029_2.bat так, вообще, один в один
Код:
@c:\TASM\BIN\make -b %1

----------------------------------------------------------------------------------------------------------
3) с факториалом
184029_3.asm
[code h=207]
.386
.model flat,STDCALL

o equ offset
d equ dword ptr
STD_INPUT_HANDLE equ (-10)
STD_OUTPUT_HANDLE equ (-11)
NULL equ 0

extrn wsprintfA:PROC
extrn AllocConsole:PROC
extrn GetStdHandle:PROC
extrn lstrlen:PROC
extrn WriteConsoleA:PROC
extrn ReadConsoleA:PROC
extrn ExitProcess:PROC

.code

;ввод строки с консоли
StdIn proc lpszText:DWORD, dwLen:DWORD
LOCAL bRead :DWORD
call GetStdHandle,STD_INPUT_HANDLE
lea ecx, bRead
call ReadConsoleA, eax, lpszText, dwLen, ecx, 0
ret
StdIn endp

;вывод строки на консоль
StdOut proc lpszText:DWORD
LOCAL hOutPut :DWORD
LOCAL bWritten :DWORD

call GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut, eax

call lstrlen, lpszText ;EAX = длина строки
lea ecx, bWritten ;ECX = адресу переменной, куда запишется длина
; реально выведенного сообщения
call WriteConsoleA,hOutPut,lpszText,eax,ecx,NULL
mov eax, bWritten ;вернем длину
ret
StdOut endp

;процедура вычисляет требуемое выражение, EAX = n
;результат - в стеке сопроцессора
CalcValue proc
sub esp,4 ;здесь будет число 2...n
mov dword ptr [esp],2 ;начинаем с 2
finit ;инициализация сопроцессора
fld1 ;1, для накопления окончательного выражения
fld st ;1, для накопления факториала
@mainLoop: ;цикл расчета
cmp [esp],eax ;проверим, дошли ли до конца, EAX = n
ja @finish ;конец расчета
fimul dword ptr [esp] ;считаем факториал, умножая предыдущее значение на очередное
fld st ;посчитаем числитель, как i!-1
fld1 ;1
fsubp st(1),st ;числитель
fdiv st, st(1) ;получим (i!-1)/i!
fmulp st(2),st ;накапливаем произведения с потерей промежуточного частного
inc dword ptr [esp] ;на следующий член
jmp @mainLoop ;пока не дойдем до n
@finish: ;конец
fstp st ;уберем из стека сопроцессора n!, теперь st = посчитанной величине!
add esp,4 ;уберем двойное слово из стека процессора
ret
CalcValue endp

;Функция преобразования строки в число
;признаками конца являются ноль, код 0dh, а также пробел и табуляция
;все остальные, кроме цифр, недопустимы
;также ошибкой будет число большее максимального целого (2^32-1)
;параметр - адрес строки, результат в EAX
atoi proc string:dword
xor edi,edi ;наше число
mov esi,string ;числовая строка
GetNumLoop:
movzx ebx,byte ptr [esi] ;очередная цифра
inc esi
; проверим на разделители
cmp bl, 0dh
je num_end_found ;конец ввода
cmp bl, 0
je num_end_found
cmp bl, ' '
je num_end_found
cmp bl, 9
je num_end_found
cmp bl, '0' ;цифра?
jb set_c ;ошибка - не цифра!
cmp bl, '9'
ja set_c

and bl,0fh ;цифра -> число (30h-39h -> 0-9)
mov eax,10 ;умножим на 10
imul edi ;предыдущее значение
test edx,edx ;больше cлова - ошибка!
jnz set_c
add eax,ebx ;добавим сохраненный разряд
jc set_c ;больше слова - ошибка!
js set_c ;больше 2^31-1 - ошибка!
mov edi,eax ;сохраним
jmp GetNumLoop ;на анализ следующего символа

num_end_found: ;встретили признак конца
mov eax,edi ;результат в eax
clc ;все ок
ret
set_c:
stc ;ошибка
ret
atoi endp

start:
call AllocConsole ;создадим консоль
test ax,ax
jz exit ;если ошибка,то просто выйдем

Continue:
call StdOut,o sEnter ;пригласим ввести N
call StdIn,o buffer,256 ;вводим строку длины максимум 256,
; в конце коды 0dh,0ah
call atoi,o buffer ;EAX = введенному числу
jnc ToCmpValue ;нет ошибки - идем дальше
call StdOut,o sErrorNum ;вывод сообщение
jmp Continue ;и на повтор ввода
ToCmpValue: ;проверим на значение
cmp eax,2
jl ToErrorValue
cmp eax,1000
jle ToCalc
ToErrorValue:
call StdOut,o sErrorValue ;ждем число от 1 до 1000
jmp Continue
ToCalc:
call CalcValue ;выполняем задание, EAX = n
;чтобы вывести вещественное число
;сделаем такой трюк
fimul c100000 ;умножаем на 100000, чтобы 5 цифр после запятой
;оказались в целой части
fistp dqValue ;сохраним из сопроцессора, как 64-битное целое
mov eax, dword ptr dqValue ;dx:ax = целому
mov edx, dword ptr dqValue+4
div c100000 ;делим обратно на 100000
;EAX = целой части, EDX = дробной
;сформируем строку в виде <целая часть>.<дробная>
;(оказалось, что у wsprintf нет формата для вывода
;вещественного числа)
call wsprintfA,o buffer,o frm_value,eax,edx
call StdOut,o buffer ;выводим

;подождем ввода чего-либо или просто нажатия на Enter,
;чтобы консоль не сразу закрылась
call StdIn,o buffer,256
exit:
call ExitProcess STDCALL,0

.data
dqValue dq ?
c100000 dd 100000
sEnter db 'Enter N: ',0
sErrorNum db 'Incorrect number',0dh,0ah,0
sErrorValue db 'Number must be from 2 to 1000',0dh,0ah,0
frm_value db 'Value = %d.%5.5d',0dh,0ah,0
;буфер
buffer db 256 dup (?) ;буфер для ввода, для формирования строк

end start
[/code]
184029_3.def
Код:
NAME	     184029_3

DESCRIPTION 'Assembly Win32 Program'

CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE

EXETYPE WINDOWS

HEAPSIZE 65536
STACKSIZE 65536

IMPORTS USER32.wsprintfA


makefile.mak
[code h=207]# Make file for Turbo Assembler 184029_3.

# make -B Will build the release version of 184029_3.exe
# make -B -DDEBUG Will build the debug version of 184029_3.exe

MAKEDIR = c:\TASM\BIN
NAME = 184029_3
OBJS = $(NAME).obj
DEF = $(NAME).def

!if $d(DEBUG)
TASMDEBUG=/zi
LINKDEBUG=/v
!else
TASMDEBUG=
LINKDEBUG=
!endif

!if $d(MAKEDIR)
IMPORT=$(MAKEDIR)\..\lib\import32
THEINCLUDE=/i$(MAKEDIR)\..\include
!else
IMPORT=..\..\..\lib\import32
THEINCLUDE=
!endif

$(NAME).EXE: $(OBJS) $(DEF)
$(MAKEDIR)\tlink32 /c /m /s /M /aa /Tpe $(LINKDEBUG) $(OBJS),$(NAME),$(NAME),$(IMPORT),$(DEF)

.asm.obj:
$(MAKEDIR)\tasm32 $(TASMDEBUG) /ml $(THEINCLUDE) $&.asm,,$&
[/code]
184029_3.bat
Код:
@c:\liv\temp\SYS\LIV\TASM\BIN\make -b %1
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
31795
6196
16.09.2011, 10:43
общий
Цитата: 380267
Про это ничего не сказано. Пусть будет 32-битный под Wndows.

Какой у Вас компилятор есть?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
17.09.2011, 00:54
общий
Добавил программу для подсчета одинаковых букв в строке.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
17.09.2011, 10:38
общий
Добавил и третью...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа