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

Привожу тексты различных математических функций, которыми периодически пользуюсь.
Основной акцент ставится на функции работы с матрицами (в 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;
КонецФункции













64 Comments

  1. lex27119

    Сам давно хотел написать в 1С функции для работы с матрицами

    Reply
  2. vasiliy_b

    Не плохо. Напишите пожалуйста в каких задачах применяете.

    Reply
  3. necropunk

    Тоже спектр задач интересен. Кажется достаточно узкоспециализированной вещью.

    Reply
  4. alex271

    (2) vasiliy_b,

    Основное применение: задачи корреляционно-регрессионного анализа.

    Или, для тех кому эта формулировка мало о чем говорит, функции применяются в задачах, где исследуются зависимости между какими-либо показателями.

    Reply
  5. hexus

    Спасибо за полезные инструменты. Иногда действительно нужны подобные функции. Обычно пишется на ходу и забывается до следующего раза. Тут все структурировано.

    Reply
  6. Andris_infostart

    (4) вопрос по применению данной обработки: «Подскажите, пожалуйста, возможно ли отображение полученных зависимостей в виде графиков и если да, то какими средствами пользуетесь?»

    Reply
  7. alex271

    (6) Andris_infostart,

    При желании график можно построить для любых данных.

    Функция MNK возвращает два вектора. Один вектор это коэффициенты регрессии, а другой коэффициенты детерминации. Это результаты оценки зависимости.

    А что делать с этими результатами личное дело каждого, их можно анализировать программно или визуально, в т.ч. с использованием графиков.

    Графики можно строить произвольным способом, в т.ч. средствами платформы 1С или с помощью внешних компонент.

    Reply
  8. vano-ekt

    я как-то матрицы юзал для хитрых скидок в одной торговой самописке на 8.2

    Правда не функциями, а запросом делал

    Reply
  9. mikmike

    А почему все названия по английски? Неудобно ж переключаться туда сюда.

    Reply
  10. alex271

    (10) mikmike,

    Во-первых, подстановка работает.

    А, во-вторых, главное алгоритм. Если кто-нибудь захочет, всегда можно переименовать.

    Reply
  11. alex271

    (9) infoengineer,

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

    Reply
  12. pbazeliuk

    (9) infoengineer, рекурсия на порядок больше использует памяти, чем цикл.

    Reply
  13. ruslan0277

    (13) pbazeliuk, правильная рекурсия она как произведение искусства — можно смотреть бесконечно. да и выглядит она более понятней и компактней.

    Reply
  14. TMV

    (11) alex271,

    Во-первых, подстановка работает.

    Как будет работать подстановка без переключения раскладки?

    Reply
  15. alex271

    (15) TMV,

    После точки список экспортных функций отображается. Нужная, конечно, сразу может не отобразиться.

    А, вообще, это личное дело каждого. Кому как удобно, так и называют.

    Я их по английски назвал, т.к. это математические функции. В математике принято функции называть на английском языке.

    Reply
  16. alex271

    (14) ruslan0277,

    Компактней да, соглашусь.

    Насчет того, что рекурсия более понятна — вопрос очень спорный.

    Когда код изобилует рекурсиями в нем становится очень трудно разобраться.

    А красота кода в данном случае не самое главное. Самое главное в коде — это его производительность и потребление ресурсов.

    Reply
  17. Герасим

    А Окр() для округления чем не устраивает?

    Reply
  18. sashocq

    Поставил «+» как только увидел функцию нормального распределения. Мне как-то понадобилась для одной необычной задачи: нужно было сгенерировать документы в базе случайными цифрами (но для достижения определенных значений за период). Много времени убил на поиск этой функции и, подозреваю, что она так и не правильно у меня заработала.

    Кстати, это же ее приближение через ряд Тейлора? Я тогда до этого не додумался.

    Reply
  19. AlX0id

    В функции MNK есть вызов некоего Math — видимо, так общий модуль называется.. Нужно убрать наверн 😉

    Reply
  20. alex271

    (20) sashocq,

    Совершенно верно, это приближение через ряд Тейлора

    Reply
  21. alex271

    (21) AlX0id,

    Да, все верно.

    Math можно убрать. Потом исправлю.

    Reply
  22. alex271

    (18) Герасим,

    Функция RoundUp округляет вверх. Функция Окр() этого делать не позволяет.

    Например, нужно чтобы 2,1 округлялось до 3, а не до 2. Как Вы это сделаете с помощью функции Окр()?

    Reply
  23. Mr.Rm

    (17) Если от предлагаемых функций требуется производительность, то многое нужно переписать. Сейчас все сделано аккуратным переложением формул.

    Reply
  24. Asmody

    А чем обосновано использование передачи матриц по значению? Требованиями производительности или потребления ресурсов?

    Reply
  25. alex271

    (25) Mr.Rm,

    Когда эти функции писались, самым главным была реализация функционала.

    Часть проблем с производительностью я решил, весь функционал использующий эти функции отрабатывает достаточно быстро.

    Если у Вас есть конкретные предложения по существенному улучшению производительности некоторых функций, то можете их обозначить.

    Я предполагаю, что для функции получения обратной матрицы существуют альтернативные алгоритмы и, возможно, мой алгоритм не самый производительный.

    В остальной части все написано достаточно оптимально на мой взгляд.

    Reply
  26. alex271

    (26) Asmody,

    В данном случае скорее логикой разработки.

    Чтобы передаваемые переменные не изменились, на всякий пожарный, передается только значение.

    В принципе, можно проанализировать функции, и существенную часть этих условий выбросить.

    Reply
  27. Герасим

    (24) alex271, виноват, поторопился)

    Reply
  28. Nebiros777

    Круть, дайте две!!! Коллекция закладок все пополняется и пополняется…

    Reply
  29. DAnry

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

    Reply
  30. Mr.Rm

    Например:

    Функция 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%.

    Reply
  31. BorovikSV

    (19) sashocq, производительность возрастает исключительно в режиме отладки, поскольку отладчику не нужно обрабатывать переход на новую строку, искать связанные точки останова и т.д.

    В штатном режиме работы 1С предприятия выигрыш ничтожен, для того чтобы превращать структурированный алгоритм в спагетти.

    Если быть до конца «дотошным», то :

    смена номера строки для виртуальной машины 1С одна из самых «легких» операций.

    Виртуальная машина 1С просто выполняет инструкцию вида <1,N>, где 1 — команда интерпретатору «смена текущей строки», N — номер строки.

    Если отладчик не подцеплен, то задача сводится к присваиванию 32 разрядного числа некой 32 разрядной переменной, что в свою очередь выглядит как одна команда ассемблера MOV.

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

    К тому же манипуляции с числами занимают больше время чем может показаться. Ведь у 1С числа реализованы особым образом («длинная арифметика»). И при каждой манипуляции с числом происходит нетривиальная работа, требующая от десятка до сотен машинных тактов.

    Другим словами, длительностью выполнения инструкции <1,N>, можно пренебречь, а значит и лепить все в одну строку нет необходимости.

    А если нужна быстрая математика — то напишите внешнюю компоненту, и получите прирост от 10 до 1000 раз.

    Reply
  32. Mr.Rm

    Добавлю, все же, еще одну исправленную функцию.

    Функция 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;
    КонецФункции
    

    Показать

    Округление кажется лишним, но пусть останется.

    Не знаю, какой типичный размер матриц у автора, но уже для 4×4 разница вдвое.

    И DecimalToBinary(х) тоже нужно переписать, даже не ради производительности.

    Reply
  33. alex271

    (34) Mr.Rm,

    Округление в этих функциях добавлено не просто так. Я расскажу как оно появилось.

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

    Проблема оказалась в формате числа. 1С позволяет хранить в переменной числа с очень большой точностью в несколько сотен знаков (я точно не помню, но где-то 400).

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

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

    Reply
  34. alex271

    (34) Mr.Rm,

    В версии 1.1 исправлены функции работы с матрицами для улучшения производительности

    Reply
  35. ildarovich

    (35) alex271,

    Проблема оказалась в формате числа. 1С позволяет хранить в переменной числа с очень большой точностью в несколько сотен знаков (я точно не помню, но где-то 400).

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

    Поэтому пришлось добавить округление

    наивно и не похоже на правду

    Reply
  36. Идальго

    (35) alex271, боюсь ошибиться, но там вроде двойная точность используется. А с тормозами — да, я тоже сталкивался. Типизация спасает.

    Reply
  37. BorovikSV

    (35) alex271,

    В 1С жесткая типизация числа по размеру памяти для переменных отсутствует в отличие от других языков, что где-то является плюсом, а где-то минусом.

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

    Нужно также отметить что при делении 1С ограничивается точностью 27-28 знаками после запятой. Умножение же может довести точность до бесконечности.

    Нужно также отдать должное 1С, она реализовала эту самую длинную арифметику довольно хорошо. Есть ряд библиотек которые тормозят не по детски над тем, что 1С делает почти мгновенно. Все таки рекомендую написать ВК по технологии Native и воткнуть ее в свою библиотеку в виде общего шаблона, и выиграете в скорости неимоверно

    Reply
  38. THXO

    http://forum.infostart.ru/forum24/topic122109/message1271074/#message1271074

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

    Я считаю, что с таким тезисом глупо вести речь о программировании математики где либо.

    да и вообще программист делать такие заявления права не имеет. это просто непрофессионально. имхо, да какое имхо — правда же.

    Reply
  39. BorovikSV

    (40) THXO, Рекурсия может дать более лаконичный код, но при этом жрет стек.

    И вообще сила программирования — в выполнении задачи разными способами.

    Но в принципе рекурсию не любить невозможно 🙂

    Reply
  40. THXO

    (41) Лисп и Пролог в вузах сейчас не учат?)

    Reply
  41. Идальго

    (40) THXO, да фиг знает. Рекурсивные алгоритмы требуют операций со стеком, даже при той же сложности, а значит медленнее и жрут больше памяти. Поэтому не следует пользоваться рекурсией там, где без этого можно обойтись. Хз, именно это автор, по моему, хотел сказать. Что в этом непрофессионального или неверного?

    Reply
  42. Идальго

    (42) THXO, а для Лиспа и Пролога всё подругому? ))

    Reply
  43. THXO

    (43) «но не очень люблю рекурсию» — это свойство считаю крамольным)

    также строитель может заявить «очень не люблю алебастр, предпочитаю бетон».

    Reply
  44. ildarovich

    (39) BorovikSV,

    в 1С реализована так называемая длинная арифметика

    а пруфы какие-нибудь есть? Что конкретно вы подразумеваете под длинной арифметикой? Хотите сказать, что время выполнения сложения, умножения, деления, например, будет зависеть от числа разрядов в числе. А проверяли? Не заблуждение ли это?

    Reply
  45. Mr.Rm

    (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 знаков.

    Reply
  46. Mr.Rm

    (46) ildarovich

    Нет, не заблуждение. Если принять время умножения или деления однозначных чисел за единицу, то время умножения 16-разрядных будет примерно 2 единицы, их деления — 2.5. Для полноразрядных чисел формата 308.308 умножение в 90, а деление в 110 раз медленнее.

    Легко проверить

    Reply
  47. ildarovich

    (48) Mr.Rm, а вот проверьте

    Reply
  48. Mr.Rm

    (49) ildarovich

    Так я это и делал, прежде чем цифры писать. Платформа 8.3.5.1248.

    Reply
  49. ildarovich

    (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 все еще непонятно.

    Reply
  50. Mr.Rm

    (51) ildarovich

    308 — это максимальная абсолютная величина порядка в стандартном double. Числа с бо́льшим количеством десятичных знаков не смогут быть корректно приведены к double для передачи во внешние функции или компоненты.

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

    Подробнее только из кода ВМ можно понять.

    Reply
  51. ildarovich

    (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 знаков после запятой

    это неточное утверждение.

    Ну и добавлю по теме статьи.

    Наиболее ценная в этой подборке функция вычисления обратной матрицы вызывает наибольшие опасения. Из-за очень вольного управления точностью. Могут быть случаи, когда, умножив матрицу на ее обратную, получим далекую от единичной матрицу. Хотя бы максимальный элемент выбирали для исключения. По виду это вроде Гаусса-Жордана метод? Кажется, у него самые большие проблемы с точностью.

    В РАУЗ, например, при решении СЛАУ итерационный алгоритм применяется.

    Reply
  52. alex271

    (37) ildarovich,

    Тем не менее, все примерно так и было, года три назад

    Reply
  53. alex271

    (40) THXO,

    Что я люблю и что я не люблю — мое личное дело.

    Почему Вы считаете, что у Вас есть право определять что мне писать, а что мне не писать?

    Reply
  54. alex271

    (45) THXO,

    У рекурсии достаточно минусов, они все названы в этой теме.

    Я не вижу смысла ставить акцент на моей нелюбви рекурсии, обсуждение которой началось с того, что мне предложили изменить код вычисления факториала.

    В библиотеке есть много других функций, а данная тема предназначена для обсуждения, прежде всего, библиотеки и ее функций.

    Reply
  55. ilialin

    (9) infoengineer,

    хоспади,

    НИКОГДА НЕЛЬЗЯ ВЫЧИСЛЯТЬ ФАКТОРИАЛ РЕКУРСИЕЙ!!!!!!!

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

    Рекурсия — интересный метод и существует четко определенный класс задач, где она себя прекрасно показывает (и которые проблематично решить без использования оной). Предназначение рекурсии — обход деревьев. Не надо совать ее в другие места.

    Reply
  56. 987ww765

    (57) ilialin, поясните безграмотному почему нельзя? Только потому что рекурсия предназначена для деревьев?

    Reply
  57. Артано

    (58) Думаю, что смысл в значительной потере производительности, ради экономии пары строк кода. Я бы конечно высказался не так категорично, но в данном случае претензию считаю обоснованной

    Reply
  58. THXO

    (55) я считаю крамольным свойство, а не вас. даже если его озвучит в той форме как у вас всевышний — я буду считать его еретиком)

    зачем так подозрительно думать о своей собственной персоне? а то претензия ко мне как от женщины «сама придумала, сама обиделась».)

    Reply
  59. ilialin

    «Для малой группы задач рекурсия позволяет создать простые, элегантные решения. Для несколько большей группы задач она позволяет создать простые, элегантные, трудные для понимания решения. Для большинства задач она создает исключительно запутанные решения — в таких случаях использование простых итераций обычно более понятно…» — Стив Макконнелл. Совершенный код.

    ———-

    Какая цель преследовалась вами при рекомендации использовать рекурсию при вычислении факториала, вместо цикла? Компактность кода? Ну допустим. А что еще? Какие еще преимущества рекурсии в данном случае? А какие недостатки? А такие:

    — трудность понимания, что делает данный код (ну ладно, в данном случае функция называется «Факториал», мы знаем как он считается, можем сообразить как работает код; но если цикл в данном случае понимается моментально, то рекурсия потребует больше времени на понимание);

    — непредсказуемые затраты памяти;

    — большее время выполнения.

    Один плюс, три минуса.

    ———-

    «В погоне за оптимизацией можно сделать программный код совершенно нечитаемым. <…> поддержка такого кода станет очень сложным делом. Человек, который не принимал участия в написании этого кода, скорее всего, просто не станет раскапывать этот кладезь оптимизации. А сам разработчик через полгода — год тоже с большим трудом сможет разобраться в том, что же он написал…» — Профессиональная разработка в системе «1С:Предприятие 8», 1 том.

    Reply
  60. alex271

    (60) THXO,

    Ничего не понял

    Reply
  61. 1cprogr_nsk

    зачем на округление вверх городить?!! можно стандартной это к (24) alex271,

    Окр(x+0.49, num)
    Reply
  62. alex271

    (63) dr.death,

    Не соглашусь с Вами.

    Точность округления не известна, число которое нужно прибавить будет зависеть от точности.

    Например x=2,0001 тогда Окр(x+0,49) = Окр(2,4901) = 2, а нужно 3

    Reply
  63. it-al

    Можно ли посчитать полином второй степени функцией

    Функция MNK(Знач Matrix,Знач Value)

    и что помещать в матрицы Matrix,Value

    Reply
  64. alex271

    (65) it-al,

    Matrix — это матрица исходных данных (параметров), Value — вектор целевых значений. Подробнее смотрите ссылку ru.wikipedia.org/wiki/Метод_наименьших_квадратов

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *