Сравнение одинаковых значений 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) > это зависит от точности, которая вам нужна.