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

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


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

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

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

Коцюрбенко Алексей aka Жерар
Статус: Профессор
Рейтинг: 2687
∙ повысить рейтинг »
Boriss
Статус: Академик
Рейтинг: 2636
∙ повысить рейтинг »
Абаянцев Юрий Леонидович aka Ayl
Статус: Профессионал
Рейтинг: 2137
∙ повысить рейтинг »

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

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

Консультация # 183961: Уважаемые эксперты! Пожалуйста, ответьте на вопрос: Нужно реализовать программы на Ассемблере (как вставка в Делфи): 1. Реализуйте с помощью логических симметричное отображение младшего байта слова на старший байт с потерей исходных значений. 2. Представить обыкновенную дробь как запись с полями «Числитель» и «...


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

Уважаемые эксперты! Пожалуйста, ответьте на вопрос:

Нужно реализовать программы на Ассемблере (как вставка в Делфи):
1. Реализуйте с помощью логических симметричное отображение младшего байта слова на старший байт с потерей исходных значений.
2. Представить обыкновенную дробь как запись с полями «Числитель» и «Знаменатель» и реализовать арифметические операции с дробями.

Помогите, пожалуйста. Желательно хотя бы с минимальным пояснением кода.
Спасибо.

Дата отправки: 04.09.2011, 23:45
Вопрос задал: Посетитель - 380267 (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


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

Здравствуйте, Посетитель - 380267!
1) Доведенное до логического конца ответ эксперта Кривенко Евгения Владимировича в вопросе№ 183949

Код :
{симметричное отображение младшего байта слова на старший байт}
{параметр - двойное слово в EAX, но используется только младшее слово}
{результат - в EAX (младший бит байта al стал старшим битом байта ah, и т.д.)}
function simm(x:integer): integer; assembler;
asm
  push   ecx     {сохраним регистр}
  mov    ecx,8  {число бит в байте}
 bit_loop:      {цикл по битам}
  ror al,1   {младший бит в старший}
  shl ax,1  {старший бит младшего байта в младший бит старшего байта}
  shr al,1   {вернем следующий бит на место}
  loop @bit_loop {по всем битам байта}
  pop ecx
end;


Вызов:
Код :
var
  i: integer;

begin
  i:=$1275;
  i:=simm(i);
end;

В результате получим i = 0ae00h

2) Дроби
Код :
{дробь - запись из двух полей: числитель (x) и знаменатель(y)}
type
 fraction = record
  x, y: integer;
end;

{нужно для Lazarus-а, для Delphi, скорее всего, нет}
{$ASMMODE intel}

{функция вычисления наибольшего общего делителя}
function GCD(A, B: integer): integer; assembler;
asm
  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
end;

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

procedure Cut_f(); assembler;
asm
  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].fraction.x, EAX
  MOV  [ECX].fraction.y, EDI
end;

{процедура складывания двух дробей}
{параметры - адреса складаемых и результата}
{правило вычисления для 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)}
procedure Add_f(var fr1, fr2, res:fraction);assembler;
asm
  PUSH EBX          {сохраним регистры}
  PUSH ESI
  PUSH EDI

  MOV  ESI, fr1     {адрес первой дроби}
  MOV  EDI, fr2     {второй}

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

  MOV  EAX, [ESI].fraction.x
  IMUL [EDI].fraction.y
  XCHG EAX, EDI     {EDI = x1*y2, EAX = адресу второй дроби}
  MOV  EAX, [EAX].fraction.x
  MUL  [ESI].fraction.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
end;

{процедура вычитания двух дробей}
{параметры - адреса уменьшаемого, вычитаемого и результата}
{правило вычисления для 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)}
procedure Sub_f(var fr1, fr2, res:fraction);assembler;
asm
  PUSH EBX
  PUSH ESI
  PUSH EDI

  MOV  ESI, fr1
  MOV  EDI, fr2

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

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

  MOV  EAX, EDI
  MOV  EDX, EBX
  call GCD

  call Cut_f

  POP  EDI
  POP  ESI
  POP  EBX
end;


{процедура умножения двух дробей}
{параметры - адреса множителей и результата}
{правило вычисления для x1/y1 * x2/y2}
{(первая строка - числитель, вторая - знаменатель):}
{(x1*x2) div GCD(x1*x2, y1*y2)}
{(y1*y2) div  GCD(x1*x2, y1*y2)}
procedure Mul_f(var fr1, fr2, res:fraction);assembler;
asm
  PUSH EBX
  PUSH ESI
  PUSH EDI

  MOV  ESI, fr1
  MOV  EDI, fr2

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

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

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

  POP  EDI
  POP  ESI
  POP  EBX
end;

{процедура деления двух дробей}
{параметры - адреса делимого, делителя и результата}
{правило вычисления для x1/y1 * x2/y2}
{(первая строка - числитель, вторая - знаменатель):}
{(x1*y2) div GCD(x1*y2, y1*x2)}
{(y1*x2) div  GCD(x1*y2, y1*x2)}
procedure Div_f(var fr1, fr2, res:fraction);assembler;
asm
  PUSH EBX
  PUSH ESI
  PUSH EDI

  MOV  ESI, fr1
  MOV  EDI, fr2

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

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

  call GCD          {НОД}

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

  POP  EDI
  POP  ESI
  POP  EBX
end;


Вызываем так:
Код :
Var
  f1, f2, f3: fraction;

begin
  f1.x:=3;
  f1.y:=4;
  f2.x:=-9;
  f2.y:=16;

  Div_f(f1, f2, f3);
  Mul_f(f1, f2, f3);
  Add_f(f1, f2, f3);
  Sub_f(f1, f2, f3);
end;

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

НЕ одобряю 0 одобряю!


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

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

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



В избранное