ФорумПрограммированиеPHP для идиотов → Хитрое определение количества дней в месяце

Хитрое определение количества дней в месяце

  • zaxar

    Сообщения: 33 Репутация: N Группа: Кто попало

    Spritz Авг. 26, 2014, 3:33 п.п.

    Привет. Давно не виделись. Много лет программирую на PHP, знаю язык довольно неплохо. Практически любую задачу в состоянии спроектировать, салгоритмировать и выполнить. Всегда считал, что знаю язык досконально. Однако следующий весьма простенький скрипт заставил меня смотреть на него, как баран смотрит на новые ворота.

    Скрипт со 100-процентной точностью определяет и выводит количество дней в заданном месяце заданного года.

    <?
    $m=8; $y=2014; //ДЛЯ ПРИМЕРА - АВГУСТ 2014
    echo (31-(($m-1)%7%2)-((($m==2)<<!!($y%4))));
    ?>


    Профи, объясните кто-нибудь пошагово, как работает это чудовище?

    Спасибо.
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Авг. 26, 2014, 3:35 п.п., спустя 1 минуту 56 секунд

    а что тут объяснять?

    прикольно ктото извратился) даж високосные учел судя по последним скобкам :D

    Сапожник без сапог
  • vasa_c

    Сообщения: 3131 Репутация: N Группа: в ухо

    Spritz Авг. 26, 2014, 3:36 п.п., спустя 1 минуту 24 секунды

    $m=2; $y=1900;
    >29
    неправильно
  • zaxar

    Сообщения: 33 Репутация: N Группа: Кто попало

    Spritz Авг. 26, 2014, 3:54 п.п., спустя 17 минут 45 секунд

    $m=2; $y=1900;
    >29
    неправильно


    Смотря где.
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 4:33 п.п., спустя 39 минут 16 секунд

    Смотря где.


    В григорианском календаре, очевидно.

    Спустя 144 сек.

    echo (31-(($m-1)%7%2)-((($m==2)<<(!!($y%4)&!($y%100)||!!($y%400)))));
    не всё полезно, что в swap полезло
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Авг. 26, 2014, 4:48 п.п., спустя 14 минут 30 секунд

    да вы ебанутые не иначе :D

    перл тут развели

    Сапожник без сапог
  • zaxar

    Сообщения: 33 Репутация: N Группа: Кто попало

    Spritz Авг. 26, 2014, 4:57 п.п., спустя 9 минут 35 секунд

    Можно условно считать, что изначальный скрипт был написан для России :) А Россия перешла на григорианский календарь в феврале 1918. До этой даты наш календарь был юлианский. Там 29 февраля 1900 вполне себе существовало. И в этот день даже происходили какие-то события, освещенные в прессе, например, 29 февраля 1900 года состоялась официальная закладка крейсера "Новик".

    Ну это ладно. Что в скрипте делает !!, << и пр. Туговато у меня с побитовыми операциями. Да и !! - вообще в мануале не нашел
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Авг. 26, 2014, 5:03 п.п., спустя 5 минут 19 секунд

    @zaxar, !! это не побитовая операция, это двойное отрицание

    в данной ситуации нужно чтобы привести все значения больше 1го к 1, а 0 к 0. некий "флажок".

    @dude /# php -r 'var_dump(!!0);'

    bool(false)

    @dude /# php -r 'var_dump(!!1);'

    bool(true)

    @dude /# php -r 'var_dump(!!2);'

    bool(true)

    @dude /# php -r 'var_dump(!!3);'

    bool(true)

    Сапожник без сапог
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 5:25 п.п., спустя 21 минуту 53 секунды

    $x<<1 - это сдвинуть на 1 бит влево, т.е. умножить на 2
    $m==2 - для февраля равно 1, 1<<1 равно 2, 1<<0 равно 1. Т.е. для високосного года вычитается 1 день, для невисокосного вычитается 2

    php -a или eval с var_dump тебе в помощь
    не всё полезно, что в swap полезло
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 5:32 п.п., спустя 7 минут 33 секунды

    битовые сдвиги

    число 16755285 в битовой форме записано например так
    00000000 11111111 10101010 01010101

    16755285 << 1 (сдвиг влево) будет выглядеть как
    00000001 11111111 01010100 10101010

    16755285 << 2 будет выглядеть как
    00000011 11111110 10101001 01010100

    т.е. в нижние биты справа дописываются нули, верхние биты теряются

    сдвиг вправо аналогично
    16755285 >> 2 будет выглядеть как
    00000000 00111111 11101010 10010101

    то есть это умножение и деление на степени двойки

    эта операция не учитывает знак, хранимый в верхнем бите. то есть, после << и >> число может изменить знак


    Спустя 49 сек.

    бже, что с парсером
    не всё полезно, что в swap полезло
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 5:42 п.п., спустя 9 минут 44 секунды

    похапэ бывает 32 и 64 битное

    это значит, что число 16755285 может быть записано как
    00000000 11111111 10101010 01010101
    или как
    00000000 00000000 00000000 00000000 00000000 11111111 10101010 01010101
    при shl (shift left, <<) это имеет значение
    поэтому при сдвиге влево нужно точно знать, в какой разрядности работаем
    не всё полезно, что в swap полезло
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 5:49 п.п., спустя 6 минут 52 секунды

    как узнать разрядность с помощью этой возможности.

    сперва я хотел посоветовать сделать shl на большое количество знаков, но обнаружилось, что shl 64 (на моей 64й похапэ) даёт то же что shl 0.

    я на самом деле не знаю, как это использовать, и по-моему это какой-то глюк.
    за это я не люблю похапэ - за непредсказуемость.
    поэтому будем делать shl на количество бит меньшее 32, чтобы наверняка.

    1<<31 в теории должно дать число
    10000000 00000000 00000000 00000000
    или
    00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000
    в первом случае это будет минимальное отрицательное число, во втором достаточно большое положительное
    можно так и сделать:
    $is_pohape_64_bit_version = (1<<31) > 0;

    Спустя 30 сек.

    да что с парсером-то
    не всё полезно, что в swap полезло
  • technobulka

    Сообщения: 4540 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 5:53 п.п., спустя 3 минуты 57 секунд

    Ну и я поумничаю до кучи.
    $m%7%2 - эта хрень считает месаца по принципу костяшек на кулаке. Косточка - в месяце 31 день; ямка между косточками - 30 дней, исключение февраль; как закончились косточки и ямки, идём по второму кругу. По модулю 7 определяется первая семёрка месяцев, а по модулю 2 - косточка и ямки. Весь кайф в том, что по какой-то неебической космической причине, в 7 и 8 месяцах по 31 дню.
    Ну а февраль высчитывается во второй половине, где, кстати, одна лишняя пара скобок.
    Высокоуровневое абстрактное говно
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz Авг. 26, 2014, 5:54 п.п., спустя 1 минуту 41 секунду

    делаем гирлянду а ля бегущие огни.

    четыре секции лампочек переключаются так
    00010001 00010001 00010001 00010001
    00100010 00100010 00100010 00100010
    01000100 01000100 01000100 01000100
    10001000 10001000 10001000 10001000
    и дальше по кругу

    делаем раз
    $a = 286331153
    делаем два
    $a = $a << 1
    делаем три
    $a = $a << 1
    делаем четыре
    $a = $a << 1
    делаем пять (возвращаемся в начальное положение)
    $a = $a << 1 | 1;
    можно конечно опять записать 286331153, но неспортивно
    не всё полезно, что в swap полезло
  • zaxar

    Сообщения: 33 Репутация: N Группа: Кто попало

    Spritz Авг. 27, 2014, 11:50 д.п., спустя 17 часов 55 минут 29 секунд

    Спасибо. Вроде бы разобрался. Действительно, несложно.

    А вот этот вариант

    echo (31-(($m-1)%7%2)-((($m==2)<<(!!($y%4)&!($y%100)||!!($y%400)))));

    отрабатывает-таки некорректно.

Пожалуйста, авторизуйтесь, чтобы написать комментарий!