Жодного розгалуження, будь ласка


14

Кожен, хто помірно оптимізує код низького рівня, знає про небезпеку розгалуження, будь то реалізована як оператори if, циклі або select-заяви, можливість помилкового прогнозування гілки - жахлива річ, що витрачає годинник.

Прості задачі можна вирішити набагато краще за допомогою простої арифметики, тому давайте це зробимо.

Для наведених нижче проблем усі змінні - це 32-бітні непідписані цілі числа, і єдиний дозволений код - це просто встановлені оператори, що включають лише наступні оператори:

+ addition
- subtraction
* multiplication
/ integer division, rounds down, division by 0 not allowed
% modulo
& binary and
| binary or
^ binary exclusive or
>> bitshift right
<< bitshift left

Logic operators, return 1 if the expression is true and 0 if it is false.
== equal
!= not equal
< less than
<= less than or equal
> greater than
>= greater than or equal

Set operator
=

Кожен рядок повинен складатися з ідентифікатора змінної, за яким слідує оператор набору, а потім - вираз.

Вираз може не містити додаткових операторів набору, але може містити ідентифікатори змінних, буквальні числа та круглі дужки.

Оцінка гольфу повинна враховувати лише кількість операторів.

Приклад:

myvar = ( ( ( foo + 5 ) * bar ) % 7 ) == 3

Має оцінку 5 операторів.

Рішення може включати стільки змінних, скільки автор вважає за потрібне.
Змінні, які не були встановлені, мають значення 0.
Дозволено переповнення та переповнення, усі негативні числа підпадають, так 3 - 5само 4294967294, навіть як частина більшого твердження.

Завдання 1: Макс

Два значення, Aі Bіснують у області, змушують RESULTзмінну містити найбільше з цих значень, коли програма припиняється.

Завдання 2: Медіана

Три значення, A, Bі C, існує в обсязі, зробити RESULTзмінний містять медіану тих значень , коли програма завершує свою роботу .

Завдання 3: квадратний корінь

Одне значення, яке Aіснує в області, змушує RESULTзмінну містити квадратний корінь A, округлений вниз, коли програма закінчується.

Неправильно розмістити відповідь лише на одне-два питання, для когось із вас просто пошук правильних рішень стане проблемою.


Де одинарні оператори? Мене не хвилює, -але ~може бути приємно (навіть якщо я не знаю, для чого).
Джон Дворак

Звичайно, 0xFFFF_FFFF_FFFF_FFFF ^ xі 0 - x. Як я міг забути?
Джон Дворак

@JanDvorak Він зробив найкоротший опис, повнота логіка не !є також досить тривіально: x == 0.
aaaaaaaaaaaa

Яка поведінка ділення на нуль?
Джон Дворак

У Mathematica (a> b) повертається True або False. Boole перетворює False в 0 та True на 1. Чи законно це використовувати Boole[a-b]?
DavidC

Відповіді:


5

Завдання 3, 23 оп

x = (A >> 16) + A / ((A >> 13) + 511) + 15
x = (x + A/x) >> 1
x = (x + A/x) >> 1
x = (x + A/x) >> 1
RESULT = x - (x > A/x)

Використовуючи метод Ньютона, як і інші рішення, з більш тактично обраним насінням. Перший біт A >> 16підтримує верхню частину діапазону, другий біт A / ((A >> 13) + 511)підтримує середину діапазону щасливою, а останній біт 15нижню, а також запобігає поділу на нульові помилки (15 - це найбільше можливе значення, яке дозволяє 0правильно збігти - вдвічі три рази мінус виправлення дорівнює нулю). Для вхідних значень 225, 275625, 82137969, 2908768489(і сусідніх значень) початкове насіння є точним. Усі корпуси кромки (ідеальні квадрати, ідеальні квадрати + 1 та ідеальні квадрати - 1) на діапазоні 0 .. 2**32-1були перевірені та є правильними.

Кілька коментарів до правил:
Дозволено переповнення та переповнення, всі негативні числа підточені, тому 3 - 5 - це 4294967294, навіть як частина більшого твердження .

Цей останній шматочок виявляється чимось вбивцею інновацій. Спочатку я спробував рішення, використовуючи узагальнену форму методу Галлея , але зрозумів, що воно було недійсним з огляду на вищезазначене обмеження. Ітерація (застосована до квадратних коренів) така:

x = x * (3*A + x*x) / (A + 3*x*x)

Ця ітерація має приємні якості, яких немає у Ньютона. Він конвергується кубічно (а не квадратично), конвергується зверху або знизу (а не тільки зверху), і він не настільки чутливий до погано вибраного насіння (якщо ітерація Ньютона надається насіння, яке є занадто низьким, воно буде сильно перекрийте точку конвергенції, а потім потрібно пропрацювати її назад.

У методу Ньютона також є проблема (принаймні, коли йдеться про цілі числа), що він досить часто досягає x такого, що A / x - x = 2 - у цьому випадку він сходиться до значення, яке більше, ніж власне ціле число, яку потрібно виправити; Метод Галлі не потребує такої корекції. Але, на жаль, значення 3*A + x*xчасто досить велике, ніж дозволений 32-бітний цілий пробіл.

Існує ряд інших узагальнених n- х кореневих алгоритмів, але всі вони мають таку саму характеристику:

x = x + x*(v - x**n)/(v*n)
x = (x*(n+1) - x**(n+1)/v)/n
x = ((n-2)*x + (4*v*x)/(v + x**n))/n
x = x*((n+2)*v + (n-2)*x**n)/(v + x**n)/n
x = ((n-2)*x + (n*x*v)/(v + (n-1)*x**n))/(n-1)
x = ((n-2)*x + x*((n*2-1)*v + x**n)/(v + (n*2-1)*x**n))/(n-1)

x = x + 2*x*(v - x**n)/(v + x**n)/n
x = x + x*31*(v - x**n)/(10*v + 21*x**n)/n
x = x + x*561*(v - x**n)/(181*v + 380*x**n)/n
x = x + x*1153*(v - x**n)/(372*v + 781*x**n)/n

тощо. Більшість із них демонструють або кубічну, або квадратичну конвергенцію. Останні чотири є частиною серії ітерацій, які сходяться на квартковій конвергенції. Але в практиці метод Ньютона отримає вам те, що вам потрібно з меншою кількістю операцій, якщо вам не потрібно обчислити багато сотень цифр.


Дуже добре, але не вдається для 4294967295. Щодо правил, вони повинні бути жорсткими, щоб зробити їх цікавими. Ви можете сперечатися, які саме приміщення створюють найкращий виклик, але в кінцевому підсумку набагато важливіше, щоб правила були чіткими та однозначними, ніж те, що саме вони дозволяють.
aaaaaaaaaaaa

Я не думаю, що Галлі все-таки того вартував би, з далекого здогаду він покращиться трохи менше, ніж в 3 рази, Ньютон - трохи менше, ніж в 2 рази. точність, Ньютон подвоїть його. Отже, одна ітерація Галлеї вартує саме log(3)/log(2) ~= 1.585ітерацій Ньютона.
aaaaaaaaaaaa

@eBusiness Спочатку у мене було 2 Галлея з аналогічно вибраним насінням на загальну суму 25 ops - з помилкою, коли A = 0- тому це насправді коротше. Щодо 4294967295 , це був недогляд: оскільки 65536² ≡ 0 ітерація виправлення не виправляється. Я побачу, чи зможу знайти альтернативу.
примо

@eBusiness виправлено.
примо

Найсолодший квадратний корінь пакету, приємна робота та офіційний знак перемоги.
aaaaaaaaaaaa

5

65 (61) операцій (5 + 13 + 47 (43))

Завдання 1 - Макс (А, В)

RESULT = A + (B - A) * (A <= B)

Це очевидне рішення. Вам потрібне призначення, вам потрібно порівняння, вам потрібно помножити порівняння з чимось, мультиплікація не може бути однією зі змінних і продукт не може бути результатом.

Завдання 2 - середина (A, B, C)

RESULT = A                               \
       + (B - A) * (A > B) ^ (B <= C)    \
       + (C - A) * (A > C) ^ (C <  B)

Це вдосконалення порівняно з моїм попереднім рішенням з 15-ти опцій, яке обумовило всі три змінні - це врятувало два віднімання, але ввело ще один тест центральності. Сам тест простий: елемент знаходиться в середині iff рівно один із двох вище.

Завдання 3 - sqrt (A)

X1     = 1024 + A / 2048
X2     = (X1  + A / X1 ) / 2
...
X10    = (X9 + A / X9 ) / 2
RESULT = X16 - (X16 * X16 > A)

Одинадцять раундів наближення Ньютона. Магічна константа 1024 вже побита WolframW (і 512 викликає ділення на нуль на a = 0 до a = 2 ** 32 сходиться), але якщо ми можемо визначити 0/0 як нуль, десять ітерацій працюватимуть із початковим значенням з 512. Я визнаю, що моя заява про десять повторень не є цілком чистою, але я все-таки стверджую їх у дужках. Мені доведеться розслідувати, чи можливо дев'ять.Рішення WolframH - це дев'ять ітерацій.


Я думаю, що перший рядок Завдання 3 невірний: другий постійний повинен бути в 4 рази більшим за першу константу (щоб був "чистий" Ньютон).
Відновіть Моніку

@WolframH Краща початкова здогадка може пояснити, чому я витрачаю цикли. Де ти придумав 4 *? Це виглядає як два повторення, зібрані в одну.
Джон Дворак

(1024 + A/1024)/2 == (512 + A/2048)(що як X0 = 1024, а потім починаючи Ньютон).
Відновіть Моніку

Гарне рішення завдання 1. Яйце Колумба.
DavidC

@DavidCarraher звичайно, правильним рішенням було б MOV RESULT, A; CMP A,B; CMOVA RESULT, B;-)
Джон Дворак

5

1: 5 операторів

RESULT = B ^ (A ^ B)*(A > B)

2: 13 операторів

RESULT = B ^ (A ^ B)*(A > B) ^ (A ^ C)*(A > C) ^ (B ^ C)*(B > C)

3: 27 операторів

g = 47|((0x00ffffff & A)>>10)|(A>>14)
r = (g + A/g)/3
r = (r + A/r)>>1
r = (r + A/r)>>1
r = (r + A/r)>>1
RESULT = r - (r*r-1>=A)

5

Завдання 3, 39 Операції

EDIT: Змінено останній рядок; дивитись коментарі.

Це реалізація методу Ньютона. Випробовується з усіма позитивними квадратами, а також із позитивними квадратами мінус один, а також одним мільйоном випадкових чисел у діапазоні від 0 до 2 ^ 32-1. Здавалося б , смішно початкове значення є абревіатурою (1022 + A/1022) / 2, яка вимагає найменшу кількість ітерацій (я думаю), а також робить RESULTдля A=0права (яке не було б в разі 1024замість 1022).

r = (511 + A/2044)
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
RESULT = r - (r > A/r)

Чи варто зберігати свою неповноцінну копію методу Ньютона, який був оптимізований паралельно вашому та розміщений пристойну кількість часу пізніше? Великі розуми думають однаково, і розв’язати рішення на дві дві відповіді погано, але ось такий сучасний стан справ, як ви ще не відповіли №2.
Джон Дворак

@JanDvorak: Дякую за запитання. Добре, якщо ви укладете мій трохи коротший метод у свою відповідь. Також дякую за те, що мені дали кредит :-)
Поновіть Моніку

Дійсно, спробуйте, але не вдалося ввести 4294965360 по 4294967295.
aaaaaaaaaaaa

@eBusiness: Який результат ви отримуєте за ці дані? Я отримую 65535 у своїх тестах, що добре.
Відновіть Моніку

Я отримую 65536. Можливо, ви не використовуєте встановлений цілий формат.
aaaaaaaaaaaa
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.