Имя: Пароль:
1C
 
v8: Анализатор произвольных формул
0 mzelensky
 
10.04.13
10:21
Доброго всем!
Есть вроде как примитивная задачка (для человека), которую никак не удается реализовать программно.

Имеется формула (ее вводит пользователь, значения параметров подаются из вне):

Результат = П1 * ( П2 + П3)

где
П1= 10
П2= 5
П3= 2

Не нужно быть гением, дабы догадаться, что результат будет равен "70".
Рассчитать данную формулу в 1С не составляет труда через "Вычислить()" или "Выполнить()".

Но у меня встает обратная задача. Допустим, мне измвестно:

Результат=70
П2= 5
П3= 2

И нужно найти значение параметра "П1".

КАК ЭТО СДЕЛАТЬ?!
1 В тылу врага
 
10.04.13
10:23
Результат = П1*П1
Результат = 4
П1 = ?
2 vde69
 
10.04.13
10:23
пусть пользователь напишет ВТОРУЮ формулу
3 cw014
 
10.04.13
10:24
Разбираешь формулу на составляющие, делаешь парсер, от него обратный парсер. Ничего сложного
4 Волшебник
 
10.04.13
10:24
П1 = Результат/(П2+П3)
5 vmv
 
10.04.13
10:25
простешие уравнения в 5-м классе проходят

*достал ранец*
6 mzelensky
 
10.04.13
10:25
(2) не вариант. Формула может быь большой (с большим количеством параметров) и искомый параметр может быть ЛЮБЫМ. Один любой из множества. Вводить формулу для каждого параметра это не вариант.
7 В тылу врага
 
10.04.13
10:26
ответьте на (1) пожалуйста
8 HeroShima
 
10.04.13
10:26
поиск апроксимирующей функции
9 mzelensky
 
10.04.13
10:26
(4) молодец! А теперь как формулу

"П1 = Результат/(П2+П3)"

получить программно?!
Или ты сам пойдешь на 0,000001 ставки - формулы переворачивать?!
10 В тылу врага
 
10.04.13
10:26
какие операции допустимы?
11 mzelensky
 
10.04.13
10:27
(3) нука, как будет выглядеть парсер такой формулы:

"((П1 + п2) * П3)/П4 "

?!
12 cw014
 
10.04.13
10:27
(9) Не майся ерундой, только если за это не заплатят более 200 000 деревянных
13 mzelensky
 
10.04.13
10:27
(10) К сожалению, любые арифметические.

Т.е. все, что могу тпереварить эти функции:

"Вычислить()" или "Выполнить()".
14 Godofsin
 
10.04.13
10:28
(12) ++++++
15 mzelensky
 
10.04.13
10:29
(7) 2
16 В тылу врага
 
10.04.13
10:29
(13) арифметичиских операций в 1С всего 4 вроде как, ну еще %
17 В тылу врага
 
10.04.13
10:29
(15) а почему не -2?
18 mzelensky
 
10.04.13
10:29
(12) это ты так признал тот факт ,что ты не можешь ничего путного предложить?!
19 cw014
 
10.04.13
10:30
(17) +++++++++++++++
20 mzelensky
 
10.04.13
10:30
(16) Ок, пусть даже так.
21 HeroShima
 
10.04.13
10:31
а если формула известна, исходим из того, что у каждой операции есть обратная. строим уравнение относительно неизвестного
22 fmrlex
 
10.04.13
10:31
23 mzelensky
 
10.04.13
10:31
(17) Может и -2, но в 99% случаев используются положительные параметры. Ты указал на "исключение". Предложи хотя бы реализацию "общего", идеального случая из (0)
24 mzelensky
 
10.04.13
10:32
(21) как построить это уравнение программно!? научи?!
25 mzelensky
 
10.04.13
10:32
(22)оооох, давненько я на этот сайт не захаживал :)
26 cw014
 
10.04.13
10:33
(25) Да, и ерунду всякую не спрашивал... ))))))
27 fmrlex
 
10.04.13
10:33
28 HeroShima
 
10.04.13
10:33
(24) порой алгоритмы солверов
29 В тылу врага
 
10.04.13
10:34
(23) это только частный случай, можно подобрать и посложнее ))
30 fmrlex
 
10.04.13
10:34
А вообще рекомендую подключаться к математическим библиотекам. Т.к. задача не тривиальная. OpenSource мат библиотеки есть, погугли
31 В тылу врага
 
10.04.13
10:36
давай лучше аналог 1С писать
32 Rovan
 
гуру
10.04.13
10:37
(0) передаешь формулу сайту nigma.ru
- он всё посчитает
например
(x + 7) * 8 = 2
33 HeroShima
 
10.04.13
10:37
(31) пишите лучше что-то превосходящее)
34 Волшебник
 
10.04.13
10:38
(9) MatLab прикрути
35 Rovan
 
гуру
10.04.13
10:38
36 Lexusss
 
10.04.13
10:39
В общем случае задача не решаема.
37 fmrlex
 
10.04.13
10:40
http://alglib.sources.ru/ загляни сюда
38 mzelensky
 
10.04.13
10:40
(32) Прикольно! А типа "сервиса" под это нет?!
39 mzelensky
 
10.04.13
10:41
(35) да. я уже попробовал. Вот ток как результат забрать?!
40 Эмбеддер
 
10.04.13
10:42
есть такая функция solve, она решает уравнения
41 HeroShima
 
10.04.13
10:43
42 В тылу врага
 
10.04.13
10:43
(33) конечно превосходящее, это просто известный мем
43 Rovan
 
гуру
10.04.13
10:43
(39) парсишь результирующую страницу - ищешь подстроку
onclick="CancelEvent(event); plainMathText('x=
44 Зойч
 
10.04.13
10:44
методом дихотомии или золотого сечения, если формула заранее не известна
45 Эмбеддер
 
10.04.13
10:46
(44) ниче не получится, если больше 1 минимума/максимума
46 mzelensky
 
10.04.13
10:46
(33) запаришься перебирать
47 mzelensky
 
10.04.13
10:47
(46) -> (44)
48 Михаил Козлов
 
10.04.13
10:47
Если речь идет о ЧИСЛЕННОМ решении уравнения, то см. численные методы решения уравнений.
Если о ФОРМУЛЕ вычисления корней уравнения, то для полиномов степени > 4 такой формулы не существует.
Поэтому, либо численное решение, либо ограничиться классом видов уравнения.
49 Зойч
 
10.04.13
10:48
(46) ты не знаком с дихотомией? фиииии
50 Torquader
 
11.04.13
00:59
В общем случае, задача решения не имеет.
Например, может быть задано уравнение пятой степени, которое аналитически не решается и т.п.
Численные методы, конечно, позволяют решить то, что не решается аналитически, но тоже не всегда.
51 Злопчинский
 
11.04.13
01:42
формулы писать через ПОЛИЗ в стек. тогда рзабор и вычисление недостающего параметра будет своидится к простому линейному чтению из стека..
???
52 Ksandr
 
11.04.13
07:50
П1*П2^4+П3*П2^2+П5=0

Найдешь П2?
53 Rovan
 
гуру
11.04.13
08:04
54 vde69
 
11.04.13
08:47
кто сможет разобрать формулу:

результат = мин(а,б,в,г)

а вот еще
Результат = МодульНДС.ПолучитьСтавку(А)

интересно какой к черту solve знает как обратить функцию из глобальника?

еще раз говорю - задача НЕРЕШАЕМА!
55 Steelvan
 
11.04.13
10:05
На инфостарте был анализатор таких выражений.
Там поищи.
56 HeroShima
 
11.04.13
10:10
(54) x > 0.0, найти x
вполне математическая формулировка
57 successful
 
11.04.13
10:21
(52) А в чем проблема
П2^2=Y

и решаем стандартное квадратичное...
58 Кирпич
 
11.04.13
10:34
Ну если в формуле только константы, переменные и стандартные операции +-/*, то задача вполне решаема. Дайте денег программисту и всё.
59 successful
 
11.04.13
10:38
(58) Серьезно? Полиномиальное уравнение 5 степени вполне представимо записью операций  +-/*
60 Кирпич
 
11.04.13
10:42
(59) Ну задача вроде то же самое, что поиск решения в Excel
61 toypaul
 
гуру
11.04.13
10:43
(0) в общем случае не всегда есть обратная функция
62 NS
 
11.04.13
10:49
(0) Численные методы поиска корня. Метод ньютона и т.д.
63 NS
 
11.04.13
10:50
64 NS
 
11.04.13
10:57
В общем случае один из корней можно найти таким методом.
Привести к виду f(x)=0;
Просто вычитая из левой части правую часть.
Найти максимум (на самом деле любое положительное значение)
Найти минимум (на самом деле любое отрицательное)
Если не смогли найти либо то, либо то - то выдаем что ответа нет.
Если нашли - то уже куча методов поиска корня, например методом деления отрезка пополам.
65 NS
 
11.04.13
11:02
Получить положительное и отрицательное значение можно просто наложив сетку на область определения.
66 GANR
 
11.04.13
12:27
wiki:Метод_бисекции, например, никто не отменял. Это простейшее, что можно предпринять.
67 Кирпич
 
11.04.13
18:16
накропал алгоритм решения уравнения с одним неизвестным типа как в (0)
короче надо, как в (64) уже сказано, привести к виду f(x)=0, а потом хитрым перебором найти неизвестное. ничего особо сложного нету.
автор, давай пять тыщ.
68 Михаил Козлов
 
11.04.13
18:45
(67) Раскройте тайну хитрого перебора. Пожалуйста.
69 Кирпич
 
11.04.13
18:56
(68) Да просто двоичный поиск. Типа как в (66)
70 Кирпич
 
11.04.13
19:15
+(69) хотя соврал я. это не двоичный поиск, а какая то другая фигня. сам изобрел. хотя это скорее всего изобретено уже.

короче берешь фиксированный диапазон значений например
 Min := -99999999999;
 Max := 99999999999;

и в нем ищешь сначала близкий к решению диапазон шириной в
в 1000000000, потом в этом диапазоне ищешь диапазон шириной 100000000, потом 1000000, потом 10000, 1000, 100, 10, 1,
потом 0.1,0.01,0.001 и далее.

вроде работает и скорость нормальная. Замерил: 100000 решений за 1,5 секунды. Правда это на Delph. На 1С конечно минут 10 будет считать.

короче велосипед едет. можно еще что нибудь попробовать, но уже лень.
71 NS
 
11.04.13
19:27
(68) А чем плохо наложить сетку на область определения, либо монте-карло по области определения, а потом дихотомией между каждой парой соседних точек с разными знаками значения функции в них?
Найти корни функции одной переменной - это совсем просто.
72 Кирпич
 
11.04.13
19:37
(71)ну вроде автору только одну переменную нужно угодать. нафиг тут монтыкарлы городить.
73 NS
 
11.04.13
19:43
(72) Чтоб искать корень функции с несколькими экстремумами (например полином третьей степени) - нужно сначала найти область, в которой этот корень содержиться.
Монте-Карло по сложности написания ничем не отличается от наложении сетки.
Сетка.
а=нач;
Пока а<=кон цикл
// взяли значение в точке
а=а+(кон-нач)/(количествоточекразбиения-1);
Конеццикла;
Монтекарло
Для а=1 по количсетвоточекрабиения
// взяли значение в точке нач+(кон-нач)*Random();
Конеццикла;

Монте-Карло это очень просто, и городить тут ничего не надо.
74 Кирпич
 
11.04.13
19:46
а. ну у меня как раз монте карло и получился :)
75 NS
 
11.04.13
19:50
Поиск самого корня.
Нужно две точки, а и b такие что f(a)>0 и f(b)<0
Тогда сам поиск корня
fa=f(a);
fb=f(b);
Пока abs(a-b)>точность цикл
 c=(a+b)/2
 fc=f(c);
 Если f(c)>0 тогда
   a=c;
   fa=fc;
 Иначеесли f(c)<0 тогда
   b=c;
   fb=fc;
 иначе
   а=с;
   b=с;
   прервать;
 конецесли;
КонецЦикла;
Сообщить("Корень: "+((a+b)/2));
76 NS
 
11.04.13
19:56
А лучше
c=окр((a+b)/2,10);
Чтоб не налететь на резкое замедление из-за того что 1С хранит все знаки после точки.
77 Лефмихалыч
 
11.04.13
20:06
(0) вело сипедо изо бретун.

Задачу озвучь
78 NS
 
11.04.13
20:17
перем maxX,minX; // область определения функции
перем точность;
Функция f(x) // искомая функция
   Возврат x*x-2; // найдем решение уравнения x^2-2=0, или что тоже самое x^2=2
КонецФункции                                                                  
Процедура СообщитьКореньВИнтервале(знач a,знач b);
   fa=f(a);
   fb=f(b);
   Если fa*fb>0 Тогда
       Возврат;
   КонецЕсли;  
   Если fa=0 Тогда
       сообщить(a);        
       возврат;
   КонецЕсли;      
   Если fb=0 Тогда
       возврат; // на следующей итерации будет выведен этот корень
   КонецЕсли;    
   Если fa<0 Тогда
       c=a;
       a=b;
       b=c; // поменяем значения местами
       fa=f(a);
       fb=f(b);    
   КонецЕсли;                          
   // теперь у нас f(a)>0 и f(b)<0
   Пока макс((a-b),(b-a))>точность цикл
       c=окр((a+b)/2,10);
       fc=f(c);
       Если f(c)>0 тогда
           a=c;
           fa=fc;
       Иначеесли f(c)<0 тогда
           b=c;
           fb=fc;
       иначе
           а=c;
           b=c;
           прервать;
       конецесли;
   КонецЦикла;
   Сообщить("Корень: "+((a+b)/2));    
Конецпроцедуры    
Процедура Сформировать()
    minX=-100;
    MaxX=100;
    точность=0.000000001;
    Для а=0 по 999 Цикл
        СообщитьКореньВИнтервале(minX+(MaxX-MinX)*а/1000,minX+(MaxX-MinX)*(а+1)/1000);
    КонецЦикла;
КонецПроцедуры
79 NS
 
11.04.13
20:32
Одна буква "а" была не в том регистре :)
Вот правильно
перем maxX,minX; // область определения функции
перем точность;
Функция f(x) // искомая функция
   Возврат x*x-2; // найдем решение уравнения x^2-2=0, или что тоже самое x^2=2
КонецФункции                                                                  
Процедура СообщитьКореньВИнтервале(знач a,знач b);
   fa=f(a);
   fb=f(b);
   Если fa*fb>0 Тогда
       Возврат;
   КонецЕсли;  
   Если fa=0 Тогда
       сообщить("Корень: "+a);        
       возврат;
   КонецЕсли;      
   Если fb=0 Тогда
       возврат; // на следующей итерации будет выведен этот корень
   КонецЕсли;    
   Если fa<0 Тогда
       c=a;
       a=b;
       b=c; // поменяем значения местами
       fa=f(a);
       fb=f(b);    
   КонецЕсли;                          
   // теперь у нас f(a)>0 и f(b)<0
   Пока макс((a-b),(b-a))>точность цикл
       c=окр((a+b)/2,10);
       fc=f(c);      
       Если fc>0 тогда
           a=c;
           fa=fc;    
       Иначеесли fc<0 тогда
           b=c;
           fb=fc;
       иначе
           a=c;
           b=c;
           прервать;
       конецесли;
   КонецЦикла;
   Сообщить("Корень: "+((a+b)/2));    
Конецпроцедуры    
Процедура Сформировать()
    minX=-100;
    MaxX=100;
    точность=0.000000001;
    Для а=0 по 999 Цикл
        СообщитьКореньВИнтервале(minX+(MaxX-MinX)*а/1000,minX+(MaxX-MinX)*(а+1)/1000);
    КонецЦикла;
КонецПроцедуры
80 Кирпич
 
12.04.13
13:31
А вот почти готовое решение. Вводи уравнение и переменную, которую нужно угадать.


Функция Абс(Ч)
   Возврат ?(Ч < 0,-Ч,Ч);
КонецФункции


Функция Решалка(Выражение, Л, П, Прм, Точность = 0.0001)
   Перем М,ТЛ,ТР,ТМ,МояПеременная;
   
   //Преобразуем уравнение из "70 = П1 * (5 + 2)" делаем "П1 * (5 + 2)-70"
   Поз = Найти(Выражение,"=");
   Ч = СокрЛП(Лев(Выражение,Поз-1));
   Выр = Прав(Выражение,СтрДлина(Выражение)-Поз);
   
   Если Лев(Ч,1) = "-" Тогда
      Выр = Выр + "+" + Ч;
   Иначе
      Выр = Выр + "-" + Ч;
   КонецЕсли;
   
   
   //заменяем переменную "П1" в выражении на свою. здесь тупая замена, нужно что-то более умное.
   // например в выражениии "П+П1+П2" заменить "П" на "МояПеременная" уже не канает
   Выр = СтрЗаменить(Выр,Прм,"МояПеременная");
       
   //поиск переменной
   Пока Истина Цикл
       М = (Л+П) / 2;

       МояПеременная = М; ТМ = Абс(Вычислить(Выр));
       
       Если ТМ <= Точность Тогда
           Возврат М;    
       КонецЕсли;
       
       МояПеременная = Л; ТЛ = Абс(Вычислить(Выр));
       МояПеременная = П; ТП = Абс(Вычислить(Выр));
       
       Если ТЛ > ТП Тогда
           Л = М;
       Иначе
           П = М;
       КонецЕсли;
   КонецЦикла;
   
КонецФункции

Процедура тест4()
   //Нужно вычислить значение П1 в уравнении
   Уравнение = "78956.256 = П1 * (5 + 2)";
   Переменная = "П1";
   Точность = 0.0001;
   П = Решалка(Уравнение, -999999999999, 999999999999, Переменная,Точность);
   П = Окр(П,4);
   Сообщить(П);
КонецПроцедуры
81 HeroShima
 
21.04.13
21:44
82 Лефмихалыч
 
21.04.13
21:46
пора секцию создавать "Что еще нафиг не нужно в 1С". Ведущим по четным будет автор, а по нечетным - Ненавижу1С (если из бани выздоровеет)
83 Кирпич
 
06.05.13
16:34
+(80) надо вынести за цикл вот эти строчки, кстати. будет быстрее работать.

       МояПеременная = Л; ТЛ = Абс(Вычислить(Выр));
       МояПеременная = П; ТП = Абс(Вычислить(Выр));
84 sda553
 
06.05.13
16:45
Предлагаю решать методом последовательного приближения
85 Кирпич
 
06.05.13
16:58
да уж решили давно. вот усовершенствовал. так будет быстрее.

Функция Решалка(Выражение, Л, П, Прм, Точность = 0.0001)
   Перем М,ТЛ,ТР,ТМ,МояПеременная;
   
   //Преобразуем уравнение из "70 = П1 * (5 + 2)" делаем "(П1 * (5 + 2))-70"
   Поз = Найти(Выражение,"=");
   Ч = СокрЛП(Лев(Выражение,Поз-1));
   Выр = Прав(Выражение,СтрДлина(Выражение)-Поз);
   
   Если Лев(Ч,1) = "-" Тогда
      Выр = "(" + Выр + ")+" + Ч;
   Иначе
      Выр = "(" + Выр + ")-" + Ч;
   КонецЕсли;
   
   
   //заменяем переменную "П1" в выражении на свою. здесь тупая замена, нужно что-то более умное.
   //например в выражениии "П+П1+П2" заменить "П" на "МояПеременная" уже не канает
   Выр = СтрЗаменить(Выр,Прм,"МояПеременная");
       
   М = (Л+П) / 2;

   МояПеременная = М; ТМ = Абс(Вычислить(Выр));
   МояПеременная = Л; ТЛ = Абс(Вычислить(Выр));
   МояПеременная = П; ТП = Абс(Вычислить(Выр));
               
   //поиск переменной
   Пока Истина Цикл    
       
       Если ТМ <= Точность Тогда
           Возврат М;    
       КонецЕсли;                
       Если ТЛ > ТП Тогда
           Л = М;
           ТЛ = ТМ;
       Иначе
           П = М;
           ТП = ТМ;
       КонецЕсли;  
       
       М = (Л+П) / 2;
       МояПеременная = М; ТМ = Абс(Вычислить(Выр));
   КонецЦикла;
   
КонецФункции
86 Infsams654
 
06.05.13
17:08
(85) - не прокатит, про обратную польскую запись слышали?
87 _Demos_
 
06.05.13
17:30
такие задачи через деревья легче всего решить
88 Aprobator
 
06.05.13
17:36
чего только народ на 1С не пытается написать. Вот интересно, молотком никто не пробовал бумагу клеить?
89 HeroShima
 
08.05.13
01:42
Только что в (82) OpenCL гонял. Никому не надо? )
90 zladenuw
 
08.05.13
01:56
(89) а че там ? подумаю это направление изучить но пока все на 1с :(
91 HeroShima
 
08.05.13
02:04
(90) Мультиплатформенный массивный параллелизм с ускорением на GPU, или без.
92 zladenuw
 
08.05.13
02:16
(91) типа понял о чем ты :)