C ++ проверка поплавков - PullRequest
       8

C ++ проверка поплавков

1 голос
/ 03 ноября 2011

Правильно, у меня есть массив для чисел с плавающей запятой, который хранит только 1 и 0. Я пытаюсь просто проверить / проверить, что текущий слот в массиве равен 1, он выведет небольшое сообщение о том, что это 1, в противном случае - 0. Вот мой код:

if(myArray[i] == 1)
{
    cout << "this is 1 !!!!!" << endl;
}
else
{
    cout << "this is 0 ";
}

но это просто продолжает входить в раздел "еще". т. е. только печать «это 0». Что не так (или что со мной ??: P) ??

Ответы [ 8 ]

5 голосов
/ 03 ноября 2011

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

Прочитав, вы поймете, что представление с плавающей запятой 1 не совсем целое числозначение 1. Это близко, но не совсем, и поэтому ваше условие всегда будет ложным.

Зачем вам использовать float s для хранения логических данных?Используйте массив bool с или битовый вектор.

РЕДАКТИРОВАТЬ: Я на самом деле не могу вспомнить ни одной ситуации, где (или почему) вы бы сравнили float с литералом, кто-нибудь знает что-нибудь?

3 голосов
/ 03 ноября 2011

При работе с числами с плавающей запятой вы должны программировать немного более оборонительно:

if (myArray[i] == 1) {
  cout << "this is 1\n";
} else if (myArray[i] == 0) {
  cout << "this is 0\n";
} else {
  cout << "this is something else, in particular " << myArray[i] << "\n";
}

Это должно дать вам представление о том, что происходит.

Кстати, если вы когда-либо толькохраните значения 1.0f и 0.0f в массиве, вполне нормально использовать оператор == для сравнения чисел с плавающей запятой.Вы просто должны быть уверены, что то, что вы считаете 1.0, действительно действительно 1.0.

2 голосов
/ 03 ноября 2011

Во-первых, не используйте поплавки для хранения 1 или 0.Нет смысла использовать float для хранения маленьких целых чисел.

Во-вторых, вам нужно прочитать в Что должен знать каждый специалист по компьютерам о числах с плавающей запятой. Хотя это часто будет работатьВы должны сравнить значения с плавающей запятой, взяв абсолютное значение разницы между ними и сравнив , что с некоторой маленькой сигмой (где сигма - это значение, которое имеет смысл в вашем приложении в допустимом диапазоне точности).

Если abs( x - y ) < sigma, вы можете считать их равными.

1 голос
/ 03 ноября 2011

В зависимости от того, как вы пришли к значениям в вашем массиве (т. Е. В результате вычислений), маловероятно, что вы получите точные 0 или 1 в качестве результата с плавающей запятой. В этом случае почти наверняка будет проверка, является ли float == 1 ложным.

С другой стороны, в плавающей точке IEEE точный 0 сохраняется как 0x00000000. Если это не результат вычислений, вставка 0 в ваш массив может быть полезна в качестве флага вместо хранения отдельного массива.

0 голосов
/ 03 ноября 2011

Я что-то ответил об этом здесь . Вы не можете сделать "==", чтобы сравнить float и int.

В вашем случае, возможно, число с плавающей запятой 1 на самом деле 0.9999999, которое будет усечено до 0, что означает, что вывод вашей программы уже верен.

0 голосов
/ 03 ноября 2011

Причина в том, что для поплавка невозможно точно представить 1. Поэтому ваше условие if никогда не выполняется. Единственный способ, которым вы сможете проверить на 1, - это выбрать порог и проверить, достаточно ли приближено значение с плавающей точкой:

const float threshold = 0.0001f;
if( fabs( myArray[ i ] - 1.0f ) < threshold )
{
 ...do whatever...
} 

Конечно, другой способ - просто использовать целые, если вы проверяете только целые числа, что было бы мудрее.

0 голосов
/ 03 ноября 2011

Может быть очень веская причина, по которой значение в вашем массиве с плавающей запятой слишком мало, чтобы быть равным 1.

Хотя это не чистое решение, это должно быть достаточной причиной для использования либо перечисления, либо массива bool.

if(myArray[i] > 0.9f && myArray[i] < 1.00001f)
...
...
0 голосов
/ 03 ноября 2011

Либо приведите элемент массива к int:

if ((int)myArray[i] == 1)

, либо приведите 1 к float:

if (myArray[i] == 1.0f)
...