Проблема с вычислениями на Arduino

Тема в разделе "Arduino & Shields", создана пользователем Troll, 2 май 2017.

  1. Troll

    Troll Гик

    Есть у нас вот такой кусок скетча:
    Код (C++):
    float x = 80;
      float y = 60;// кординаты на плоскости

      float R = sqrt(x*x + y*y);// расстояние от начала кординат до точки (это теорема Пифагора)
      Serial.println(R);// выводим
     
      float a;// так неуклюже расписано дла удобства анализирования
      a = (y*y-x*x-R*R)/(-2*x*R);//находим косинус угла между гипотенузой(расстоянием до точки) и осью  Х
      Serial.println(acos(a));// выводим значение угла в радианах
      a = acos(a) * 180;//первый шаг в переводе в градусы
      Serial.println(a);
      a= a / 3,14;//второй шаг в переводе радиан в градусы
      Serial.println(a);//окончательный ответ в градусах
    Выводит он следующее:
    Код (C++):
    100.00  //расстояние до точки (R)  
    0.64  //угол в радианах
    115.83  //после умножения на 180
    38.61  //после деления на Пи
    А должен(проверял на калькуляторе):
    Код (C++):
    100.00  //расстояние до точки (R)
    0.64  //угол в радианах
    115.2  //после умножения на 180
    36.68  //после деления на Пи
     
    Проанализировав два вывода порта можно сделать вывод , что ардуинка ошибается в умножении и делении(я был удивлен, поняв то, что арккосинус она рассчитала правильно, а ошиблась в простом умножении/делении).
    Последнее значение загоняется в серву, и ,поверьте мне, погрешность в 2 градуса фатальна.

    Вопрос: как решить эту проблему?
     
  2. ANV

    ANV Гуру

    Замените в 3,14 запятую на точку
     
  3. Richard

    Richard Нерд

    Супер хитропопая но зато точная тактика:

    Делить в int через div, забирать остаток через mod, дальше сравниваешь с Х div 2: если больше, то к первому прибавляешь 1, если меньше, то не трогаешь.

    Почему в integer считать лучше:
    Приколюха в том, что это а) быстрее, б) надежней. Если ты к первому float (2) прибавишь второй (скажем, 3), то в зависимости от ситуации он может выдать или 5.0 или 4.99999994. Или еще как. Так что по возможности, стоит обходиться без float. Чем больше используешь тем обширней может быть погрешность. Ну это так, на всякий.
     
  4. Tomasina

    Tomasina Сушитель лампочек Модератор

    Код (C++):
    float x = 80.0;
      float y = 60.0;// кординаты на плоскости
      float R = sqrt(x*x + y*y);// расстояние от начала кординат до точки (это теорема Пифагора)
      Serial.println(R);// выводим
      float a;// так неуклюже расписано дла удобства анализирования
      a = (y*y-x*x-R*R)/(-2.0*x*R);//находим косинус угла между гипотенузой(расстоянием до точки) и осью  Х
      Serial.println(acos(a));// выводим значение угла в радианах
      a = acos(a) * 180.0;//первый шаг в переводе в градусы
      Serial.println(a);
      a= a / 3.14;//второй шаг в переводе радиан в градусы
      Serial.println(a);//окончательный ответ в градусах
    Найдите 5 отличий ;)
     
    ИгорьК нравится это.
  5. Troll

    Troll Гик

    80.0
    60.0
    -2.0
    180.0
    и точка в числе Пи)
    Спасибо, опробую уже завтра
     
  6. Tomasina

    Tomasina Сушитель лампочек Модератор

    ага :)
    Тип float надо всегда записывать с точкой, иначе в некоторых случаях (зависит от очередности переменной в выражении) число без точки воспринимается как int и дробная часть отбрасывается.
     
  7. Troll

    Troll Гик

    Результаты радуют)
    Но все равно грешок есть
    Код (C++):
    100.00
    0.64
    115.83  // в идеале 115.2
    36.89 // в идеале 36.68
    Спасибо
     
  8. Troll

    Troll Гик

    integer для моей задачи очень груб и неточен, но возьму на заметку
     
  9. Troll

    Troll Гик

    А вот в чем разница между запятой и точкой ?
     
  10. Tomasina

    Tomasina Сушитель лампочек Модератор

    запятая разделяет два числа или переменные, точка разделяет целую и дробную часть одного числа.
     
  11. Richard

    Richard Нерд

    Кстати, а что за дичь такая -- разделять дробную часть, кхм, запятой? Это кто так делает вообще? Тем более на вычислительной технике
     
    Igor68 нравится это.
  12. Igor68

    Igor68 Гуру

    После калькулятора все так делают! Только почему вот компилятор промолчал?
     
  13. ANV

    ANV Гуру

    В вычислительной технике да, но вообще-то в России дробная часть отделяется запятой. Что тут дикого то?

    Потому что в случае a=a/3,14;компилятор делает следующие вещи:
    - поделить а на три и положить в а
    - 14. Что 14? Ничего, просто взять 14 и ничего не сделать
     
    Tomasina нравится это.
  14. Troll

    Troll Гик

    Я тоже не понимаю...
     
  15. Tomasina

    Tomasina Сушитель лампочек Модератор

    Исторически так сложилось, что в запятая служит разделителем целой и дробной части, даже в англоязычных странах. А в некоторых еще заморочнее - каждая триада числа разделяется где пробелом, где точкой, где запятой:
    [​IMG]

    Но программисты решили что именно им в коде удобнее разделять дробную часть точкой, а запятую оставить для перечисления. Так как молодежь больше пялится в/на экраны, а не в книги, то наблюдается постепенный глобальный переход от запятой к точке в качестве разделителя.
     
  16. Igor68

    Igor68 Гуру

    После таких махинаций в GCC (опечатках)... я как правило получаю "по рогам" от компилятора... и даже за меньшие провинности. Возможно, что для Arduino IDE и правила иные.
     
  17. mcureenab

    mcureenab Гуру

    Синтаксически тут все правильно. Запятая в C++ это оператор перечисления.
    A,B
    вычисляет A и возвращает B.
     
  18. Igor68

    Igor68 Гуру

    Думаю спор совсем ни к чему... не за чем. Просто быть внимательным и всё. С++ редко пользуюсь - только по необходимости, но чистым Си постояннно. Отсюда и не на "слуху" его тонкости (C++). Хотя g++ и cpp тоже строги... и там, где проскакивало для gcc для g++ приходилось изменять код... точнее тщательно пересматривать.

    хотя:
    Код (C++):

    float a = a/3,14; //переменной а будет два раза присвоено?
    //сначала a=a/3, а потом a=14? я правильно понял?
    //и в резултате после всего a=14?
     
    Компилятор конечно не телепат!
    Перестрахуйтесь... коли сомневаетесь:
    Код (C++):

    float a /= (float)(3.14); //не будет перечисления - компилятор отматерит при запятой!
     
     
    Последнее редактирование: 3 май 2017
  19. ANV

    ANV Гуру

    И кстати такие константы неприлично достопочтенным донам циферками писать
    Есть же в math.h M_PI
     
  20. Igor68

    Igor68 Гуру

    Челом бью! Ай не признали холопа своего?
    Каков был вопрос... таков и ответ, а 3.14 может они и не Число Пи имели ввиду, а вообще какая-то другая константа... думаю в запятой был вопрос.
    Извините!