Эта тема описывает, как обновить ваши файлы MEX, чтобы использовать чередованный комплексный API. Можно продолжить использовать отдельный комплексный API путем вызова команды mex с опцией -R2017b. Однако для получения дополнительной информации об использовании этой опции, смотрите, что я должен Обновить Свои файлы MEX, чтобы Использовать Чередованный Комплексный API?
Если вы создаете свои файлы MEX с помощью команды mex с опцией -compatibleArrayDims, то сначала необходимо обновить исходный код, чтобы использовать 64-битный API. Для получения информации смотрите файлы MEX Обновления, чтобы Использовать 64-битный API.
Чтобы обновить ваш исходный код MEX, используйте следующий контрольный список.
Рассмотрите свой код для использования pr и указателей pi, указателей, возвращенных mxGetPr/mxGetPi и mxGetData/mxGetImagData функции. В чередованном комплексном API существует один указатель, pa, значение, возвращенное mxGetDoubles и другими введенными функциями данных. Важно проверить входной массив на сложность прежде, чем попытаться считать данные. Вызовы mxGetPr и mxGetData на комплексных массивах возвращают различные результаты в чередованном комплексном API, чем в отдельном комплексном API.
Подготовьте свой код перед редактированием.
Прежде, чем изменить ваш код, проверьте, что MEX-функция работает с API -R2017b. Как минимум создайте список из ожидаемых вводов и выводов или создайте полный тестовый набор. Используйте эти тесты, чтобы сравнить результаты с обновленным исходным кодом. Результаты должны быть идентичными.
Поддержите весь источник, двоичный файл и тестовые файлы.
Многократно осуществите рефакторинг свой существующий код путем проверки на следующие условия.
После каждого изменения скомпилируйте использование чередованного комплексного API. Чтобы создать myMexFile.c, введите:
mex -R2018a myMexFile.c
myMexFile.F, введите:mex -R2018a myMexFile.F
Разрешите отказы и предупреждения.
Протестируйте после каждого рефакторинга.
Сравните результаты выполнения вашей MEX-функции, скомпилированной с чередованным комплексным API с результатами вашего исходного двоичного файла. Если существуют какие-либо различия или отказы, используйте отладчик, чтобы исследовать причину. Для получения информации о возможностях вашего отладчика обратитесь к своей документации компилятора.
mxIsComplexЕсли ваш код вызывает функцию mxGetPi, чтобы определить, имеет ли массив комплексные элементы, используйте функцию mxIsComplex вместо этого. Эта функция создает и с -R2017b и с API -R2018a. Ищите свой код следующие шаблоны.
| Замена C исходный код: | С: |
|---|---|
mxArray *pa;
...
if (mxGetPi(pa)) {
/* process complex array */
}
|
mxArray *pa;
...
if (mxIsComplex(pa)) {
/* process complex array */
} |
double *ptr;
ptr = mxGetPi(pa);
if (ptr != NULL) {
/* process complex array */
}
|
MX_HAS_INTERLEAVED_COMPLEX, чтобы поддержать оба представления комплексного числаЧтобы записать код, который создает и с -R2017b и с API -R2018a, добавьте макрос MX_HAS_INTERLEAVED_COMPLEX. Этот макрос возвращает true, если вы создаете файл MEX с опцией -R2018a.
Перенос следующего кода в операторе #if MX_HAS_INTERLEAVED_COMPLEX гарантирует, что этот код создаст или с -R2017b или с -R2018a
опция mex. Однако в этом примере, нет никакого кода, чтобы выполниться, когда создано с -R2018a.
| Замена C исходный код: | С: |
|---|---|
static void
analyze_double(const mxArray *array_ptr)
{
mwSize total_num_of_elements, index;
double *pr, *pi;
total_num_of_elements = mxGetNumberOfElements(array_ptr);
pr = mxGetPr(array_ptr);
pi = mxGetPi(array_ptr);
for (index=0; index<total_num_of_elements; index++) {
if (mxIsComplex(array_ptr)) {
mexPrintf("%g + %gi\n", *pr++, *pi++);
}
else {
mexPrintf("%g\n", *pr++);
}
}
}
|
static void
analyze_double(const mxArray *array_ptr)
{
mwSize total_num_of_elements, index;
total_num_of_elements = mxGetNumberOfElements(array_ptr);
#if MX_HAS_INTERLEAVED_COMPLEX
/* add interleaved complex API code here */
#ELSE
/* separate complex API processing */
double *pr, *pi;
pr = mxGetPr(array_ptr);
pi = mxGetPi(array_ptr);
for (index=0; index<total_num_of_elements; index++) {
if (mxIsComplex(array_ptr)) {
mexPrintf("%g + %gi\n", *pr++, *pi++);
}
else {
mexPrintf("%g\n", *pr++);
}
}
#endif
} |
| Замена исходный код Фортрана: | С: |
|---|---|
mwPointer prhs(*), pr pr = mxGetPr(prhs(1)) |
mwPointer prhs(*), pr
#if MX_HAS_INTERLEAVED_COMPLEX
pr = mxGetDoubles(prhs(1))
#else
pr = mxGetPr(prhs(1))
#endif
|
Чтобы использовать mxGetData и функции mxGetImagData, необходимо проверить тип входного параметра mxArray и вручную бросить указатель вывод к правильному типу. Введенные функции доступа к данным проверяют тип массива и возвращают правильный тип указателя. Когда вы используете mxGetInt16s и функции mxGetComplexInt16s в следующем коде, чтобы обработать массив int16, вы не должны помнить соответствующий тип C, short int.
| Замена C исходный код: | С: |
|---|---|
static void
analyze_int16(const mxArray *array_ptr)
{
short int *pr, *pi;
pr = (short int *)mxGetData(array_ptr);
pi = (short int *)mxGetImagData(array_ptr);
if (mxIsComplex(array_ptr)) {
/* process complex data *pr,*pi */
}
else {
/* process real data *pr */
}
} |
static void
analyze_int16(const mxArray *array_ptr)
{
mxComplexInt16 *pc;
mxInt16 *p;
if(mxIsComplex(array_ptr)) {
pc = mxGetComplexInt16s(array_ptr);
/* process complex data (*pc).real,(*pc).imag */
}
}
else {
p = mxGetInt16s(array_ptr);
/* process real data *p */
}
}
} |
mxArraysСледующие примеры показывают, как MATLAB® использует одну переменную типа массив, чтобы представлять комплексный массив.
mxArrays CПредположим, что вы имеете следующие комплексные переменные mxArray и хотите добавить вещественные числа и мнимые числа x и y, чтобы создать массив z. Массивы x и y одного размера.
mxArray * x, y, z;
Вместо того, чтобы создать два указателя xr и xi для массива x, создайте один указатель xc типа mxComplexDouble. Чтобы получить доступ к действительным и мнимым частям элемента xc[i], используйте xc[i].real и xc[i].imag imag.
| Замена C исходный код: | С: |
|---|---|
double *xr, *xi, *yr, *yi, *zr, *zi; /* get pointers to the real and imaginary parts of the arrays */ xr = mxGetPr(x); xi = mxGetPi(x); yr = mxGetPr(y); yi = mxGetPi(y); zr = mxGetPr(z); zi = mxGetPi(z); ... /* perform addition on element i */ zr[i] = xr[i] + yr[i]; zi[i] = xi[i] + yi[i]; |
/* get pointers to the complex arrays */ mxComplexDouble * xc = mxGetComplexDoubles(x); mxComplexDouble * yc = mxGetComplexDoubles(y); mxComplexDouble * zc = mxGetComplexDoubles(z); ... /* perform addition on element i */ zc[i].real = xc[i].real + yc[i].real; zc[i].imag = xc[i].imag + yc[i].imag; |
Следующий код копирует mxArray в выходной аргумент. Код показывает, как протестировать на и скопировать комплексные массивы.
| Замена C исходный код: | С: |
|---|---|
mxGetPr(plhs[0])[0] = mxGetPr(prhs[0])[index];
if (mxIsComplex(prhs[0])) {
mxGetPi(plhs[0])[0] = mxGetPi(prhs[0])[index];
}
|
if (mxIsComplex(prhs[0])) {
mxGetComplexDoubles(plhs[0])[0] = mxGetComplexDoubles(prhs[0])[index];
}
else {
mxGetDoubles(plhs[0])[0] = mxGetDoubles(prhs[0])[index];
}
|
mxArraysПредположим, что у вас есть два комплекса, удваивают mxArrays и хотят передать их функции Фортрана с входными параметрами x и y, заданный можно следующим образом.
complex*16 x(*), y(*)
Вместо того, чтобы отдельно преобразовать действительные и мнимые части каждого mxArray, используйте функцию mxGetComplexDoubles.
| Замена исходный код Фортрана: | С: |
|---|---|
mwPointer mxGetPr, mxGetPi
C Copy the data into native COMPLEX Fortran arrays.
call mxCopyPtrToComplex16(
+ mxGetPr(prhs(1)),
+ mxGetPi(prhs(1)),x,nx)
call mxCopyPtrToComplex16(
+ mxGetPr(prhs(2)),
+ mxGetPi(prhs(2)),y,ny)
|
mwPointer mxGetComplexDoubles
integer*4 status
integer*4 mxCopyPtrToComplex16, mxCopyComplex16ToPtr
C Copy the data into native COMPLEX Fortran arrays.
status =
+ mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(1)),x,nx)
C Test status for error conditions
status =
+ mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(2)),y,ny)
C Test status for error conditions
|
mxArrayЭтот отрывок кода С показывает, как преобразовать действительный, дважды, входной массив prhs[0] в комплексный массив. Следующие кодовые наборы переменные раньше заполняли комплексную часть массива с последовательными числами.
// code to check number of arguments and expected types mwSize rows = mxGetM(prhs[0]); mwSize cols = mxGetN(prhs[0]); mwSize sz = mxGetElementSize(prhs[0]);
Следующий код показывает, как использовать mxMakeArrayComplex, чтобы преобразовать действительный, дважды, входной массив в чередованный комплексный mxArray. Для большего количества примеров смотрите mxMakeArrayComplex (C).
| Замена C исходный код: | С: |
|---|---|
plhs[0] = mxDuplicateArray(prhs[0]);
mxDouble *dc = (mxDouble*)mxMalloc(rows*cols*sz);
mxSetImagData(plhs[0], dc);
for (int i = 0 ; i < rows*cols ; i++)
{
dc[i] = i+1;
}
|
plhs[0] = mxDuplicateArray(prhs[0]);
if (mxMakeArrayComplex(plhs[0])) {
mxComplexDouble *dt = mxGetComplexDoubles(plhs[0]);
for (int i = 0 ; i < rows*cols ; i++)
{
dt[i].imag = i+1;
}
}
|
Следующие функции не находятся в чередованном комплексном API. Необходимо заменить их на чередованные комплексные функции при обработке комплексных данных.
mxGetPi
mxSetPi
mxGetImagData
mxSetImagData
Можно заменить вызовы mxGetPr и mxGetPi с вызовом mxGetComplexDoubles. Эта функция проверяет, что ваш массив содержит элементы типа mxComplexDouble. Аналогично, mxSetComplexDoubles заменяет mxSetPr и mxSetPi.
mxGetData и функции mxGetImagData не проверяют тип массива. Вместо этого необходимо бросить возвращаемое значение к типу указателя, который совпадает с типом, заданным входным параметром. Замените вызовы mxGetData и mxGetImagData с единственной, соответствующей, введенной функцией доступа к данным, например, mxGetComplexInt64s.
| Замена C исходный код: | С: |
|---|---|
mxArray *pa; mwSize numElements; int64_T *pr, *pi; pr = (int64_T *)mxGetData(pa); pi = (int64_T *)mxGetImagData(pa); numElements = mxGetNumberOfElements(pa); |
mxArray *pa; mwSize numElements; mxComplexInt64 *pc; pc = mxGetComplexInt64s(pa); numElements = mxGetNumberOfElements(pa); |
mxGetElementSizeВ API -R2018a функция mxGetElementSize (C) возвращает sizeof(std::complex<T>) для комплексного mxArray с типом данных T. Это значение является дважды значением, возвращенным функцией в API -R2017b. Точно так же mxGetElementSize (Fortran) в API -R2018a возвращает дважды значение как функцию в API -R2017b.
Следующие функции находятся и в -R2017b и в API -R2018a. В то время как вы не должны заменять их на введенные функции доступа к данным, введенные функции данных обеспечивают проверку типа. Кроме того, если вы используете mxGetPr, вы можете выбрать mxGetPi для любой обработки комплексного массива. Этот шаблон кода вызывает ошибки при записи MEX-функций -R2018a.
mxGetPr
mxSetPr
mxGetData (C) и mxGetData (Fortran) - для числовых массивов
mxSetData (C) и mxSetData (Fortran) - для числовых массивов
Можно заменить вызовы mxGetPr с вызовом mxGetDoubles. Эта функция проверяет, что ваш массив содержит элементы типа mxDouble. Аналогично, mxSetDoubles заменяет mxSetPr. Чтобы заменить вызовы mxGetData и функций mxSetData, выберите соответствующую введенную функцию доступа к данным, например, mxGetInt64s и mxSetInt64s.
| Замена C исходный код: | С: |
|---|---|
double *y; /* create a pointer y to input matrix */ y = mxGetPr(prhs[1]); |
mxDouble *p; p = mxGetDoubles(prhs[1]); |
| Замена исходный код Фортрана: | С: |
|---|---|
mwPointer pr
mwPointer mxGetPr
C Create a pointer to input matrix
pr = mxGetPr(prhs(1))
|
mwPointer pr
mwPointer mxGetDoubles
pr = mxGetDoubles(prhs(1))
|
Рассмотрите создание справочного файла, описанного в Использовании справочных файлов с MEX-функциями, который содержит информацию о сборке. Например, создайте файл displayTypesafeNumeric.m, содержащий следующий текст.
% displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function % % Use the following command to build this MEX file: % mex -R2018a displayTypesafeNumeric.c
В подсказке команды MATLAB введите:
help displayTypesafeNumericdisplayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function Use the following command to build this MEX file: mex -R2018a displayTypesafeNumeric.c