gifts2017

Библиотека математических функций 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; 
КонецФункции
 


 
 
 
 

 
 
 
 
 
 

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

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

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Иван Иванов (lex27119) 18.12.14 10:46
Сам давно хотел написать в 1С функции для работы с матрицами
2. Василий Зайцев (vasiliy_b) 18.12.14 11:46
Не плохо. Напишите пожалуйста в каких задачах применяете.
3. Сергей (necropunk) 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) 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) 19.12.14 09:51
я как-то матрицы юзал для хитрых скидок в одной торговой самописке на 8.2
Правда не функциями, а запросом делал
9. Наиль Хамитов (infoengineer) 19.12.14 12:30
Более компактное решение для вычисления факториала с помощью рекурсивной функции:

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

Время выполнения цикла может уменьшиться в несколько раз. Тут где-то была статья на эту тему. Но листинг в статье, естественно, менять не нужно.
oleg212; Герасим; +2 3 Ответить 1
20. Александр Кузин (sashocq) 23.12.14 09:52
Поставил "+" как только увидел функцию нормального распределения. Мне как-то понадобилась для одной необычной задачи: нужно было сгенерировать документы в базе случайными цифрами (но для достижения определенных значений за период). Много времени убил на поиск этой функции и, подозреваю, что она так и не правильно у меня заработала.
Кстати, это же ее приближение через ряд Тейлора? Я тогда до этого не додумался.
21. Алексей 1 (AlX0id) 23.12.14 10:49
В функции MNK есть вызов некоего Math - видимо, так общий модуль называется.. Нужно убрать наверн ;)
22. Александр Анисин (alex271) 23.12.14 11:10
(20) sashocq,
Совершенно верно, это приближение через ряд Тейлора
23. Александр Анисин (alex271) 23.12.14 11:24
(21) AlX0id,
Да, все верно.
Math можно убрать. Потом исправлю.
24. Александр Анисин (alex271) 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) 24.12.14 05:47
(25) Mr.Rm,
Когда эти функции писались, самым главным была реализация функционала.
Часть проблем с производительностью я решил, весь функционал использующий эти функции отрабатывает достаточно быстро.
Если у Вас есть конкретные предложения по существенному улучшению производительности некоторых функций, то можете их обозначить.
Я предполагаю, что для функции получения обратной матрицы существуют альтернативные алгоритмы и, возможно, мой алгоритм не самый производительный.
В остальной части все написано достаточно оптимально на мой взгляд.
28. Александр Анисин (alex271) 24.12.14 05:55
(26) Asmody,
В данном случае скорее логикой разработки.
Чтобы передаваемые переменные не изменились, на всякий пожарный, передается только значение.
В принципе, можно проанализировать функции, и существенную часть этих условий выбросить.
29. Михаил Ляпин (Герасим) 24.12.14 09:09
(24) alex271, виноват, поторопился)
30. Игорь Матюшин (Nebiros777) 24.12.14 11:52
Круть, дайте две!!! Коллекция закладок все пополняется и пополняется...
31. DAnry (DAnry) 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) 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) 26.12.14 06:07
(34) Mr.Rm,
Округление в этих функциях добавлено не просто так. Я расскажу как оно появилось.
Я написал функцию получения обратной матрицы без округления, но она повисала даже на относительно небольших матрицах.
Проблема оказалась в формате числа. 1С позволяет хранить в переменной числа с очень большой точностью в несколько сотен знаков (я точно не помню, но где-то 400).
При вычислении обратной матрицы совершается большое количество операций, числа становятся длинными и производительность падает практически до нуля.
Поэтому пришлось добавить округление. В 1С жесткая типизация числа по размеру памяти для переменных отсутствует в отличие от других языков, что где-то является плюсом, а где-то минусом.
36. Александр Анисин (alex271) 26.12.14 07:17
(34) Mr.Rm,
В версии 1.1 исправлены функции работы с матрицами для улучшения производительности
37. Сергей (ildarovich) 26.12.14 08:27
(35) alex271,
Проблема оказалась в формате числа. 1С позволяет хранить в переменной числа с очень большой точностью в несколько сотен знаков (я точно не помню, но где-то 400).
При вычислении обратной матрицы совершается большое количество операций, числа становятся длинными и производительность падает практически до нуля.
Поэтому пришлось добавить округление
наивно и не похоже на правду
38. Михаил Гусев (Идальго) 26.12.14 09:17
(35) alex271, боюсь ошибиться, но там вроде двойная точность используется. А с тормозами - да, я тоже сталкивался. Типизация спасает.
39. Сергей Боровик (BorovikSV) 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) 26.12.14 11:13
(40) THXO, Рекурсия может дать более лаконичный код, но при этом жрет стек.
И вообще сила программирования - в выполнении задачи разными способами.
Но в принципе рекурсию не любить невозможно :)
42. Валерий Елисеев (THXO) 26.12.14 11:21
(41) Лисп и Пролог в вузах сейчас не учат?)
43. Михаил Гусев (Идальго) 26.12.14 11:22
(40) THXO, да фиг знает. Рекурсивные алгоритмы требуют операций со стеком, даже при той же сложности, а значит медленнее и жрут больше памяти. Поэтому не следует пользоваться рекурсией там, где без этого можно обойтись. Хз, именно это автор, по моему, хотел сказать. Что в этом непрофессионального или неверного?
44. Михаил Гусев (Идальго) 26.12.14 11:26
(42) THXO, а для Лиспа и Пролога всё подругому? ))
45. Валерий Елисеев (THXO) 26.12.14 11:32
(43) "но не очень люблю рекурсию" - это свойство считаю крамольным)

также строитель может заявить "очень не люблю алебастр, предпочитаю бетон".
46. Сергей (ildarovich) 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) 26.12.14 16:32
50. Michael Rybakin (Mr.Rm) 26.12.14 17:16
(49) ildarovich
Так я это и делал, прежде чем цифры писать. Платформа 8.3.5.1248.
51. Сергей (ildarovich) 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) 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) 29.12.14 08:11
(37) ildarovich,
Тем не менее, все примерно так и было, года три назад
55. Александр Анисин (alex271) 29.12.14 08:15
(40) THXO,
Что я люблю и что я не люблю - мое личное дело.
Почему Вы считаете, что у Вас есть право определять что мне писать, а что мне не писать?
56. Александр Анисин (alex271) 29.12.14 08:21
(45) THXO,
У рекурсии достаточно минусов, они все названы в этой теме.
Я не вижу смысла ставить акцент на моей нелюбви рекурсии, обсуждение которой началось с того, что мне предложили изменить код вычисления факториала.
В библиотеке есть много других функций, а данная тема предназначена для обсуждения, прежде всего, библиотеки и ее функций.
57. Илья Козлов (ilialin) 29.12.14 12:02
(9) infoengineer,
хоспади,
НИКОГДА НЕЛЬЗЯ ВЫЧИСЛЯТЬ ФАКТОРИАЛ РЕКУРСИЕЙ!!!!!!!

К сожалению, эта детская ошибка встречается в большинстве отечественных учебников по программированию. Как заходит речь о рекурсии, так обязательно следует пример с факториалом.
Рекурсия - интересный метод и существует четко определенный класс задач, где она себя прекрасно показывает (и которые проблематично решить без использования оной). Предназначение рекурсии - обход деревьев. Не надо совать ее в другие места.
58. Erik Nas (987ww765) 30.12.14 08:50
(57) ilialin, поясните безграмотному почему нельзя? Только потому что рекурсия предназначена для деревьев?
59. Артано Майаров (Артано) 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) 01.01.15 18:22
63. Андрей Старченко (dr.death) 12.01.15 14:19
зачем на округление вверх городить?!! можно стандартной это к (24) alex271,
Окр(x+0.49, num)
64. Александр Анисин (alex271) 13.01.15 05:18
(63) dr.death,
Не соглашусь с Вами.
Точность округления не известна, число которое нужно прибавить будет зависеть от точности.
Например x=2,0001 тогда Окр(x+0,49) = Окр(2,4901) = 2, а нужно 3
65. Алексей Никитин (it-al) 30.01.15 16:30
Можно ли посчитать полином второй степени функцией
Функция MNK(Знач Matrix,Знач Value)
и что помещать в матрицы Matrix,Value
66. Александр Анисин (alex271) 31.01.15 12:19
(65) it-al,
Matrix - это матрица исходных данных (параметров), Value - вектор целевых значений. Подробнее смотрите ссылку ru.wikipedia.org/wiki/Метод_наименьших_квадратов
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа