How can I get MEX function to return the right value?

Below is an example of the MEX code I am trying to implement, I am wondering why does the code return different values instead of 5 5 5?
CODE:
#include "mex.h"
void merge(int x, float *y, int n){
for (int i = 0; i < n; i++){
y[i] = x;
}
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double x;
float *y;
int n;
if(nrhs !=2 )
mexErrMsgTxt("Wrong number of input arguments.");
x = mxGetScalar(prhs[0]);
n = mxGetScalar(prhs[1]);
/* --- output --- */
plhs[0] = mxCreateDoubleMatrix(1, n, mxREAL);
y = (float *)mxGetPr(plhs[0]);
// mexPrintf("Before %30.25f\n", y);
merge(x,y,n);
mexPrintf("The first value is %30.25f\n", y[0]);
mexPrintf("The second value is %30.25f\n", y[1]);
mexPrintf("The third value is %30.25f\n", y[2]);
// return;
}

댓글 수: 4

Where in the algorithm is it suggested that 5 5 5 is in any way what is expected?
Sorry, I meant if I mex it and run it as y = merge(5, 3) it does not return an array of [5, 5, 5]...
And what result does it give?
It returns this...
y =
1.0e+03 *
2.0480 0.0000 0

댓글을 달려면 로그인하십시오.

 채택된 답변

Geoff Hayes
Geoff Hayes 2016년 9월 12일
Cheryl - according to mxCreateDoubleMatrix, this call creates a 2-D, double-precision, floating-point array. Note how in your code, you are referencing this array using float or single-precision. If I take your code and replace the float with double, then
>> y = merge(5, 3)
returns
The first value is 5.0000000000000000000000000
The second value is 5.0000000000000000000000000
The third value is 5.0000000000000000000000000
y =
5 5 5
So you need to change this in three places - where you define y, where you assign y, and in the merge function signature.
#include "mex.h"
void merge(int x, double *y, int n){
for (int i = 0; i < n; i++){
y[i] = x;
}
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double x;
double *y;
int n;
if(nrhs !=2 )
mexErrMsgTxt("Wrong number of input arguments.");
x = mxGetScalar(prhs[0]);
n = mxGetScalar(prhs[1]);
/* --- output --- */
plhs[0] = mxCreateDoubleMatrix(1, n, mxREAL);
y = (double *)mxGetPr(plhs[0]);
merge(x,y,n);
mexPrintf("The first value is %30.25f\n", y[0]);
mexPrintf("The second value is %30.25f\n", y[1]);
mexPrintf("The third value is %30.25f\n", y[2]);
}

댓글 수: 3

Hi Geoff, Thanks for identifying the mistake and providing a solution!
Just wondering if you know what was it returning previously?
Guillaume
Guillaume 2016년 9월 12일
편집: Guillaume 2016년 9월 12일
It was returning the bit patterns of two 5 as single in the first double, and the bit-pattern of the 3rd 5 as half of the 2nd double.
If you picture the memory that you've allocated as bytes
plhs[0]: allocated 3 double = 3 x 4 bytes
1st double 2nd double 3rd double
---------------|---------------|---------------
d11 d12 d13 d14 d21 d22 d23 d24 d31 d32 d33 d34
To start with all the bxx are set to 0 by mxCreateDoubleMatrix
You then lie to the compiler and says that the above is an array of float (2 bytes only). This thus what the compiler thinks y is:
1st 2nd 3rd 4th 5th 6th
float float float float float float
-------|-------|-------|-------|-------|-------
d11 d12 d13 d14 d21 d22 d23 d24 d31 d32 d33 d34
So in your loop, you're putting the first 5 in d11 d12, the 2nd in d13 d14, the 3rd in d21 d22 and leave d23 to d34 as 0:
1st 2nd 3rd 4th 5th 6th
float float float float float float
-------|-------|-------|-------|-------|-------
d11 d12 d13 d14 d21 d22 d23 d24 d31 d32 d33 d34
5 | 5 | 5 | 0 | 0 | 0 <- what you put in there in the loop
---------------|---------------|---------------
1st double 2nd double 3rd double
Matlab still sees the array as double. The bit patterns of two single 5 makes 2048 when interpreted as double, the first result that you had
>> typecast(single([5 5]), 'double')
ans =
2048.
The bit pattern of a single 5 stuck to a single 0 makes for a very small number, which I assume is the 2nd value that you see
>> typecast(single([5 0]), 'double')
ans =
5.3568e-315
And since 0 is just zero bits everywhere for both float and double, you're seeing 0 for the last double since you never put anything there.
FYI, one other place you would probably want to change to a double is in this line:
void merge(int x, double *y, int n){
The way this is coded, when you make the following call
merge(x,y,n);
The first argument x (which is double) will get auto-converted to an int when its value gets placed on the stack. So anything that is not an integer in range (fractional values, etc) won't get stuffed into the result as you probably expected. You should consider changing the signature to this instead:
void merge(double x, double *y, int n){

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

도움말 센터File Exchange에서 Write C Functions Callable from MATLAB (MEX Files)에 대해 자세히 알아보기

태그

질문:

2016년 9월 12일

댓글:

2016년 9월 12일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by