Магія числа PI

Нещодавно виповнилося 250 років з того дня, як було доведено іраціональність числа пі. Число це, як відомо, можна зустріти не тільки при обчисленні довжини кола, а й у найнесподіваніших місцях.

Ось який фрагмент коду мені прислали сьогодні:

unsigned char func(unsigned char c) {
  return c - 128 + (c >> 5&3)["(PI)"];
}
Цей код (не зовсім цей, але дуже подібний), кажуть, був присутній у деяких версіях браузера Chrome, пізніше його замінили на іншу реалізацію. Тобто це реальний код, який виконує корисну функцію.

Питання до знавців мови C: що робить ця функція?

Скажу одразу, що я не здогадалась, хоч і вивчала мову C, та порядком підзабула. Але насправді, як виявилось, визначити призначення функції неважко.

коментарі:

webdevbyjoss 10.03.2011 16:29
спочатку подумав що це робота з регістром символів але тіршки погугливши :)
треба бути сильних хардкор С-ішником щоб ТАК написати таку операцію
+1tercius 24.03.2011 17:09
ще про магічне число, з несподіваного ракурсу - музиканти спробували його озвучити. получилося доволі симпатично )

ось як воно звучить:

Ян Лі 26.03.2011 14:02
Симпатично, але мені здалося, що там озвучено не все число пі :), а повторюються тільки перші кілька цифр з його десяткового розкладу. Я не пам'ятаю, чи доведено рівномірність розподілу цифр пі, але взагалі-то воно повинно давати щось на зразок "білого шуму". Хоча при вдалому підборі інструментів може вийти такий собі амбієнт :)
+1Ян Лі 26.03.2011 14:25
Забула я про цей пост, про всяк випадок напишу відповідь.

Зрозуміло, що такий дивний вигляд функція має лише через бажання авторів заплутати читача, у реальному коді воно було не так. Для заплутування вжито кілька прийомів:

запис c >> 5&3, виходячи з пріоритету операцій C, насправді означає (c >> 5) & 3,

запис ["(PI)"] базується на тому, що індексування масивів у C перетворюється в додавання числа до вказівника, і комутативності додавання, тобто (c >> 5&3)["(PI)"] еквівалентно char *s = "(PI)"; s[(c>>5)&3].

Якщо подивитися на переписану функцію:
unsigned char func(unsigned char c) {
  char *s = "(PI)";
  return c - 128 +  s[(c>>5)&3];
}
і пригадати ascii-коди символів "P", "I" та дужок, то вже можна побачити, що функція переводить шістнадцяткові цифри "0"-"9", "a"-"f" та "A"-"F" у відповідні значення 0-15.

До чого ж тут пі? Ні до чого, це просто збіг, що після віднімання 128 потрібні зміщення мають символи "P", "I" та одна з дужок (інша не використовується).

додати коментар: