Сравнение вещественных чисел

В связи с текущей возней с EFCore пришлось «освежить» понимание множества базовых вещей.

Одна из этих вещей — вещественные числа.

Задача

1. Добавляем запись с FLOAT колонкой.
2. Выбираем эту запись и сравниваем значение FLOAT колонки с ожидаемым значением. Ожидаемое float-значение передается в запросе в виде текста.

Выглядит это как-то так:

 const string c_valueSource="-3.40282347E+38";
 const float c_valueTarget=float.MinValue; //-3.40282347E+38

 System.Int64? testID=Helper__InsertRow(db,c_valueSource,c_valueTarget);

 var recs=db.testTable.Where(r => (float)(object)c_valueSource==r.COL_TARGET && r.TEST_ID==testID);

В конечном итоге, на сервер уезжает запрос вида:

SELECT "t"."TEST_ID", "t"."COL_VARCHAR_128", "t"."COL2_FLOAT"
FROM "TEST_MODIFY_ROW2" AS "t"
WHERE (-3.40282347E+38 = "t"."COL2_FLOAT") AND ("t"."TEST_ID" = CAST(:__testID_0 AS BIGINT))

То есть, вроде все путем. Но сервер возвращает 0 записей.

Почему, Карл?

Потому что сервер (FB3) приведет левую и правую часть к double и будет сравнивать значение -3.4028234700000002e+38 с -3.4028234663852886e+38.

То есть, литера «-3.40282347E+38» преобразуется в более менее похожее значение «-3.4028234700000002e+38», а вот значение колонки (float.MinValue) преобразуется в -3.4028234663852886e+38.

А вот если ожидаемое значение передать в виде float-параметра, то все нормально — запрос возвращает нашу запись.

 const string c_valueSource="-3.40282347E+38";
 const float c_valueTarget=float.MinValue;

 System.Int64? testID=Helper__InsertRow(db,c_valueSource,c_valueTarget);

 float vv=c_valueSource;

 var recs=db.testTable.Where(r => (float)(object)vv==r.COL_TARGET && r.TEST_ID==testID);

Потому что, Карл, сервер сравнивает float-значения как есть, без каких-либо преобразований.

Вот такая вот трава ботва.

PS. Пока писал эту заметку, ласково вспоминал разработчиков WordPress, которые в своем обновлении 5.7 сломали «preview» и вставку картинок.

Leave a Comment