За последние 24 часа нас посетил 22741 программист и 1259 роботов. Сейчас ищут 722 программиста ...

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

Тема в разделе "MySQL", создана пользователем IvanKut, 11 июл 2020.

  1. IvanKut

    IvanKut Активный пользователь

    С нами с:
    27 июл 2018
    Сообщения:
    258
    Симпатии:
    0
    Привет
    Я делаю вычисления времени выполнения операции и округляю до 2 знаков
    Код (Text):
    1. ROUND((SUM(
    2.     UNIX_TIMESTAMP(`dateFinish`) - UNIX_TIMESTAMP(`dateStart`)
    3.   )/60),2) AS calcTimerMinute
    Дальше записываю в тип FLOAT в базу и дальше делаю проверку(timerMinute - сохраненное вычисленное значение в БД)
    Код (Text):
    1. HAVING calcTimerMinute!=`timerMinute` OR `timerMinute` IS NULL
    Визуально одинаковые числа не сравниваются MYSQL видно какая-то проблема в типах, о которой я не знаю/понимаю.
    Понимаю - что надо достаточно также mt.timerMinute обернуть в ROUND и все будет ок - но это лишние операции, хочется понять смысл - почему эти два визуально одинаковых числах не сравниваются?
    Благодарю
    [​IMG]
     
  2. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Изучи правила сравнения вещественных чисел и будет тебе счастье.
     
  3. IvanKut

    IvanKut Активный пользователь

    С нами с:
    27 июл 2018
    Сообщения:
    258
    Симпатии:
    0
    @Chushkin я читал доку и вот такие статьи
    https://leehblue.com/match-a-float-in-mysql/
    Я понял что числа хранятся с большим кол-вом знаков после запятой и поэтому прямое = не прокатывает.

    Тут больше вопрос как правильно?
    Round делать? Cast?
    Ведь преобразование при выполнении запросах - это нагрузно.

    Может если мне до сотен тысяч копеек не важно значение, лучше использовать decimal 10,2?

    Именно хочется совет по Вашему опыту услышать
     
  4. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    >> я читал доку и вот такие статьи
    >> ...
    >> Тут больше вопрос как правильно?
    >> Round делать? Cast?

    Плохо читал.
    Прочти ещё раз "как правильно сравнивать вещественные числа". Читай до тех пор, пока не дойдёт.

    >> Может ... decimal 10,2?

    Для твоей задачи - да.
    К decimal можно применять оператор "=".
     
  5. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Значения float неточные. А функция round() возвразвращает float. Поэтому огругляй - не округляй, точности не добавится )
    Decimal это другое дело, это всё равно что целое, только отмасштабированное на указанное число десятичных знаков. Жаль что в PHP нет достойного встроенного аналога decimal. Поэтому там где важна точность, приходится работать с int или string + специальные классы.

    Гуглить: "почему float неточный"
     
  6. IvanKut

    IvanKut Активный пользователь

    С нами с:
    27 июл 2018
    Сообщения:
    258
    Симпатии:
    0
    @artoodetoo благодарю! Я единственное не могу понять, а зачем float? Если он не точный в каких случаях его стоит применять?
    Ведь получается данные записанные в float придется всегда думать как одинаково округлять для проверки checksum?
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    float позволяет работать с огромными числами. Или с числами, где ты не знаешь заранее какого они будут порядка. Надо только иметь в виду, что текстовое представление float не всегда точно отражает их реальное состояние. Погрешность очень возможна.

    И ещё раз: округление (round) не гарантирует что сравнение станет точным!!! Числа с плавающей запятой надо сравнивать с допустимой погрешностью. Типа так:
    PHP:
    1. // нас устроит точность до третьего знака после запятой
    2. define('EPSILON', 0.001);
    3. // . . .
    4. // Числа "примерно равны"
    5. if (abs($x - $y) < EPSILON) {
    6.   // . . .
    7. }
    --- Добавлено ---
    Поясню за текстовое представление и точность.
    Как ты думаешь, чему равно это выражение: 0.1 + 0.2 ?
    Код (Text):
    1.  
    2. $ php -r 'var_dump(0.1 + 0.2);'
    3. float(0.3)
    как бы всё в порядке... или таки нет? :)
    Код (Text):
    1.  
    2. $ php -r 'var_dump(0.1 + 0.2 == 0.3);'
    3. bool(false)
    --- Добавлено ---
    Разница с текстовым представлением всё-таки есть. Сумма немного не равна 0.3
    Код (Text):
    1.  
    2. $ php -r 'var_dump(abs((0.1 + 0.2) - 0.3));'
    3. float(5.5511151231258E-17)
    не равна на очень маленькую величину: порядка 10 в минус 17-й
    --- Добавлено ---
    Есть такая настройка PHP precision. Она отвечает за то как числа с плавающей запятой отображаются в текстовом виде. На точность математических вычислений она не влияет, только на вывод (т.е. echo и т.п. операции). Я нашел такой показательный пример с round:
    PHP:
    1. $php -a
    2. php > echo ini_get("precision");
    3. 14// default
    4. php > echo round(9.7752,2);
    5. 9.78
    6.  
    7. php > echo ini_set("precision",16);
    8. 14
    9. php > echo round(9.7752,2);
    10. 9.779999999999999
     
  8. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Быстрее считается, к примеру. Не везде нужна такая точность, как в случае работы с суммами денег, например.

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