Сравнение вещественных чисел
В связи с текущей возней с 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» и вставку картинок.