Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Реализация анализатора (парсера) формул времени выполнения
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Script. Интеграция WebKit
Страницы: 1, 2
AntonTatu
Всем привет !

Вопрос в следующем, имеется прога которая генерирует некоторую формулу (формула меняет количество своих параметров в зависимости от исходных значений в программе ), в этой же проге есть массив который использует полученную формулу в дальнейших расчетах, хочется создать из формулы dll ку и потом ее вызывать в нужном месте программы, как это сделать? С вызовом полученной dll я вроде бы разобрался, а вот как научить прогу генерить dll ку понять не могу.

ЗЫ: Какие можно использовать компилятор/линковщик (минимум занимаемого места, требуемых для работы файлов, потдержка STL требуется)

Выручайте ! :) Спасибо !
kuler
если в студии, то там всего лишь надо указать тип выходного файла
Litkevich Yuriy
Цитата(AntonTatu @ 4.3.2009, 20:56) *
а вот как научить прогу генерить dll ку понять не могу.
ни как, надо создать проект для dll'ки

см тему
SABROG
Можно таскать вместе с программой MinGW :lol:

Зачем генерить dll? Лучше скрипты генерить.
ViGOur
SABROG, думаю твой пост не к месту. ;)

Просто есть два варианта: AntonTatu, не совсем понимает, как и что раюотает и что должно происходить или он прекрасно понимает что ему нужно, но не правильно объяснил. Надеюсь вы знаете насчет криптованных exe файлов, которые сами себя перевоссоздают, правда это относится к вирусо писательству. ;)
SABROG
Цитата(ViGOur @ 4.3.2009, 18:31) *
SABROG, думаю твой пост не к месту. ;)

Человеку надо генерить dll, я предложил единственно правильный способ как для linux, так для windows - кроссплатформенная компиляция (MinGW). В принципе надо всего-то сгенерить С++ файл и вызвать компилятор с параметрами.
trdm
А я вообще не врубился в "генерирует формулу"....
Очень смахивает на патерн интерпретатор, название которого уже и есть решение: использовать интерпретатор и создавать не формулу,
а файло на скриптовом языке... и юзать его...
или я ничерта не понял.....
Короче, автор, используй встроенный интерпретатор.
AntonTatu
Цитата(ViGOur @ 4.3.2009, 18:31) *
Человеку надо генерить dll, я предложил единственно правильный способ как для linux, так для windows - кроссплатформенная компиляция (MinGW). В принципе надо всего-то сгенерить С++ файл и вызвать компилятор с параметрами.


Попробую объяснить по другому:
Во время выполнения программы из рисунка по некоему алгоритму составляется формула в конце концов принимающая вид типа:

QString str = "A+B*C+D*E+G"

переменные этой формулы (числовые значения A, B, C и т.д.) на момент компиляции программы не известны, длинна формулы (количество переменных ) то же, может быть и такой вариант: A+A+A*D*E+B+C, соответственно единственный выход (который я вижу) это:
1.Запустить программу, получить формулу
2.Загнать формулу в фунцию, создать с этой функцией C++ файл
3. Создать из этого C++ файла библиотеку dll
4. Использовать этот dll в программе
5. Получить числовой ответ

PS: Формула может быть огромна, разбирать ее на лету с помощью ну к примеру конечных автоматов нереально долго (пробовал)
Как сохранить формулу в текстовый файл (С++) проблемы нет, как использовать созданную dll вроде то же понятно (в Google есть)
Вопрос в том какой компилятор (С++) использовать ? (должен уметь STL и требовать как можно меньше файлов для запуска себя (один
экзешник и все было бы замечательно), что бы вместе со своей прогой еще и 200 мб, компилятора не таскать) , может есть где пример
вызова компилятора из командной строки очень поможет.
И еще вопрос, какие компиляторы можно использовать если я пишу софт на продажу (ну это так для общего развития) :)


Что то прочитал свой опус, наверно опять непонятно объяснил, не суть вопрос больше касается именно выбора компилятора.

Цитата(trdm @ 4.3.2009, 19:38) *
А я вообще не врубился в "генерирует формулу"....
Очень смахивает на патерн интерпретатор, название которого уже и есть решение: использовать интерпретатор и создавать не формулу,
а файло на скриптовом языке... и юзать его...
или я ничерта не понял.....
Короче, автор, используй встроенный интерпретатор.


зачем придумывать интерпритатор, если можно воспользоваться обычным вызовом dll ки, весь вопрос в том как ее правильно создавать используя сторонние компиляторы C++ из командной строки ? (так полюбому быстрее будет, а скорость в моем случае очень важна)

а пример использования файла на скриптовом языке где можно посмотреть ? :)
Admin
SABROG, перечитал твое сообщение, и решил извиниться перед тобой. ЭТО Я БЫЛ НЕ ПРАВ! Извини, не понял, что ты имел ввиду. :blush:

p.s. удаленный тобой пост вернул на место. Нужно больше отдыхать, мне. :)
Litkevich Yuriy
AntonTatu, а QtScript тебе для этих целей тоже не подходит?
AntonTatu
Цитата(Litkevich Yuriy @ 4.3.2009, 20:40) *
AntonTatu, а QtScript тебе для этих целей тоже не подходит?

А с ним я не разбирался, я в программировании новичек..., а "скрипты генерить" это и есть QtScript ? (что почитать ?)
ViGOur
Цитата(AntonTatu @ 4.3.2009, 21:04) *
а "скрипты генерить" это и есть QtScript ? (что почитать ?)
QtScript - для того, чтобы скрипты писать. А что они будут делать, зависит только от тебя. :)
Почитай: QtScript Module
trdm
Цитата(AntonTatu @ 4.3.2009, 20:25) *
Попробую объяснить по другому:
....поскипано....

все это крайне странно выглядит....

Цитата(ViGOur @ 4.3.2009, 21:10) *
Цитата(AntonTatu @ 4.3.2009, 21:04) *
а "скрипты генерить" это и есть QtScript ? (что почитать ?)
QtScript - для того, чтобы скрипты писать. А что они будут делать, зависит только от тебя. :)
Почитай: QtScript Module

QtScript - для того, чтобы скрипты ИСПОЛНЯТЬ.
Разница существенная. Таки как раз в скрипт можно передавать сгенеренную формулу, а на выходе получит результ её исполнения.
AntonTatu
[/quote]
QtScript - для того, чтобы скрипты ИСПОЛНЯТЬ.
Разница существенная. Таки как раз в скрипт можно передавать сгенеренную формулу, а на выходе получит результ её исполнения.
[/quote]
А что по скорости выполнения ? , вот что написано у М.Шлее:

"При создании объектов функций важно учитывать то обстоятельство, что
трансляция объекта Function выполняется при каждом его использовании,
вследствие чего исполнение кода будет гораздо медленнее, чем при
исполнении обычных функций языка сценариев. "
Насколько на Ваш взгляд такая функция будет выполнятся медленнее чем скомпилированная в dll ку ?
trdm
Цитата(AntonTatu @ 4.3.2009, 21:55) *
Цитата

QtScript - для того, чтобы скрипты ИСПОЛНЯТЬ.
Разница существенная. Таки как раз в скрипт можно передавать сгенеренную формулу, а на выходе получит результ её исполнения.

А что по скорости выполнения ? , вот что написано у М.Шлее:
"При создании объектов функций важно учитывать то обстоятельство, что
трансляция объекта Function выполняется при каждом его использовании,
вследствие чего исполнение кода будет гораздо медленнее, чем при
исполнении обычных функций языка сценариев. "
Насколько на Ваш взгляд такая функция будет выполнятся медленнее чем скомпилированная в dll ку ?

нормальное замечание. не знаю.
если верить Шлее и предположить, что трансляция - есть разбор+интерпретирование,
тогда использование QtScript может быть и не оправдано....
есть скриптовые языки у которых разделены фазы разбора+формирование байткода и интерпретация.
я так понял формула некоторое время не меняется, а входные параметры меняются.
правильно?
AntonTatu
Цитата
нормальное замечание. не знаю.
если верить Шлее и предположить, что трансляция - есть разбор+интерпретирование,
тогда использование QtScript может быть и не оправдано....
есть скриптовые языки у которых разделены фазы разбора+формирование байткода и интерпретация.
я так понял формула некоторое время не меняется, а входные параметры меняются.
правильно?


ну в общем да, получается что то вроде цикла:
формула 1 -> фходные параметры 1
формула 1 -> фходные параметры 2
формула 1 -> фходные параметры 3
формула 1 -> фходные параметры N
формула 2 -> фходные параметры 1
формула 2 -> фходные параметры 2
формула 2 -> фходные параметры N
формула k -> фходные параметры N
формула 1 -> фходные параметры 1
формула 1 -> фходные параметры 2
формула 1 -> фходные параметры 3
и т.д.

Я в принципе уже написал вариант на Delphi, в нем для того чтобы использовать компилятор достаточно выдрать экзешник + пару дллок.., теперь переписываю под QT, а вот компилятор С++ подобрать не могу все за собой хвост тащат в энное кол во мегабайт и файлов...
SABROG
Цитата(AntonTatu @ 4.3.2009, 20:25) *
Формула может быть огромна, разбирать ее на лету с помощью ну к примеру конечных автоматов нереально долго (пробовал)
Как сохранить формулу в текстовый файл (С++) проблемы нет, как использовать созданную dll вроде то же понятно (в Google есть)
Вопрос в том какой компилятор (С++) использовать ? (должен уметь STL и требовать как можно меньше файлов для запуска себя (один
экзешник и все было бы замечательно), что бы вместе со своей прогой еще и 200 мб, компилятора не таскать) , может есть где пример
вызова компилятора из командной строки очень поможет.
И еще вопрос, какие компиляторы можно использовать если я пишу софт на продажу (ну это так для общего развития) :)

Если взвешивать все за и против, то получается такая картина.
Лучше C/C++ компилятора никакой скриптовый язык не даст нужной оптимизации кода под конкретный процессор, к тому же, естественно, машинный код будет выполняться гораздо быстрее.
Из-за такой особенности получается, что саму программу придется разбить на серверную (демон) и клиентские части.
Если клиентская часть достаточно быстро разбирает рисунок и переводит её в формулу, то на сервер можно отправлять только сам текст этой формулы. Иначе тупо предоставлять интерфейс для заливки рисунка на сервер. Это может быть и php скрипт.
Задача сервера по формуле сформировать исходники и передать на выполнение компилятору. Затем сервер информирует клиента, что модуль готов и клиент добавляет его к себе в лист. После этого этим модулем можно пользоваться, но запускаться он будет на серверной машине по команде клиента.
Смена компиляторов и ОС будет для пользователя прозрачной.

Совсем другое дело, если пишется какой-нибудь новый архиватор типа winrar'a, тут тогда ситуация безвыходная. Либо размер дистрибутива вместе с компилятором, либо скорость.
Константин
потому, что компилятор предназначен для компилирования. и тащит компилятор за собой ровно столько, сколько хочет за собой таскать, т.к. является опциональной базой любого дистриутива, в котором может потребоваться что-то собрать. и люди в здравом уме используют компилятор по прямому назначению, а не таскают его /* куски */ за своими проектами в весьма сомнительных целях.

если беспокоит скорость работы QtScript, welcome to Python; иначе QtScript и минимум мозго????ва.
Litkevich Yuriy
Цитата(AntonTatu @ 5.3.2009, 0:55) *
А что по скорости выполнения ? , вот что написано у М.Шлее:
рекомендую для начала по пробовать, и если на практике окажется неприемлемое быстродействие, тогда будешь искать другой вариант.
trdm
Цитата(AntonTatu @ 4.3.2009, 20:25) *
PS: Формула может быть огромна, разбирать ее на лету с помощью ну к примеру конечных автоматов нереально долго (пробовал)

странно, у меня например глобальный модуль от 1С-ки весит 1.5 Мб.
Разбирал с пом. bison-a, 2-3 секунды....
не пойму, что у вас с быстродействием.
AntonTatu
Цитата(Litkevich Yuriy @ 5.3.2009, 8:19) *
Цитата(AntonTatu @ 5.3.2009, 0:55) *
А что по скорости выполнения ? , вот что написано у М.Шлее:
рекомендую для начала по пробовать, и если на практике окажется неприемлемое быстродействие, тогда будешь искать другой вариант.

ну вобщем попробовал, если использовать QtScript получается оччень медлено, использовал следующий скрипт:
var x; 
function(j, num) {тело функции}


х - это массив значений посчитанный в С++ и переданный скрипту
engine.globalObject().setProperty("x", MyArray);
в теле функции в скрипте используются различные значения массива x[i][j],

я так понимаю что медленно потому что приходится скрипту передавать весь массив целиком (т.е. делать для него копию), а при использовании dll ки весь массив не копируется, а значение передается по ссылке, а может быть можно как то в скрипту указывать ссылку а не делать "копию" всех значений массива ?
BRE
Цитата(AntonTatu @ 6.3.2009, 0:07) *
я так понимаю что медленно потому что приходится скрипту передавать весь массив целиком (т.е. делать для него копию), а при использовании dll ки весь массив не копируется, а значение передается по ссылке, а может быть можно как то в скрипту указывать ссылку а не делать "копию" всех значений массива ?

Самое простое сделать класс (еще проще (но не обязательно) если наследоваться от QObject), который будет управлять твоим массивом и обеспечить доступ к объекту этого класса из контекста скрипта.

class Array2D : public QObject
{
    Q_OBJECT
public:
    ....

public Q_SLOTS:
    int    at( int i, int j ) const;
    void  set( int i, int j, int value );
};

{
    Array2D *arr = new Array2D( 100, 100 );

    // Заполнили массив
    for( ... )
        for( ... )
             arr->set( i, j, ... );

}

// Предоставили в контекс script engine для объекта arr.
// Смотри в assistant по QScriptable и QSciptEngine


А дальше из скрипта можно доставать значения используя arr.at( i, j ).
BRE
Пример:

array2d.h
#ifndef __ARRAY2D
#define __ARRAY2D

#include <QObject>
#include <vector>

class Array2D : public QObject
{
        Q_OBJECT
public:
        Array2D( int dx, int dy );

public Q_SLOTS:
        char    at( int i, int j ) const;
        void    set( int i, int j, char val );

        inline  int             dx() const { return m_dx; }
        inline  int             dy() const { return m_dy; }

private:
        int             m_dx;
        int             m_dy;
        std::vector< std::vector<char> > *m_data;
};

#endif


array2d.cpp
#include "array2d.h"

Array2D::Array2D( int dx, int dy )
        : m_dx( dx ), m_dy( dy )
{
        m_data = new std::vector< std::vector<char> >( m_dx );
        for( int i = 0; i < m_dx; ++i )
                (*m_data)[ i ] = std::vector<char>( m_dy );
}

char Array2D::at( int i, int j ) const
{
        Q_ASSERT( i > 0 && i < m_dx );
        Q_ASSERT( j > 0 && j < m_dy );
        return (*m_data)[ i ][ j ];
}

void Array2D::set( int i, int j, char val )
{
        Q_ASSERT( i > 0 && i < m_dx );
        Q_ASSERT( j > 0 && j < m_dy );
        (*m_data)[ i ][ j ] = val;
}


main.cpp
#include <QApplication>         
#include <QScriptEngine>        
#include <QDebug>
#include "array2d.h"

const int arrDx = 5;
const int arrDy = 5;

void dump( const Array2D &arr )
{
        for( int i = 0; i < arr.dx(); ++i )
                for( int j = 0; j < arr.dy(); ++j )
                        qDebug( "item [%i, %i] = %i", i, j, arr.at( i, j ) );
}

int main( int argc, char *argv[] )
{
        QApplication app( argc, argv );

        Array2D arr( arrDx, arrDy );

        for( int i = 0; i < arr.dx(); ++i )
                for( int j = 0; j < arr.dy(); ++j )
                        arr.set( i, j, i + j );

        dump( arr );

        QScriptEngine se;
        se.globalObject().setProperty( "arr", se.newQObject( &arr ) );

        QScriptValue fun = se.evaluate( "function( i, j ) { print( i, j ); return arr.at( i, j ); }" );
        QScriptValueList args;
        args << QScriptValue( &se, 1 ) << QScriptValue( &se, 4 );
        QScriptValue y = fun.call( QScriptValue(), args );
        qDebug() << y.toNumber();

        return 0;
}


Высокой скорости вычисления от скриптов ожидать не стоит (от нативной она будет сильно отличаться).
BRE
Цитата(BRE @ 6.3.2009, 9:29) *
Пример:

array2d.h
#ifndef __ARRAY2D
#define __ARRAY2D

#include <QObject>
#include <vector>

class Array2D : public QObject
{
        Q_OBJECT
public:
        Array2D( int dx, int dy );
                ~Array2D();

public Q_SLOTS:
        char    at( int i, int j ) const;
        void    set( int i, int j, char val );

        inline  int             dx() const { return m_dx; }
        inline  int             dy() const { return m_dy; }

private:
        int             m_dx;
        int             m_dy;
        std::vector< std::vector<char> > *m_data;
};

#endif


array2d.cpp
#include "array2d.h"

Array2D::Array2D( int dx, int dy )
        : m_dx( dx ), m_dy( dy )
{
        m_data = new std::vector< std::vector<char> >( m_dx );
        for( int i = 0; i < m_dx; ++i )
                (*m_data)[ i ] = std::vector<char>( m_dy );
}

Array2D::~Array2D()
{
                delete m_data;
}

char Array2D::at( int i, int j ) const
{
        Q_ASSERT( i > 0 && i < m_dx );
        Q_ASSERT( j > 0 && j < m_dy );
        return (*m_data)[ i ][ j ];
}

void Array2D::set( int i, int j, char val )
{
        Q_ASSERT( i > 0 && i < m_dx );
        Q_ASSERT( j > 0 && j < m_dy );
        (*m_data)[ i ][ j ] = val;
}


main.cpp
#include <QApplication>         
#include <QScriptEngine>        
#include <QDebug>
#include "array2d.h"

const int arrDx = 5;
const int arrDy = 5;

void dump( const Array2D &arr )
{
        for( int i = 0; i < arr.dx(); ++i )
                for( int j = 0; j < arr.dy(); ++j )
                        qDebug( "item [%i, %i] = %i", i, j, arr.at( i, j ) );
}

int main( int argc, char *argv[] )
{
        QApplication app( argc, argv );

        Array2D arr( arrDx, arrDy );

        for( int i = 0; i < arr.dx(); ++i )
                for( int j = 0; j < arr.dy(); ++j )
                        arr.set( i, j, i + j );

        dump( arr );

        QScriptEngine se;
        se.globalObject().setProperty( "arr", se.newQObject( &arr ) );

        QScriptValue fun = se.evaluate( "function( i, j ) { print( i, j ); return arr.at( i, j ); }" );
        QScriptValueList args;
        args << QScriptValue( &se, 1 ) << QScriptValue( &se, 4 );
        QScriptValue y = fun.call( QScriptValue(), args );
        qDebug() << y.toNumber();

        return 0;
}


Высокой скорости вычисления от скриптов ожидать не стоит (от нативной она будет сильно отличаться).
Гость_AntonTatu_*
Цитата
Высокой скорости вычисления от скриптов ожидать не стоит (от нативной она будет сильно отличаться).

спасибо, так то же попробывал..., очень медленно в 1000 раз на глазок если, вобщем вопрос не снят, каким образом можно из проги получать код и компилить его "нативно"....? я уже весь инет перелазил, ну не писать же собственный компилятор.... (для меня это не реально :) )
BRE
Цитата(Гость_AntonTatu_* @ 6.3.2009, 12:11) *
спасибо, так то же попробывал..., очень медленно в 1000 раз на глазок если, вобщем вопрос не снят, каким образом можно из проги получать код и компилить его "нативно"....? я уже весь инет перелазил, ну не писать же собственный компилятор.... (для меня это не реально :) )

Уточни, из каких операций будет состоять формула (+ - * /)? Или будут еще какие-то функции?
Опиши подробней.
Ты используешь 2-мерный массив, это не изображение часом, а формула - не фильтр ли?
AntonTatu
Цитата(BRE @ 6.3.2009, 12:26) *
Цитата(Гость_AntonTatu_* @ 6.3.2009, 12:11) *
спасибо, так то же попробывал..., очень медленно в 1000 раз на глазок если, вобщем вопрос не снят, каким образом можно из проги получать код и компилить его "нативно"....? я уже весь инет перелазил, ну не писать же собственный компилятор.... (для меня это не реально :) )

Уточни, из каких операций будет состоять формула (+ - * /)? Или будут еще какие-то функции?
Опиши подробней.
Ты используешь 2-мерный массив, это не изображение часом, а формула - не фильтр ли?


все намного про ще, генерится специальным образом массив, считается формула такого вида:
x[0,j]*x[2,j]*x[5,j]*x[10,j]+x[0,j]*x[3,j]*x[4,j]+N+.....
формула считается в цикле, с каждой итерацией формула новая, ее длинна то же может изменится..., переменные в формуле это значения разных ячеек массива, на выходе каждой итерации необходимо получить расчетное значение итой формулы, колличество прогонов (итераций) миллионы.... :)
BRE
Цитата(AntonTatu @ 6.3.2009, 12:34) *
все намного про ще, генерится специальным образом массив, считается формула такого вида:
x[0,j]*x[2,j]*x[5,j]*x[10,j]+x[0,j]*x[3,j]*x[4,j]+N+.....
формула считается в цикле, с каждой итерацией формула новая, ее длинна то же может изменится..., переменные в формуле это значения разных ячеек массива, на выходе каждой итерации необходимо получить расчетное значение итой формулы, колличество прогонов (итераций) миллионы.... :)

Возможно ли выделить из формулы одинаковые части, например
x[0,j]*x[2,j]*x[5,j]*x[10,j]
x[0,j]*x[3,j]*x[4,j]
которые повторяются от формулы к формуле?
trdm
Может быть ассемблер? :)
Данные то все числовые, компилятор небольшой :)
SABROG
Тогда можно глянуть на fasmlib.
BRE
Цитата(AntonTatu @ 6.3.2009, 12:34) *
формула считается в цикле, с каждой итерацией формула новая, ее длинна то же может изменится..., переменные в формуле это значения разных ячеек массива, на выходе каждой итерации необходимо получить расчетное значение итой формулы, колличество прогонов (итераций) миллионы.... :)

Исходя из этого сообщения, я не представляю реализацию с dll. :blink:
Алгоритм:

Рассчитали и заполнили массив с переменными;
for( миллион итераций )
{
Получили строку с формулой;
Сгенерировали исходный файл (не важно С/asm);

Запустили компилятор;
Дождались завершения компиляции;

Запустили линкер;
Дождались завершения линковки;

Загрузили dll;
Resolve функцию;
Выполнили функцию;

Вернули результат;
}

Тебе не кажется, что время исполнения это цикла будет значительно больше чем выполнения того же скрипта на QtScript? А я так понял, что его скорость тебя уже не устраивает.

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

На самом деле мне приходит на ум только одна область где может применяться технология - архивация/сжатие данных, а dll или exe - SFX распаковщик. Но это с учетом того, что архиватор генерит некую уникальную формулу на основе подсунутых файлов, которые надо сжать.
BRE
Цитата(SABROG @ 6.3.2009, 20:24) *
Я так понял, что у него проблема с тем, что в рантайме надо выполнять сгенеренную формулу, но из-за всяких проверок (машина с конечным автоматом) это происходит медленно, в то время как современные компиляторы оптимизируют любую формулу еще на этапе компиляции и превращают её в машинный код, который не проверяет никаких условий (тип операции: умножение, деление и т.д.), а работает только с данными. Короче готовый продукт.


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


Т.е. на каждой итерации как-то генерируется разная формула -> собирать библиотеку на каждой итерации.

На самом деле встает вопрос, почему не вычислять формулу на этапе ее генерации?
Получили x[0,j]*x[2,j]*x[5,j]*x[10,j] - посчитали, получили x[0,j]*x[3,j]*x[4,j] - посчитали, прибавили. Конечно, здесь необходимо уточнить как, кто и какую формулу можно сгенерировать. Может формула состоит из повторяющихся выражений с разными переменными, здесь тоже можно попробовать помудрить.

Короче, тут простор для исследований, все нужно пробавать.

IMHO, путь с realtime-генерацией библиотеками, ээээ, ну не опревданный что-ли.
AntonTatu
Цитата
Исходя из этого сообщения, я не представляю реализацию с dll. :blink:


Я дико извиняюсь, ввел всех в заблуждение (сижу понять не могу фигню какую то написал в предыдущем своем посте), правильно так:

Алгоритм:

1. Считается формула такого вида:

x[0,j]*x[2,j]*x[5,j]*x[10,j]+x[0,j]*x[3,j]*x[4,j]+N+.....

формула может быть разной в зависимости от задачи (разной длинны, с разным количеством переменных, но структура именно такая как показано
2. Из формулы генерится dll

в цикле (100000 раз){
2. Генерится специальным образом массив, ячеек в массиве столько сколько переменных x[переменная,j] в формуле
3. формула высчитывается по массиву (подготовленной dll)
4. Записывается ответ
}

ЗЫ: понял почему фигню написал, голова была занята тем как считать не всю формулу сразу, а почастям... :) (хотя с этим разобрался)

Теперь алгоритм верный, может у кого рнибудь есть предложения , куда "копать" ?
BRE
Цитата(AntonTatu @ 6.3.2009, 21:19) *
Алгоритм:

1. Считается формула такого вида:

x[0,j]*x[2,j]*x[5,j]*x[10,j]+x[0,j]*x[3,j]*x[4,j]+N+.....

формула может быть разной в зависимости от задачи (разной длинны, с разным количеством переменных, но структура именно такая как показано
2. Из формулы генерится dll

в цикле (100000 раз){
2. Генерится специальным образом массив, ячеек в массиве столько сколько переменных x[переменная,j] в формуле
3. формула высчитывается по массиву (подготовленной dll)
4. Записывается ответ
}

Ага.
Как вариант:

1. Считается формула
2. Распарсивается в обратную польскую, только место конкретных чисел храняться ссылки на соответствующие элементы в массиве.
в цикле (100000 раз)
{
3. Генерится специальным образом массив, ячеек в массиве столько сколько переменных x[переменная,j] в формуле
4. запускается расчет формулы (место ссылок на элементы подставляются значения из массива)
5. Записывается ответ
}

Т.е. сначала готовим формулу для быстрого вычисления.
AntonTatu
Цитата(BRE @ 6.3.2009, 21:31) *
4. запускается расчет формулы (место ссылок на элементы подставляются значения из массива)


я вот этот пункт понять не могу, есть у меня формула (строка типа QString), преобразовал я ее в обратную польскую, (это значит распарсил ?), а что значит "в место ссылок на элементы подставляются значения из массива" ?
я просто не понимаю, если я формулу преобразовал в обратную польскую на выходе тоже ж QString ?

просто я итак могу формулу разобрать считывая строчку слево на право (без польской нотации), смотреть индекс переменных и сверяясь с ячейками массива считать функцию, но этот способ медленный (не быстрее чем с помощью QScript)


подумал еще :), а может как вариант создать класс (структуру) в котором хранить переменные функции, ссылки на ячейки массива и знак (+ или *) следуемый за переменной , и запихать все это в односвязаный список, делать обход списка от начала в конец и таким образом проводить расчет функции ?
BRE
Цитата(AntonTatu @ 7.3.2009, 0:23) *
подумал еще :), а может как вариант создать класс (структуру) в котором хранить переменные функции, ссылки на ячейки массива и знак (+ или *) следуемый за переменной , и запихать все это в односвязаный список, делать обход списка от начала в конец и таким образом проводить расчет функции ?

+1

Парсер переводит математическую формулу в список необходимых операций.

Делаем класс стек выполнений:
class MathStack : protected QStack<double>
{
public:
    void     push( double );
    double pop();
};


Вводим виртуальный базовый класс для всех операций:
class Operation
{
public:
    void    run() = 0;    //выполнить операцию

protected:
    static MathStack    m_stack;    // стек общий для всех операций
    friend class Formula;                // для возможности доступа к арифметическому стеку
};

class VarOp : public Operation
{
public:
    VarOp( const double &val  );

    void    run();

private:
    const double    &m_var;
};

class AddOp : public Operation
{
public:
    void    run();
};

class SubOp : public Operation
{
    ...
};


VarOp::VarOp( const double &var )
    : m_var( var )
{
}

// Поместить переменную на арифметический стек
void VarOp::run()
{
    m_stack.push( var );
}

// Снять с арифметического стека два числа, сложить их и результат положить обратно на стек
void AddOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v1 + v2 );
}

// Снять с арифметического стека два числа, вычесть их и результат положить обратно на стек
void SubOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v1 - v2 );
}


Вводим класс формулу (список операций):
class Formula
{
public:
    void     addOp( Operation *op );
    double calc() const;

private:
    typedef QList<Operation*> ListOp;
    ListOp     m_ops;
};

// Добавить операцию в список
void Formula::add( Operation *op )
{
    m_ops.append( op );
}

// Вычислить формулу
double Formula::calc()
{
    // Выполнить все операции
    for( ListOp::ConstIteration iOp = m_ops.begin(); iOp != m_ops.end(); ++i )
        (*iOp)->run();

    // После выполнения на вершине арифметического стека результат
    return Operation::m_stack.pop();
}


Теперь, формула A + B * C + D в обратной польской нотации будет: ABC*+D+

Для примера:
A - arr[ 0 ][ 4 ];
B - arr[ 3 ][ 7 ];
C - arr[ 7 ][ 1 ];
D - arr[ 4 ][ 8 ];

Array2D arr;

Formula f;
f.addOp( new VarOp( &arr[ 0 ][ 4 ] ) );
f.addOp( new VarOp( &arr[ 3 ][ 7 ] ) );
f.addOp( new VarOp( &arr[ 7 ][ 1 ] ) );
f.addOp( new MulOp() );
f.addOp( new AddOp() );
f.addOp( new VarOp( &arr[ 4 ][ 8 ] ) );
f.addOp( new AddOp() );

for( много итераций )
{
    calcArray( arr );
    double res = f.calc();
}


Как с этим закончим, можно будет попробовать оптимизировать. ;)
AntonTatu
Цитата
Как с этим закончим, можно будет попробовать оптимизировать. ;)


Третий день сижу, что то не побороть никак,

------ Построение начато: проект: one, Конфигурация: Debug Win32 ------
Компиляция...
main.cpp
Компоновка...
main.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: void __thiscall MathStack::push(double)" (?push@MathStack@@QAEXN@Z) в функции "public: virtual void __thiscall VarOp::run(void)" (?run@VarOp@@UAEXXZ)
main.obj : error LNK2001: неразрешенный внешний символ ""protected: static class MathStack Operation::m_stack" (?m_stack@Operation@@1VMathStack@@A)"
C:\Documents and Settings\Anton\Мои документы\Visual Studio 2008\Projects\one\Debug\one.exe : fatal error LNK1120: 2 неразрешенных внешних элементов
Журнал построения был сохранен в "file://c:\Documents and Settings\Anton\Мои документы\Visual Studio 2008\Projects\one\one\Debug\BuildLog.htm"
one - ошибок 3, предупреждений 0
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========

Переписал вот что :

class Operation
{
public:
    virtual void    run() = 0;    //выполнить операцию


и

class VarOp : public Operation
{
public:
    VarOp( const double &var  );


но это что называется в глаза бросилось... а ошибки все равно сыплет...
BRE
Цитата(AntonTatu @ 9.3.2009, 2:24) *
main.obj : error LNK2019: ссылка на неразрешенный внешний символ "public: void __thiscall MathStack::push(double)"

Все, что я написал выше это набросок, что бы описать идею, а не законченный код.

Ты определили функции MathStack?
void MathStack::push( double )
{
    ...
}

double MathStack::pop()
{
    ...
}

или сделай пока так:
class MathStack : public QStack<double>
{
};


Цитата(AntonTatu @ 9.3.2009, 2:24) *
но это что называется в глаза бросилось... а ошибки все равно сыплет...

Ошибки я сам видел, набирал прямо здесь, но функция редактирования у меня была еще не активна. :)

Покажи, что сейчас получилось...
AntonTatu
Цитата
Покажи, что сейчас получилось...



Прежде всего огромное спасибо за участие ! Я понимаю что это "набросок", но к сожалению моих знаний и понимания катастрофически не хватает..
"Набросок" в кавычках, потому что понятно что все уже разжовано до мелочей, а у мне с ручника не снятся ;)

Не компилируется если написано
    static MathStack m_stack;    // стек общий для всех операций

как только static убираю ошибка в этой строчке уходит,
еще ругается вот в этом месте
Цитата
Operation::m_stack.pop();

.\main.cpp(123) : error C2228: выражение слева от ".pop" должно представлять класс, структуру или объединение


сейчас получилось вот что (переписывал все в однин cpp файл, как зарабортает (будет супер) разнесу в h)
код
#include <QtCore/QCoreApplication>
#include <QStack>



class MathStack
{
public:
    void   push( double var);
    double pop ();
private:
    QStack <double> MyStack;
};

void MathStack::push (double var){
    MyStack.push(var);

}

double MathStack::pop(){
    return MyStack.pop();
}

class Operation
{
public:
    virtual void  run() = 0;    //выполнить операцию

protected:
    //static MathStack m_stack;    // стек общий для всех операций
    MathStack m_stack;              
    friend class Formula;                // для возможности доступа к арифметическому стеку
};

class VarOp : public Operation
{
public:
    VarOp( const double &var  );

    void    run();

private:
    const double    &m_var;
};

VarOp::VarOp( const double &var )
    : m_var( var )
{
}
// Поместить переменную на арифметический стек
void VarOp::run()
{
    m_stack.push( m_var );
}

class AddOp : public Operation
{
public:
    void    run();
};

class SubOp : public Operation
{
public:
    void    run();
};

class MulOp : public Operation
{
public:
    void    run();
};
// Снять с арифметического стека два числа, сложить их и результат положить обратно на стек
void AddOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v1 + v2 );
}

// Снять с арифметического стека два числа, вычесть их и результат положить обратно на стек
void SubOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v1 - v2 );
}
// Снять с арифметического стека два числа, перемножить их и результат положить обратно на стек
void MulOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v1 * v2 );
}


//Вводим класс формулу (список операций)
class Formula
{
public:
    void     addOp( Operation *op );
    double calc() const;

private:
    typedef QList<Operation*> ListOp;
    ListOp     m_ops;
};

// Добавить операцию в список
void Formula::addOp( Operation *op )
{
    m_ops.append( op );
}

// Вычислить формулу
double Formula::calc() const
{
    // Выполнить все операции
    for( ListOp::ConstIterator iOp = m_ops.begin(); iOp != m_ops.end(); ++iOp )
        (*iOp)->run();

    // После выполнения на вершине арифметического стека результат
    return Operation::m_stack.pop();
}



int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // Объявляем двухзначный вектор
    std::vector < std::vector <char> > *znach;
    // Распределяем память под вектор
    znach = new std::vector< std::vector <char> >( 2, std::vector<char>(5) );
    //заполним массив значениями
     for (int i=0; i<2; i++)
         for (int j=0; j<5; j++) {
            (*znach)[i][j] = i+j;
        
         }

Formula f;
f.addOp( new VarOp( (*znach)[ 0 ][ 0 ] ) );
f.addOp( new VarOp( (*znach)[ 0 ][ 1 ] ) );
f.addOp( new VarOp( (*znach)[ 1 ][ 1 ] ) );
f.addOp( new MulOp() );
f.addOp( new AddOp() );
f.addOp( new VarOp( (*znach)[ 1 ][ 2 ] ) );
f.addOp( new AddOp() );

//одна итерация
//double res = f.calc(); //не работает


    return a.exec();
}
BRE
Цитата(AntonTatu @ 9.3.2009, 13:35) *
    static MathStack m_stack;    // стек общий для всех операций

static нужен для того, чтобы стек был один для всех операций.
static раскомментируем. :)

В исходник за описанием класса Operation добавляем строку:
MathStack Operation::m_stack;


В таком виде у меня все копилируется без ошибок.
По функционированию посмотрю вечером, сейчас должен уехать по делам. ;)
Litkevich Yuriy
Цитата(AntonTatu @ 9.3.2009, 16:35) *
выражение слева от ".pop" должно представлять класс, структуру или объединение
вот и убери лишнее слева, зачем тебе Operation::

Для всех:
Читайте тему Справка по кнопкам и тэгам форума
AntonTatu
Цитата(BRE @ 9.3.2009, 13:50) *
В исходник за описанием класса Operation добавляем строку:
MathStack Operation::m_stack;


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


все заработало ! :) (фух...) спасибо !!!
SABROG
Как по скорости?
BRE
Еще небольшое уточнение, насчет операций вычитания и деления:
void SubOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v2 - v1 );      // Вычитаем число с вершины стека
}

void DivOp::run()
{
    double v1 = m_stack.pop();
    double v2 = m_stack.pop();
    m_stack.push( v2 / v1 );      // Делим на число с вершины стека
}

Для сложения/умножения не принципиально. :)
AntonTatu
Цитата(SABROG @ 9.3.2009, 16:11) *
Как по скорости?

на первый взгляд не плохо, наднях обязательно отпишусь... :rolleyes:

Цитата(BRE @ 9.3.2009, 17:24) *
Для сложения/умножения не принципиально. :)

:rolleyes: спасибо еще раз !!!
BRE
Цитата(AntonTatu @ 9.3.2009, 18:59) *
Цитата(SABROG @ 9.3.2009, 16:11) *
Как по скорости?

на первый взгляд не плохо, наднях обязательно отпишусь... :rolleyes:

Погонял тесты, при замене QStack на std::stack, получил увеличение производительности больше чем в 12 раз.
Раскрывающийся текст

#include <stack>

class MathStack
{              
public:        
        void   push( double var);
        double pop ();          

private:
        std::stack<double> m_stack;
};                                

void MathStack::push( double var )
{                                
        m_stack.push( var );      
}                                

double MathStack::pop()
{                      
        double val = m_stack.top();
        m_stack.pop();            
        return val;                
}

AD
Цитата(BRE @ 9.3.2009, 20:32) *
Погонял тесты, при замене QStack на std::stack, получил увеличение производительности больше чем в 12 раз.

Кстати, а почему так? С чем это связано?
BRE
Цитата(AD @ 9.3.2009, 20:36) *
Цитата(BRE @ 9.3.2009, 20:32) *
Погонял тесты, при замене QStack на std::stack, получил увеличение производительности больше чем в 12 раз.

Кстати, а почему так? С чем это связано?

Пока не разбирался, сам в недоумении. :blink:
Будем посмотреть... :)

Посмотрел.
QStack построен на базе QVector, и при добавлении/удалении элемента постоянно делает resize вектора.
std::stack построен на std::deque, соответственно скорость добавления/удаления на высоте.
Litkevich Yuriy
Ребята подумайте как переименовать тему, я ее читаю вскользь. Вы лучше должны суть понимать, но название Как создать dll из собственной программы ? не отражает суть обсуждения.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.