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

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


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

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

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

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

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

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

Консультация # 183962: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: Помогите пожалуйста реализовать программы на Ассемблере (как вставка в Делфи) 3. Реализуйте подпрограмму, которая возвращает символы имеющиеся в данной строке с указанием числа вхождений каждого символа. 4. Дано натуральное число n. Вычи...


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

Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:

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

Спасибо.

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


Консультирует Зенченко Константин Николаевич (Модератор):

Здравствуйте, Посетитель - 380267!

Код заданий в приложении:
№1

Код :
program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;
type
  tMass=array[0..255]of byte;
var
  a:ShortString;
  b:tMass;
  c:integer;
 procedure A001(a1:ShortString;var b1:tMass);assembler;
   asm
     {edx указатель на массив b1}
     {eax указатель на строку a1}
{сбрасываем значение счетчиков в массиве}
     mov        ecx,256{количество элементов в массиве}
     push       edx{запоминаем указатель на массив В1}
 @001:
     mov        byte ptr[edx],0{сбрасываем значение счетчика}
     inc        edx{следующее значение}
     loop       @@001{пока СХ больше нуля}
     pop        edx{востанавливаем значение указателя на массив В1}
{выполняем задание}
     xor        ecx,ecx{команда не нужна, т.к. после цикла там будет ноль, но всетаки}
     xor        ebx,ebx{сбрасываем значение регистра ЕВХ}
     mov        cl,[eax]{загружаем количество символов}
 @002:
     inc        eax{следующее значение}
     mov        bl,[eax]{считываем текущий символ}
     inc        byte ptr[ebx+edx]{увеличиваем значение счетчика соответсвующего коду символа}
     loop       @@002{пока не кончится введенная строка}
   end;
begin
  {вводим строку}
  write('enter string:');
  readln(a);
  {выполняем задание}
  a001(a,b);
  {выводим результат}
  for c:=0 to 255 do if b[c]>0 then write(chr(c):6,b[c]:4);
  readln;
end.

Как я не старался, мой компилятор не хочет передавать параметры в процедуру через стек. Использована строка длиной до 256-ти, 8-ми битных символов.

№2
Код :
program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;
var n:integer;
    a:double;
begin
  {ввод целого числа с контролем}
  repeat
    write('enter N:');
    readln(n);
  until(n>1)and(n<1000);
  {сбрасываем результат}
  a:=1;
  asm
    mov         ecx,n{загружаем введенное целое}
    FINIT{инициализируем сопроцессор}
{считаем факториал}
 @000:
    push        ecx{запоминаем счетчик}
    mov         eax,1{сбрасываем начальное значение факториала}
 @001:
    xor         edx,edx{сбрасываем старший операнд}
    mul         ecx{умножаем на счетчик}
    loop        @@001{пока СХ больше нуля}
    mov         n,eax{записываем факториал}
    pop         ecx{востанавливаем счетчик}
    dec         ecx{уменьшаем счетчик}
    jz          @@002{ноль выходим}
{считаем формулу}
    FLD1{заружаем в стек первую единицу}
    FLD1{загружаем в стек единицу дроби}
    FILD        n{загружаем в стек факториал}
    FDIV{получаем значение дроби}
    FSUB{получаем значение текущей итерации}
    FMUL        a{умножаем с предыдущими значениями}
    FSTP        a{запоминаем рузультат}
    jmp         @@000{следующая итерация}
 @002:
  end;
  write('result:',a);
  readln;
end.

Обращаю Ваше внимание, что регистры сопроцессора называются стеком. Не путайте со стеком программы.

Всё проверялось в delphi 6.
Удачи!

Консультировал: Зенченко Константин Николаевич (Модератор)
Дата отправки: 06.09.2011, 17:57

5
нет комментария
-----
Дата оценки: 06.09.2011, 19:40

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

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


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

Здравствуйте, Посетитель - 380267!
3) Предлагаю свою версию программы.
Работает со строками типа String.
В результате формируется строка String, состоящая из разных символов, и массив из Integer с количествами символов.
Массив из 256 integer необходимо передать параметром, он используется для подсчета, а также в нем возвращаются счетчики символов.

Код :
program q183962;

{$APPTYPE CONSOLE}
{$ASMMODE intel}

uses
  SysUtils;

{процедура формирует String из разных символов и массив из количеств символов}
procedure CharsCount(Src:String; var Tgt:String; var Cnt:array of Integer); stdcall; Assembler;
asm
   sub   esp, 256     {выделим буфер под разные символы в стеке}
   mov   edx, esp     {адрес буфера разных символов}
   push  edi          {сохраним регистры}
   push  esi
   push  ebx
   mov   esi, Src     {адрес исходной строки}
   mov   edi, Cnt     {адрес счетчиков}
   mov   ecx, 256     {предполагаем, что там 256 dword-ов}
   xor   eax, eax     {0}
   rep   stosd        {обнуляем}
   mov   edi, Cnt     {адрес счетчиков}
   mov   ecx, [esi-4] {длина исходного string-а}
   jcxz  @FormString  {обойдем пустую строку}
 CalcCharsLoop:       {цикл по символам строки}
   lodsb              {очередной символ}
   inc   dword ptr [edi+eax*4] {считаем в массиве счетчиков}
   loop  @CalcCharsLoop        {по всем символам}
 FormString:          {формируем результат}
   xor   ebx, ebx     {индекс для 256 значений счетчиков}
   xor   eax, eax     {счетчик разных значений}
   mov   ecx, 256     {счетчик в буфере}
 FormStringLoop:      {цикл формирования результата}
   mov   esi, [edi+ebx*4]      {читаем счетчик}
   test  esi, esi     {проверяем на 0}
   jz    @FormStringNext       {если 0, то обходим}
   mov   [edx+eax], bl         {для ненулевого сохранякм индекс, как код символа}
   mov   [edi+eax*4], esi      {и количество, сохраняем с начала массива счетчиков}
   inc   eax          {считаем разные значения}
 FormStringNext:      {на следующий счетчик}
   inc   ebx          {индекс следующего счетчика}
   loop  @FormStringLoop       {по всем}
{сформируем string из массива разных символов}
   mov   ecx, eax              {количество}
   mov   eax, Tgt              {адрес string}
                               {edx = адресу массива символов!}
   call  SetString             {формируем string}
   pop   ebx                   {восстанавливаем регистры}
   pop   esi
   pop   edi
   add   esp, 256              {убираем из стека буфер}
end;

Var
  i, N: integer;
  a: string;
  Tgt: string;
  Cnt: array[0..255] of integer;
  work: string;
  num: string;
begin;
  {вводим строку}
  write('enter string:');
  readln(a);

  {выполняем задание}
  CharsCount(a, Tgt, Cnt);

  {сформируем результат}
  N:=Length(Tgt);         {длина строки}
                          {строка разных символов}
  work:='Target = ' + Tgt + char(10)+'Counts = ';
  for i:=0 to N-1 do      {и счетчики}
    begin
      Str(Cnt[i],num);
      work:=work+num+',';
    end;
  SetLength(work,Length(work)-1);     {уберем последнюю запятую}
  {выводим результат}
  write(work);
  readln;
end.



4) Предлагаю свое решение и этой задачи тоже.
Расчет факториала ведется, начиная с 2 и с учетом предыдущего значения.
Чем достигается значительное убыстрение выполнения.
Каждый член произведения используется в виде (i! - 1) / i!

Код :
program q183962b;

{$APPTYPE CONSOLE}
{$ASMMODE intel}

uses
  SysUtils;

{процедура вычисляет требуемое выражение}
{результат - в стеке сопроцессора}
function CalcValue(n: Integer):double; Assembler;
asm
  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            {уберем двойное слово из стека процессора}
end;

Var
  n, pos: integer;
  d: double;
  a: string;

begin
  {вводим число}
  write('Enter number: ');
  readln(a);
  Val (a, n, pos);          {преобразуем в число}
  if pos<>0 then            {проверка на корректность числа}
    Writeln ('Error at position ',pos,' : ',a[pos])
  else
    begin
      if (n>1) and (n<=1000) then           {проверка на диапозон}
        begin
          {выполняем задание}
          d := CalcValue(n);                {считаем}
          Writeln ('Value = ', d:10:8);     {выводим}
        end
      else
         Writeln ('Number must be from 2 to 1000');
    end;
  readln;
end.

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

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


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

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

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



В избранное