Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > Низкоуровневое программирование > Assembler
Регистрация

Восстановить пароль
Повторная активизация e-mail

Ответ
 
Опции темы
Старый 12.06.2018, 21:38   #1
Fillimon
 
Регистрация: 16.04.2018
Сообщений: 9
Репутация: 10
По умолчанию Функции ввода/вывода вещ.чисел (помогите найти ошибку) TASM!

Всем привет, нашёл на одном из форумов как вводить и выводить вещественные числа, но почему-то не работает так, как надо, помогите понять причину. С виду процедуры правильные, но когда пытаюсь ввести число, и сразу его вывести, выводит какой-то бред, даже понять не могу что не так.
Выводит из st(0)
Код:

a dw 0 - вспомогательная переменная

outfloat proc
        push    ax
        push    cx
        push    dx
; Формируем кадр стэка, чтобы хранить в нём десятку
; и ещё какую-нибудь цифру.
        push    bp
        mov     bp, sp
        push    10
        push    0
; Проверяем число на знак, и если оно отрицательное,
        ftst
        fstsw a
		fwait
		mov ax,a
        sahf
        jnc     @of1
; то выводим минус
        mov     ah, 02h
        mov     dl, '-'
        int     21h
; и оставляем модуль числа.
        fchs
; Пояснение далее пойдёт на примере.   ; ST(0) ST(1) ST(2) ST(3) ...
; Отделим целую часть от дробной.      ; 73.25 ... что-то не наше
@of1:   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 ...
		fwait
; Сначала поработаем с целой частью. Считать количество цифр будем в CX.
        xor     cx, cx
; Поделим целую часть на десять,
@of2:   fidiv   word ptr [bp - 2]      ;  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   word ptr [bp - 2]      ;  3     1     7     0.25 ...
        fistp   word ptr [bp - 4]      ;  1     7     0.25 ...
		fwait
        inc     cx
; в стэке.
        push    word ptr [bp - 4]
        fxch    st(1)                  ;  7     1     0.25 ...
; Так будем повторять, пока от целой части не останется ноль.
        ftst
        fstsw a
		fwait
		mov ax,a
        sahf
        jnz     short @of2
; Теперь выведем её.
        mov     ah, 02h
@of3:   pop     dx
; Вытаскиваем очередную цифру, переводим её в символ и выводим.
        add     dl, 30h
        int     21h
; И так, пока не выведем все цифры.
        loop    @of3                   ;  0     1     0.25 ...
; Итак, теперь возьмёмся за дробную часть, для начала проверив её существование.
        fstp    st(0)                  ;  1     0.25 ...
        fxch    st(1)                  ;  0.25  1    ...
        ftst
        fstsw a
		fwait
		mov ax,a
        sahf
        jz      short @of5
; Если она всё-таки ненулевая, выведем точку
        mov     ah, 02h
        mov     dl, '.'
        int     21h
; и не более шести цифр дробной части.
        mov     cx, 6
; Помножим дрообную часть на десять,
@of4:   fimul   word ptr [bp - 2]      ;  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   word ptr [bp - 4]      ;  1     0.5  ...
		fwait
; и сразу выведем.
        mov     ah, 02h
        mov     dl, [bp - 4]
        add     dl, 30h
        int     21h
; Теперь, если остаток дробной части ненулевой
        fxch    st(1)                  ;  0.5   1    ...
        ftst
        fstsw a
		fwait
		mov ax,a
        sahf
; и мы вывели менее шести цифр, продолжим.
        loopnz  @of4                   ;  0     1    ...
; Итак, число выведено. Осталось убрать мусор из стэка.
@of5:   fstp    st(0)                  ;  1     ...
        fstp    st(0)                  ;  ...
		fwait
; Точнее, стэков.
        mov sp,bp
		pop bp
        pop     dx
        pop     cx
        pop     ax
        ret
outfloat endp

Fillimon вне форума   Ответить с цитированием
Старый 12.06.2018, 21:39   #2
Fillimon
 
Регистрация: 16.04.2018
Сообщений: 9
Репутация: 10
По умолчанию Функция считывания

Код:

 value_s2f   dw  0         ;переменая для функции преобразования строки в число
string  db  20, ?, 20 dup (0) - сода читаю
;+==============================================+
;|          ПЕРЕВОД ИЗ STRING В FLOAT           |
;+==============================================+
;| SI - указатель на строку                     |
;+----------------------------------------------+
;| ST(0) - преобрезованное число                |
;| cf=1 если в строке ошибка            |
;+==============================================+
STRTOFLOAT  PROC
    jmp     @STARTCONVERSATION_S2F  ; стартуем в рабочую область
@STARTCONVERSATION_S2F:
    mov     value_s2f, 0            ; обнуляем локальную переменную
    xor     bx, bx              ; очищаем указатель позиции
    cmp byte ptr [si], '-'      ; проверяем на отрицательность
    jne     @POSITIVE_S2F       ; число не отрицательное
    inc     bx                  ; число отрицательное, увеличиваем позицию
@POSITIVE_S2F:
    mov     value_s2f, 10       ; загружаем число в переменную
    fild        value_s2f           ; загружаем в стэк число 10
    fldz   	; загружаем в стэк число 0
	fwait
@REPEAT_BEFORE:
    mov     al, byte ptr si[bx]     ; получаем символ
    cmp al, byte ptr '.'            ; проверяем точка ли это
    je      @ISPOINTBEFORE  ; точка - идем дальше
    cmp al, byte ptr 13         ; проверяем конец ли строкиа
    je      @ENDASINT       ; уже конец и хватит искать дроби
    cmp al, '0'             ; если текущий символ не цифра
    jc  @END_S2F_ERR            ; то выход с ошибкой
    cmp     al,'9'
    ja  @END_S2F_ERR
    sub     al, 30h             ; делаем из CHAR - INT
    mov     byte ptr value_s2f, al  ; копируем в память
    fiadd   value_s2f           ; складываем из тем, что есть в стэке
    fmul    st(0), st(1)            ; умножаем на 10
	fwait
    inc     bx                  ; увеличиваем указатель
    jmp     @REPEAT_BEFORE  ; повторяем
@ISPOINTBEFORE:
    inc     bx                  ; увеличиваем указатель
    fdiv        st(0), st(1)            ; делим число на 10, т.к. оно уже больше
    fxch        st(1)               ; меняем местами регистры
	fwait
    mov     al, byte ptr 13         ; ищем символ конца строки
@FINDNEXT:
    cmp si[bx], al              ; ищем конец строки
    je      @FINDEND            ; нешел конец строки
    inc     bx                  ; получаем следующий адрес символа
    jmp     @FINDNEXT           ; не нашел, еще ищем
@FINDEND:
    dec     bx                  ; переходим на предыдущий символ
    fldz                            ; загружаем в стэк число 0
	fwait
@REPEAT_AFTER:
    mov     ax, word ptr si[bx]     ; получаем символ
    cmp al, byte ptr '.'            ; проверяем точка ли это
    je      @WASPOINTAFTER  ; точка - идем дальше
    cmp al, '0'         ; если текущий символ не цифра
    jc  @END_S2F_ERR            ; то выход с ошибкой
    cmp     al,'9'
    ja  @END_S2F_ERR
    sub     al, 30h             ; делаем из CHAR - INT
    mov     byte ptr value_s2f, al  ; копируем в память
    fiadd   value_s2f           ; складываем из тем, что есть в стэке
    fdiv        st(0), st(1)            ; делим на 10
	fwait
    dec     bx                  ; декрементируем указатель
    loop    @REPEAT_AFTER   ; повторяем
@WASPOINTAFTER:
    fxch        st(1)               ; меняем число 10 и остаток местами
    fxch        st(2)               ; меняем целое и 10 местами
    faddp   st(1)               ; складываем число до и после запятой
    fxch        st(1)               ; меняем местами результат и 10
    fistp       value_s2f           ; извлекаем из стэка 10
	fwait
    jmp     @FULLEND            ; полный конец процедуры
@ENDASINT:
    fdiv        st(0), st(1)            ; делим число на 10, т.к. оно уже больше
    fxch        st(1)               ; меняем местами регистры
    fistp       value_s2f           ; извлекаем из стэка 10
	fwait
@FULLEND:
    cmp byte ptr [si], '-'      ; проверяем на отрицательность
    jne     @END_S2F            ; число не отрицательное
    fchs                            ; число отрицательное, меняем знак
	fwait
@END_S2F:
    clc                     ;ошибки нет
    ret                         ; возврат из процедуры
 
@END_S2F_ERR:
    fistp value_s2f             ;очищаем st0
	fwait
    stc                 ;ошибка
    ret                         ; возврат из процедуры
STRTOFLOAT  ENDP

Вот как вызываю функции:
Код:

;string  db  20, ?, 20 dup (0) - сода читаю

mov ah,10
lea dx,string
int 21h
lea si,string
call STRTOFLOAT
lea dx,SecondString
mov ah,09h
int 21h
call outfloat

Fillimon вне форума   Ответить с цитированием
Старый 12.06.2018, 21:47   #3
Fillimon
 
Регистрация: 16.04.2018
Сообщений: 9
Репутация: 10
По умолчанию

Ошибку нашёл, извините за потраченное время! Функция преобразования строки в число работает с 3-го элемента, то есть надо было к si добавить 2 перед вызовом STRTOFLOAT
Fillimon вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Помогите найти ошибку в коде (TASM) Fillimon Помощь студентам 3 22.05.2018 23:07
Помогите, пожалуйста, найти ошибку в коде (найти сумму факториалов чётных чисел в заданном диапазоне) kris14 Паскаль 8 25.10.2017 16:42
[Очередь] Помогите найти ошибку...программа после компиляции и ввода значения не выдает ответ Калючка Паскаль 8 07.11.2016 17:57
Си++ Функции ввода-вывода с консоли Karina* Помощь студентам 0 27.04.2012 18:38
tasm, использование команд ввода/вывода. Доступ к портам iggor Assembler 1 17.06.2009 22:58


15:57.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru