Форум программистов, компьютерный форум, киберфорум
Наши страницы
Assembler: математика, вычисления
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
EkaterinaDM
0 / 0 / 1
Регистрация: 16.10.2018
Сообщений: 6
1

Задан массив a(n)=sin(5*n). Вычислить номер элемента, при котором сумма станет больше 3

06.11.2019, 17:41. Просмотров 940. Ответов 9
Метки нет (Все метки)

Задан массив a(n)=sin(5*n). Вычислить номер элемента, при котором сумма станет больше 3

Подскажите, как правильно организовать условный переход в ассемблерной вставке вместе с С++. Был дан вот такой пример-черновик.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main() // 
{
    float A = 5.3;          // 
    long B = 5, C = 20000, N = 0;
    __asm {;                
    finit;                  // очищение регистров
        fld1;               // регистр для функции
        fldz;               // регистр для Sn
        m1 : inc N;         // аргумент ++
        fld A;              // ST(0) = 5, 3
        fmulp ST(2), ST;    // вычисление степенной функции 5, 3n
        fild B
        fimul N
        fadd ST, ST(2);     //очищение элемента прогрессии
        fadd;               // увеличение  Sn
        ficom C;            //сравнение суммы с 20000
        fstsw AX;           
        sahf;               
        jc m1;              // переход если Sn<20000
    } 
}
Найти синус не проблема, но не получается правильно сделать переход. Наш руководитель ничем не смог помочь. У меня есть много вариантов кода, но они все не рабочие. Очень интересно, какой должен быть правильный результат. Это небольшая часть того, что должно быть.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "pch.h"
#include <iostream>
using namespace std;
 
int main()
{
    long five = 5;
    long N=0;
    long D = 180;
    //float result;
    //float Sum=0;
    long C = 3;
    _asm {
        fldpi;      //ST(0)=pi
//  m1:inc N;
        fimul N;            //ST(0)=pi*n
        fimul   five;               //ST(0)=pi*n*5
        fidiv D;            //(pi*n*5)/180
        fsin;               //ST(0)=sin(ST(0))
    //      fstp result;         сохранение с выталкиванием
    //      fld result;     
    //      fld Sum;
    //      fadd ST, ST(1);
    //      fstp Sum;
    
        //ficom C;            
        //fstsw AX;
        //sahf;
    //jc m1;                   переход если меньше
    }
    cout << N<<endl;
}
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.11.2019, 17:41
Ответы с готовыми решениями:

Задан массив А. Определить значение k, при котором сумма минимальна
Есть задание: Задан массив А. Определить значение k, при котором сумма минимальна |A1+A2+A3.....

9

ФедосеевПавел
Модератор
4732 / 2633 / 1051
Регистрация: 01.02.2015
Сообщений: 8,616
Записей в блоге: 1
07.11.2019, 17:17 2
EkaterinaDM,
1. попробуйте найти ответ без ассемблера, на C++ - проверьте, он существует?
2. можно оптимизировать программу, вернее формулу выполнив преобразования по формулам тригонометрии, как в темах
Рекуррентная формула
Вычислить сумму для заданного n
это не просто игра в формулы, у аргумента инструкции fsin есть допустимый диапазон, а преобразованиями вы как раз ограничите этот аргумент областью допустимых значений.

Добавлено через 23 минуты
По поводу проверки существования ответа в пределах значений, обычно используемых при изучении синтаксиса языка, а не реализации алгоритмов.
Набрал программку, которая ищет сумму синусов, максимальную сумму по абсолютному значению
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
program test;
 
{$mode Delphi}
var
  i, n: integer;
  s, x: real;
  numerator: real;
begin
  s := 0;
  x := 0;
  for i := 0 to 1000000000 do
  begin
    s := s + sin(5 * i);
    if x < abs(s) then
      x := abs(s);
    if abs(s) > 3 then
    begin
      writeln(s: 0: 3, ' ', i);
      break;
    end;
  end;
  writeln(s: 0: 10);
  writeln(x: 0: 10);
end.
и получил такие результаты
Код
0.2701305511
1.5047848369
Т.е. при количестве слагаемых в пределах 1'000'000'000 максимальное абсолютное значение суммы едва превышает число 1,5. Таким образом, в этом диапазоне количества слагаемых решения вашей задачи нет.

Я не знаю, как вам быть. Лучше всего подойти к преподавателю, показать распечатку тестовой программы на C++ и привести результаты вычислений. Предложите изменить условие задачи на "Вычислить номер элемента, при котором абсолютное значение суммы станет больше 1,503" - почему 1,503 - чтобы слагаемых было по-больше, ведь для 1,5 будет всего 2 слагаемых.
Чисто теоретически, где-то, когда-то, сумма должна превысить число 3, но это потребует других усилий по написанию программы.

Добавлено через 1 час 14 минут
Реккурентная формула для вычисления элементов последовательности an=sin(5n)

Выразим значения sin(5n) и cos(5n) через константы и sin(5(n-1)) и cos(5(n-1)), т.е. значений на предыдущей итерации
http://www.cyberforum.ru/cgi-bin/latex.cgi?sin(5n)=sin[5(n-1)+5]=sin[5(n-1)]\cdot cos5+cos[5(n-1)]\cdot sin5
http://www.cyberforum.ru/cgi-bin/latex.cgi?cos(5n)=cos[5(n-1)+5]=cos[5(n-1)]\cdot cos5-sin[5(n-1)]\cdot sin5

Введём обозначения:
sinN=sin(5n)
sinP=sin[5(n-1)]
cosN=cos(5n)
cosP=cos[5(n-1)]

Запишем sin(5n) и cos(5n) через новые обозначения
sinN=sinP*cos5+cosP*sin5
cosN=cosP*cos5-sinP*sin5

Вот собственно и всё, осталось создать программу.

Добавлено через 1 час 26 минут
вычисление суммы 10000 слагаемых в цикле, сохранение суммы в переменной Result
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
        finit
 
        fld1
        fld1
        fadd    st(0),  st(0)
        fadd    st(0),  st(0)
        faddp   st(1),  st(0)
        fsincos
 
        fldz
        fsincos
 
        fldz
 
        ;st(0) - сумма ряда
        ;st(1) - cosP
        ;st(2) - sinP
        ;st(3) - cos5
        ;st(4) - sin5
        mov     ecx,    1
        @@for:
                ;cosN := cosP * cos5 - sinP * sin5
                fld     st(1)
                fmul    st(0),  st(4)
                fld     st(3)
                fmul    st(0),  st(6)
                fsubp   st(1),  st(0)
                ;sinN := sinP * cos5 + cosP * sin5
                fld     st(3)
                fmul    st(0),  st(5)
                fld     st(3)
                fmul    st(0),  st(7)
                faddp   st(1),  st(0)
                ;s := s + sinN
                fadd    st(2),  st(0)
                ;sinP := sinN
                ;cosP := cosN
                fstp    st(4)
                fstp    st(2)
 
                inc     ecx
                cmp     ecx,    10000
        jbe     @@for
        ;сохранение результата
        fstp    [Result]
0
EkaterinaDM
0 / 0 / 1
Регистрация: 16.10.2018
Сообщений: 6
07.11.2019, 19:18  [ТС] 3
Большое вам спасибо за ответ! Попробую реализовать эту задачу с другим условием
0
ФедосеевПавел
Модератор
4732 / 2633 / 1051
Регистрация: 01.02.2015
Сообщений: 8,616
Записей в блоге: 1
07.11.2019, 19:47 4
Начните с согласования обновления условия задачи с преподавателем.

Добавлено через 21 минуту
Думаю, что общим представлением невозможности получить сумму ряда, превышающую 3, может послужить такое подобие доказательства.
Пусть элементы массива это комплексные числа
Z[n]=sin(5n)+i*cos(5n)
Для получения исходного элемента массива a[n] нужно только взять действительную часть от соответствующего комплексного элемента массива Z.
Аналогично и для суммы этих элементов.

Итак, суммируем комплексные числа Z - это фактически суммируем единичные вектора.
Посмотрим, может ли в какой-то момент оказаться, что последовательно складывается 3 и более элементов с положительной действительной частью. А вот - нет!
Каждый новый вектор Z[n] повернут на (2http://www.cyberforum.ru/cgi-bin/latex.cgi?\pi-5) радиан http://www.cyberforum.ru/cgi-bin/latex.cgi?\approx 73,52 градуса против часовой стрелке относительно предыдущего вектора.
Другими словами, подряд три значения Re(Z) одного знака возможны только в одном случае - одно около 0, следующее около 1 и третье около 0. После этого знак меняется и значение суммы убывает. И даже в этом оптимальном случае сумма будет 0,3+0,9+0,3 приблизительно 1,5. Что и получается при практических вычислениях.

Эту лабуду можно доказать и без комплексных чисел, просто с векторами нагляднее.
0
07.11.2019, 19:47
EkaterinaDM
0 / 0 / 1
Регистрация: 16.10.2018
Сообщений: 6
07.11.2019, 20:23  [ТС] 5
А если угол задан в градусах? Их можно перевести в радианы. Разве тогда нельзя узнать сумму? Нашла замечание в методичке, что нужно сначала перевести
0
ФедосеевПавел
Модератор
4732 / 2633 / 1051
Регистрация: 01.02.2015
Сообщений: 8,616
Записей в блоге: 1
07.11.2019, 20:46 6
Ё! Это же всё меняет!
Тогда моя реккурентная формула неверна - точнее требует уточнения коэффициентов.

Заменяйте 5 на радианы и всё получится. 2http://www.cyberforum.ru/cgi-bin/latex.cgi?\pi радиана равны 360 градусов.

Добавлено через 19 минут
Реккурентная формула для вычисления элементов последовательности an=sin(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan)

Выразим значения sin(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan) и cos(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan) через константы и sin(http://www.cyberforum.ru/cgi-bin/latex.cgi?\theta(n-1)) и cos(http://www.cyberforum.ru/cgi-bin/latex.cgi?\theta(n-1)), т.е. значений на предыдущей итерации
http://www.cyberforum.ru/cgi-bin/latex.cgi?sin(\theta n)=sin[\theta(n-1)+\theta]=sin[\theta(n-1)]\cdot cos\theta+cos[\theta(n-1)]\cdot sin\theta
http://www.cyberforum.ru/cgi-bin/latex.cgi?cos(\theta n)=cos[\theta(n-1)+\theta]=cos[\theta(n-1)]\cdot cos\theta-sin[\theta(n-1)]\cdot sin\theta

Введём обозначения:
sinN=sin(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan)
sinP=sin[http://www.cyberforum.ru/cgi-bin/latex.cgi?\theta(n-1)]
cosN=cos(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan)
cosP=cos[http://www.cyberforum.ru/cgi-bin/latex.cgi?\theta(n-1)]
sinT=sinhttp://www.cyberforum.ru/cgi-bin/latex.cgi?\theta
cosT=coshttp://www.cyberforum.ru/cgi-bin/latex.cgi?\theta

Запишем sin(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan) и cos(http://www.cyberforum.ru/cgi-bin/latex.cgi?\thetan) через новые обозначения
sinN=sinP*cosT+cosP*sinT
cosN=cosP*cosT-sinP*sinT
0
EkaterinaDM
0 / 0 / 1
Регистрация: 16.10.2018
Сообщений: 6
07.11.2019, 22:27  [ТС] 7
Видимо получился бред
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "pch.h"
#include <iostream>
using namespace std;
 
int main() // початок програми на С++
{
    long A = 5; // 
    long D = 180, N = 0;
    long C = 3;
 
    __asm {;
    finit;
    fldpi;      // ST(0)=pi
    fimul N;    // ST(0)=5*pi
    fidiv D;    //ST(0)=(5*pi*n)/180
    fsin;           
    fldz;       //ST(0) = Sn=0 , ST(1)=(sin(5*pi*n)/180)
 
m1: inc N;
    
    fld ST(0);          //ST(0)=Sn  ST(1)= Sn = 0; ST(2) = (sin(5*pi*n)/180)
    fadd ST(0), ST(2);  // ST(0)=Sn+(sin(5*pi*n)/180)
    fadd;                       //здесь не очень понятно
        
        ficom C;         порівняння суми з
        fstsw AX;       збереження регістру стану SW(FPU) в
                            ; регістрі AX(CPU)
        sahf;           збереження старшого байту АХ в рег.флагів
        
        jc m1;          
            
 
    } // закінчення асемблерної вставки
    cout << N << endl << endl;
}
Сложность в переводе градусов при использовании формулы разложения состоит в том, что чтобы в итоге при i =9 сумма была правильной, нужно переводить уже (5*n) в радианы. Именно если считать синус (5*1*pi)/180 , синус (5*pi*2)/180, синус (5*3*pi)/180 и далее. Ну значит не вышло у меня за два месяца с начала изучения ассемблера стать таким профи). Проще было бы попросить преподавателя разрешения убрать условие расчета в градусах.
0
ФедосеевПавел
Модератор
4732 / 2633 / 1051
Регистрация: 01.02.2015
Сообщений: 8,616
Записей в блоге: 1
07.11.2019, 23:04 8
Стоять-бояться!

Зачем вы цепляетесь за это магическое число 5?!

Вычисляйте некую константу T=5*pi/180 и сохраните её в стеке FPU на всё время вычислений. Там целых 8 регистров, а вам что - одного жалко? А потом загружаете N и умножаете на содержимое регистра FPU. При необходимости ко всем командам можно добавить суффикс r, который "разворачивает" направление применения инструкции:
Assembler
1
2
fsub st(2), st(0)  ;st(2)=st(2)-st(0)
fsubr st(2), st(0) ;st(2)=st(0)-st(2)
что может пригодится когда инструкция не предполагает первым операндом вершину стека

Добавлено через 1 минуту
На C
C
1
2
3
4
5
6
7
float t;
t=5*pi/180;
do
{
  N++;
  s=s+sin(t*N);
}while(s<3);
0
ФедосеевПавел
Модератор
4732 / 2633 / 1051
Регистрация: 01.02.2015
Сообщений: 8,616
Записей в блоге: 1
08.11.2019, 20:08 9
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
        finit
 
        fld1
        fld1
        fadd    st(0),  st(0)
        fadd    st(0),  st(0)
        faddp   st(1),  st(0)
        push    180
        fild    dword ptr [esp]
        sub     esp,    4
        fdivp   st(1),  st(0)
        fldpi
        fmulp   st(1),  st(0)
        fsincos
 
        fldz
        fsincos
 
        fldz
 
        ;st(0) - сумма ряда
        ;st(1) - cosP
        ;st(2) - sinP
        ;st(3) - cosT
        ;st(4) - sinT
        mov     ecx,    0
        @@repeat:
                inc     ecx
                ;cosN := cosP * cosT - sinP * sinT
                fld     st(1)
                fmul    st(0),  st(4)
                fld     st(3)
                fmul    st(0),  st(6)
                fsubp   st(1),  st(0)
                ;sinN := sinP * cosT + cosP * sinT
                fld     st(3)
                fmul    st(0),  st(5)
                fld     st(3)
                fmul    st(0),  st(7)
                faddp   st(1),  st(0)
                ;s := s + sinN
                fadd    st(2),  st(0)
                ;sinP := sinN
                ;cosP := cosN
                fstp    st(4)
                fstp    st(2)
 
                fcom    [SumMax]
                fstsw   ax
                sahf
        jb      @@repeat
        ;сохранение результата
        fstp    [Result]                ;значение суммы
        mov     [N],    ecx             ;количество слагаемых
0
EkaterinaDM
0 / 0 / 1
Регистрация: 16.10.2018
Сообщений: 6
09.11.2019, 19:41  [ТС] 10
Лучший ответ Сообщение было отмечено ФедосеевПавел как решение

Решение

Спасибо! Благодаря вашему ответу у меня получилось лучше разобраться со всем этим, с работой команд. Ну и сделать следующие задания
0
09.11.2019, 19:41
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.11.2019, 19:41

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.