Помогите разобраться в проблеме импорта функции из dll - страница 3

 

Не благодарите :-). Все будете делать сами :-).

Расписал по шагам:

.

#1 (тестовый, можно не делать ;-) :

В С++ создайте матрицу с числом строк MAX_ROW = 5..10, столбцов MAX_COL = 5..10 (числа случайным образом).

Сделайте случайное заполнение данными.

.

#2 (тестовый, можно не делать ;-) : решите следующую задачу:

Матрицу с шага #1 нужно представить в одномерном виде.

создайте одномерный массив double размера=MAX_ROW*MAX_COL, в котором данные хранятся по формуле

for(line = 0 .. MAX_COL-1)

for(column = 0 .. MAX_COL-1)

array[line*MAX_COL + column] = data[line][column];

.

#3: решите следующую задачу / в виде функции

Вам приходит одномерный массив double из шага (2), число строк и столбцов.

Вы должны данные из этого массива положить в объект ap::real_2d_array

.

#4: Вам приходит объект ap::real_2d_array / в виде функции

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

.

#5 (тестовый, можно не делать ;-) :

Одномерный массив Вы должны преобразовать в двумерную матрицу (как в шаге 1).

Полученную матрицу сравнить с исходной матрицей из шага 1.

В случае несовпадения- разбираться.

.

Главные функции, которые будут нужны- это функции 3 и 4.

Шаги 1,2 = тренировочные, Вам придется так запаковывать данные в Mql, шаг 5 = проверочный.

.

В общем-то, я сделал бы функции для каждого из 5-ти шагов.

.

Сингулярное преобразование на Mql.

https://www.mql5.com/ru/code/7359

 

Спасибо за подробный расклад как должен работать этот алгоритм сингулярного разложения. Пункты 1-3 у меня реализованы. Осталась проблема с пунктом 4, т.к. у меня пока не получается создать рабочую dll с экспортом функции rmatrixsvd(...), как я писал ранее,

из-за внесения в первоначальный код на С++: extern "C" bool __declspec(dllexport) __stdcall rmatrixsvd(...), начинаются ошибки... хотя, если компилировать просто bool rmatrixsvd(...), то ошибок нет... но мне то нужна экспортируемая функция... Вот здесь и ступор...

Спасибо за помощь.

 

Относительно пункта 4 (и всех остальных). rmatrixsvd к нему не имеет никакого отношения.

Равно как и алгоритм сингулярного разложения. Это пункты, относящиеся

к передаче-получению данных из/в Dll.

.

Прототип функции, которую нужно написать для п. 4:

void Convert_real_2d_array_to_double(

const ap::real_2d_array & arr,

double * data,

int & lines,

int & columns

);

.

Т.е. Вам нужно научиться доставать из ap::real_2d_array кол-во строк, столбцов и данные.

.

Из этого:

const ap::real_2d_array & arr

---->>>

получить это:

double * data,

int & lines,

int & columns

 

Спасибо огромное ещё раз, что уделяете мне время.

Ещё раз прочитал все записи очень внимательно и похоже наконец-то до меня дошло :-), что нужно делать.

Действительно, сама функция rmatrixsvd тут как бы является "рабочей лошадкой" и не надо пытаться её экспортировать,

а нужно всего лишь вовремя положить груз на телегу, а потом аккуратно его выгрузить в нужное место, когда оно будет доставлено

по назначению. если говорить образно. Я правильно сейчас Вас понял?

Т.е. мне надо на С++ сделать эти конверторы данных пункт 3 и 4 и по сути дела в MQL работать с ними, т.е. объявлять их в MQL, а в DLL они

должны объявляться как экспортируемые, чтобы Метатрейдер мог с ними работать. Я правильно понимаю суть своей проблемы?

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

Тем более, что в MQL же нельзя объявлять массив как a[ ][ ]? Т.е. нужно хотя бы объявить как a[ ][100]. Это же так? или я ошибаюсь?

А это не очень удобно, т.к. заранее не знаешь какова будет размерность двумерного массива, а резервировать память под массив заранее, в прок - не лучший вариант,

а в С++ такой проблемы нет? т.е. двумерный массив может быть образно говоря "резиновый". Это так? Или в С++ тоже есть некие нюансы?

Ещё хотел узнать у Вас по поводу Borland Builder 2009. Может он не такой глючный как 6-ка? И в принципе на нём можно работать?

А то alsu вообще, как я понимаю, сказал, что он - дебилдер. :-) А Вы программируете, насколько я понял, на Visual Studio? Он круче? И без глюков? А какая сейчас последняя версия?

Я рад, что я понял суть своей проблемы с Вашей помощью. Теперь попробую всё это реализовать...

 
boysn >>:

Тем более, что в MQL же нельзя объявлять массив как a[ ][ ]? Т.е. нужно хотя бы объявить как a[ ][100]. Это же так? или я ошибаюсь?

А это не очень удобно, т.к. заранее не знаешь какова будет размерность двумерного массива, а резервировать память под массив заранее, в прок - не лучший вариант,

Отлично! :-) Я очень рад, что процесс куда-то движется :-).

.

Двумерные массивы в Mql4 объявлять, конечно же, можно.

И точно так же можно импортировать функцию из Dll 

#import myLib

void showMatrix(double & array[][], int rows, int cols);

#import

.

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

число строк и столбцов void showMatrix(double *array, int rows, int cols);

И array работает как одномерный массив, адресация в котором устроена циклом:

for(line = 0 .. MAX_COL-1)
for(column = 0 .. MAX_COL-1)
array[line*MAX_COL + column] = data[line][column];

.

Т.е. Mql кидает двумерный массив непрерывным буфером.

.

Только не наступайте на те же грабли - функции с шага 3 и 4 используются внутри Вашей Dll,

внутри интерфейсной функции Dll-ины, которая примет от Mql одномерные массивы с числом строк/столбцов.

Она конвернтнет их в ap::real_2d_array, передаст в rmatrixsvd

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

должна быть правильная.

.

Выходной буфер резервируйте, естественно, заранее- это нужно сделать в Mql.

А если размеренности неизвестны, то мое мнение, что нужно сделать

одномерный массив большой размеренности, например

double out[2500];

и массивы из одного элемента для выходных значений кол-во строк/столбцов

double raws[1];

double cols[1];

.

Visual Studio круче. Особенно с Visual Assist'ом. Как в дебилдере работает STL, я не знаю. С юникодом проблемы почти 100%.

Справка Win SDK ни в какое сравнение с MSDN. Ходят слухи, что для интеграции с дельфи компилятор борланда

для плюсов претерпел неположительные изменения.

.

А работа с памятью- это тема для занятия.

 

Вроде бы теоретически всё понятно, буду приступать к реализации, а там видно будет :-). "Глаза страшат, а руки делают.."

Ещё раз спасибо за ценные указания. Очень бы хотелось реализовать этот алгоритм... А то как обычно, мысль уже ушла далеко стратегически, а вот тактически и практически

приходится её догонять. Надеюсь, что всё у меня получится. Если возникнут у меня вопросы, Вы уж не откажите мне в любезности, помочь советом. Благодарю!

 

Хотелось бы ещё раз уточнить по поводу размерности динамических массивов.

В MQL одномерный массив можно определить как array[ ], а потом когда будет известно в программе размерность массива N,

то с помощью функции ArrayResize(array, N). Двумерный же массив можно определить только как array[ ][100], т.е. вторую размерность

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

двумерный массив array[ ][ ], компилятор на это не ругается, но функция ArrayResize у станавливает новый размер в первом измерении массива,

для второго измерения подобной функции в MQL нет. Если определить двумерный массив array[N][M], компилятор на это выдаст ошибку, что ожидается

целое число, т.е. размерности нужно определить заранее, по крайней мере второе измерение массива.

В С++ также? Никуда от этого не уйти? Ещё раз хотелось бы уточнить.

В сингулярном разложении используется Библиотека AP для C++ (описание в прикрепленном файле). Там есть некоторые функции, насколько я понял решающие

проблемы динамического первого и второго измерения массивов. Могу ли я ими воспользоваться в моём случае внутри DLL при написании конверторов данных?

void setbounds(int iLow1, int iHigh1, int iLow2, int iHigh2)
Выделение памяти под массив. При этом старое содержимое массива удаляется и освобождается выделенная под него память, затем заново выделяется отдельная область памяти размером (iHigh1-iLow1+1)*(iHigh2-iLow2+1) элементов.
Нумерация элементов в новом массива по первой размерности начинается с iLow1 и заканчивается iHigh1, аналогично для второй размерности.
Содержимое нового массива не определено.

А ещё там есть такая функция:

void setcontent(int iLow1, int iHigh1, int iLow2, int iHigh2, const T *pContent)
Метод аналогичен методу setbounds() за тем исключением, что после выделения памяти в неё копируется содержимое массива pContent[].
Массив pContent содержит двухмерный массив, записанный построчно, т.е. первым идет элемент [iLow1, iLow2], затем [iLow1, iLow2+1] и т.д.

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

Я правильно понял?

 

Библиотека AP для C++

 
Библиотека AP для C++
Файлы:
 

MQL : в одномерном размерность меняем как хотим, да. Потом достаем все по индексам (line * MAX_COL + col).

В двумерном 2я размерность зафиксирована. Т.е. элементы матрицы [15][32] из массива a[100][100] мы уже не cсчитаем.

.

А как работают функции библиотеки AP- я предлагаю Вам проверить.

Не останавливайтесь на Dll. Напишите Exe, его проще запускать и отлаживать.

Вставьте debug print (отладочную печать).

Совет я дать, конечно, могу- но для совета, по-хорошему, нужно это проверять-

писать тестовый код.

.

А насчет содержимого массива и переменных- неважно где-

лучше взять за правило их принудительно, жестко инициализировать.