Неверные результаты при делении

enclouder
Offline
Зарегистрирован: 22.09.2014

Здравствуйте. Подскажите, пожалуйста, где я прокололся?

Использую Arduino Uno R3, LCD HD44780

Arduino неправильно все считает!

Есть обычный пример: 

double Hotangle=45.0,ColdAngle=45.0;

if(Ratio<1.00)
  {
   ColdAngle=HotAngle * Ratio;
   lcd.clear();
   lcd.print(HotAngle);
   lcd.setCursor(7, 0);
   lcd.print(Ratio);
   delay(2000);
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("Ratio=");
   lcd.setCursor(6, 0);
   lcd.setCursor(11, 0);
   lcd.print(HotAngle);
   lcd.setCursor(0, 1);
   lcd.print(ColdAngle);
   Serial.println(ColdAngle);
   }
Так вот, Ratio выше вычисляется и равняется 0.67 (и на дисплей и в монитор выводится как результат 0.67, проверял на калькуляторе) Должно быть 45*0,67 = 30.15, у меня же все время выходит результат 30.00. Если я напишу: ColdAngle=HotAngle * 0.67 то результат получается как раз 30.15, но при выводе значения на дисплей Ratio и так равняется 0.67. К тому же, если я запишу вот так:
 
if(Ratio<1.00)
      {
        Ratio=0.67;
        ColdAngle=HotAngle * Ratio;
        lcd.print(Ratio);
      }

то результат будет равен тоже 30.15. Но опять же Ratio и так уже равно 0.67.

Подскажите, пожалуйста, в чем может быть проблема.

 

enclouder
Offline
Зарегистрирован: 22.09.2014

Прошу прощения, всю ночь не спал:

"Неверные результаты при умножении"

inspiritus
Offline
Зарегистрирован: 17.12.2012

Фокусы компилятора, оно считает, что Ratio имеет тип int.  Объявите в начале Ratio явным образом, или напишите в ифе Ratio <1.01

enclouder
Offline
Зарегистрирован: 22.09.2014

double Ratio=0.0;

Вычисление Ratio:

Ratio=(60-40)/(40-10);

Ratio=0.67;

ColdAngle=HotAngle * Ratio;

ColdAngle=45*0.67=30.15

Но у меня по прежнему результат равен 30.00, даже после изменения условия на 1.01

inspiritus
Offline
Зарегистрирован: 17.12.2012

Весь код покажите.

enclouder
Offline
Зарегистрирован: 22.09.2014
#include <IRremote.h>
#include <LiquidCrystal.h>
#include <Servo.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
int res=-1,x=0;
float HotTemp=60.0,ColdTemp=10.0,HotAngle=45.0,ColdAngle=45.0; 
int OutTemp=0;
double Ratio=0.0;
String param="";
//Servo myservo;

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(9, OUTPUT);
  analogWrite(9, 50);
  lcd.begin(16, 2);
  //myservo.attach(10);
  lcd.print("Vvedite Temp");
}

void loop() 
{  
  delay(700);
  if (irrecv.decode(&results)) 
  {
    if(results.value>100) results.value-=2048;
    res=results.value;

    if(res!=24)
    {
      param+=res;
      lcd.setCursor(0, 1);
      lcd.print(param);
    }  else
         {
           if(param.toInt()>HotTemp)
             {
               lcd.clear();
               lcd.setCursor(0, 0);
               lcd.print("Temp must be<Ht");
               param="";
               delay(2000);
               lcd.clear();
               lcd.print("Vvedite Temp");
             } else
                 {
                   OutTemp=param.toInt();
                   Ratio=(HotTemp-OutTemp)/(OutTemp-ColdTemp);
                   lcd.clear();
                   lcd.print("Ratio=");
                   lcd.setCursor(6, 0);
                   lcd.print(Ratio);
                   x=1;
                   Serial.println(Ratio);
                   delay(2000);
                 }
         }
    if(x==1)
    {
      if(Ratio>1.00)
      {
        HotAngle=ColdAngle / Ratio;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Ratio=");
        lcd.setCursor(6, 0);
        lcd.print(Ratio);
        lcd.setCursor(11, 0);
        lcd.print(HotAngle);
        lcd.setCursor(0, 1);
        lcd.print(ColdAngle);
        Serial.println(HotAngle);
        x=2;
      }
      if(Ratio<1.00)
      { 
        ColdAngle=HotAngle * Ratio;
        lcd.clear();
        lcd.print(HotAngle);
        lcd.setCursor(7, 0);
        lcd.print(Ratio);
        delay(2000);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Ratio=");
        lcd.setCursor(6, 0);
        lcd.print(Ratio);
        lcd.setCursor(11, 0);
        lcd.print(HotAngle);
        lcd.setCursor(0, 1);
        lcd.print(ColdAngle);
        x=2;
      }
    }
            
    if(results.value==19)
    {
      lcd.clear();
      lcd.setCursor(0, 0);
    }
  }
  irrecv.resume();  
}

Ввожу постоянно значение 40.

Ratio=(60-40)/(40-10)=20/30=0.67

Во всех выводах значения переменной (lcd.print, Serial.println) Ratio = 0.67 Тоесть считает правильно, но при операции: ColdAngle=HotAngle * Ratio; почему то расчет идет не верный, хотя при выводе значения каждой переменной, результат верный.

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Может стоит попробовать тип данных float ? Может его компилятор нормально обрабатывает.

вычисления принудительно проводя с типом float

float Ratio = (float)(60-40)/(float)(40-10);

 

enclouder
Offline
Зарегистрирован: 22.09.2014

NeiroN пишет:

Может стоит попробовать тип данных float ? Может его компилятор нормально обрабатывает.

вычисления принудительно проводя с типом float

float Ratio = (float)(60-40)/(float)(40-10);

 

Объявил все как float, результат тот же

Как такое вообще может быть?) Уже голова лопается, весь день на это потратил и не могу понять в чем проблема. Если ввожу вместо сорока - 44, то уравнение приобретает вид: Ratio=(60-44)/(44-10)=16/34=0.47

0.47 считает правильно, но опять при вычислении ColdAngle=HotAngle * Ratio; (ColdAngle=45*0.47) ошибка в результате: ответ по факту 21.15, ответ в переменной: 21.18

 

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

надо будет написать прогу калькулятор для проверки. Еще не проверял как микроконтроллер работает с дробными значениями.

enclouder
Offline
Зарегистрирован: 22.09.2014

Создал новый скетч для проверки и записал все следующим образом:

  float HotTemp=60.0,OutTemp=40.0,ColdTemp=10.0;
  float Ratio=(float)(HotTemp-OutTemp)/(float)(OutTemp-ColdTemp);
  Ratio=45*Ratio;
  Serial.println(Ratio);

Тут все тоже самое. Ratio=30.00

Что делать?

 

vdk
Offline
Зарегистрирован: 14.04.2013

Если изменить вывод на

Serial.println(Ratio*100);

то что покажет?

enclouder
Offline
Зарегистрирован: 22.09.2014

vdk пишет:

Если изменить вывод на

Serial.println(Ratio*100);

то что покажет?

3000.00
Что интересно:
Прорешал все на калькуляторе:
(60-40)/(40-10) = 0.666666666667 
0.666666666667*45 = 30.000000000015 
30.000000000015*100 = 3000.0000000015 
Но при выводе результатов, Ratio равен не 0.666666666667, а округляет до 0.67
А при умножении 45*Ratio за значение переменной берется не округленное число, а 0.666666666667
Поэтому и результат такой.
Получаются разные результаты. Как заставить компилятор умножать то число, которое он мне выдает уже округленным (0.67 Serial.println(Ratio))?
 
vdk
Offline
Зарегистрирован: 14.04.2013
inspiritus
Offline
Зарегистрирован: 17.12.2012

Так чем все закончилось ?

ourlive
Offline
Зарегистрирован: 26.05.2012

Хотите чтобы умножалось округленное число, так округлите его сначала как положено до нужного числа знаков.

JollyBiber
JollyBiber аватар
Offline
Зарегистрирован: 08.05.2012

Убийца - мосфет, ну или ДОСААФ. Мы все прекрасно знаем что даже взрослые процессоры с длинными цифрами после запятой имеет определенные трудности. Кто не верит - в гугль.

Бублик
Бублик аватар
Offline
Зарегистрирован: 05.12.2012
ColdAngle=45.0*0.67