Встретилась задача о вычислении факториала числа без использования цикла. Для платформы 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;
КонецФункции
ПоказатьПо теме из базы знаний
- Алгоритм расчета Факториала
- Объединение двух таблиц значений запросом, циклом
- Вычисление произвольного факториала
- Модель Рагнара Фриша: анализ экономических циклов и эконометрическая верификация
- Движущие силы деловых циклов: От технологических шоков до инвестиционной активности (в духе Финна Кидланда)
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
(4)
&НаСервереБезКонтекста
Функция ФакториалБезЦикла(size=100) экспорт
перем f;
Если size = 0 Тогда
Возврат 1;
КонецЕсли;
arr = new array(size);
Запрос1 = Новый Запрос("
|ВЫБРАТЬ
| 0 КАК Х
|ПОМЕСТИТЬ Регистр1
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| 1
|;
|
|//////////////////////////////////////////////////////////// ////////////////////
|ВЫБРАТЬ
| Младшие.Х + 2 * Старшие.Х КАК Х
|ПОМЕСТИТЬ Регистр2
|ИЗ
| Регистр1 КАК Младшие,
| Регистр1 КАК Старшие
|;
|
|//////////////////////////////////////////////////////////// ////////////////////
|ВЫБРАТЬ
| Младшие.Х + 4 * Старшие.Х КАК Х
|ПОМЕСТИТЬ Регистр4
|ИЗ
| Регистр2 КАК Младшие,
| Регистр2 КАК Старшие
|;
|
|//////////////////////////////////////////////////////////// ////////////////////
|ВЫБРАТЬ ПЕРВЫЕ " + size + "
| Младшие.Х + 16 * Старшие.Х КАК Х
|ИЗ
| Регистр4 КАК Младшие,
| Регистр4 КАК Старшие
|ГДЕ
| Младшие.Х + 16 * Старшие.Х > 0
|
|УПОРЯДОЧИТЬ ПО
| Х");
arr = Запрос1.Выполнить().Выгрузить().ВыгрузитьКолонку("Х");
Выполнить("f="+СтрСоединить(arr,"*"));
возврат f;
КонецФункции
ПоказатьФакториал = 1;
Множитель = 1;
~НачалоЦикла:
Факториал = Факториал * Множитель;
Множитель = Множитель + 1;
Если Множитель <= Цель Тогда
Перейти ~НачалоЦикла;
КонецЕсли;
Сообщить(Факториал); Показать
(5) "Это и я так могу!" (с) Промокашка
В вашем коде нет оператора цикла, но сам цикл - есть. А автор вроде как поставил задачу "без использования цикла".
Как говорится "почувствуйте разницу", аналогичная тема:
P.S. Можно гораздо проще, чем в (1), вот код (фрагмент):
...и так далее. :-)
В вашем коде нет оператора цикла, но сам цикл - есть. А автор вроде как поставил задачу "без использования цикла".
Как говорится "почувствуйте разницу", аналогичная тема:
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; Показать...и так далее. :-)
(6)
Спасибо, кэп!
Увы, но нельзя, т.к. программу, считающую любой факториал таким способом не написать даже теоретически.
Я всего лишь привёл код, подходящий под условия задачи, которые, обычно звучат как "не используя оператор цикла", так как ориентированы на изучающих язык. Думаю, что единственный вариант, строго подходящий под условия - рекурсия, остальные будут просто ухищрениями для обхода прямого использования оператора цикла путём перекладывания этой функции на внутренности платформы. Ведь "СтрЗаменить" и "запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("j");" сами по себе внутри платформы ещё как используют циклы.
В вашем коде нет оператора цикла, но сам цикл - есть.
Спасибо, кэп!
Можно гораздо проще, чем в (1), вот код (фрагмент):
Увы, но нельзя, т.к. программу, считающую любой факториал таким способом не написать даже теоретически.
Я всего лишь привёл код, подходящий под условия задачи, которые, обычно звучат как "не используя оператор цикла", так как ориентированы на изучающих язык. Думаю, что единственный вариант, строго подходящий под условия - рекурсия, остальные будут просто ухищрениями для обхода прямого использования оператора цикла путём перекладывания этой функции на внутренности платформы. Ведь "СтрЗаменить" и "запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("j");" сами по себе внутри платформы ещё как используют циклы.
(7) Какой переменной в 1С вы будете возвращать факториал ста? Или даже 20? В каких реальных задачах интерпрайза это может быть нужно? Так что код в (6) в реальной жизни и для реальных цифр не будет столь уж большим и страшным. А под любое число вы будете то там, то там натыкаться на различные ограничения.
(14)
код в (5) в реальной жизни и для реальных цифр
Сама задача, поставленная автором, к реальной жизни не имеет никакого отношения: цикл является одной из базовых структур любого языка программирования и сознательный отказ от него - очередная попытка натянуть сову на глобус.
не будет столь уж большим и страшным
Для совы? Ой, не уверен в этом... ;-)
(18) Не поленился. Файловая дала 636 рекурсивных вызовов сделать, но неизвестно что там у нее еще на стеке было окормя моей рекурсии.
P.S. Не знал что по переполнению стека 1С вываливает "Аварийное завершение" и все - попробуй найди.
P.S. Не знал что по переполнению стека 1С вываливает "Аварийное завершение" и все - попробуй найди.
(20)
попробуй найди
Мы в файл писали, каждый раз дописывая номер итерации (append). На 8.3.13+ было как раз 1700++ итераций (запомнилось, как "1748"). При том не зависело от количества и размера передаваемых параметров.
(23)
обход дерева или же XDTO какое-нибудь вылетит, то
Что-то сомневаюсь я, что такие деревья существуют (даже 100+ вложений). Ни разу не сталкивался с проблемами рекурсивных алгоритмов, т.к. они подразумевают сравнительно небольшую степень вложенности (те же деревья или XDTO-пакеты, они же типы XML, если только зацикленные - был такой момент в XBRL-отчетности, поставил проверку на повторяемость вложения - достаточно было одного соответствия). Ну и при наличии циклической сцылки и нерекурсивный алгоритм зациклится, просто будет работать бесконечно, а рекурсия хоть вышибет программу. А тут уж не знаю, что лучше (хуже)...
Если требуется часто получать, то лучше регистр сведений.
измерение - аргумент, ресурс - значение, или несколько ресурсов для разбивки по разрядам, например, 10^12 и 10^18.
разово заполнить до какого-то значения, далее для вычисления получать из регистра запросом.
Если в регистре отсутствует, то в фоновом выполнять процедуру расчета, брать ближайший аргумент и умножать (или делить, если ближайший аргумент выше) в цикле или деревом, в клиентском подключить ожидание.
Например,как в фоновом рассчитать
измерение - аргумент, ресурс - значение, или несколько ресурсов для разбивки по разрядам, например, 10^12 и 10^18.
разово заполнить до какого-то значения, далее для вычисления получать из регистра запросом.
Если в регистре отсутствует, то в фоновом выполнять процедуру расчета, брать ближайший аргумент и умножать (или делить, если ближайший аргумент выше) в цикле или деревом, в клиентском подключить ожидание.
Например,как в фоновом рассчитать
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот
