начертить график функции из textbox

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

DreamShark
Новичок
Новичок
 
Сообщения: 32
Зарегистрирован: 20.02.2010 (Сб) 15:43

начертить график функции из textbox

Сообщение DreamShark » 14.05.2010 (Пт) 19:43

Приветсвую

Хочу сделать прогу, пользователь вводит по определенным правилам функцию в текстовое поле.
например так "|x^3|-12*sin(x/10)" а прога будет рисовать график.
Понятно - основная сложность программы распознавание функции записанной в таком формате.

Как это сделать, возможно ли вообще, с чего начать и на чем основывать код???
Обидно что в целом не сложно перевести функцию в тот формат который понимает язык при написании кода(для примера это будет "abs(x^3)-12*sin(x/10)"), вот бы динамически вставлять это в программный код и усе:)
Я программирую на vb.net 2005

Денис
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2734
Зарегистрирован: 07.11.2006 (Вт) 13:55
Откуда: Ейск, Краснодарский край

Re: начертить график функции из textbox

Сообщение Денис » 14.05.2010 (Пт) 21:12

1. Чтобы рассчитать результат функции нужен класс, который называется "парсер математических выражений". Таких очень много у нас в разделе "кирпичный завод" и даже для дотнета есть.
2. Чтобы нарисовать график, нужно просто рассчитывать парсером точки с заданным интервалом и рисовать их.
3. Возможно в дотнете уже есть готовые классы для рисования графиков, я не знаю.
Программирование — богоизбранная дисциплина! Если бог и есть, то вселенную он скомпилировал, не иначе.

DreamShark
Новичок
Новичок
 
Сообщения: 32
Зарегистрирован: 20.02.2010 (Сб) 15:43

Re: начертить график функции из textbox

Сообщение DreamShark » 15.05.2010 (Сб) 13:00

Спасибо, Денис! Нашел отличный парсер для дотнета. Сам бы не сделал!
Только я его как-то криво вставил в проект...
Скажи, как првильно импортировать уже готовый класс, форму, модуль в проект.
Я создал новый класс и просто перекопировал туда код - мне так не нравится)

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Re: начертить график функции из textbox

Сообщение Viper » 15.05.2010 (Сб) 14:09

DreamShark писал(а):Спасибо, Денис! Нашел отличный парсер для дотнета. Сам бы не сделал!
Только я его как-то криво вставил в проект...
Скажи, как првильно импортировать уже готовый класс, форму, модуль в проект.
Его нужно просто добавить.
Весь мир матрица, а мы в нем потоки байтов!

Samsonov
Новичок
Новичок
 
Сообщения: 30
Зарегистрирован: 22.04.2010 (Чт) 7:32
Откуда: DC

Re: начертить график функции из textbox

Сообщение Samsonov » 26.05.2010 (Ср) 7:54

Денис писал(а):Чтобы рассчитать результат функции, нужен класс, который называется «парсер математических выражений». Таких очень много у нас в разделе «кирпичный завод» и даже для дотнета есть.
Насколько я понял, все они ориентированы на обычную (инфиксную) нотацию. Куда проще работать с т. н. «польской» (префиксной) записью, наиболее известной по языку Лисп.

Например, вместо
Код: Выделить всё
Abs(x ^ 3) - 12 * Sin(x / 10)
будет
Код: Выделить всё
(- (Abs (^ x 3)) (* 12 (Sin (/ x 10))) )


Очевидное преимущество такого формата входных данных — очень лёгкое написание парсера и ещё более лёгкое расширение своего языка. Не нужны никакие регулярные выражения, не нужно составлять никакие деревья обхода операндов, учитывать приоритет операторов. (Кстати, заметьте: здесь у любого оператора может иметься произвольное количество аргументов.) От языка требуется только поддержка рекурсии.

Если нужно только считать математические формулы, то парсер можно написать даже на таком ограниченном (для подобных вещей) языке, как досовский QuickBasic. Если же в наших руках вся мощь .NET с его variant-типами данных и поддержкой списков и словарей, то несложно будет создать целый язык программирования, чтобы позволить пользователю применять более сложные конструкции, например:
Код: Выделить всё
(defun MyFunction (t)
(if (< t 0) 0 (^ t 1.5))
)

(+ 1 x (MyFunction (- 3 x)) )
То есть создавать ветвления, циклы, переменные и функции.

Кстати, вопреки распространённому синтаксису, продемонстрированному в этом примере, мне кажется, проще поступать немного иначе:
Код: Выделить всё
(defun 'MyFunction ('t) ...)
Отличие здесь — в апострофе перед именем «символа», который указывает, что символ надо воспринимать как сам символ (по сути, как ссылку на объект), а не как значение этого символа. Такой подход упрощает создание парсера, позволяя унифицировать схему вычислений, вместо того чтобы требовать какого-то особого отношения к элементам подобных синтаксических конструкций.



Очевидный недостаток префиксной нотации — сложность для написания и восприятия, даже у программистов, не говоря про обычных пользователей. Но эту задачу можно облегчить, если редактор формул будет помогать автоматически закрывать открытые скобки, а также подсвечивать текущий блок скобок (как это делает Excel, например).



PS. Давно задавался вопросом, но всё как-то лень было копнуть эту тему: позволяют ли средства рефлексии в .NET не только изучать свой собственный код, но и модифицировать его? То есть чтобы пользовательская строка, написанная на одном из языков .NET, могла быть динамически транслирована внутрь исполняемой программы как новая функция или что-то вроде того.

Самое забавное, что нечто похожее было реализовано ещё в древнем ZX Spectrum Бейсике. Там достаточно было бы создать программу:
Код: Выделить всё
10 INPUT V$
20 FOR X = -10 TO 10 STEP 0.1
30 PLOT (128 + 10 * X), (88 - 10 * VAL(V$))
40 NEXT X
50 GOTO 10
и мы получали бы ровно то, что хотел автор — благодаря тому, что функция VAL(V$) интерпретировала строковое выражение почти как часть программы. После перехода на платформу PC, меня немало удивило, что ни GW-Basic и последующие творения Microsoft, ни тем более TurboBasic (просто потому что он чисто компилирующий), ни другие популярные диалекты не предлагают подобной функциональности.

Денис
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2734
Зарегистрирован: 07.11.2006 (Вт) 13:55
Откуда: Ейск, Краснодарский край

Re: начертить график функции из textbox

Сообщение Денис » 26.05.2010 (Ср) 13:03

Samsonov писал(а):позволяют ли средства рефлексии в .NET не только изучать свой собственный код, но и модифицировать его? То есть чтобы пользовательская строка, написанная на одном из языков .NET, могла быть динамически транслирована внутрь исполняемой программы как новая функция или что-то вроде того.


ммм, а разве ООП не для этого?
Программирование — богоизбранная дисциплина! Если бог и есть, то вселенную он скомпилировал, не иначе.

Samsonov
Новичок
Новичок
 
Сообщения: 30
Зарегистрирован: 22.04.2010 (Чт) 7:32
Откуда: DC

Re: начертить график функции из textbox

Сообщение Samsonov » 27.05.2010 (Чт) 6:37

Денис писал(а):
Samsonov писал(а):Позволяют ли средства рефлексии в .NET модифицировать собственный код?
Разве ООП не для этого?
ООП — это инкапсуляция, наследование и полиморфизм; про интроспекцию и метапрограммирование оно ни слова не говорит. Верно и обратное: возможностями рефлексии могут обладать языки, не являющиеся объектно-ориентированными, — взять хоть тот же Лисп в его древних инкарнациях.

Другое дело, что конкретно в .NET могут наличествовать средства самомодификации, но я пока не встречал упоминаний подобного. Однако можно попробовать применить генеративный подход, эксплуатируя то обстоятельство, что любая .NET-среда времени выполнения имеет компиляторы для VB, C# и J# и, разумеется, компоновщик. Поэтому можно генерировать файл вида:
Код: Выделить всё
Public Class MyFunction
  Public Function F(ByVal x As Double) As Double
    Return пользовательская_строка
  End Function
End Class
Потом делать из него DLL, активировать оттуда нужный класс (для упрощения связывания, можно определить родительский класс в основной программе) и вызывать пользовательскую функцию в цикле.

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

Samsonov
Новичок
Новичок
 
Сообщения: 30
Зарегистрирован: 22.04.2010 (Чт) 7:32
Откуда: DC

Re: начертить график функции из textbox

Сообщение Samsonov » 27.05.2010 (Чт) 19:33

Беглое чтение раздела справки о пространстве System.Reflection.Emit наводит на мысли, что это и есть оно самое:
The System.Reflection.Emit namespace contains classes that allow a compiler or tool to emit metadata and Microsoft intermediate language (MSIL) and optionally generate a PE file on disk. The primary clients of these classes are script engines and compilers.
Но! Как нетрудно заметить, и убедиться по «простеньким» примерчикам, для генерации IL-кода таким образом вы должны скармливать этой штуке весьма низкоуровневый поток инструкций и метаданных. То есть фактически вы уже должны иметь на руках полностью распарсенное дерево выражений, потом самостоятельно скомпилировать его в пседокод, снабдить всеми необходимыми метаданными, — и тогда получите программный образ пользовательской функции, как будто она изначально была встроена в вашу программу.

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

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: начертить график функции из textbox

Сообщение FireFenix » 27.05.2010 (Чт) 21:22

Samsonov писал(а):Куда проще работать с т. н. «польской» (префиксной) записью, наиболее известной по языку

Samsonov писал(а):Иными словами, как способ лёгкого и беспроблемного вычисления пользовательских выражений — явно не катит. Видимо, тогда остаётся только вышеупомянутый трюк с использованием штатных компиляторов.

Да вы товарищ извращенец! И судя по всему плохо гуглите :) http://msdn.microsoft.com/en-us/library ... vider.aspx

Код: Выделить всё
Public Sub Compile()
        Dim Code As String
        Dim Eval As String = "Sin(Pi/2) - Cos(Pi/2)"

        Dim CodeProvider As New VBCodeProvider

        Dim Params As New CompilerParameters
        Dim Assembly As System.Reflection.Assembly
        Dim Instance As Object = Nothing
        Dim Results As CompilerResults
        Dim RetObj As Object = Nothing
        Dim MethodInfo As System.Reflection.MethodInfo
        Dim ObjType As Type

        Try
            Params.ReferencedAssemblies.Add("System.dll")
            Params.ReferencedAssemblies.Add("mscorlib.dll")
            Params.GenerateInMemory = True

            Code = "Imports System" & vbCrLf &
                   "Imports System.Math" & vbCrLf &
                   "" & vbCrLf &
                   "Namespace Compiler" & vbCrLf &
                       "Class Code" & vbCrLf &
                            "Public Function Eval() as Decimal" & vbCrLf &
                                "Return " & Eval & vbCrLf &
                            "End Function" & vbCrLf &
                       "End Class" & vbCrLf &
                   "End Namespace"

            Try
                Results = CodeProvider.CompileAssemblyFromSource(Params, Code)

                Assembly = Results.CompiledAssembly
                Instance = Assembly.CreateInstance("Compiler.Code")


                ObjType = Instance.GetType
                MethodInfo = ObjType.GetMethod("Eval")

                RetObj = MethodInfo.Invoke(Instance, Nothing)
            Catch ex As Exception
                MsgBox(ex.Message)
                Exit Sub
            End Try

        Catch ex As Exception
            MsgBox(ex.Message)
            Exit Sub
        End Try

        MsgBox(RetObj.ToString)
    End Sub

Как всегда есть 3 доступных решения
1) Написать эвалютер мат. выражений
2) Компилить код на лету
3) Прикрутить скриптовый язык
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Samsonov
Новичок
Новичок
 
Сообщения: 30
Зарегистрирован: 22.04.2010 (Чт) 7:32
Откуда: DC

Re: начертить график функции из textbox

Сообщение Samsonov » 28.05.2010 (Пт) 7:17

FireFenix писал(а):Плохо гуглите: есть VBCodeProvider.
По сути, это тот же метод с компиляцией полностью сгенерированного .vb-файла, о котором я говорил в предпоследнем постинге, — только с удобной оболочкой вместо того, чтобы вручную общаться с vbc.exe и ilasm.exe и использовать внешние файлы исходников. Конечно, ваш способ проще и корректнее (чего ж вы его сразу-то не предложили топикстартеру?), но я всё-таки надеялся, что может существовать ещё более простой способ — что-то типа упомянутого выше для ZX Basic:
Код: Выделить всё
compiled = CodeProvider.CompileAssemblyFromSource("Sin(Pi/2) - Cos(Pi/2)")
result = MethodInfo.Invoke(compiled)
Ну, или вместо голого выражения — блок Function. Но не более того. То есть чтобы код компилировался как бы в рамках текущего кода — то есть не просто в рамках текущего модуля, со всеми его ссылками и с доступом ко всем внутренним переменным, а именно что как часть текущего блока внутри функции. Но, наверное, это чересчур даже для .NET. :)


А по поводу Lisp-исходников — я совершенно серьёзно, без шуток. По большому счёту, это такой же императивный язык, как и Basic, C, etc. Только вот последние сочетают префиксный синтаксис вызова функций с инфиксной нотацией выражений (плюс специфические конструкции для определения переменных, организации ветвлений и циклов), а в Лиспе используется единая форма записи — функциональная. Повторюсь: такая форма позволяет легко парсить, легко расширять язык, передавать произвольное количество параметров в любую функцию (то есть экономить на количестве вызовов, повышая качество), избавляет от необходимости определять приоритет операторов.

Денис
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2734
Зарегистрирован: 07.11.2006 (Вт) 13:55
Откуда: Ейск, Краснодарский край

Re: начертить график функции из textbox

Сообщение Денис » 28.05.2010 (Пт) 8:19

Samsonov писал(а):надеялся, что может существовать ещё более простой способ — что-то типа упомянутого выше для ZX Basic:
Код: Выделить всё
compiled = CodeProvider.CompileAssemblyFromSource("Sin(Pi/2) - Cos(Pi/2)")
result = MethodInfo.Invoke(compiled)
Ну, или вместо голого выражения — блок Function. Но не более того. То есть чтобы код компилировался как бы в рамках текущего кода — то есть не просто в рамках текущего модуля, со всеми его ссылками и с доступом ко всем внутренним переменным, а именно что как часть текущего блока внутри функции. Но, наверное, это чересчур даже для .NET. :)


Объясните, в чем преимущество? Я не понимаю. Но весьма любопытно. Это что-то типа квайна?

Например в VB6 самодельные компоненты (.ctl) компилировались при их размещении на форме в дизайнере. Это оно?
(наверняка в .Net у них такое же поведение)
Программирование — богоизбранная дисциплина! Если бог и есть, то вселенную он скомпилировал, не иначе.


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 44

    TopList