Имя: Пароль:
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) типа понял о чем ты :)
Я не хочу быть самым богатым человеком на кладбище. Засыпать с чувством, что за день я сделал какую-нибудь потрясающую вещь — вот что меня интересует. Стив Джобс