Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Математика в AvrStudio
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Aiva
Здравствуйте.
Помогите, пожалуйста, советом, в каком месте описано как правильно организовывать переменные и проводить вычисления в Atmeg-ах.

Пишу программку для , в которой нужно проводить множество математических операций (в основном умножений, делений, сложений). Чо-то очень туго у меня получается. Компилятор выдает вовсе не то что прошу. Не могу уловить систему моих ошибок sad.gif.
Я раньше с IARом работал - там как-то проще было (правда и вычислений в тех задачах особых не было).
defunct
Цитата(Aiva @ May 13 2009, 18:56) *
Я раньше с IARом работал - там как-то проще было (правда и вычислений в тех задачах особых не было).

Так работайте дальше с IAR'ом. В чем вопрос?
IXFN50N80Q2
Хм. Ну ANSI C а вообще для начала отключите опимизатор. Уровень O0.
Бывает что и сам WIN AVR GCC не так поймет и подумает что эти строчки кода лишние.
И самое главное в скобках, там где переменная после умножения выше unsigned char становится, то надо ставить в скобках тип контейнера.
А лучше всегда его прописывать.

unsigned char X,Y;
unsigned int Result

Result=(unsigned int)X*Y ----->Перемножение 2х CHARов пораждает тип INT. И нужно указать, что считать X-16разрядным числом. Это я имел ввиду под типом контейнера.
Вот так.

Если Result=X*Y
хоть и Result ИНТ, могут быть проблемы.

А остальное это документуха по ANSI C.
А вообще смотрите Дизассемблер. Говорят помогает.
Сергей Борщ
Цитата(Aiva @ May 13 2009, 18:56) *
Компилятор выдает вовсе не то что прошу. Не могу уловить систему моих ошибок sad.gif.
Я раньше с IARом работал - там как-то проще было (правда и вычислений в тех задачах особых не было).
Будьте добры, задавайте вопросы конкретнее: что вы пишете, что ожидаете получить и что получаете. Было бы совсем замечательно, если бы вы подкрепили конкретным примером - что именно было в IAR проще. Пока по предоставленной вами информации можно лищь ответить: "пишите правильно".
Цитата(IXFN50N80Q2 @ May 13 2009, 21:57) *
Хм. Ну ANSI C а вообще для начала отключите опимизатор. Уровень O0.
Очень вредный совет. Пользы никакой, только размер кода увеличится и скорость вычислений упадет.
Цитата(IXFN50N80Q2 @ May 13 2009, 21:57) *
Бывает что и сам WIN AVR GCC не так поймет и подумает что эти строчки кода лишние.
Вот только не надо валить все с больной головы на компилятор. Компилятор делает то, что попросили. Если попросили некоррекно - виноват не компилятор.
777777
Цитата(IXFN50N80Q2 @ May 13 2009, 22:57) *
Хм. Ну ANSI C а вообще для начала отключите опимизатор. Уровень O0.

Глупости. Этот режим сделан для того, чтобы люди, думающие, что виноват оптимизатор, могли его отключить и убедиться, что на самом деле ошибка в их программе.
Цитата(IXFN50N80Q2 @ May 13 2009, 22:57) *
Бывает что и сам WIN AVR GCC не так поймет и подумает что эти строчки кода лишние.

Если он так подумает - значит они и в самом деле лишние.
Aiva
Хотя я методом тыка раздуплил проблемку, которая подвигнула меня на оформление данной темы, на будущее очень хочется услышать комментарии спецов smile.gif. С Вашего позволения привожу код примера моих проблем.

Итак некоторая функция должна рассчитывать пилу по заданному углу. Сперва я написал все формулы влоб:

Код
const unsigned int N0=0b10000000000000;
const unsigned int Nmax=0b11111111111111;
unsigned long  Wvariable2;

unsigned long sinus(unsigned int angle)
{
  if (angle<=90)
   { Wvariable2=N0+angle*Nmax/180;}
  if (angle>270)
   { Wvariable2 = (angle-270)*Nmax/180;}
  if ((angle>90)&(angle<=270))
   { Wvariable2 = Nmax-(angle-90)*Nmax/180;}
return Wvariable2;}


Вроде по разрядной сетке противоречий нет. Но ничего не получилось sad.gif
Далее я крутил крутил и интуитивно получил рабочий вариант:

Код
unsigned int sinus(unsigned int angle)
{
unsigned long  Wvariable2;
unsigned int Wv1;

      Wvariable2 = Nmax;
  if (angle<=90)
    {
      Wvariable2 *= angle;
      Wvariable2 = Wvariable2/180;
      Wvariable2 += N0;
      Wv1=Wvariable2;    
    }
  if (angle>270)
    {
      Wvariable2 *= (angle-270);
      Wv1= (Wvariable2/180);
    }
  if ((angle>90)&(angle<=270))
    {
      Wvariable2 *= (angle-90);
      Wvariable2 = Wvariable2/180;
      Wv1 = (Nmax-Wvariable2);
    }
return Wv1;}


Как же правильно решать подобные задачки ?
DpInRock
Цитата
if ((angle>90)&(angle<=270))

Чисто тут лучше && ставить. Полезнее на будущее. И быстрее.

Во-вторых (тут уже говорили) учитывать, что тип результата всегда равен типу операндов(или самого длинного), если специально не указать иное.
Вот в первом случае angle*Nmax приводит временами к переполнению промежуточного результата.
SysRq
Цитата(Aiva @ May 16 2009, 23:21) *
Как же правильно решать подобные задачки ?
Взять любимую книжку-учебник по языку C, прочесть об приведении типов, автоматическом приведении типов, и уверенно решать.

& и && - вообще разные вещи. Результат (1 & 2) и (1 && 2) вообще-то противоположный...
DpInRock
В данном случае работать должно и &.
777777
Цитата(DpInRock @ May 17 2009, 00:29) *
Цитата
if ((angle>90)&(angle<=270))

Чисто тут лучше && ставить. Полезнее на будущее. И быстрее.

И к тому же можно обойтись без лишних скобок. В Си приоритеты выбраны так, чтобы можно было в большинстве случаев обойтись без скобок.


Цитата(Aiva @ May 16 2009, 23:21) *
Код
unsigned long sinus(unsigned int angle)
{
...
}

А что, эта функция вычисляет синус?
Aiva
Цитата(777777 @ May 17 2009, 07:21) *
А что, эта функция вычисляет синус?


Я ее просто так назвал. Она вычисляет пилу, похожую на синус.
_Diman_
Цитата(Aiva @ May 16 2009, 23:21) *
Код
   { Wvariable2=N0+angle*Nmax/180;}
//------------------
{
      Wvariable2 *= angle;
      Wvariable2 = Wvariable2/180;
      Wvariable2 += N0;
      Wv1=Wvariable2;    
    }


Интересно, а так работать будет?
Код
   { Wvariable2=N0+(angle*Nmax)/180UL;}

Я так понял не работает из-за того, что выражение считается для int.
Сергей Борщ
Цитата(_Diman_ @ May 17 2009, 17:53) *
Интересно, а так работать будет?
Код
   { Wvariable2=N0+(angle*Nmax)/180UL;}
Тоже не будет. А вот Wvariable2=N0+ angle * (unsigned long)Nmax/180 будет.
_Diman_
Цитата(Сергей Борщ @ May 17 2009, 19:16) *
Тоже не будет. А вот Wvariable2=N0+ angle * (unsigned long)Nmax/180 будет.


Объясните, пожалуйста, если не трудно, почему так.
Умножение и деление имеют один приоритет и в строке выполняются слева на право
почему, например, (unsigned long)angle * Nmax/180 будет не верно, по идее то angle уже 32битная. Я почему-то думал, что проблем с переменными при операциях не возникнет, возникнут, когда действия будут с константой и переменной. А тут получается, что angle*Nmax не расширяется до 32бит?
Сергей Борщ
Цитата(_Diman_ @ May 17 2009, 18:42) *
Объясните, пожалуйста, если не трудно, почему так.
Правила вычисления подвыражений. Тип результата определеяется типом наибольшего операнда. Второй операнд приводится к этому же типу. Если оба операнда меньше int, они приводятся к int (integer promotion rules). Оптимизатор имеет право потом убрать действия, которые не влияют на конечный результат.
Разбиваем ваше выражение на подвыражения: angle * Nmax - оба операнда unsigned int, результат unsigned int. В процессе вычисления происходит переполнение. Для исключения ошибки надо один из операндов привести к unsigned long. Любой, не обязательно именно Nmax. А вот приведение 180 ничего не дает, потому что в подвыражении деления первый операнд - уже обрезанный до unsigned int результат умножения. И именно этот усеченный результат будет расширен до 32 бит.
_Diman_
Спасибо!
Блин, я то думал что так тоже правильно int a,b; uint32_t u; u= (uint32_t)(a*b);
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.