Встретилась задача о вычислении факториала числа без использования цикла. Для платформы 1С:Предприятие придумал следующий код. Какие еще есть варианты кроме рекурсии ?
Функция ФакториалБезЦикла(size=100) экспорт
перем f;
arr=new array(size);
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
//конвертация массива
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, arr);
МассивСтр = ЗаписьXML.Закрыть();
//превращаем массив в таблицу
Шапка="<Array xmlns=""http://v8.1c.ru/8.1/data/core"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">";
Замена="<ValueTable xmlns=""http://v8.1c.ru/8.1/data/core"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
|<column>
|<Name xsi:type=""xs:string"">N</Name>
|<ValueType>
| <Type>xs:decimal</Type>
| <NumberQualifiers>
| <Digits>0</Digits>
| <FractionDigits>0</FractionDigits>
| <AllowedSign>Any</AllowedSign>
| </NumberQualifiers>
|</ValueType>
|</column>";
МассивСтр=СтрЗаменить(МассивСтр,Шапка,Замена);
Замена="<row>
|<Value xsi:type=""xs:decimal"">1</Value>
|</row>";
МассивСтр=СтрЗаменить(МассивСтр,"<Value xsi:nil=""true""/>",Замена);
МассивСтр=СтрЗаменить(МассивСтр,"Array","ValueTable");
//Читаем таблицу значений из XML
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(МассивСтр);
тз = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
Текст="ВЫБРАТЬ
| vt.N КАК N,
| АВТОНОМЕРЗАПИСИ() КАК j
|ПОМЕСТИТЬ T
|ИЗ
| &Параметр КАК vt
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| T.N КАК N,
| T.j КАК j
|ИЗ
| T КАК T";
запрос=новый запрос(Текст);
запрос.МенеджерВременныхТаблиц=новый МенеджерВременныхТаблиц;
запрос.Параметры.Вставить("Параметр",тз);
arr=запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("j");
Выполнить("f="+СтрСоединить(arr,"*"));
возврат f;
КонецФункции
P.S. Можно гораздо проще, чем в (1), вот код (фрагмент):
Функция ФакториалБезЦикла(size=100) экспорт
Если size=1 Тогда
Возврат 1;
ИначеЕсли size=2 Тогда
Возврат 2;
ИначеЕсли size=3 Тогда
Возврат 6;
ИначеЕсли size=4 Тогда
Возврат 24;
ИначеЕсли size=5 Тогда
Возврат 120;
ИначеЕсли size=6 Тогда
Возврат 720;
ИначеЕсли size=7 Тогда
Возврат 5040;
ИначеЕсли size=8 Тогда
Возврат 40320;
ИначеЕсли size=9 Тогда
Возврат 362880;
ИначеЕсли size=10 Тогда
Возврат 3628800;
В вашем коде нет оператора цикла, но сам цикл - есть.
Спасибо, кэп!
Можно гораздо проще, чем в (1), вот код (фрагмент):
Увы, но нельзя, т.к. программу, считающую любой факториал таким способом не написать даже теоретически.
Я всего лишь привёл код, подходящий под условия задачи, которые, обычно звучат как "не используя оператор цикла", так как ориентированы на изучающих язык. Думаю, что единственный вариант, строго подходящий под условия - рекурсия, остальные будут просто ухищрениями для обхода прямого использования оператора цикла путём перекладывания этой функции на внутренности платформы. Ведь "СтрЗаменить" и "запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("j");" сами по себе внутри платформы ещё как используют циклы.
(7) Какой переменной в 1С вы будете возвращать факториал ста? Или даже 20? В каких реальных задачах интерпрайза это может быть нужно? Так что код в (6) в реальной жизни и для реальных цифр не будет столь уж большим и страшным. А под любое число вы будете то там, то там натыкаться на различные ограничения.
Сама задача, поставленная автором, к реальной жизни не имеет никакого отношения: цикл является одной из базовых структур любого языка программирования и сознательный отказ от него - очередная попытка натянуть сову на глобус.
(16) Если для платформы это несущественно, то для языка запросов уже все не так однозначно, а народ тут топит за язык запросов, почему-то считая, что SQL там циклы не крутит.
Мы в файл писали, каждый раз дописывая номер итерации (append). На 8.3.13+ было как раз 1700++ итераций (запомнилось, как "1748"). При том не зависело от количества и размера передаваемых параметров.
Что-то сомневаюсь я, что такие деревья существуют (даже 100+ вложений). Ни разу не сталкивался с проблемами рекурсивных алгоритмов, т.к. они подразумевают сравнительно небольшую степень вложенности (те же деревья или XDTO-пакеты, они же типы XML, если только зацикленные - был такой момент в XBRL-отчетности, поставил проверку на повторяемость вложения - достаточно было одного соответствия). Ну и при наличии циклической сцылки и нерекурсивный алгоритм зациклится, просто будет работать бесконечно, а рекурсия хоть вышибет программу. А тут уж не знаю, что лучше (хуже)...
Если требуется часто получать, то лучше регистр сведений.
измерение - аргумент, ресурс - значение, или несколько ресурсов для разбивки по разрядам, например, 10^12 и 10^18.
разово заполнить до какого-то значения, далее для вычисления получать из регистра запросом.
Если в регистре отсутствует, то в фоновом выполнять процедуру расчета, брать ближайший аргумент и умножать (или делить, если ближайший аргумент выше) в цикле или деревом, в клиентском подключить ожидание.