Задний план
В некоторых возможных видах будущего мир преобразует свои числовые системы из десятичной (основание 10 или b10
) в некоторую другую базу (двоичную b2
, восьмеричную b8
, шестнадцатеричную b16
или даже унарную b1
, в этом случае мы облажались!). Таким образом, готовясь к этому возможному изменяющему мир событию, вы решаете проверить все свои программы. Это можно сделать, используя только сингулярные 0
s и 1
s в сочетании с операторами для замены существующих числовых констант.
Однако есть только одна проблема: вам нужно изменить массу программ, и ручное преобразование каждого числа в выражение займет недели! Таким образом, вы решаете написать программу (или функцию), чтобы решить, какое выражение должно заменить каждое число.
вход
На входе будет положительное целое число. Ваш код должен быть в состоянии обработать любое целое число до 1000.
(Если ваш код поддерживает десятичные дроби и / или отрицательные значения, см. Оценка ниже.)
Выход
Ваш код должен выводить выражение, которое оценивает ввод по крайней мере на одном языке. Это может быть любой язык; оно не обязательно должно быть тем же, в котором написана ваша программа или функция. Кроме того, это выражение не обязательно должно быть полной программой или функцией.
Для ясности вывод может содержать любую из следующих операций:
- увеличение / уменьшение
- добавить / сумма
- вычесть / отрицать
- умножить / удвоить (только если это не связано непосредственно с числом
2
!) - разделить / по модулю
- показатели / логарифмы
- квадрат / sqrt (опять же, только если они не связаны непосредственно с числом
2
!) - побитовые операции (bOR, bAND, bNOT, bXOR, битовые сдвиги)
- установка / получение переменных
- манипулирование стеком
Вы не можете использовать eval()
или любые подобные функции в выводе. Вы также не можете использовать в выходных данных любые функции, которые выполняют действия, отличные от упомянутых выше.
Да, и еще одна вещь: так как мы хотим, чтобы вывод был действительным в максимально возможном количестве баз, единственные числовые константы, которые он может содержать, это 0
и 1
. Числа, такие как 10
(десять), не допускаются, если только язык не интерпретирует их как a 1
и a 0
. Использование строк, содержащих числа, также недопустимо, как и использование символов, таких как CJam A
- K
(которые представляют 10
- 20
).
Тест-кейсы
(Все выходные данные в JavaScript, но могут работать на других языках.)
Вход 1:
2
Возможный вывод 1:
1+1
Вход 2:
13
Возможный вывод 2:
(a=1+1+1)*a+a+1
Вход 3:
60
Возможный вывод 3:
(b=(a=1+1+1+1)*a)*a-a
Вход 4:
777
Возможный вывод 4:
(c=(b=((a=1+1+1+1)*a-a+1)*a)*a+b)+c+c-a+1
Вход 5:
1000
Возможный вывод 5:
Math.pow((a=1+1+1)*a+1,a)
счет
Цель этой задачи - максимально сократить вывод вашего кода. Ваша оценка будет рассчитана следующим образом:
Базовая оценка: среднее число байтов всех выходных данных для целых чисел от 1 до 1000.
Десятичная оценка: если ваш код поддерживает как минимум 3 десятичных знака, это среднее число байтов всех выходных данных последовательности чисел, начинающихся с
0.001
и заканчивающихся на1000
, увеличивающихся с1.001
каждым разом.0.001, 1.002, 2.003...998.999, 1000.000
Тогда возьмите 50% от этой оценки.Отрицательная оценка: если ваш код поддерживает отрицательные числа и ноль, это среднее число байтов выходных данных всех целых чисел от
-1000
до0
. Тогда возьмите 10% от этой оценки.
(Самый простой способ рассчитать их - это цикл с вашей программой / функцией внутри.)
Ваша итоговая оценка является средним значением любой из приведенных выше формул.
Если выходные данные являются недетерминированными (т. Е. В некоторой степени случайными; многократные прогоны с одним и тем же входом дают несколько уникальных выходов), то оценка для каждого входа определяется по наибольшему результату за десять прогонов на моем ЦП.
Кроме того, поскольку вы не знаете, насколько ценными будут компьютерные данные в будущем, количество байт кода вашего генератора должно быть меньше 512 байт.
Самый низкий результат за две недели (30 сентября) будет объявлен победителем. Поздравляем вашего победителя, @ThomasKwa !
Leaderboard
Чтобы убедиться, что ваш ответ отображается правильно, начните его с этого заголовка:
# Language name/Other language name, X points
Где X
оценка вашего ответа. Пример:
# CJam/Pyth, 25.38 points
Если у вас есть какие-либо вопросы или предложения, пожалуйста, дайте мне знать. Удачи!
источник
0
или1
по умолчанию?Integer.parseInt("1000", 1+1+1+1+1+1+1+1+1+1)
? Я уверен, чтоparseInt
использует только разрешенные операции ;-)Ответы:
Машинный код Python / Zilog Z80,
11.65311.488Бонусы: отрицательные числа.
Предполагается, что
hl
пара регистров изначально содержит 0 и возвращает результат вhl
.Используются только эти три инструкции:
Мы используем небольшую модификацию сбалансированного двоичного представления минимального веса BBR2 . Поскольку BBR2 минимизирует вес (количество ненулевых цифр), но мы хотим минимизировать вес плюс количество битовых сдвигов, мы меняем постоянную в алгоритме с
3/2
на5/3
.Чтобы вычислить счет и проверить, используйте этот код:
Пример вывода:
Или в сборке:
Еще примеры программ:
Возможные оптимизации: правила О.П. , что
inc h
иdec h
инструкция, которые непосредственно изменяют верхние байтыhl
, является незаконной, ноsla h
и не имеющими документыsl1 h
(левый бит сдвигает на 1 наh
этом сдвиг в0
и1
, соответственно) разрешены.sla h
иsl1 h
два байта каждый, но иногда они могут сократить выход.источник
+
переводитсяdec
. Я продолжаю читать негативные примеры неправильно.CJam / CJam,
143,26342,71328,89923,90121,90320,468Бонусы не применяются.
Попробуйте онлайн: пример прогона | счет калькулятор | проверка
Пример работает
источник
%
из них более длинным выражением. Ссылки должны работать сейчас.ß / BrainFuck, 34.201 балла
ß источник (194B):
Если кому-то будет интересно, я добавлю объяснение. Вывод BF уже довольно оптимизирован, но я думаю, что я мог бы использовать оставшиеся 318B кода ß для реализации
удаление оператора.Образцы:
Бег в окнах:
Запуск в Linux:
Подтвердите в онлайн-переводчике BF .
Счет:
= 37.495
.= 60.959 * 0.5 = ~30.48
.= 38.4765234765235 * 0.9 = ~34.629
= (37.495 + 30.48 + 34.629)/3 = 34.201
.источник
Рубин / Ruby, 29,77885
31,873 * 0,9 (отрицательно) 30,872 (положительно).
Базовая стратегия - симметричное базовое представление 3 («сбалансированная троичная»), т. Е. Когда цифры
-1,0,1
вместо0,1,2
Вот вывод от 0 до 40 до очистки
И после уборки
источник
Цейлон / Цейлон,
49,8640,95 баллаТретья версия использует Ceylon 1.2 для генератора и 509 байт кода:
import ceylon.language{S=String,I=Integer,e=expand}S q(I n)=>n==0then"0"else(n<0then"-"+p(-n,"-")else p(n,"+"));variable Map<[I,S],S>c=map{};S p(I n,S s){S v=c[[n,s]]else(n<8then s.join([1].repeat(n)))else(let(a="+-".replace(s,""))e(e{for(x in 2..8)let(l=(n^(1.0/x)).integer){for(r in l:2)if(r>1)let(w=r^x){if(w-n<n)"("+p(r,"+")+")^("+p(x,"+")+")"+(w<n then s+p(n-w,s)else(n<w then a+p(w-n,a)else""))}}}).reduce<S>((x,y)=>x.size<y.size then x else y))else"";c=[n,s]in c then c else map{[n,s]->v,*c};return v;}
Он опустился до 35,22 балла, но я не буду помещать это в строку заголовка, потому что Celyon 1.2 был опубликован только 29 октября. Я не думаю, что смогу реализовать этот алгоритм в Ceylon 1.1 в таком размере.). Более подробно там, здесь я опишу вторую версию. (Первую версию можно увидеть в истории - она поддерживала только положительные числа, но вмещалась в 256 байтов.)
Вторая версия
Теперь вторая версия, которая поддерживает отрицательные целые числа (и 0) и, как правило, создает немного более короткий вывод, используя дополнительно
-
. (Эта версия на самом деле использует разрешенную длину, первая пыталась остаться в 256 байтах вместо 512).Код имеет длину 487, поэтому еще есть место для дальнейшей оптимизации. (Есть также много резервов в виде пробелов и длинных имен переменных.)
Подсчет очков:
Некоторые примеры выходов:
Как видите, отрицательные всегда на один байт (ведущий
-
) длиннее соответствующих положительных.Основная идея та же, что и в предыдущей программе: найти квадрат рядом с нашим целевым числом и рекурсивно представить его корень и остаток. Но теперь мы допускаем, что наш квадрат также будет немного больше целевого числа, что делает остаток отрицательным. (
+0.5
Можно изменить на другую константу, чтобы настроить алгоритм, но, похоже, я уже достиг оптимального значения - и 0,4, и 0,6 дают худшие результаты.)Чтобы сделать отрицательные значения отрицательными (и в противном случае иметь ту же структуру, что и положительные, мы передаем оператор
sign
нашей рекурсивной функцииp
- то есть либо,"+"
либо"-"
. Мы можем использовать это также для соединения в тривиальных случаях (т.е. n <9) что касается остатка, если он положительный, и используйте противоположный знак для остатка, если он отрицательный.В
proof
функции ручки начальный знак (с особым случаем для 0), тоp
функция выполняет фактическую работу, с помощью рекурсии.Третья версия, для Цейлона 1.2
Версия для игры в гольф (то есть комментарии и удаленные пробелы) размещена сверху, ровно в 509 байтах кода.
При этом используется тот же базовый принцип, что и во второй версии, но вместо квадратов он также пытается использовать более высокие степени чисел (пробуя показатели от 2 до 8) и использует самый короткий результат. Он также кэширует результаты, так как в противном случае это было бы неприемлемо медленно для больших номеров со многими рекурсивными вызовами.
Подсчет очков:
Большая конструкция с отступом в середине - это три вложенных итерируемых понимания, внутренние два внутри выражения let. Затем они не передаются, используя функцию расширения дважды, и
reduce
функция находит самую короткую из этих строк.Я подал запрос на функцию, чтобы иметь возможность сделать это в одном понимании.
Внутри понимания мы строим строку из корня
r
, показателя степениx
и остатка (n-w
илиw-n
).let
Выражение иmap
функции являются новыми в Цейлоне 1.2.map
можно было бы заменить наHashMap
(для этого потребовалось бы больше символов для импорта, хотя, вероятно, это было бы еще быстрее, поскольку я не буду строить карту новой для каждой новой записи). Этиlet
выражения , какlet (w = r ^ x)
могли бы быть заменены с помощьюif
оговорки , какif(exists w = true then r ^ x)
(и тогда я не нуждался бы в двухexpand
вызовов либо), но это все равно будет немного больше, не вписывается в 511 разрешенных байтов.Вот пример выходных данных, соответствующих выбранным выше, все они, за исключением действительно небольших чисел, короче:
Например, теперь у нас есть 1000 = (3 ^ 2 + 1) ^ 3 вместо 1000 = (6 ^ 2-4) ^ 2-5 ^ 2 + 1.
источник
less than 512
. Су вы можете использовать макс. 511 байт;)Рубин / постоянный ток,
20,29618,41416,968Динамическое программирование! Определяет список функций, которые с учетом инструкции dc возвращают новое выражение и числовое значение этого выражения. Затем, начиная с
1
предопределенного, он создает список всех достижимых значений вплоть до требуемого значения.редактировать:
Добавил функцию для n-1 и заставил ее запускать алгоритм через несколько проходов. Кажется, нужно 7 проходов, чтобы стабилизироваться. Пришлось сократить некоторые имена переменных, чтобы они оставались в пределах 512 байт.
редактировать 2:
Добавлены функции для n (n-1) , n (n + 1) и n ^ 3, пока я был на этом. Еще немного укоротил код, высадив ровно 512 байт.
Сгенерированные номера:
Вывод полностью состоит из пяти различных символов:
1
помещает значение 1 в стек;d
дублирует вершину стека;+
,-
и*
выводит два верхних значения и выводит их сумму, разность и произведение соответственно. Каждое сгенерированное выражение добавляет только одно значение в стек после выполнения....
источник
-
оператора, оставаясь в пределах количества байтов?Python 2,6,
78,069- 66,265 баллаОтправляю мой ответ для того, что он стоит (не много в этом случае ... но ясно демонстрирует, что для этой задачи недостаточно просто думать о том, чтобы составить результат как сумму значений со сдвигом в битах; если принять во внимание, что нет цифр за пределами 0 или 1 может появиться на выходе). Я мог бы вернуться позже с другим способом генерации результатов.
Сам код не слишком длинный (176 символов):
Он генерирует правильный, но подробный вывод:
Фрагмент, который вычисляет счет:
источник