|
On Nov 10, 5:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
> As Chris already said, it is not clear that you actually want a mex
> file that handles mxLogical data as input. Maybe your data is 0's and
> 1's but it is always double class. But taking you at your word, here
> are some comments about your code:
>
> (Chris has already noted the first two. I simply repeat them here)
>
> 1) You have made no checks for proper input type, size, etc. This can
> cause nasty problems with memory if you don't pass the function
> exactly what the code expects. Always check the input. For example, if
> you pass in a double class variable, then you have passed in 8*5 = 40
> bytes of data (plus the overhead stuff), but this line
>
> > memcpy(mxGetLogicals(plhs[0]),V,5*mxGetElementSize(plhs[0]));
>
> only copies 5*1 = 5 bytes of data. In fact, if the first element of
> the double vector you passed in is 0 (such as your example), then the
> data area of prhs[0] will start with eight bytes of exactly 0, the
> first four of which you used for your logical calculations. You will
> always get five zeros for your result in this case. Things would have
> gotten really nasty here had you used prhs[0] for any memory copying
> in a statement like this. For example, consider a similar statement:
>
> memcpy(mxGetLogicals(plhs[0]),V,5*mxGetElementSize(prhs[0]));
>
> I only changed the argument of mxGetElementSize to use prhs[0] instead
> of plhs[0]. This would cause 40 bytes to be written to a data area
> only capable of holding 5 bytes, probably resulting in a MATLAB crash.
>
> 2) You change the actual memory of the input variable. This should
> *never* be done. You have actually changed the value of the input
> variable (bad enough), but may *also* have inadvertantly changed the
> value of a completely different variable in the MATLAB workspace (one
> that isn't even involved in the argument list) because it may have
> shared memory with the input variable you are using. This is very bad,
> so never do this.
>
> 3) You are assuming that an mxLogical is the same thing as a bool in
> c. This is not a safe thing to do in general. mxLogical may be a bool
> on some systems, but it may be something else (e.g., unsigned char) on
> other systems. Since MATLAB uses 1 byte for a logical element in the
> MATLAB workspace, they will probably always define mxLogical to be
> something that is guaranteed to be 1 byte on the system it is
> installed. For c in general the only thing you can count on is that a
> char (or unsigned char) is 1 byte. You can't count on anything else.
> You can't be sure how many bytes a short is, an int is, a long is, etc
> etc. And you can't be sure how many bytes a bool is either. Unless you
> know a lot about the system you will be running on ahead of time, the
> only data length you can count on is char and unsigned char being 1
> byte. A lot of systems (most?) these days define a bool to be 1 byte,
> but strictly speaking this is processor dependent. So ... I advise
> against using bool in your code. Use mxLogical, since MATLAB has
> supplied that data type for you to use.
>
> 4) When using mxLogicals there is the problem that you don't know
> exactly what it is (or will be if your code gets used on another
> system). Will the underlying type be a bool? An unsigned char? So this
> will have to be kept in mind when working with them in your code and
> dereferencing them. I chose to use the bitwise operator | instead of
> the logical operator || so that there wouldn't be any inadvertant type
> conversions going on with this section of code:
>
> > *(V+4) = *(V+0)||*(V+1)||*(V+2)||*(V+3);
>
> The way you have it written, if the underlying type is unsigned char,
> then the result of the logical operations will be a bool, and then the
> final bool result will be cast back into an unsigned char. It would
> not be obvious to a casual reader that there was type conversions
> going on behind the scenes here. By rewriting it like this:
>
> *(V+4) = *(V+0) | *(V+1) | *(V+2) | *(V+3);
>
> the bitwise operator keeps all of the intermediate and final result
> types the same throughout the operations, regardless of what mxLogical
> may really be. There are no hidden type conversions going on behind
> the scenes.
>
> The other advantage of using | is that the underlying bits of an
> mxLogical true value are kept intact, regardless of what they might
> be. As it happens, MATLAB uses the value 1 for logic true and so does
> c for a bool value true, so there would not have been a problem here
> using ||. But a similar construct like this in a Fortran mex file
> would be a problem since logical true values can be -1 in Fortran,(all
> bits set for a twos complement integer). (I mostly make this point for
> other readers who might be Fortran mex programmers.)
>
> 5) When you are returning an mxArray of exactly the same class & size
> etc. as an input mxArray, I find it convenient to use the
> mxDuplicateArray function rather than getting the sizes, creating the
> dims array, calling the mxCreate... etc function. Then I modify the
> data in the new duplicate mxArray. The resulting code is often
> simpler. mxDuplicateArray makes a deep copy, so you are assured that
> there will be no shared data with the original.
>
> Below I have included a version of your code that I have rewritten
> according to my comments.
>
> James Tursa
>
> #include "mex.h"
> #include "matrix.h"
>
> void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
> {
> mxLogical *vlhs;
>
> if( nrhs != 1 )
> mexErrMsgTxt("Need exactly one input argument\n");
> if( !mxIsLogical(prhs[0]) )
> mexErrMsgTxt("Input argument must be logical\n");
> if( mxGetNumberOfDimensions(prhs[0]) != 2 )
> mexErrMsgTxt("Input argument has too many dimensions\n");
> if( mxGetNumberOfElements(prhs[0]) != 5 )
> mexErrMsgTxt("Input argument must have five elements\n");
>
> plhs[0] = mxDuplicateArray(prhs[0]);
> vlhs = mxGetLogicals(plhs[0]);
>
> *(vlhs+4) = *(vlhs+0) | *(vlhs+1) | *(vlhs+2) | *(vlhs+3);
>
>
>
> }- Hide quoted text -
>
> - Show quoted text -
I have had a chance to implement the changes that you suggested,
and am happy to say that your solution works very well! I suspected
that if I could get this MEX function to work with boolean variables,
the function would be much faster. As of now, I have noticed that
functions based on your changes work approximately 3 times faster than
with type "double" variables.
I want to thank all who responded to my post. All of your
suggestions have been very helpful. I don't work with MEX files very
often, and your inputs have saved me lots of time and discouragement.
Thanks again,
Steven Evans
|