Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема с вещественными числами, Срочно нужна помощь 
:(
    Опции темы
Molkov Alexandr
  Дата 3.6.2003, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.6.2003

Репутация: нет
Всего: нет



Приветствую знатоков!

Может быть у меня вопрос не в топик но дело в том, что я выполняю лабораторную работу на ассемблере с использованием вставки ассемблерного кода в функцию(процедуру) языка Turbo Pascal. В процедуру передаются параметры байты и переменная-результат, которая должна содержать итоги вычислений получается вещественного типа.

Пример: Procedure Do_ASM_Reshenie(a,b,c,i:byte; var Rez:Double);Assembler;

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

Так вот, проблема в том что я не могу вернуть в тело программы паскаля вещественное значение, т.е. присвоить языком ассемблера результат переменной Rez.

Помогите, пожайлуста, кто чем сможет, жду советов!

PM MAIL Jabber   Вверх
Chingachguk
Дата 3.6.2003, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1232
Регистрация: 25.3.2002
Где: Москва

Репутация: нет
Всего: 18



Вернуть double можно через @Result:

Цитата

Function Ret_Double:double;
var
  MyLocInteger: integer;
begin
  asm
  mov  MyLocInteger,666
  fild MyLocInteger
  fstp @Result
  end;
end;


Но зачем тебе double, когда можно и long ? ;)


--------------------
I don't like the drugs (but the drugs like me). M.Manson.
PM MAIL ICQ   Вверх
Molkov Alexandr
Дата 4.6.2003, 09:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.6.2003

Репутация: нет
Всего: нет



Прошу прощения!
Я забыл сказать, что это выполняется на ассемблере под процессор 80186, под DOS. Т.е. я хочу сказать, что никаких макрокоманд использовать нельзя, всё нужно делать простыми командами(mov,add,div). Сам я специально ассемблер не изучал, просто немного самостоятельно поковырял, команды и операторы запомнил и вот вояю! А о приведённых выше командах fild и fstp я ничего не знаю.

PS: А разве в Паскале сущестует тип Long (к тому же вещественный)? Насколько я знаю в Паскале есть только LongInt(Long Integer - Длинное ЦЕЛОЕ)!

Это сообщение отредактировал(а) Molkov Alexandr - 4.6.2003, 11:18
PM MAIL Jabber   Вверх
Chingachguk
Дата 4.6.2003, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1232
Регистрация: 25.3.2002
Где: Москва

Репутация: нет
Всего: 18



Написал две подпрограммы - как раз для случая без сопроцессора. fild и fstp -- это команды сопроцессора (смотри ключ $N+). Но в твоем случае все же лучше юзать long. real у Паскаля без сопроцессора - 6 байт:

Цитата

Function Ret_Real:real;
const
  MyLocVar: real = 666.00;
begin
  writeln('Start Real !');
  asm
  mov  ax,word ptr ds:MyLocVar
  mov  word ptr ss:@Result,ax
  mov  ax,word ptr ds:MyLocVar+2
  mov  word ptr ss:@Result+2,ax
  mov  ax,word ptr ds:MyLocVar+4
  mov  word ptr ss:@Result+4,ax
  end;
end;
Function Ret_Long:longint;
const
  MyLocVar: longint = 666;
begin
  writeln('Start Long !');
  asm
  mov  ax,word ptr ds:MyLocVar
  mov  word ptr ss:@Result,ax
  mov  ax,word ptr ds:MyLocVar+2
  mov  word ptr ss:@Result+2,ax
  end;
end;

begin
  {writeln(quantity(100,2));}
  writeln(Ret_Real);
  writeln(Ret_Long);
end.



--------------------
I don't like the drugs (but the drugs like me). M.Manson.
PM MAIL ICQ   Вверх
Molkov Alexandr
Дата 4.6.2003, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.6.2003

Репутация: нет
Всего: нет



OK! Большое спасибо!
И ещё один вопросик в догонку:
В книжке Питера Абеля вычитал пример о том как нужно складывать двойные слова(т.е. сначало младшие слова операндов, а потом старшие с учётом переноса). В моей программе вычисления идут подобным образом и в результате у меня получается в AX-старшее слово целой части результата, в DX-младшее слово целой части результата, а в BX - остаток от деления(либо всё это в стеке).
Так вот я, по своей наивности, думал, что последовательно их закину в переменную и всё будет хорошо. А в жизни всё оказывается гораздо сложнее sad.gif
Может быть есть какой-нибудь совет в этом направлении?
PM MAIL Jabber   Вверх
Chingachguk
Дата 5.6.2003, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1232
Регистрация: 25.3.2002
Где: Москва

Репутация: нет
Всего: 18



Разумеется, формат чисел real(double, float..etc) - чисел с плавающей точкой - отличается от формата целых чисел. Если целое число представляется как разложение числа по степеням двойки (для word степени от 0-ой до 15-ой, например), то вещественные числа представляются иначе: в общем случае они состоят из трех частей: знака (как правило - старший бит числа), экспоненты (для настоящих real-чисел из 4-х байт - смотри сопроцессор Intel - это один байт) и мантиссы. Грубо говоря, число в вещественном формате записывется также разложением по степеням двойки (коэффициенты и есть мантисса), но со степени, равной экспоненте:

Число=(-1)^(Знаковый_Бит) x ( 2^(Экспонента) x (Старший_Бит_Мантиссы) + 2^(Экспонента-1) x (Следующий_Бит_Мантиссы) + ... )

Для real-чисел экспонента вроде бы равна ((Биты 30..23) - 127).

Вообще об этом можно почитать у Зубкова С.В. в его книге по ассемблеру. Я недавно ее находил в интерненте. Очень полезная книга ;)

Все эти проблемы совершенно отсутствуют при программировании сопроцессора (на ассемблере):

Цитата

; Преобразование int(2 байта) в real (4 байта)

   MyInteger dw -35
   MyResultReal dd ?

   fild word ptr MyInteger ; Загрузить в сопроцессор короткий int
   fstp dword ptr MyResultReal ; Выгрузить в формате 4-х байтный Real


Цитата

; Преобразование int(4 байта) в double (8 байт)

   MyInteger dd -35
   MyResultDouble dq ?

   fild dword ptr MyInteger ; Загрузить в сопроцессор int
   fstp qword ptr MyResultDouble ; Выгрузить в формате 8-х байтный double


Т.е. я не вижу деталей формата и все работает ;)

Это сообщение отредактировал(а) Chingachguk - 5.6.2003, 09:18


--------------------
I don't like the drugs (but the drugs like me). M.Manson.
PM MAIL ICQ   Вверх
Molkov Alexandr
Дата 5.6.2003, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.6.2003

Репутация: нет
Всего: нет



А как можно к вещественному числу прибавить байт без использования команд сопроцессора?
Т.е. , например, A=0,5 и нужно А=А+AL?
PM MAIL Jabber   Вверх
Chingachguk
Дата 5.6.2003, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1232
Регистрация: 25.3.2002
Где: Москва

Репутация: нет
Всего: 18



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

Цитата

Program Test;
{$N-}
const
  a: real = 0.625;
  b: real = 0.375;
  c: real = 0.000;
begin
  c:=a+b;
  writeln©;
end.


Скомпиллируем ее на диск (COMPILE->Destination Memory->Destination Disk),
посмотрим исполнимый код (td.exe test.exe):

Цитата

{c:=a+b;}

{dx:bx:ax = a}
cs:00F0 A10C00        mov    ax,[000C]
cs:00F3 8B1E0E00      mov    bx,[000E]
cs:00F7 8B161000      mov    dx,[0010]

{di:si:cx = b}
cs:00FB 8B0E1200      mov    cx,[0012]
cs:00FF 8B361400      mov    si,[0014]
cs:0103 8B3E1600      mov    di,[0016]

{Сложить a и b, результат вернуть в dx:bx:ax}
cs:0107 9AD10B9167    call  6791:0BD1

{Заопомнить результат в c}
cs:010C A31800        mov    [0018],ax
cs:010F 891E1A00      mov    [001A],bx
cs:0113 89161C00      mov    [001C],dx

{writeln©;}

cs:0117 BF6E01        mov    di,016E
cs:011A 1E            push  ds
cs:011B 57            push  di
cs:011C FF361C00      push  word ptr [001C]
cs:0120 FF361A00      push  word ptr [001A]
cs:0124 FF361800      push  word ptr [0018]
cs:0128 B81100        mov    ax,0011
cs:012B 50            push  ax
cs:012C B8FFFF        mov    ax,FFFF
cs:012F 50            push  ax
cs:0130 9A8A079167    call  6791:078A


Ну а что делает подпрограмма сложения (6791:078A) ?
Зайдем в нее:

Цитата

{Код подпрограммы сложения двух чисел 6791:0BD1: точка входа}

cs:0BD1 E8ECFC    call  08C0
cs:0BD4 723B        jb    0C11
cs:0BD6 CB            retf


Вызывается еще одна подпрограмма. Зайдем и в нее:

Цитата

{Код сложения двух чисел}

cs:08C0 0AC9          or    cl,cl
cs:08C2 747B          je    093F
cs:08C4 0AC0          or    al,al
cs:08C6 7478          je    0940
cs:08C8 3AC1          cmp    al,cl
cs:08CA 7605          jbe    08D1
cs:08CC 91            xchg  cx,ax
cs:08CD 87DE          xchg  si,bx
cs:08CF 87D7          xchg  di,dx
cs:08D1 2AC1          sub    al,cl
cs:08D3 F6D8          neg    al
cs:08D5 3C29          cmp    al,29h
cs:08D7 7367          jnb    0940
cs:08D9 86C1          xchg  cl,al
cs:08DB 55            push  bp
cs:08DC 50            push  ax
cs:08DD 8AE6          mov    ah,dh
cs:08DF 80E480        and    ah,80h
cs:08E2 8BE8          mov    bp,ax
cs:08E4 33C7          xor    ax,di
cs:08E6 58            pop    ax
cs:08E7 9C            pushf
cs:08E8 B000          mov    al,00
cs:08EA 80CE80        or    dh,80h
cs:08ED 81CF0080      or    di,8000h
cs:08F1 80F908        cmp    cl,08
cs:08F4 7211          jb    0907
cs:08F6 8AC4          mov    al,ah
cs:08F8 8AE3          mov    ah,bl
cs:08FA 8ADF          mov    bl,bh
cs:08FC 8AFA          mov    bh,dl
cs:08FE 8AD6          mov    dl,dh
cs:0900 32F6          xor    dh,dh
cs:0902 80E908        sub    cl,08
cs:0905 EBEA          jmp    08F1
cs:0907 0AC9          or    cl,cl
cs:0909 740A          je    0915
cs:090B D1EA          shr    dx,1
cs:090D D1DB          rcr    bx,1
cs:090F D1D8          rcr    ax,1
cs:0911 FEC9          dec    cl
cs:0913 75F6          jne    090B
cs:0915 9D            popf
cs:0916 7837          js    094F
cs:0918 03C1          add    ax,cx
cs:091A 13DE          adc    bx,si
cs:091C 13D7          adc    dx,di
cs:091E 8BCD          mov    cx,bp
cs:0920 5D            pop    bp
cs:0921 730A          jnb    092D
cs:0923 D1DA          rcr    dx,1
cs:0925 D1DB          rcr    bx,1
cs:0927 D1D8          rcr    ax,1
cs:0929 FEC1          inc    cl
cs:092B 7420          je    094D
cs:092D 058000        add    ax,0080h
cs:0930 83D300        adc    bx,0000
cs:0933 83D200        adc    dx,0000
cs:0936 720F          jb    0947
cs:0938 8AC1          mov    al,cl
cs:093A 80E67F        and    dh,7Fh
cs:093D 0AF5          or    dh,ch
cs:093F C3            ret
cs:0940 8BC1          mov    ax,cx
cs:0942 8BDE          mov    bx,si
cs:0944 8BD7          mov    dx,di
cs:0946 C3            ret
cs:0947 D1DA          rcr    dx,1
cs:0949 FEC1          inc    cl
cs:094B 75EB          jne    0938
cs:094D F9            stc
cs:094E C3            ret
cs:094F 2BC1          sub    ax,cx
cs:0951 1BDE          sbb    bx,si
cs:0953 1BD7          sbb    dx,di
cs:0955 8BCD          mov    cx,bp
cs:0957 5D            pop    bp
cs:0958 7310          jnb    096A
cs:095A F7D2          not    dx
cs:095C F7D3          not    bx
cs:095E F7D8          neg    ax
cs:0960 F5            cmc
cs:0961 83D300        adc    bx,0000
cs:0964 83D200        adc    dx,0000
cs:0967 80F580        xor    ch,80h
cs:096A 8BFA          mov    di,dx
...


Немного сложновато, ты не находишь ? ;)

Варианты:

- Сделай лучше сам;
- Позови подпрограмму Паскаля для сложения;
- Используй целые числа в программе - нафига тебе real confused.gif


--------------------
I don't like the drugs (but the drugs like me). M.Manson.
PM MAIL ICQ   Вверх
Molkov Alexandr
Дата 6.6.2003, 09:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.6.2003

Репутация: нет
Всего: нет



Ну и ну!

Вызвать подпрограмму Паскаля я не могу, т.к. по условию задачи нужно в программе реализовать вычисления в двух процедурах(функциях): одна на Паскале, другая на Ассемблере, и, в результате, сравнив ответы этих процедур дать себе оценку(если результаты равны - значит молодец и всё правильно сделал, а если нет - иди изучай Ассемблер). Вот я пока и изучаю! sad.gif
Насчёт использования челых чисел в программе:
по условию нужно просчитать сумму ((a+1/b)*c*i) для i от 1 до 4, где a,b,c,i определить как переменные типа байт, а результат - исходя из задания. (см. мой аватар)
В связи с тем, что в условии используется деление(1/b), то соответственно результат не может быть целым числом!

Это сообщение отредактировал(а) Molkov Alexandr - 6.6.2003, 10:04
PM MAIL Jabber   Вверх
Chingachguk
Дата 6.6.2003, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1232
Регистрация: 25.3.2002
Где: Москва

Репутация: нет
Всего: 18



1. Если ты делаешь вычисление 1/b, говоришь при этом, что сопроцессор использовать нельзя, то как ты это делаешь ? Через целочисленное деление ? ( div или idiv ) Если так, то через одну операцию деления тебе не получить вещественное число, ибо целочисленное деление возвращает в одном регистре (ax,al...) целое от деления, а в другом - остаток, те:

Делим 27 на 5:

mov ax,27
mov bl,5
div bl

В результате al=5, ah=2. А не 27/5=5.4

2. Если ты все же делаешь деление вручную, т.е. например реализуя что-то вроде алгоритма деления в столбик, т.е.:

Цитата

{$N-}
procedure Display_RealStr(a,b:byte);
  const
    StrSize = 4;
  var
    RealStr: string[1+StrSize];
  begin
    asm
      {Работаем с строками в Паскале}
      lea  bx,RealStr
      {Первый байт - счетчик символов в строке, сначала пустая строка}
      mov  byte ptr ss:[bx],0
      {Индекс символов в строке}
      mov  di,1
      {ax=делимое}
      mov  al,a
      {si=0/1 - флаг вывода десятичной точки}
      mov  si,0
@@GetRealStr:
      {Делим al на b}
      mov  ah,0
      div  byte ptr b
      {Запоминаем остаток в ch}
      mov  ch,ah
      {Целое может быть больше 10: 10,11..255}
      {Поэтому преобразуем его в число в формате NNN}
      {Делим целое на 100,10,1:}
      mov  cl,100
      {dl=0/1 - флаг вывода ненулевого коэффициента}
      mov  dl,0
@@GetNNNFormat:
      mov  ah,0
      div  cl
      {Если коэффициент разложения целого по степеням 10-ти не равен нулю}
      cmp  al,0
      {То помещаем число в строку}
      jnz  @@PutToStr
      {Если получаем коэффицинт при единице, то выводим в любом случае}
      cmp  cl,1
      jz  @@PutToStr
      cmp  dl,1
      jz  @@PutToStr
      {Иначе ничего не выводим в строку}
      jmp  @@SkipPutToStr
@@PutToStr:
      {Преобразуем число к ASCII-коду, 3->"3"}
      add  al,'0'
      {Увеличваем счетчик символов в строке}
      inc  byte ptr ss:[bx]
      mov  ss:[bx+di],al
      inc  di
      cmp  di,StrSize
      ja  @@StringDone
      mov  dl,1
@@SkipPutToStr:
      mov  al,ah
      mov  ah,0
      push ax
      mov  al,cl
      mov  cl,10
      div  cl
      mov  cl,al
      pop  ax
      cmp  cl,0
      ja  @@GetNNNFormat
      {После первого деления выводим десятичную точку}
      cmp  si,0
      jnz  @@SkipDecPoint
      inc  si
      inc  byte ptr ss:[bx]
      mov  byte ptr ss:[bx+di],'.'
      inc  di
      cmp  di,StrSize
      ja  @@StringDone
@@SkipDecPoint:
      {Умножаем остаток на 10 для дальнейшего деления}
      mov  al,ch
      mov  ah,10
      mul  ah
      jmp  @@GetRealStr
@@StringDone:
    end;
    writeln(RealStr);
  end;
begin

  Display_RealStr(150,7);

end.


то тебе придется точно также для того, чтобы вернуть результат в виде вещественного real, разобраться в нем. Это не так уж и сложно: посмотри, что я писал про мантиссу и экспоненту. Ведь это всего лишь разложение по степеням двойки.


--------------------
I don't like the drugs (but the drugs like me). M.Manson.
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Asm: Общие вопросы"
MAKCim
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой КОД.
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, MAKCim.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Asm: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0492 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.