работа с числами float

AlexBajdin59rus
Offline
Зарегистрирован: 17.12.2019

Здравствуйте! У меня возникла некоторая проблема с правильностью вычислений. Прилагаю код, на переменные не смотрите.

#define delitel_T1_1 244.140625

uint16_t cnt_rpm;
float r, f, f1, f2;

void setup() 
{ Serial.begin(9600);
  r = 0.1;
  f = 0.0;
  f1 = r * 200.0;             // 200; 
  f2 = delitel_T1_1 / f2;     // 1,22;
  
  while (f2 > 1.0)
      {r = r + 0.1;              
       f2 = r * 200.0;             
       f2 = delitel_T1_1 / f2;   
       Serial.println(" r = " + String(r) + "; ");      
       }
  //r = 1.3;     
// ЗДЕСЬ r РАВНО 1.30  
  Serial.println("r = " + String(r) + " после расчётов");      

// ЗДЕСЬ f РАВНО 18.00     ВСЁ ПРАВИЛЬНО
  f = ((3.0 - r + 0.1) * 10.0);
  Serial.println("f = " + String(f) + "; ");      // f = 18.00

// ПОЧЕМУ ЗДЕСЬ CNT_RPM = 17 .... ???  НЕПРАВИЛЬНО!!!!!!!
  cnt_rpm = int(f);
  Serial.println("cnt_rpm = " + String(cnt_rpm) + "; ");    // 17

// ПОЧЕМУ ЗДЕСЬ ТОЖЕ CNT_RPM = 17 .... ???    НЕПРАВИЛЬНО!!!!!!!
  cnt_rpm = int((3.0 - r + 0.1) * 10.0);
  Serial.println("cnt_rpm = " + String(cnt_rpm) + "; ");
}

void loop() 
{
}

Вся загвоздка для меня после цикла

  while (f2 > 1.0)
      {r = r + 0.1;              
       f2 = r * 200.0;             
       f2 = delitel_T1_1 / f2;   
       Serial.println(" r = " + String(r) + "; ");      
       }

В цикле переменная r увеличивается с шагом 0,1 , происходит проверка переменной f2 на больше, чем 1. Итог - как только f2 стало меньше 1.0, переменная r (как должно быть для меня) принимает значение 1.30! Далее нужно вычислить переменную cnt_rpm, которая должна быть 18, но она у меня принимает значение 17.... CNT_RPM вычисляю 2-мя способами (строки 27 - 33). 

Самое главное, почему, когда я раскомментирую строку 19 (чем дублирую значение переменной r после цикла)

  //r = 1.3;     

, тогда CNT_RPM принимает правильное значение (18) ...

Кто может подсказать в чем подвох.

 

Feofan
Offline
Зарегистрирован: 28.05.2017
В 24-й строке вычисления равны 17.9999980000.
 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Просто погрешность накопилась. Вот с чего Вы взяли, что здесь неправильно?

  Serial.println("f = " + String(f) + "; ");      // f = 18.00

// ПОЧЕМУ ЗДЕСЬ CNT_RPM = 17 .... ???  НЕПРАВИЛЬНО!!!!!!!
  cnt_rpm = int(f);
  Serial.println("cnt_rpm = " + String(cnt_rpm) + "; ");    // 17

напечатайте в первой строке не с двумя знаками, а с 6 или 8 и увидите, что там она равна не 18, а, скажем 17,999999. Ну, а при преобразовании к int, таком, как в строке №4, дробная часть просто отбрасывается - вот и получается 17. Всё нормально.

У Вас в коде в строках №№13-18 крайне неудачно вычисляется r (Вы её итеративно вычисляете, чего следует всячески избегать) вот и накопилась ошибка. Вот здесь есть сравнение итеративного вычисления (такого, как у Вас) и более правильного - посмотрите, сравните накопленные ошибки.

С флоатом вообще нужно аккуратно работать и понимать как он устроен, а то, при неаккуратной работе, можно и при вычитании чисел, отличающихся на 1, получить результат больше сотни (см., например).

AlexBajdin59rus
Offline
Зарегистрирован: 17.12.2019

Да, СПАСИБО, разъяснили на пальцах! Ведь читал же у AlexaGiver'a про осторожность с float'ом. Но вот когда дело до практики, тогда и учимся все мы на ошибках! Евгений, спасибо за предоставленные статьи, очень полезно!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AlexBajdin59rus пишет:

Ведь читал же у AlexaGiver'a ...

Тогда не удивительно :-)

sadman41
Offline
Зарегистрирован: 19.10.2016

ЕвгенийП пишет:

AlexBajdin59rus пишет:

Ведь читал же у AlexaGiver'a ...

Тогда не удивительно :-)

Гувер прям дышит в затылок Петровичу...

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

AlexBajdin59rus пишет:

Ведь читал же у AlexaGiver'a ...

Тогда не удивительно :-)

Лана, лана, у него тоже полезные весчи встречаются (мошт спертые), но узнал от него. Вот на днях, усб тестер заказал себе, для контроля аккумуляторов литиевых. Вроде оно и на поверхности, а тож.((((

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:
у него тоже полезные весчи встречаются (мошт спертые),
Так никто ж не спорит. Но, у него также встречается очень много "городских легенд и откровенных суеверий", поэтому, когда человек позиционирует себя его учеником ... :-)

vvadim
Offline
Зарегистрирован: 23.05.2012

привлекательность Гайвера основана на "щас по-быстрому соберём девайс из гавна и палок и без всяких знаний".

и на это снят видосик и оно работает. безпроигрышный ход. ну и нельзя сказать что бездельник - времени и сил на всю эту деятельность он тратит до фига.

кроме того он юн и это ещё больше привлекает к нему таких же "сваять быстренько потому что очень нужно"

AlexBajdin59rus
Offline
Зарегистрирован: 17.12.2019

Вопросик! Есть такой код

#define MIN_SPEED 0,1


  f = MIN_SPEED * 200.0;      // 0.1 * 200 = 0 !!!!!!!!!!!!!!!!!!!!!!!! 
  Serial.println(" f = " + String(f, 8) + ";    ");

  f = 0.1 * 200.0;      // 0.1 * 200 = 20 
  Serial.println(" f = " + String(f, 8) + ";    ");

У меня много где есть MIN_SPEED, и я его хочу вставлять где мне нужно, как мне правильно делать вычисление в 4 строке? Не уследить просто за числом 0.1

kalapanga
Offline
Зарегистрирован: 23.10.2016

0,1 это не 0.1

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AlexBajdin59rus пишет:
как мне правильно делать вычисление в 4 строке?
А чё гивер говорит? Вы на https://community.alexgyver.ru/ спрашивали?

Ну, про ошибку в константе Вам уже сказали.

AlexBajdin59rus
Offline
Зарегистрирован: 17.12.2019

Еще раз помогли мне исправить ошибку, спасибо!