Вопрос по if else

Тема в разделе "Флудилка", создана пользователем Felix102, 16 апр 2019.

  1. Felix102

    Felix102 Нерд

    Почему данный код выдает False, если f=0.1 ?
     

    Вложения:

  2. А что по вашему должно быть?
     
  3. KindMan

    KindMan Гик

    Почитайте про ошибки округления плавающей точки. Используйте »= и «= в if при работе с такими числами. Тут почитайте
     
    Daniil нравится это.
  4. Daniil

    Daniil Гуру

    Разрядность мк конечна => не все числа могут быть записаны.
    Screenshot_2019-04-16-22-54-47-799_com.blogspot.kcmapps.compudata.png
    смотрите снизу подписи
     
  5. DIYMan

    DIYMan Гуру

    Потому что числа с плавающей точкой так не сравнивают на совпадение, от слова "совсем".
     
  6. 0.1 - это литерал типа double
    0.1f - это литерал типа float

    На строке 4 объявление переменной типа float и выполнение присваивания значения, при этом для значения double выполняется приведение типа.
    На строке 7 вызываете оператор if для дух значений с разными типами, компилятор приводит зачем-то тип float к типу double и вызывает оператор сравнения.

    Вы можете помочь компилятору решить эту сложную задачу ;)
    Код (Text):

    int main() {
      float f = 0.1;
      std::cout << "float value: " << f << std::endl;

      std::cout << " (f == 0.1) ";
      if (f == 0.1) std::cout << "true" << std::endl;
      else std::cout << "false" << std::endl;

      std::cout << " ((double)f == 0.1) ";
      if ((double)f == 0.1) std::cout << "true" << std::endl;
      else std::cout << "false" << std::endl;

      std::cout << " (f == 0.1f) ";
      if (f == 0.1f) std::cout << "true" << std::endl;
      else std::cout << "false" << std::endl;

      std::cout << " (f == (float)0.1) ";
      if (f == (float)0.1) std::cout << "true" << std::endl;
      else std::cout << "false" << std::endl;

      return 0;
    }
     
    Код (Text):

    float value: 0.1
    (f == 0.1) false
    ((double)f == 0.1) false
    (f == 0.1f) true
    (f == (float)0.1) true
     
     
  7. Felix102

    Felix102 Нерд

    Спасибо за ответ, вот только непонятно почему ((double)f == 0.1) ?
     
  8. Из за округления, в этом вся печаль типов двойной точности.
    В переменной f сохранен float, из него делаем грубую поделку, похожую на 0.1 и сравниваем с кошерным даблом от 0.1
     
  9. DIYMan

    DIYMan Гуру

    Потому что Алексей написал вырожденный пример, где сравнение ВЫЧИСЛЯЕТСЯ оптимизатором. В реале сравнивать вещественные числа на равенство надо так, и только так:
    Код (C++):
    if (fabs(a-b) < eps) { равны. }
    Короче, если не вдаваться в подробности, единственно верный вариант сравнения на равенство - в первом абзаце этого поста, остальное - от лукавого, и может привести к некислой попоболи в некоторых случаях.

    Правка: удалил сентенцию про платформозависимость, ибо есть IEEE. Хотя, емнип, на некоторых платформах AVR double 32х-битный (sic!).
     
    Последнее редактирование: 16 апр 2019
    ИгорьК, DetSimen и Daniil нравится это.
  10. parovoZZ

    parovoZZ Гуру

    В том же IAR для того же AVR double можно настроить как 64 бита. Так что от самой платформы зависимости нет. Есть зависимость от компилятора.
     
    DetSimen и DIYMan нравится это.
  11. DIYMan

    DIYMan Гуру

    Да, пробежался - в GCC действительно для совместимости по умолчанию 32-х битный double в настройках случается.

    Спс за поправку.
     
  12. Да все верно было, так оно и есть.
    float представлен в памяти по стандарту ieee754 и использует 32 бита, double как правило тоже по этому стандарту, только совсем не обязательно что на double отведено тоже 32, зачастую отводится 64.
     
    DIYMan нравится это.