Привет Я делаю вычисления времени выполнения операции и округляю до 2 знаков Код (Text): ROUND((SUM( UNIX_TIMESTAMP(`dateFinish`) - UNIX_TIMESTAMP(`dateStart`) )/60),2) AS calcTimerMinute Дальше записываю в тип FLOAT в базу и дальше делаю проверку(timerMinute - сохраненное вычисленное значение в БД) Код (Text): HAVING calcTimerMinute!=`timerMinute` OR `timerMinute` IS NULL Визуально одинаковые числа не сравниваются MYSQL видно какая-то проблема в типах, о которой я не знаю/понимаю. Понимаю - что надо достаточно также mt.timerMinute обернуть в ROUND и все будет ок - но это лишние операции, хочется понять смысл - почему эти два визуально одинаковых числах не сравниваются? Благодарю
@Chushkin я читал доку и вот такие статьи https://leehblue.com/match-a-float-in-mysql/ Я понял что числа хранятся с большим кол-вом знаков после запятой и поэтому прямое = не прокатывает. Тут больше вопрос как правильно? Round делать? Cast? Ведь преобразование при выполнении запросах - это нагрузно. Может если мне до сотен тысяч копеек не важно значение, лучше использовать decimal 10,2? Именно хочется совет по Вашему опыту услышать
>> я читал доку и вот такие статьи >> ... >> Тут больше вопрос как правильно? >> Round делать? Cast? Плохо читал. Прочти ещё раз "как правильно сравнивать вещественные числа". Читай до тех пор, пока не дойдёт. >> Может ... decimal 10,2? Для твоей задачи - да. К decimal можно применять оператор "=".
Значения float неточные. А функция round() возвразвращает float. Поэтому огругляй - не округляй, точности не добавится ) Decimal это другое дело, это всё равно что целое, только отмасштабированное на указанное число десятичных знаков. Жаль что в PHP нет достойного встроенного аналога decimal. Поэтому там где важна точность, приходится работать с int или string + специальные классы. Гуглить: "почему float неточный"
@artoodetoo благодарю! Я единственное не могу понять, а зачем float? Если он не точный в каких случаях его стоит применять? Ведь получается данные записанные в float придется всегда думать как одинаково округлять для проверки checksum?
float позволяет работать с огромными числами. Или с числами, где ты не знаешь заранее какого они будут порядка. Надо только иметь в виду, что текстовое представление float не всегда точно отражает их реальное состояние. Погрешность очень возможна. И ещё раз: округление (round) не гарантирует что сравнение станет точным!!! Числа с плавающей запятой надо сравнивать с допустимой погрешностью. Типа так: PHP: // нас устроит точность до третьего знака после запятой define('EPSILON', 0.001); // . . . // Числа "примерно равны" if (abs($x - $y) < EPSILON) { // . . . } --- Добавлено --- Поясню за текстовое представление и точность. Как ты думаешь, чему равно это выражение: 0.1 + 0.2 ? Код (Text): $ php -r 'var_dump(0.1 + 0.2);' float(0.3) как бы всё в порядке... или таки нет? Код (Text): $ php -r 'var_dump(0.1 + 0.2 == 0.3);' bool(false) --- Добавлено --- Разница с текстовым представлением всё-таки есть. Сумма немного не равна 0.3 Код (Text): $ php -r 'var_dump(abs((0.1 + 0.2) - 0.3));' float(5.5511151231258E-17) не равна на очень маленькую величину: порядка 10 в минус 17-й --- Добавлено --- Есть такая настройка PHP precision. Она отвечает за то как числа с плавающей запятой отображаются в текстовом виде. На точность математических вычислений она не влияет, только на вывод (т.е. echo и т.п. операции). Я нашел такой показательный пример с round: PHP: $php -a php > echo ini_get("precision"); 14// default php > echo round(9.7752,2); 9.78 php > echo ini_set("precision",16); 14 php > echo round(9.7752,2); 9.779999999999999
Быстрее считается, к примеру. Не везде нужна такая точность, как в случае работы с суммами денег, например. Decimal - это вообще не числа, строго говоря, а строки (по одному символу на каждый порядок). И арифметические операции с ними делаются, насколько я знаю, так же как мы в школе складывали/вычитали столбиком.