Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

И станет 3 бесконечностью


Посмотрим на классический цикл (с пустым телом), который обычно выполняет 3 итерации:

for (int x=0; x<3; ++x);


Задача заключается в том, чтобы сделать его бесконечным.



Соревнование завершено, но ответы публиковать можно

Длительность соревнования 2 недели, начало отсчёта после окончания
Код-гольф - Реализация алгоритма выборки комбинаций

Опубликовал это соревнование на codegolf'е.

При оформлении ответа рекомендуется язык делать заголовком (# в начале строки).

Оценка

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

Голосующих просьба учесть, что система SO откатит 3 и более минуса, поставленны
одному участнику (но не 3 плюса). Больше 3 плюсов одному участнику за день ставить тож
не стоит. Лучше вернитесь завтра и доставьте :)

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

Подробные условия


Можно использовать любой язык в котором поддерживается подобная форма циклов.
В чистой программе на этом языке тип данных должен раскрываться в целочисленный ил
числовой (если в языке поддерживается типизация), а цикл выполняться 3 раза. Использовани
пользовательских типов недопустимо.

for (int          x=0; x<3; ++x);   // C, C++, C#
for (var          x=0; x<3; ++x);   // C#, Javascript
for (auto         x=0; x<3; ++x);   // C, C++
for (auto signed  x=0; x<3; ++x);   // C, C++
for (register int x=0; x<3; ++x);   // C, C++

В дополненной программе цикл должен быть бесконечным, а все ограничения кроме сохранени
этого фрагмента кода снимаются.
Участок с циклом должен быть одинаковым в чистой и дополненных программах.
for должен остаться циклом. Более того, он должен сам стать бесконечным. Просто обернут
его во внешний бесконечный цикл нельзя.
Тело цикла не должно менять значение переменной. Программа должна работать аналогичны
образом с пустым телом цикла.




Кстати, есть 3 мои решения (на C#, C++ и Javascript), использующие совершенно разны
подходы. Если никто не предложит такие варианты в течение недели с момента начала отсчёта
я их опубликую. А пока только это:

oCrfu6vbxewj8k8eMw9TDog83T


Первое (на Си++) нашёл @pavel: https://ru.stackoverflow.com/a/587588/178988
Моя версия: http://ideone.com/xgTeCr

Второе (на C#) нашёл @VladD: https://ru.stackoverflow.com/a/587673/178988
Моя версия: http://ideone.com/8bkwoD

Третье (на JS) не написали, публикую: https://ru.stackoverflow.com/a/593174/178988
Фиддл: https://jsfiddle.net/893f6vw8/
Но есть 3 решения с похожей идеей. Подробнее в ответе.



Результаты


Первое место с 24 голосами занимает решение участника @soon на Си/Си++:


   #define x x,y

Второе место с отставанием всего в 1 голос занимает решение участника @pavel на Си++
Интересно, что это решение было одним из трёх анонсированных.


   #define int bool

Третье место с 20 голосами получает решение участника @Mike на Перле


   в котором константа 3 переопределяется значением бесконечнось





PS: Напоминаю про чат
    


Ответы

Ответ 1



По аналогии с @Qwertiy, но работает еще и в Си #define x x,y int main() { for (int x=0; x<3; ++x); return 0; } Развернется в int main(void) { for (int x,y=0; x,y<3; ++x,y); return 0; } y инициализируется нулем и не меняется в теле цикла, поэтому всегда <3

Ответ 2



C++ int main() { #define int bool for (int x=0; x<3; ++x); return 0; } http://ideone.com/VwMh2z bool при всегда 1 или 0, при сравнении с 3 это всегда правда), true++ == true.

Ответ 3



Java Итак, чистейшее, дистиллированное зло, хуже не бывает. Хотите насолить тимлиду вылететь с работы при следующем code review — спросите меня как! Interning + reflectio = <3! import java.lang.reflect.*; class Golf { public static void main(String[] args) throws java.lang.Exception { Field value = Integer.class.getDeclaredField("value"); value.setAccessible(true); Integer victim = 0; value.setInt(victim, -2); for (Integer x = 0; x < 3; x++) System.out.println(x); } } Проверка: http://ideone.com/3Q0Kzc Что здесь происходит? Дело в том, что в Java небольшие целые константы интернятся их значения записываются в общий кэш. При помощи рефлексии можно добраться до этог самого закешированного значения, и подменить его! В примере кода константа 0 подменяется на -2. Не понимаю, почему, но при этом значени в цикле осциллируют между -2 и -1, цикл становится бесконечным. Вариант Integer victim = 3; value.setInt(victim, -1); тоже загоняет программу в бесконечный цикл (http://ideone.com/WD3qw7), значения меняютс как 0, 1, 2, -1, 0, 1, 2, -1, ... Наверное, самое чистое решение (если вообще можно назвать этот код хоть в каком-т смысле чистым) — подменить 3 на Integer.MIN_VALUE Integer victim = 3; value.setInt(victim, Integer.MIN_VALUE); Тогда при сравнении нужное неравенство не сможет выполниться никогда: http://ideone.com/VxIVT7

Ответ 4



Perl, Если 3 должно быть бесконечностью - так пусть ей и будет ! Перегрузим метод определения констант таким образом, что бы константа "3" считалас бесконечностью. Любые другие константы пусть означают сами себя. use overload; BEGIN { overload::constant ( integer => sub { return inf if($_[1]==3); $_[1]; } ); } for ($x=0; $x<3; ++$x); Тест на ideone (введено искусственное ограничение внутри цикла, что бы сайт не вис)

Ответ 5



C89 и выше ideone #define for(unused) for(;;) int main() { int x; for (x = 0; x < 3; ++x); } C99 и выше ideone #define for(...) for(;;) int main(void) { for (int x = 0; x < 3; ++x); } Первое решение (C89) работает практически везде с циклом из задания, второе (C99 работает на чуть меньшем кол-ве реализаций, но зато делает бесконечным абсолютно любой for.

Ответ 6



C# Подменяем структуру данных, используя default: using System; // если убрать эту структуру, цикл станет конечным struct Int32 { public static implicit operator Int32(int i) => new Int32(); public static implicit operator int(Int32 x) => 0; } class Program { static void Main(string[] args) { for (var x = default(Int32); x < 3; ++x) Console.WriteLine("iteration"); } } Проверка: http://ideone.com/2evCtl Идея в том, чтобы подменить структуру данных. Создать свою структуру с именем in невозможно, но int — всего лишь алиас к System.Int32, зато возможно создать структур с именем Int32 во вложенном пространстве имён System. Если такая структура данных определена во внутреннем пространстве имён, она буде использоваться вместо глобального System.Int32. Старый вариант: namespace Golf { // если убрать это пространство имён с содержимым, цикл станет конечным namespace System { struct Int32 { static public bool operator < (Int32 x, int y) { return true; } static public bool operator > (Int32 x, int y) { return false; } static public Int32 operator ++ (Int32 z) { return z; } } } class Program { static void Main(string[] args) { for (var x = default(System.Int32); x < 3; ++x) global::System.Console.WriteLine("итерация"); } } } Проверка: чистый код, дополненный код. Идея переносится на C++, хотя реализация не портабельна, т. к. #define ключевог слова int стандартом не разрешается: #include struct INT { INT(int i) { } bool operator < (int i) { return true; } INT operator++(int dummy) { return *this; } }; int main(int argc, char *argv[]) { // если это убрать, цикл станет конечным #define int INT for (int i = 0; i < 3; i++) std::cout << "iteration" << std::endl; } Работает под MSVC 2015, с другими компиляторами может и не работать.

Ответ 7



PowerShell: class AlwaysZeroAttribute : System.Management.Automation.ArgumentTransformationAttribute { [object] Transform([System.Management.Automation.EngineIntrinsics] $engineIntrinsics [object] $inputData) { return 0 } } [AlwaysZero()]$x=0 for($x = 0; $x -lt 3; ++$x) { } Или Set-PSBreakpoint -Variable x -Mode Write -Action {([ref]$x).Value=0} for($x = 0; $x -lt 3; ++$x) { }

Ответ 8



C# Ещё одна идея состоит в том, что ключевое слово var — контекстное, а значит, ег можно переопределить. Поехали! // если убрать эту структуру, цикл завершается struct var { public static implicit operator var(int i) => new var(); public static implicit operator int(var x) => 0; } class Program { static void Main(string[] args) { for (var x = 0; x < 3; ++x) Console.WriteLine("iteration"); } } Проверка: http://ideone.com/L6H7b7

Ответ 9



C++, но не C http://ideone.com/2m4FCy int main() { int y; #define x x=y for (int x=0; x<3; ++x); return 0; } PS: Этот ответ придуман после создания соревнования, поэтому публикуется без задержки На анонсированный выше ответ на плюсах он совсем не похож.

Ответ 10



JavaScript: Воспользуемся возможностью переписать сеттер: (function() { "use strict"; // Обычный тест Object.defineProperty(window, 'x', { get: _ => window._value, set: n => window._value = n }) && (window._value = 0); for (x = 0; x < 3; x++) console.info(x); }()); // Бесконечность — не предел! © Базз Лайтер // ВНИМАНИЕ: Запуск этого сниппета убьёт эту вкладку или даже браузер // Запускать с диспетчером вкладок на руках Object.defineProperty(window, 'x', { get: _ => this._value, set: n => this._value = 0 }) && (window._value = 0); for(x = 0; x < 3; x++) console.info(x);

Ответ 11



Что в инет попало - то там навсегда xD PHP declare + тики

Ответ 12



Подключаю тяжелую артиллерию: using Mono.Cecil; using Mono.Cecil.Cil; using System; using System.IO; using System.Linq; class Program { static void Main(string[] args) { var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(typeof(Program).Assembly.Location); var type = assembly.MainModule.GetType(typeof(Program).FullName); var il = type.Methods.Single(m => m.Name == nameof(Test)).Body.GetILProcessor(); foreach (var instr in il.Body.Instructions.ToList()) { switch (instr.OpCode.Code) { case Code.Brtrue: instr.OpCode = OpCodes.Br; il.InsertBefore(instr, il.Create(OpCodes.Pop)); break; case Code.Brtrue_S: instr.OpCode = OpCodes.Br_S; il.InsertBefore(instr, il.Create(OpCodes.Pop)); break; case Code.Brfalse: case Code.Brfalse_S: instr.OpCode = OpCodes.Pop; break; } } var ms = new MemoryStream(); assembly.Write(ms); var assembly2 = System.Reflection.Assembly.Load(ms.ToArray()); var type2 = assembly2.GetType(typeof(Program).FullName); type2.GetMethod(nameof(Test)).Invoke(null, new object[0]); } public static void Test() { for (int i = 0; i < 3; i++) { Console.WriteLine($"i = {i}"); } } }

Ответ 13



Perl Играем с переменными. Свеженькое, по результатам чата. Вообще без typeglob: #!/usr/bin/env perl use Modern::Perl; use Variable::Magic qw/wizard cast/; # тут одна переменная $x: cast our $x, wizard( set => sub { my ($ref) = @_; $$ref = 0; } ); # а тут - другая :-) for ( local $x = 0; $x < 3; ++$x ) { say "[x = $x]"; } А здесь мы явно создаём алиас для записи в глобальной таблице имён и вешаем визар на него. Сама же переменная, к которой прицеплен алиас (и на которую указывает запись) формально объявляется позже, в цикле. В принципе того же самого можно было бы добитьс и с tie, но так веселей :) #!/usr/bin/env perl use Modern::Perl; use Variable::Magic qw/wizard cast/; use Data::Alias; alias my $foo = *x{SCALAR}; cast $$foo, wizard( set => sub { my ($ref) = @_; $$ref = 0; } ); for( our $x = 0; $x < 3; ++$x ) { say "[x = $x]"; } То же самое, но без Data::Alias: use Modern::Perl; use Variable::Magic qw/wizard cast/; my $foo = \${*x{SCALAR}}; cast $$foo, wizard( set => sub { my ($ref) = @_; $$ref = 0; } ); for ( our $x = 0; $x < 3; ++$x ) { say "[x = $x]"; } Ideone, к сожалению, ничего не знает про Data::Alias и Variable::Magic.

Ответ 14



Javascript Вариант с сеттером и с freeze уже был. Посему представлю вариант с Proxy - хоть это и геттер, но прокси по-своему интересен: var p = new Proxy({},{ get: function(){return 0;}, has: function(){return true;} }); with(p) { for(x=0; x < 3; ++x); } О прокси можно узнать тут . Понравится программистам языков с магическими методами вроде __get или __set в PHP

Ответ 15



D Чистая программа похожа на вариант с C/C++ import std.stdio; void main() { for(int x=0; x<3; ++x) { writeln(x); } } Язык D при помощи строковых миксинов позволяет компилировать любое выражение, результато которого является строка, как будто содержимое строки было напрямую вставлено в исходны код. Оборачиваем цикл в строку (вместо кавычек используются ограничители q{}, которы удобны для строк содержащих код, но можно использовать и обычные кавычки), функцие из стандартной библиотеки заменяем "++" на пустоту и микшируем результат в тело функци main. Переменная цикла больше не увеличивается и всегда равна нулю, цикл становитс бесконечным: import std.stdio; import std.string; void main() { mixin(q{ for(int x=0; x<3; ++x) { writeln(x); } }.replace("++", "")); }

Ответ 16



Javascript Нагло спер идею из чата :-) Начальный вариант: for (var x = 0; x < 3..valueOf(); ++x); Бесконечный var vof = Number.prototype.valueOf; Number.prototype.valueOf = function() { if (this.toString() == 3) { return Infinity; } return vof.call(this); } for (var x = 0; x < 3..valueOf(); ++x);

Ответ 17



Javascript И еще одно решение, нагло подслушанное в чате Начальный код: for (x = 0; x < 3; ++x); Бесконечный: var o = { x: 0 } Object.freeze(o); with(o) { for (x = 0; x < 3; ++x); }

Ответ 18



Groovy Groovy, в отличие от Java, позволяет полностью контролировать синтаксическое дерев (AST) единицы компиляции. Этим и воспользуемся. Чистая программа: for(int x = 0; x < 3; x++); или для наглядности for(int x = 0; x < 3; x++) { println(x) } Начинаем колдовать. Добавим в скрипт явное имя пакета и пометим его своей аннотацией @LoopMagic: @LoopMagic package foo for(int x = 0; x < 3; x++); Аннотация должна быть к чему-то привязана, а прицепить ее непосредственно к цикл не получится, поэтому нужен пакет. Теперь опишем саму аннотацию в отдельном файле (почем - ниже): @Target([ElementType.PACKAGE]) @GroovyASTTransformationClass(classes = [ LoopMagicTransformation ]) public @interface LoopMagic {} Мета-аннотация @GroovyASTTransformationClass заставляет компилятор применять к е носителям AST-трансформации, указанные в массиве classes. Теперь остается реализоват сам класс трансформации LoopMagicTransformation. Можно сделать это ниже в этом же файле: @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) // 1 class LoopMagicTransformation implements ASTTransformation { def void visit(ASTNode[] nodes, SourceUnit sourceUnit) { def ast = ([] << sourceUnit.AST.methods*.code << sourceUnit.AST.classes*.methods*.cod << sourceUnit.AST.statementBlock).flatten() // 2 ast.each { node -> node.visit(new CodeVisitorSupport() { // 3 @Override void visitForLoop(ForStatement forLoop) { super.visitForLoop(forLoop) if (forLoop.collectionExpression instanceof ClosureListExpression) { (forLoop.collectionExpression as ClosureListExpression).expressions[1 = new BooleanExpression(new ConstantExpression(true)) // 4 } } }) } } } Разберем все по-порядку. Мета-аннотация @GroovyASTTransformation задает фазу в которой будет происходить трансформация А нашем случае это фаза семантического анализа. Это самый ранний этап, когда код уж разобран в дерево. Механизм AST-трансформаций вызовет метод visit для каждого владельц аннотации @MagicLoop. Как мы помним, согласно нашему определению это может быть тольк пакет. Сам пакет нам совершенно не интересен, но через параметр sourceUnit мы може получить доступ ко всей единице компиляции - скрипту. Скрипт из-за своей природы имеет три AST корня - для задекларированных классов, дл методов, не принадлежащих явным образом классам, и для самого тела скрипта. Так чт сольем все statement-ы верхнего уровня в общий список ast (оператор *. работает ка map - вызывает метод на каждом элементе коллеции и возвращает новую коллекцию из результатов). На получившийся лес statement-ов натравим традицонно применяющийся для AST деревье паттерн Visitor. Groovy нам помогает, предоставляя абстрактный класс CodeVisitorSupport который берет на себя обход дочерних веток. Так что остается только переопределить мето `visitForLoop(), который будет вызван для найденных for-циклов. Убеждаемся, что это именно for, а не for-each цикл, и подменяем условие продолжени на константу true. Теперь любой цикл, объявленный в классе, методе без класса или само теле скрипта будет крутиться вечно. Аннотация и трансформация должны находиться в отдельном файле и собираться раньш скрипта, т.к. к тому моменту, когда компилятор будет заниматься компиляцией скрипта наши вспомогательные классы должны быть уже собраны. По этой причине я не привожу действующи пример на ideone.

Ответ 19



C++ Специально для @Harry вариант без define. Хотя он и почти не отличается от варианта с define. http://ideone.com/InWt0t #include using namespace std; int main() { typedef bool size_t; for (size_t x=0; x<8; ++x); return 0; }

Ответ 20



BASH Точно работает в GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15) #!/bin/bash set +e declare -rx i=0 for (( i=0; i<3; i++ )) do echo $i done Вывод: bash-3.2$ ./test.sh ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0 ./test.sh: line 4: i: readonly variable 0

Ответ 21



Javascript Всё-таки публикую это решение, хотя не совсем уверен, насколько оно отличается о имеющихся. with({get x() {return 0}, set x(val){}}) for(var x=0; x<3; ++x) https://jsfiddle.net/893f6vw8/ var i=0; with({get x() {return 0}, set x(val){}}) for(var x=0; x<3; ++x) if(document.write(x+' '), ++i>15) break; Разница с решением @Other в том, что моё представляет более чистую чистую версию а также позволяет объявить переменную в for. Разница с решением @ГончаровАлександр в отсутствии Proxy. Ещё из похожего есть решение @Grundy, но я бы сказал, что оно принципиально отличается хотя и использует ту же идею с неизменяемым свойством.

Ответ 22



Исправлено C++11 #include #define for(x) [](){std::string i("x"); while(1);}(); int main() { for(int i=0; i<3; ++i); return 0; } На ideone.com Включите, плс, в конкурс)

Ответ 23



PHP Вариант 2. Так как тоже можно формально объявить не соответствующим условиям, т небольшой дисклаймер. PHP - язык с динамической типизацией. И не объявленная переменная $x==null==0==false=="" Код echo (int) $x; напечатает 0. Следовательно, с точки зрения логики работы, эти два цикла одинаковы. Т.е. они об выполнятся ровно три раза. Первый вариант при этом один раз, в начале, ругнется, н это ни на что не повлияет: for(;$X<3;$X++); for($x=0;$x<3;$x++); Собственно код:

Ответ 24



C# static class Program { static void Main() { InfLoop.Test(); } } public class InfLoop { public class var { public var(int i){val = i;} public int val; public static var InfDo(var v) { return v.val < -1 ? v=v+1 :--v ; } public static implicit operator int (var a) { return a.val; } public static implicit operator var (int i) { return new var(i); } public static var operator ++(var v) { return InfDo(v); } } public static void Test() { for (var x = 0; x < 3; ++x) { Console.Write("Inf"); } } }

Ответ 25



Вне конкурса, поскольку нарушены требования for должен остаться циклом. Более того, он должен сам стать бесконечным. Прост обернуть его во внешний бесконечный цикл нельзя. Тело цикла не должно менять значение переменной. Программа должна работать аналогичны образом с пустым телом цикла. C# Не уверен, что абсолютно подходит под условия, но идея с переопределением операторо и т.п. исчерпала себя, а на 100% под условия, кажется, подходит только она. Чистый вариант: using System; public class Test { public static void Main() { l: for(var i = 0; i < 3; i++) { #if (infinity) goto l; #endif } } } Грязный: #define infinity using System; public class Test { public static void Main() { l: for(var i = 0; i < 3; i++) { #if (infinity) goto l; #endif } } } http://ideone.com/4mQYWa

Ответ 26



Вне конкурса, поскольку нарушено требование Участок с циклом должен быть одинаковым в чистой и дополненных программах. Perl Пришло время волшебства. use strict; use warnings; use utf8; my $х=0; for (my $x=0; $x<3; ++$х) { print $х."\n"; } Проверить на ideone.com (добавил ограничение до 100)

Комментариев нет:

Отправить комментарий