Статус: Advanced Member Группы: Registered
Зарегистрирован: 02.06.2009(UTC) Сообщений: 346 Сказал «Спасибо»: 50 раз Поблагодарили: 156 раз в 105 постах
|
Вижу, что в SMath Studio 0.80 (build 3408) от 01.01.1601 г (ну и старьё) есть попытки поддерживать нечто вложенное в матрицах. Могу показать как были устроены структуры, называемые nested arrays, у Mathcad. По крайней мере те, что передавались внутрь пользовательских библиотек. Вот два работающих варианта на С и на Паскале. Описание структур на С: Код:typedef struct
{
DWORD dwType;
char * str;
} EXTPTR, *PEXTPTR;
typedef struct
{
PEXTPTR pMCType;
DWORD dwMark;
} EXTCELL, *PEXTCELL;
typedef struct
{
DWORD dwType; // тип расширенного содержимого
DWORD dwUnknown1;
DWORD dwBytesSize;// размер реальной (мнимой) части в байтах
DWORD dwUnknown2;
double* pReal; // pReal[...], == NULL когда реальная часть равна нулю
double* pImag; // pImag[...], == NULL когда мнимая часть равна нулю
DWORD dwRows;
DWORD dwCols;
} EXTCMPLXARR, *PEXTCMPLXARR;
Чтобы понять, что в элементе матрицы находится нечто отличное от числа типа double, второе двойное слово (DWORD 4 байта) равнялось 0xFFFFFFFF, а первое было указателем на расширенное описание. Первое и второе при просмотре от младших адресов к старшим. Если нет такой метки, то считалось, что в памяти находится число типа double (8 байт). Вот пример кода дешифровки из Отладчика. Этот код рисует список переданных переменных в окне списка переменных: Код:////////////////////////////////////
// 1. Сначала отображаем информацию
// Очищаем список переменных
m_pLView->SetRedraw( FALSE );
m_pLView->DeleteAllItems();
LVITEM lvi;
TCHAR szRe[32], szIm[32];
int strmark, rows, cols;
PEXTCELL ptr;
PEXTCMPLXARR m_pExtCmplxArr;
// Формируем новый список
for ( i = 0; i < (int)Vars->rows; i++ ) {
for ( j = 0; j < (int)Vars->cols; j++ ) {
nItemIndx = i * int(Vars->cols) + j;
// Insert the first item
lvi.mask = LVIF_IMAGE | LVIF_TEXT;
strItem.Format(_T("#%i"), nItemIndx);
lvi.iItem = nItemIndx;
lvi.iSubItem = 0;
lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
// Выбираем картинку в соответствии с типом переменной
lvi.iImage = VarTypeFromAddress( (PDWORD) &Vars->hReal[j][i] );
m_pLView->InsertItem(&lvi);
// Находим для каждой переменной значение
// Узнаём что находится в ячейке массива
ptr = (PEXTCELL)((PDWORD)Vars->hReal[j] + i*sizeof(double)/sizeof(DWORD));
strmark = int(~ptr->dwMark);
if (strmark == 0) {
switch ( ptr->pMCType->dwType ) {
case 0x03: { // Если параметр задан в виде строки, то ...
strItem.Format("\"%s\"", (LPCTSTR)ptr->pMCType->str );
break;
}
case 0x05: {
m_pExtCmplxArr = ( PEXTCMPLXARR ) ptr->pMCType;
rows = m_pExtCmplxArr->dwRows;
cols = m_pExtCmplxArr->dwCols;
if ( ( rows == 1 ) && ( cols == 1 ) ) {
int strmark2;
PEXTCELL ptr2;
PEXTCMPLXARR pTmpArr;
ptr2 = (PEXTCELL)((PDWORD) m_pExtCmplxArr->pReal );
strmark2 = int(~ptr2->dwMark);
if (strmark2 == 0) {
switch ( ptr2->pMCType->dwType ) {
case 0x03: { // Если параметр задан в виде строки
strItem.Format("{\"%s\"}", (LPCTSTR)ptr2->pMCType->str );
break;
}
case 0x05: {
pTmpArr = ( PEXTCMPLXARR ) ptr2->pMCType;
strItem.Format("{{%i,%i}}", pTmpArr->dwRows, pTmpArr->dwCols ) ;
break;
}
case 0x08: {
strItem.Format("{function}");
break;
}
default:
wsprintf(szRe, "[%#08x]?", ptr2->pMCType->dwType );
strItem.Format("{%s}", szRe );
}
} else { // нет признака указателя, будем считать, что это число типа double
if ( ( m_pExtCmplxArr->pImag != NULL ) && ( m_pExtCmplxArr->pReal != NULL ) ) {
if ( m_pExtCmplxArr->pReal[ 0 ] == 0.) {
if ( m_pExtCmplxArr->pImag[ 0 ] == 0. ) {
strItem.Format( "{0}" );
break;
}
sprintf_s(szIm, _T("%.*G"), nPrecision, m_pExtCmplxArr->pImag[ 0 ] );
strItem.Format("{%si}", szIm );
break;
}
if ( m_pExtCmplxArr->pImag[ 0 ] == 0.) {
sprintf_s(szRe, _T("%.*G"), nPrecision, m_pExtCmplxArr->pReal[ 0 ] );
strItem.Format("{%s}", szRe );
break;
}
sprintf_s(szRe, _T("%.*G"), nPrecision, m_pExtCmplxArr->pReal[ 0 ] );
sprintf_s(szIm, _T("%.*G"), nPrecision, m_pExtCmplxArr->pImag[ 0 ] );
strItem.Format("{%s %s %si}", szRe, (szIm[0]=='-')?("-"):("+"),
(szIm[0]=='-')?(szIm + 1):(szIm) );
break;
}
if ( m_pExtCmplxArr->pReal != NULL ) {
sprintf_s(szRe, _T("%.*G"), nPrecision, m_pExtCmplxArr->pReal[ 0 ] );
strItem.Format("{%s}", szRe );
break;
}
if ( m_pExtCmplxArr->pImag != NULL ) {
if ( m_pExtCmplxArr->pImag[ 0 ] == 0. ) {
strItem.Format("{0}");
break;
} else {
sprintf_s(szIm, _T("%.*G"), nPrecision, m_pExtCmplxArr->pImag[ 0 ] );
strItem.Format("{%si}", szIm );
break;
}
}
}
} else strItem.Format("{%i,%i}", rows, cols ) ;
break;
}
case 0x08: {
strItem.Format("function");
break;
}
default:
wsprintf(szRe, "[%#08x]?", ptr->pMCType->dwType );
strItem.Format("%s", szRe );
}
} else { // нет признака указателя, будем считать, что это число типа double
if ( ( Vars->hImag != NULL ) && ( Vars->hReal != NULL ) ) {
if ( Vars->hReal[j][i] == 0.) {
if ( Vars->hImag[j][i] == 0. ) {
strItem.Format( "0" );
} else {
sprintf_s(szIm, _T("%.*G"), nPrecision, Vars->hImag[j][i] );
strItem.Format("%si", szIm );
}
} else
if ( Vars->hImag[j][i] == 0.) {
sprintf_s(szRe, _T("%.*G"), nPrecision, Vars->hReal[j][i] );
strItem.Format("%s", szRe );
} else {
sprintf_s(szRe, _T("%.*G"), nPrecision, Vars->hReal[j][i] );
sprintf_s(szIm, _T("%.*G"), nPrecision, Vars->hImag[j][i] );
strItem.Format("%s %s %si", szRe, (szIm[0]=='-')?("-"):("+"),
(szIm[0]=='-')?(szIm + 1):(szIm) );
}
} else
if ( Vars->hReal != NULL ) {
sprintf_s(szRe, _T("%.*G"), nPrecision, Vars->hReal[j][i] );
strItem.Format("%s", szRe );
} else
if ( Vars->hImag != NULL ) {
if ( Vars->hImag[j][i] == 0. ) {
strItem.Format("0");
} else {
sprintf_s(szIm, _T("%.*G"), nPrecision, Vars->hImag[j][i] );
strItem.Format("%si", szIm );
}
}
}
m_pLView->SetItemText( nItemIndx, 1, strItem);
// В поле адреса вписываем адрес переменной в памяти
wsprintf(szRe, "%#08x", (DWORD) &Vars->hReal[j][i] );
strItem.Format("%s", szRe );
m_pLView->SetItemText( nItemIndx, 2, strItem);
// Set item data
m_pLView->SetItemData( nItemIndx, (DWORD) &Vars->hReal[j][i] );
}
}
if (m_pLView->GetItemCount() > 1) {
m_pLView->SetItemState(0, LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
m_pLView->EnsureVisible(0, FALSE);
}
m_pLView->SetRedraw();
//////////////////////////////////////////
Ещё один пример из Delphi. Описание структур: Код:type
EXTCMPLXARR = record
dwType : DWORD;
dwUnknown1 : DWORD;
dwBytesSize : DWORD;
dwUnknown2 : DWORD;
pReal : ^tColumn; // столбец матрицы в Mathcad
pImag : ^tColumn;
dwRows : DWORD;
dwCols : DWORD;
end;
EXTCELL = record
pMCType : ^EXTCMPLXARR;
dwMark : DWORD;
end;
var
i, i1, k : longint;
NumPoints : LongInt;
pExtCell: ^EXTCELL;
pExtArr: ^EXTCMPLXARR;
Далее я сам создаю вложенный массив, который Mathcad благополучно принимает. Код:// Сам массив точек находится в массивах zz1, zz2, zz3
// Чтобы отрисовать точки нужно создать вектор из
// трёх элементов, каждый элемент содержит вектор
// координат, соответственно X, Y, Z.
MathcadArrayAllocate(OutArr, 3, 1, TRUE, FALSE);
// -=[ Вставляем вектор координат X ]=-
// OutArr.hReal^[Столбец]^[Строка] - отсчёт с нуля
pExtCell := @ OutArr.hReal^[0]^[0];
pExtCell^.dwMark := DWORD(-1);
// Выделяем память под заголовок расширенного массива
// pExtArr := MathcadAllocate(sizeof(EXTCMPLXARR));
pExtArr := AllocMem(sizeof(EXTCMPLXARR));
// Заполняем структуру расширенного массива
with pExtArr^ do begin
dwType := $05; // тип - расширенный комплексный массив
dwUnknown1 := NumPoints; // здесь должно быть число не менее 5
dwBytesSize := dwUnknown1 * sizeof(double); // размер массива в байтах
dwUnknown2 := $00;
// pReal := MathcadAllocate(dwBytesSize);
pReal := AllocMem(dwBytesSize);
pImag := nil;
dwRows := NumPoints; // количество строк
dwCols := 1; // количество столбцов
end;
// Подцепляем её к элементу массива
pExtCell^.pMCType := @ pExtArr^;
// В расширенном массиве столбцы расположены в памяти
// один за другим
for i1 := 0 to NumPoints - 1 do begin
pExtArr^.pReal^[i1] := double(zz1[i1]);
end;
// -=[ Вставляем вектор координат Y ]=-
// OutArr.hReal^[Столбец]^[Строка] - отсчёт с нуля
pExtCell := @ OutArr.hReal^[0]^[1];
pExtCell^.dwMark := DWORD(-1);
// Выделяем память под заголовок расширенного массива
// pExtArr := MathcadAllocate(sizeof(EXTCMPLXARR));
pExtArr := AllocMem(sizeof(EXTCMPLXARR));
// Заполняем структуру расширенного массива
with pExtArr^ do begin
dwType := $05; // тип - расширенный комплексный массив
dwUnknown1 := NumPoints; // здесь должно быть число не менее 5
dwBytesSize := dwUnknown1 * sizeof(double); // размер массива в байтах
dwUnknown2 := $00;
// pReal := MathcadAllocate(dwBytesSize);
pReal := AllocMem(dwBytesSize);
pImag := nil;
dwRows := NumPoints; // количество строк
dwCols := 1; // количество столбцов
end;
// Подцепляем её к элементу массива
pExtCell^.pMCType := @ pExtArr^;
// В расширенном массиве столбцы расположены в памяти
// один за другим
for i1 := 0 to NumPoints - 1 do begin
pExtArr^.pReal^[i1] := double(zz2[i1]);
end;
// -=[ Вставляем вектор координат Z ]=-
// OutArr.hReal^[Столбец]^[Строка] - отсчёт с нуля
pExtCell := @ OutArr.hReal^[0]^[2];
pExtCell^.dwMark := DWORD(-1);
// Выделяем память под заголовок расширенного массива
// pExtArr := MathcadAllocate(sizeof(EXTCMPLXARR));
pExtArr := AllocMem(sizeof(EXTCMPLXARR));
// Заполняем структуру расширенного массива
with pExtArr^ do begin
dwType := $05; // тип - расширенный комплексный массив
dwUnknown1 := NumPoints; // здесь должно быть число не менее 5
dwBytesSize := dwUnknown1 * sizeof(double); // размер массива в байтах
dwUnknown2 := $00;
// pReal := MathcadAllocate(dwBytesSize);
pReal := AllocMem(dwBytesSize);
pImag := nil;
dwRows := NumPoints; // количество строк
dwCols := 1; // количество столбцов
end;
// Подцепляем её к элементу массива
pExtCell^.pMCType := @ pExtArr^;
// В расширенном массиве столбцы расположены в памяти
// один за другим
for i1 := 0 to NumPoints - 1 do begin
pExtArr^.pReal^[i1] := double(zz3[i1]);
end;
// Выходной массив имеет недокументированную организацию,
// чтобы можно было сразу отображать результат
Result := 0;
В общем, так как это сделано в Mathcad, думаю, что делать не надо. Не красиво. |