Библиотека математических функций 1.1

Опубликовал Александр Анисин (alex271) в раздел Программирование - Универсальные функции

Привожу тексты различных математических функций, которыми периодически пользуюсь.
Основной акцент ставится на функции работы с матрицами (в 1С в качестве матриц использовались двумерные массивы).
В версии 1.1 функции работы с матрицами немного переписаны для улучшения производительности.

Все функции писал сам. Надеюсь, кому-нибудь они будут полезны.

//кумулятивная функция нормального распределения
Функция NormCDF(x) Экспорт
    Base = 1/2+1/Sqrt(6.283185)*(x-Pow(x,3)/6+Pow(x,5)/40-Pow(x,7)/336+Pow(x,9)/3456-Pow(x,11)/42240);
	Если x < 0 Тогда
        Возврат 1-Base;
    Иначе	
        Возврат Base;
    КонецЕсли; 
КонецФункции 

//факториал числа
Функция Factor(x) Экспорт
    Result = 1;
    Для Индекс = 1 По x Цикл
        Result = Result*Индекс;
    КонецЦикла; 
    Возврат Result;
КонецФункции

//транспонирование матрицы
Функция TransMatrix(Знач х) Экспорт
    r1 = х.Количество();
    r2 = х[0].Количество();
    Result = Новый Массив(r2,r1);
	Для Индекс1 = 0 По r1-1 Цикл
		row = х[Индекс1];
        Для Индекс2 = 0 По r2-1 Цикл
            Result[Индекс2][Индекс1] = row[Индекс2];
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции 

//произведение матриц
Функция ProdMatrix(Знач х,Знач у) Экспорт
    кх1 = х.Количество();
    кх2 = х[0].Количество();
    ку1 = у.Количество();
    ку2 = у[0].Количество();
    Result = Новый Массив(кх1,ку2);
	Для Индекс1 = 0 По кх1-1 Цикл
		rowResult = Result[Индекс1];
        Для Индекс2 = 0 По ку2-1 Цикл
            rowResult[Индекс2] = 0;
            Для Индекс3 = 0 По кх2-1 Цикл
                rowResult[Индекс2] = rowResult[Индекс2]+х[Индекс1][Индекс3]*у[Индекс3][Индекс2];
            КонецЦикла; 
            rowResult[Индекс2] = Окр(rowResult[Индекс2],12);
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции

//обратная матрица
Функция InverseMatrix(Знач у) Экспорт
    х = CopyMatrix(у);
    Ранг = х.Количество();
    Result = IdentityMatrix(Ранг);
	Для Индекс = 0 По Ранг-1 Цикл
        Коэффициент = х[Индекс][Индекс];
        Если Коэффициент = 0 Тогда
            Поиск1 = Неопределено;
            Поиск2 = Неопределено;
            Для Индекс1 = Индекс По Ранг-1 Цикл
                Для Индекс2 = Индекс По Ранг-1 Цикл
                    Если х[Индекс2][Индекс1] <> 0 Тогда
                        Поиск1 = Индекс2;
                        Поиск2 = Индекс1;
                    	Прервать;
                    КонецЕсли;         
                КонецЦикла; 
                Если Поиск1 <> Неопределено Тогда
                    Прервать;
                КонецЕсли; 
            КонецЦикла;
            Если Поиск1 = Неопределено Тогда
                ВызватьИсключение "Матрица вырождена";
            КонецЕсли; 
            х = MatrixPermutation(х,Индекс,Индекс,Поиск1,Поиск2);
            Result = MatrixPermutation(Result,Индекс,Индекс,Поиск1,Поиск2);
		КонецЕсли; 
		rowResult = Result[Индекс];
        Для Индекс3 = 0 По Индекс Цикл
            rowResult[Индекс3] = Окр(rowResult[Индекс3]/Коэффициент,12);
		КонецЦикла;
		row = х[Индекс];
        Для Индекс3 = Индекс По Ранг-1 Цикл
            row[Индекс3] = Окр(row[Индекс3]/Коэффициент,12);
        КонецЦикла;
        Для Индекс4 = 0 По Ранг-1 Цикл
            Если Индекс4 <> Индекс Тогда
                Коэффициент = х[Индекс4][Индекс];
                Для Индекс5 = 0 По Индекс Цикл
                    Result[Индекс4][Индекс5] = Окр(Result[Индекс4][Индекс5]-rowResult[Индекс5]*Коэффициент,12);
                КонецЦикла;     
                Для Индекс5 = Индекс По Ранг-1 Цикл
                    х[Индекс4][Индекс5] = Окр(х[Индекс4][Индекс5]-row[Индекс5]*Коэффициент,12);
                КонецЦикла;     
            КонецЕсли; 
        КонецЦикла;
    КонецЦикла;
    Возврат Result;	
КонецФункции

//единичная матрица
Функция IdentityMatrix(Знач х) Экспорт
    Result = Новый Массив(х,х);
	Для Индекс1 = 0 По х-1 Цикл
		row=Result[Индекс1];
        Для Индекс2 = 0 По х-1 Цикл
            row[Индекс2] = ?(Индекс1 = Индекс2,1,0);
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции

//перемещение строк и колонок внутри матрицы
Функция MatrixPermutation(Знач х,Строка0,Столбец0,Строка1,Столбец1) Экспорт
    Result = CopyMatrix(х);
    кх1 = х.Количество();
    кх2 = х[0].Количество();
    Для Индекс1 = 0 По кх1-1 Цикл
        Для Индекс2 = 0 По кх2-1 Цикл
            Строка = Индекс1;
            Столбец = Индекс2;
            Если Строка = Строка0 Тогда
                Строка = Строка1;
            ИначеЕсли Строка = Строка1 Тогда
                Строка = Строка0;    
            КонецЕсли;
            Если Столбец = Столбец0 Тогда
                Столбец = Столбец1;
            ИначеЕсли Столбец = Столбец1 Тогда
                Столбец = Столбец0;    
            КонецЕсли;
            Result = х[Строка][Столбец];
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции

//копия матрицы
Функция CopyMatrix(Знач х) Экспорт
    r1 = х.Количество();
    r2 = х[0].Количество();
    Result = Новый Массив(r2,r1);
    Для Индекс1 = 0 По r1-1 Цикл
        Для Индекс2 = 0 По r2-1 Цикл
            Result[Индекс2][Индекс1] = х[Индекс2][Индекс1];
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции 

//метод наименьших квадратов
Функция MNK(Знач Matrix,Знач Value) Экспорт
    Trans = TransMatrix(Matrix);
    F1 = ProdMatrix(Trans,Matrix);
    F2 = InverseMatrix(F1);
    F3 = ProdMatrix(F2,Trans);
    Weights = ProdMatrix(F3,Value);
    Отклонения = SumMatrix(ProdMatrix(Matrix,Weights),OppositeMatrix(Value));
    Детерминация = 1-ProdMatrix(TransMatrix(Отклонения),Отклонения)[0][0]/ProdMatrix(TransMatrix(Value),Value)[0][0];
    Возврат Новый Структура("Коэффициенты,Детерминация",Weights,Детерминация);
КонецФункции

//матрица плюс скаляр
Процедура MatrixPlusScalar(Matrix,Scalar) Экспорт
    r1 = Matrix.Количество();
    r2 = Matrix[0].Количество();
	Для Индекс1 = 0 По r1-1 Цикл
		row = Matrix[Индекс1];
        Для Индекс2 = 0 По r2-1 Цикл
            row[Индекс2] = row[Индекс2]+Scalar;
        КонецЦикла; 
    КонецЦикла; 
КонецПроцедуры

//минус матрица
Функция OppositeMatrix(Знач х) Экспорт
    r1 = х.Количество();
    r2 = х[0].Количество();
    Result = Новый Массив(r1,r2);
	Для Индекс1 = 0 По r1-1 Цикл
		rowResult = Result[Индекс1];
		row = х[Индекс1]; 
        Для Индекс2 = 0 По r2-1 Цикл
            rowResult[Индекс2] = -row[Индекс2];
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции

//сумма матриц
Функция SumMatrix(Знач х,Знач у) Экспорт
    r1 = х.Количество();
    r2 = х[0].Количество();
    Result = Новый Массив(r1,r2);
	Для Индекс1 = 0 По r1-1 Цикл
		rowResult = Result[Индекс1];
		rowх = х[Индекс1];
		rowу = у[Индекс1]; 
        Для Индекс2 = 0 По r2-1 Цикл
            rowResult[Индекс2] = rowх[Индекс2]+rowу[Индекс2];
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;	
КонецФункции

//десятичное число в двоичное
Функция DecimalToBinary(х) Экспорт
    Остаток = х;
    Индекс = 0;
    Результат = 0;
    Пока Остаток > 0 Цикл
        Знак = Остаток%2;
        Остаток = (Остаток-Знак)/2;
        Результат = Результат+Знак*Pow(10,Индекс); 
        Индекс = Индекс+1;
    КонецЦикла; 
    Возврат Результат;	
КонецФункции

//коэффициент отклонения двух чисел
Функция RelativeDeviation(х,у,Num = 4) Экспорт
    Возврат Окр(?(х >= у,х/у,у/х),Num)-1;	
КонецФункции 

//модуль числа
Функция AbsValue(х) Экспорт
	Возврат Макс(х,-х);
КонецФункции  

//округление вверх
Функция RoundUp(x,Num = 1) Экспорт
	z = x/Num;
	res = Цел(z);
	Если z <> res Тогда
		z = res+1;
	КонецЕсли; 	
	Возврат z*Num; 
КонецФункции
 


 
 
 
 

 
 
 
 
 
 

Скачать файлы

Наименование Файл Версия Размер
Конфигурация с интегрированной библиотекой функций
.cf 7,59Kb
26.12.14
38
.cf 1.1 7,59Kb 38 Скачать

См. также

Комментарии
1. Иван Иванов (lex27119) 18.12.14 10:46 Сейчас в теме
Сам давно хотел написать в 1С функции для работы с матрицами
2. Василий Зайцев (vasiliy_b) 270 18.12.14 11:46 Сейчас в теме
Не плохо. Напишите пожалуйста в каких задачах применяете.
3. Сергей (necropunk) 4 18.12.14 12:06 Сейчас в теме
Тоже спектр задач интересен. Кажется достаточно узкоспециализированной вещью.
4. lex271 (alex271) 18.12.14 12:07 Сейчас в теме
(2) vasiliy_b,

Основное применение: задачи корреляционно-регрессионного анализа.
Или, для тех кому эта формулировка мало о чем говорит, функции применяются в задачах, где исследуются зависимости между какими-либо показателями.
ekaterinaeon; Andris_infostart; +2 Ответить 1
5. Joda Jedi (hexus) 3 18.12.14 12:13 Сейчас в теме
Спасибо за полезные инструменты. Иногда действительно нужны подобные функции. Обычно пишется на ходу и забывается до следующего раза. Тут все структурировано.
6. Андрей Андреич (Andris_infostart) 18.12.14 17:18 Сейчас в теме
(4) lex271, вопрос по применению данной обработки: "Подскажите, пожалуйста, возможно ли отображение полученных зависимостей в виде графиков и если да, то какими средствами пользуетесь?"
7. lex271 (alex271) 19.12.14 05:50 Сейчас в теме
(6) Andris_infostart,
При желании график можно построить для любых данных.
Функция MNK возвращает два вектора. Один вектор это коэффициенты регрессии, а другой коэффициенты детерминации. Это результаты оценки зависимости.
А что делать с этими результатами личное дело каждого, их можно анализировать программно или визуально, в т.ч. с использованием графиков.
Графики можно строить произвольным способом, в т.ч. средствами платформы 1С или с помощью внешних компонент.
8. Ivan Khorkov (vano-ekt) 816 19.12.14 09:51 Сейчас в теме
я как-то матрицы юзал для хитрых скидок в одной торговой самописке на 8.2
Правда не функциями, а запросом делал
9. Наиль Хамитов (infoengineer) 3 19.12.14 12:30 Сейчас в теме
Более компактное решение для вычисления факториала с помощью рекурсивной функции:

Функция Факториал(n)
Возврат ?(n <= 1, 1, n * Факториал(n - 1))
КонецФункции
10. Михаил Афанасьев (mikmike) 5 19.12.14 12:53 Сейчас в теме
А почему все названия по английски? Неудобно ж переключаться туда сюда.
11. Александр Анисин (alex271) 286 19.12.14 13:02 Сейчас в теме
(10) mikmike,
Во-первых, подстановка работает.
А, во-вторых, главное алгоритм. Если кто-нибудь захочет, всегда можно переименовать.
12. Александр Анисин (alex271) 286 19.12.14 13:04 Сейчас в теме
(9) infoengineer,
Соглашусь, но не очень люблю рекурсию, поэтому как-правило заменяю ее циклами (для лучшего понимания).
13. Петр Базелюк (pbazeliuk) 1218 19.12.14 14:44 Сейчас в теме
(9) infoengineer, рекурсия на порядок больше использует памяти, чем цикл.
Идальго; +1 Ответить 1
14. Руслан Новиков (ruslan0277) 4 19.12.14 15:09 Сейчас в теме
(13) pbazeliuk, правильная рекурсия она как произведение искусства - можно смотреть бесконечно. да и выглядит она более понятней и компактней.
15. TMV 14 20.12.14 10:12 Сейчас в теме
(11) alex271,
Во-первых, подстановка работает.
Как будет работать подстановка без переключения раскладки?
16. Александр Анисин (alex271) 286 22.12.14 05:53 Сейчас в теме
(15) TMV,
После точки список экспортных функций отображается. Нужная, конечно, сразу может не отобразиться.
А, вообще, это личное дело каждого. Кому как удобно, так и называют.
Я их по английски назвал, т.к. это математические функции. В математике принято функции называть на английском языке.
17. Александр Анисин (alex271) 286 22.12.14 13:36 Сейчас в теме
(14) ruslan0277,
Компактней да, соглашусь.
Насчет того, что рекурсия более понятна - вопрос очень спорный.
Когда код изобилует рекурсиями в нем становится очень трудно разобраться.
А красота кода в данном случае не самое главное. Самое главное в коде - это его производительность и потребление ресурсов.
18. Михаил Ляпин (Герасим) 23.12.14 07:20 Сейчас в теме
А Окр() для округления чем не устраивает?
19. Александр Кузин (sashocq) 187 23.12.14 09:48 Сейчас в теме
Я бы добавил к статье примечание, что для производительности лучше циклы записывать в одну строку:
Для Индекс1 = 0 По r1-1 Цикл Для Индекс2 = 0 По r2-1 Цикл Result[Индекс2][Индекс1] = х[Индекс1][Индекс2]; КонецЦикла; КонецЦикла;

Время выполнения цикла может уменьшиться в несколько раз. Тут где-то была статья на эту тему. Но листинг в статье, естественно, менять не нужно.
oleg212; Герасим; +2 3 Ответить 1
20. Александр Кузин (sashocq) 187 23.12.14 09:52 Сейчас в теме
Поставил "+" как только увидел функцию нормального распределения. Мне как-то понадобилась для одной необычной задачи: нужно было сгенерировать документы в базе случайными цифрами (но для достижения определенных значений за период). Много времени убил на поиск этой функции и, подозреваю, что она так и не правильно у меня заработала.
Кстати, это же ее приближение через ряд Тейлора? Я тогда до этого не додумался.
21. Алексей 1 (AlX0id) 23.12.14 10:49 Сейчас в теме
В функции MNK есть вызов некоего Math - видимо, так общий модуль называется.. Нужно убрать наверн ;)
22. Александр Анисин (alex271) 286 23.12.14 11:10 Сейчас в теме
(20) sashocq,
Совершенно верно, это приближение через ряд Тейлора
23. Александр Анисин (alex271) 286 23.12.14 11:24 Сейчас в теме
(21) AlX0id,
Да, все верно.
Math можно убрать. Потом исправлю.
24. Александр Анисин (alex271) 286 23.12.14 11:28 Сейчас в теме
(18) Герасим,
Функция RoundUp округляет вверх. Функция Окр() этого делать не позволяет.
Например, нужно чтобы 2,1 округлялось до 3, а не до 2. Как Вы это сделаете с помощью функции Окр()?
25. Michael Rybakin (Mr.Rm) 23.12.14 11:56 Сейчас в теме
(17) Если от предлагаемых функций требуется производительность, то многое нужно переписать. Сейчас все сделано аккуратным переложением формул.
infoengineer; +1 Ответить 1
26. Asmody (Asmody) 23.12.14 15:03 Сейчас в теме
А чем обосновано использование передачи матриц по значению? Требованиями производительности или потребления ресурсов?
27. Александр Анисин (alex271) 286 24.12.14 05:47 Сейчас в теме
(25) Mr.Rm,
Когда эти функции писались, самым главным была реализация функционала.
Часть проблем с производительностью я решил, весь функционал использующий эти функции отрабатывает достаточно быстро.
Если у Вас есть конкретные предложения по существенному улучшению производительности некоторых функций, то можете их обозначить.
Я предполагаю, что для функции получения обратной матрицы существуют альтернативные алгоритмы и, возможно, мой алгоритм не самый производительный.
В остальной части все написано достаточно оптимально на мой взгляд.
28. Александр Анисин (alex271) 286 24.12.14 05:55 Сейчас в теме
(26) Asmody,
В данном случае скорее логикой разработки.
Чтобы передаваемые переменные не изменились, на всякий пожарный, передается только значение.
В принципе, можно проанализировать функции, и существенную часть этих условий выбросить.
29. Михаил Ляпин (Герасим) 24.12.14 09:09 Сейчас в теме
(24) alex271, виноват, поторопился)
30. Игорь Матюшин (Nebiros777) 2 24.12.14 11:52 Сейчас в теме
Круть, дайте две!!! Коллекция закладок все пополняется и пополняется...
31. DAnry (DAnry) 3 24.12.14 15:03 Сейчас в теме
Плюсанул конечно. Безусловно, статья хорошая и полезная. Но, если честно, в практике програмирования бухгалтерского и управленческого учета в 1С, сложными математическими функциями пользуюсь крайне редко.
32. Michael Rybakin (Mr.Rm) 24.12.14 21:49 Сейчас в теме
Например:
Функция NormCDF(x) Экспорт
    x2=x*x;
    Base = 0.5+0.39894228*(x+x2*(x/-6+x2*(x/40+x2*(x/-336+x2*(x/3456+x2*x/-42240)))));
    Возврат ?(x < 0, 1-Base, Base );
КонецФункции 
...Показать Скрыть

Это быстрее примерно на 25%.
33. Сергей Боровик (BorovikSV) 1108 25.12.14 01:07 Сейчас в теме
(19) sashocq, производительность возрастает исключительно в режиме отладки, поскольку отладчику не нужно обрабатывать переход на новую строку, искать связанные точки останова и т.д.
В штатном режиме работы 1С предприятия выигрыш ничтожен, для того чтобы превращать структурированный алгоритм в спагетти.

Если быть до конца "дотошным", то :
смена номера строки для виртуальной машины 1С одна из самых "легких" операций.
Виртуальная машина 1С просто выполняет инструкцию вида <1,N>, где 1 - команда интерпретатору "смена текущей строки", N - номер строки.
Если отладчик не подцеплен, то задача сводится к присваиванию 32 разрядного числа некой 32 разрядной переменной, что в свою очередь выглядит как одна команда ассемблера MOV.
Остальные инструкции (увеличение счетчика цикла, проверка на выполнения условий цикла, сложение вычитание и т.д.) требуют помещение и извлечение значений (или переменных) из стека виртуальной машины, что вносит задержку.
К тому же манипуляции с числами занимают больше время чем может показаться. Ведь у 1С числа реализованы особым образом ("длинная арифметика"). И при каждой манипуляции с числом происходит нетривиальная работа, требующая от десятка до сотен машинных тактов.

Другим словами, длительностью выполнения инструкции <1,N>, можно пренебречь, а значит и лепить все в одну строку нет необходимости.
А если нужна быстрая математика - то напишите внешнюю компоненту, и получите прирост от 10 до 1000 раз.
Steelvan; iTony73; bforce; Mr.Rm; alex271; +5 Ответить
34. Michael Rybakin (Mr.Rm) 25.12.14 22:13 Сейчас в теме
Добавлю, все же, еще одну исправленную функцию.
Функция ProdMatrix(х, у) Экспорт
    кх1 = х.Количество();
    кх2_1 = х[0].Количество()-1;
    ку1 = у.Количество();
    ку2 = у[0].Количество();
    Result = Новый Массив(кх1,ку2);
	Для Индекс1 = 0 По кх1-1 Цикл
		х1=х[Индекс1];
		R1=Result[Индекс1];
        Для Индекс2 = 0 По ку2-1 Цикл
            R = 0;
            Для Индекс3 = 0 По кх2_1 Цикл
                R = R+х1[Индекс3]*у[Индекс3][Индекс2];
            КонецЦикла; 
            R1[Индекс2] = Окр(R,12);
        КонецЦикла; 
    КонецЦикла; 
    Возврат Result;    
КонецФункции
...Показать Скрыть

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

И DecimalToBinary(х) тоже нужно переписать, даже не ради производительности.
35. Александр Анисин (alex271) 286 26.12.14 06:07 Сейчас в теме
(34) Mr.Rm,
Округление в этих функциях добавлено не просто так. Я расскажу как оно появилось.
Я написал функцию получения обратной матрицы без округления, но она повисала даже на относительно небольших матрицах.
Проблема оказалась в формате числа. 1С позволяет хранить в переменной числа с очень большой точностью в несколько сотен знаков (я точно не помню, но где-то 400).
При вычислении обратной матрицы совершается большое количество операций, числа становятся длинными и производительность падает практически до нуля.
Поэтому пришлось добавить округление. В 1С жесткая типизация числа по размеру памяти для переменных отсутствует в отличие от других языков, что где-то является плюсом, а где-то минусом.
36. Александр Анисин (alex271) 286 26.12.14 07:17 Сейчас в теме
(34) Mr.Rm,
В версии 1.1 исправлены функции работы с матрицами для улучшения производительности
37. Сергей (ildarovich) 4844 26.12.14 08:27 Сейчас в теме
(35) alex271,
Проблема оказалась в формате числа. 1С позволяет хранить в переменной числа с очень большой точностью в несколько сотен знаков (я точно не помню, но где-то 400).
При вычислении обратной матрицы совершается большое количество операций, числа становятся длинными и производительность падает практически до нуля.
Поэтому пришлось добавить округление
наивно и не похоже на правду
38. Михаил Гусев (Идальго) 58 26.12.14 09:17 Сейчас в теме
(35) alex271, боюсь ошибиться, но там вроде двойная точность используется. А с тормозами - да, я тоже сталкивался. Типизация спасает.
39. Сергей Боровик (BorovikSV) 1108 26.12.14 10:43 Сейчас в теме
(35) alex271,
В 1С жесткая типизация числа по размеру памяти для переменных отсутствует в отличие от других языков, что где-то является плюсом, а где-то минусом.


в 1С реализована так называемая длинная арифметика. Длинная арифметика всегда - плюс, тем более для бизнес приложений, и тем более что у вас все равно нет возможности использовать чистый DOUBLE. Функция ОКР как раз и является "поводком" для этой длинной арифметики.
Нужно также отметить что при делении 1С ограничивается точностью 27-28 знаками после запятой. Умножение же может довести точность до бесконечности.

Нужно также отдать должное 1С, она реализовала эту самую длинную арифметику довольно хорошо. Есть ряд библиотек которые тормозят не по детски над тем, что 1С делает почти мгновенно. Все таки рекомендую написать ВК по технологии Native и воткнуть ее в свою библиотеку в виде общего шаблона, и выиграете в скорости неимоверно
40. Валерий Елисеев (THXO) 26.12.14 10:49 Сейчас в теме
http://forum.infostart.ru/forum24/topic122109/message1271074/#message1271074

Соглашусь, но не очень люблю рекурсию, поэтому как-правило заменяю ее циклами (для лучшего понимания).


Я считаю, что с таким тезисом глупо вести речь о программировании математики где либо.
да и вообще программист делать такие заявления права не имеет. это просто непрофессионально. имхо, да какое имхо - правда же.
41. Сергей Боровик (BorovikSV) 1108 26.12.14 11:13 Сейчас в теме
(40) THXO, Рекурсия может дать более лаконичный код, но при этом жрет стек.
И вообще сила программирования - в выполнении задачи разными способами.
Но в принципе рекурсию не любить невозможно :)
42. Валерий Елисеев (THXO) 26.12.14 11:21 Сейчас в теме
(41) Лисп и Пролог в вузах сейчас не учат?)
43. Михаил Гусев (Идальго) 58 26.12.14 11:22 Сейчас в теме
(40) THXO, да фиг знает. Рекурсивные алгоритмы требуют операций со стеком, даже при той же сложности, а значит медленнее и жрут больше памяти. Поэтому не следует пользоваться рекурсией там, где без этого можно обойтись. Хз, именно это автор, по моему, хотел сказать. Что в этом непрофессионального или неверного?
44. Михаил Гусев (Идальго) 58 26.12.14 11:26 Сейчас в теме
(42) THXO, а для Лиспа и Пролога всё подругому? ))
45. Валерий Елисеев (THXO) 26.12.14 11:32 Сейчас в теме
(43) "но не очень люблю рекурсию" - это свойство считаю крамольным)

также строитель может заявить "очень не люблю алебастр, предпочитаю бетон".
46. Сергей (ildarovich) 4844 26.12.14 12:41 Сейчас в теме
(39) BorovikSV,
в 1С реализована так называемая длинная арифметика
а пруфы какие-нибудь есть? Что конкретно вы подразумеваете под длинной арифметикой? Хотите сказать, что время выполнения сложения, умножения, деления, например, будет зависеть от числа разрядов в числе. А проверяли? Не заблуждение ли это?
47. Michael Rybakin (Mr.Rm) 26.12.14 13:29 Сейчас в теме
(39) BorovikSV
При делении 1С дает до 54 знаков после запятой. Длинная арифметика позволяет работать с числами до 308 десятичных знаков целой и 306 дробной части, как раз по порядку double. Можно использовать дробную часть до 324 знаков, но начинаются проблемы при вызове математических функций, т.к. число преобразуется в double, а разрядной сетки не хватает.

Это приводит к очень плохим эффектам. Например, сделаем умножением в цикле x=10e-307 (кстати, в double умещается). Вычислим y=log10(x). И получим какой-то Not-a-Number: ТипЗнч(y) = Число, Строка(y) = ПустаяСтрока, y<0 = Да.
Более того, любые арифметические действия это свойство сохраняют. z=y+1; ТипЗнч(z) = Число, Строка(z) = ПустаяСтрока, и самое интересное z<0 = Да, что приводит к тому, что
Для i=y По 1 Цикл ... КонецЦикла; зависает напрочь.

Значения, возвращенные из мат. функций имеют стандартную разрядность double - 15 знаков.
48. Michael Rybakin (Mr.Rm) 26.12.14 13:38 Сейчас в теме
(46) ildarovich
Нет, не заблуждение. Если принять время умножения или деления однозначных чисел за единицу, то время умножения 16-разрядных будет примерно 2 единицы, их деления - 2.5. Для полноразрядных чисел формата 308.308 умножение в 90, а деление в 110 раз медленнее.
Легко проверить
49. Сергей (ildarovich) 4844 26.12.14 16:32 Сейчас в теме
50. Michael Rybakin (Mr.Rm) 26.12.14 17:16 Сейчас в теме
(49) ildarovich
Так я это и делал, прежде чем цифры писать. Платформа 8.3.5.1248.
51. Сергей (ildarovich) 4844 26.12.14 17:21 Сейчас в теме
(50) Mr.Rm, а приведите обработку или код, если можно ... хотя не нужно - уже нашел объяснение этого феномена.
Числовые величины и в 1С:Предприятии 7.7 и в 1С:Предприятии 8.x представляются как десятичные числа с фиксированной точкой и неограниченной точностью. Сделано это вполне сознательно, так как десятичные числа более адекватны для представления различных величин в программном обеспечении делового назначения.

Если еще точнее, то в 1С:Предприятии 7.7 используется система счисления с основанием 10000, а в 1С:Предприятии 8.x – система счисления с основанием 1000000000. Но, по сути, речь все равно идет о десятичной арифметике. Большее, но кратное десяти основание системы счисления выбрано для повышения эффективности вычислений.

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

В 1С:Предприятии 7.7 при делении точность результата ограничивалась 20-ю десятичными разрядами после точки.

В 1С:Предприятии 8.1 при делении точность результата определяется как точность делимого плюс три разряда по основанию 1000000000. То есть, при делении 1 / 3 результат будет представлен с точностью до 3-х разрядов по основанию 1000000000 или до 27-и десятичных разрядов. А при делении 0.1 / 3 результат будет с точностью до 4-х разрядов по основанию 1000000000 или до 36-и десятичных разрядов.
Хотя происхождение числа 308 все еще непонятно.
52. Michael Rybakin (Mr.Rm) 26.12.14 20:24 Сейчас в теме
(51) ildarovich
308 - это максимальная абсолютная величина порядка в стандартном double. Числа с бо́льшим количеством десятичных знаков не смогут быть корректно приведены к double для передачи во внешние функции или компоненты.

Из приведенного объяснения понятно, что используются binary-coded decimals неограниченного (теоретически, практически - см. выше) размера, разрядностью 16 бит в 7.7 и 32 бита в 8.x. Термин "система счисления с основанием ..." кажется тут неподходящим.

Подробнее только из кода ВМ можно понять.
53. Сергей (ildarovich) 4844 26.12.14 22:23 Сейчас в теме
(52) Mr.Rm,
Длинная арифметика позволяет работать с числами до 308 десятичных знаков целой и 306 дробной части
Но, кажется, до вызова функций, где требуется преобразование, это ограничение не существенно. То есть можно работать (умножать, делить, складывать, вычитать) с числами любой точности без ограничений. Получаем лишь замедление, которое нарастает не плавно, а скачками по 9-ть разрядов у операндов. До 9-ти разрядов - одно время. С 10-ти до 18-ти другое и так далее. Это связано с обработкой отдельных мега-разрядов. Кажется, что длительность умножения будет определяться как О(]М/9[ x ]N/9[), где N, M - число разрядов сомножителей, а ]x[ - ближайшее к x сверху целое.

Например, если 2 х 2 будет выполняться за время t, то 2000000000 х 2000000000 за 4t, а 2000000000000000000 х 2000000000000000000 за 8t.

Из (51) также следует, что высказанное в (39)
при делении 1С ограничивается точностью 27-28 знаков после запятой
это неточное утверждение.

Ну и добавлю по теме статьи.
Наиболее ценная в этой подборке функция вычисления обратной матрицы вызывает наибольшие опасения. Из-за очень вольного управления точностью. Могут быть случаи, когда, умножив матрицу на ее обратную, получим далекую от единичной матрицу. Хотя бы максимальный элемент выбирали для исключения. По виду это вроде Гаусса-Жордана метод? Кажется, у него самые большие проблемы с точностью.
В РАУЗ, например, при решении СЛАУ итерационный алгоритм применяется.
54. Александр Анисин (alex271) 286 29.12.14 08:11 Сейчас в теме
(37) ildarovich,
Тем не менее, все примерно так и было, года три назад
55. Александр Анисин (alex271) 286 29.12.14 08:15 Сейчас в теме
(40) THXO,
Что я люблю и что я не люблю - мое личное дело.
Почему Вы считаете, что у Вас есть право определять что мне писать, а что мне не писать?
56. Александр Анисин (alex271) 286 29.12.14 08:21 Сейчас в теме
(45) THXO,
У рекурсии достаточно минусов, они все названы в этой теме.
Я не вижу смысла ставить акцент на моей нелюбви рекурсии, обсуждение которой началось с того, что мне предложили изменить код вычисления факториала.
В библиотеке есть много других функций, а данная тема предназначена для обсуждения, прежде всего, библиотеки и ее функций.
57. Илья Козлов (ilialin) 29.12.14 12:02 Сейчас в теме
(9) infoengineer,
хоспади,
НИКОГДА НЕЛЬЗЯ ВЫЧИСЛЯТЬ ФАКТОРИАЛ РЕКУРСИЕЙ!!!!!!!

К сожалению, эта детская ошибка встречается в большинстве отечественных учебников по программированию. Как заходит речь о рекурсии, так обязательно следует пример с факториалом.
Рекурсия - интересный метод и существует четко определенный класс задач, где она себя прекрасно показывает (и которые проблематично решить без использования оной). Предназначение рекурсии - обход деревьев. Не надо совать ее в другие места.
58. Erik Nas (987ww765) 10 30.12.14 08:50 Сейчас в теме
(57) ilialin, поясните безграмотному почему нельзя? Только потому что рекурсия предназначена для деревьев?
59. Артано Майаров (Артано) 318 31.12.14 11:04 Сейчас в теме
(58) Думаю, что смысл в значительной потере производительности, ради экономии пары строк кода. Я бы конечно высказался не так категорично, но в данном случае претензию считаю обоснованной
60. Валерий Елисеев (THXO) 31.12.14 14:57 Сейчас в теме
(55) я считаю крамольным свойство, а не вас. даже если его озвучит в той форме как у вас всевышний - я буду считать его еретиком)

зачем так подозрительно думать о своей собственной персоне? а то претензия ко мне как от женщины "сама придумала, сама обиделась".)
61. Илья Козлов (ilialin) 31.12.14 16:31 Сейчас в теме
"Для малой группы задач рекурсия позволяет создать простые, элегантные решения. Для несколько большей группы задач она позволяет создать простые, элегантные, трудные для понимания решения. Для большинства задач она создает исключительно запутанные решения - в таких случаях использование простых итераций обычно более понятно..." - Стив Макконнелл. Совершенный код.
----------
Какая цель преследовалась вами при рекомендации использовать рекурсию при вычислении факториала, вместо цикла? Компактность кода? Ну допустим. А что еще? Какие еще преимущества рекурсии в данном случае? А какие недостатки? А такие:
- трудность понимания, что делает данный код (ну ладно, в данном случае функция называется "Факториал", мы знаем как он считается, можем сообразить как работает код; но если цикл в данном случае понимается моментально, то рекурсия потребует больше времени на понимание);
- непредсказуемые затраты памяти;
- большее время выполнения.
Один плюс, три минуса.
----------
"В погоне за оптимизацией можно сделать программный код совершенно нечитаемым. <...> поддержка такого кода станет очень сложным делом. Человек, который не принимал участия в написании этого кода, скорее всего, просто не станет раскапывать этот кладезь оптимизации. А сам разработчик через полгода - год тоже с большим трудом сможет разобраться в том, что же он написал..." - Профессиональная разработка в системе "1С:Предприятие 8", 1 том.
987ww765; +1 Ответить
62. Александр Анисин (alex271) 286 01.01.15 18:22 Сейчас в теме
63. Андрей Старченко (dr.death) 43 12.01.15 14:19 Сейчас в теме
зачем на округление вверх городить?!! можно стандартной это к (24) alex271,
Окр(x+0.49, num)
64. Александр Анисин (alex271) 286 13.01.15 05:18 Сейчас в теме
(63) dr.death,
Не соглашусь с Вами.
Точность округления не известна, число которое нужно прибавить будет зависеть от точности.
Например x=2,0001 тогда Окр(x+0,49) = Окр(2,4901) = 2, а нужно 3
65. Алексей Никитин (it-al) 8 30.01.15 16:30 Сейчас в теме
Можно ли посчитать полином второй степени функцией
Функция MNK(Знач Matrix,Знач Value)
и что помещать в матрицы Matrix,Value
66. Александр Анисин (alex271) 286 31.01.15 12:19 Сейчас в теме
(65) it-al,
Matrix - это матрица исходных данных (параметров), Value - вектор целевых значений. Подробнее смотрите ссылку ru.wikipedia.org/wiki/Метод_наименьших_квадратов