Сравнение одинаковых значений Float в C [дубликат]
Возможные Дубликаты:
странный выход по сравнению с float с float literal
когда я пытаюсь сравнить 2 одинаковые float значения он не печатает "равные значения" в следующем коде:
void main()
{
    float a = 0.7;
    clrscr();
    if (a < 0.7)
        printf("value :  %f",a);
    else if (a == 0.7)
        printf("equal values");
    else
        printf("hello");
    getch();
}
спасибо заранее.
7 ответов
хотя многие люди скажут вам всегда сравнивать числа с плавающей запятой с Эпсилоном (и это обычно хорошая идея, хотя это должен быть процент сравниваемых значений, а не фиксированное значение), это на самом деле не нужно здесь, так как вы используете константы.
код конкретные проблема вот в чем:
float a = 0.7;
использует двойной постоянный 0.7 создать один точности число (потери точности) при:
if (a == 0.7)
сравним два двойной точность чисел (a сначала продвигали).
точность, которая была потеряна при повороте double 0.7 в поплавковой a не восстанавливается при продвижении a обратно в дубль.
если вы измените все эти 0.7 значения 0.7f (заставить плавать, а не двойной), или если вы просто сделать a двойной, он будет работать нормально - я редко пользуюсь float в настоящее время, если у меня есть массив из них и нужно экономить пространство.
вы можете увидеть это в действии с:
#include <stdio.h>
int main (void){
    float f = 0.7;    // double converted to float
    double d1 = 0.7;  // double kept as double
    double d2 = f;    // float converted back to double
    printf ("double:            %.30f\n", d1);
    printf ("double from float: %.30f\n", d2);
    return 0;
}
который выведет что-то вроде (слегка измененное, чтобы показать разницу):
double:            0.6999999|99999999955591079014994
double from float: 0.6999999|88079071044921875000000
                            \_ different beyond here.
число с плавающей запятой не то, что вы думаете: вот два источника с дополнительной информацией:Что Каждый Компьютерщик Должен Знать Об Арифметике С Плавающей Запятой и Руководство С Плавающей Запятой.
короткий ответ заключается в том, что из-за способа представления чисел с плавающей запятой вы не можете выполнить базовое сравнение или арифметику и ожидать, что это сработает.
вы сравниваете приближение с одной точностью 0,7 с приближением с двойной точностью. Чтобы получить ожидаемый результат, вы должны использовать:
if(a == 0.7f) // check a is exactly 0.7f
обратите внимание, что из-за ошибок представления и округления он может быть очень маловероятным, чтобы когда-либо получить точно 0.7 f от любой операции. В общем, вы должны проверить, если fabs(a-0.7) - Это достаточно близко к 0.
Не забывайте, что точное значение 0.7 f на самом деле не 0.7, но немного ниже:
0.7f = 0.699999988079071044921875
точное значение представления двойной точности 0,7 является лучшим приближением, но все же не совсем 0,7:
0.7d = 0.6999999999999999555910790149937383830547332763671875
a Это float; 0.7 - значение типа double.
сравнение между ними требует преобразования. Компилятор преобразует float значение double значение ... и значение, полученное в результате преобразования float в double, не совпадает со значением, полученным в результате преобразования компилятором строки текста (исходного кода) в double.
но никогда не сравнивайте числа с плавающей точкой (float, double или long double) С ==.
вы могли бы прочитать "Что Каждый Программист Должен Знать Об Арифметике С Плавающей Запятой".
числа с плавающей запятой не должны сравниваться с оператором"==".
вместо сравнения чисел float с оператором "= = " вы можете использовать такую функцию :
 //compares if the float f1 is equal with f2 and returns 1 if true and 0 if false
 int compare_float(float f1, float f2)
 {
  float precision = 0.00001;
  if (((f1 - precision) < f2) && 
      ((f1 + precision) > f2))
   {
    return 1;
   }
  else
   {
    return 0;
   }
 }
отсутствие абсолютной точности в поплавках затрудняет тривиальные сравнения, чем для целых чисел. См.этой страница по сравнению поплавков в C. В частности, один фрагмент кода, поднятый оттуда, демонстрирует "обходной путь" к этой проблеме:
bool AlmostEqual2sComplement(float A, float B, int maxUlps)
{
    // Make sure maxUlps is non-negative and small enough that the
    // default NAN won't compare as equal to anything.
    assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
    int aInt = *(int*)&A;
    // Make aInt lexicographically ordered as a twos-complement int
    if (aInt < 0)
        aInt = 0x80000000 - aInt;
    // Make bInt lexicographically ordered as a twos-complement int
    int bInt = *(int*)&B;
    if (bInt < 0)
        bInt = 0x80000000 - bInt;
    int intDiff = abs(aInt - bInt);
    if (intDiff <= maxUlps)
        return true;
    return false;
}
простым и распространенным обходным путем является предоставление epsilon кода следующим образом:
if (fabs(result - expectedResult) < 0.00001)
это по существу проверяет разницу между значениями в пределах порога. Посмотреть связанная статья что касается того, почему это не всегда оптимально, хотя:)
еще одна статья в значительной степени является стандартом де-факто того, что связано с тем, когда люди спрашивают о поплавках на SO.
Если вам нужно сравнить a С 0.7 чем 
if( fabs(a-0.7) < 0.00001 )
  //your code
здесь 0.00001 можно изменить на меньше (например, 0.00000001) или больше (например, 0.0001) > это зависит от точности, которая вам нужна.
