如果您想获得 C 风格的数值运算,可以使用 MEX 函数直接调用 C 运算符,根据定义,它们将像 C 数据类型一样工作。
这种方法比 gnovice 的覆盖要多得多,但它应该更好地集成到大型代码库中,并且比更改内置类型的定义更安全,所以我认为应该提到它的完整性。
这是一个 MEX 文件,它对 Matlab 数组执行 C“+”操作。为您希望 C 风格行为的每个运算符制作其中一个。
/* c_plus.c - MEX function: C-style (not Matlab-style) "+" operation */
#include "mex.h"
#include "matrix.h"
#include <stdio.h>
void mexFunction(
int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]
)
{
mxArray *out;
/* In production code, input/output type and bounds checks would go here. */
const mxArray *a = prhs[0];
const mxArray *b = prhs[1];
int i, n;
int *a_int32, *b_int32, *out_int32;
short *a_int16, *b_int16, *out_int16;
mxClassID datatype = mxGetClassID(a);
int n_a = mxGetNumberOfElements(a);
int n_b = mxGetNumberOfElements(b);
int a_is_scalar = n_a == 1;
int b_is_scalar = n_b == 1;
n = n_a >= n_b ? n_a : n_b;
out = mxCreateNumericArray(mxGetNumberOfDimensions(a), mxGetDimensions(a),
datatype, mxIsComplex(a));
switch (datatype) {
case mxINT32_CLASS:
a_int32 = (int*) mxGetData(a);
b_int32 = (int*) mxGetData(b);
out_int32 = (int*) mxGetData(out);
for (i=0; i<n; i++) {
if (a_is_scalar) {
out_int32[i] = a_int32[i] + b_int32[i];
} else if (b_is_scalar) {
out_int32[i] = a_int32[i] + b_int32[0];
} else {
out_int32[i] = a_int32[i] + b_int32[i];
}
}
break;
case mxINT16_CLASS:
a_int16 = (short*) mxGetData(a);
b_int16 = (short*) mxGetData(b);
out_int16 = (short*) mxGetData(out);
for (i=0; i<n; i++) {
if (a_is_scalar) {
out_int16[i] = a_int16[0] + b_int16[i];
} else if (b_is_scalar) {
out_int16[i] = a_int16[i] + b_int16[0];
} else {
out_int16[i] = a_int16[i] + b_int16[i];
}
}
break;
/* Yes, you'd have to add a separate case for every numeric mxClassID... */
/* In C++ you could do it with a template. */
default:
mexErrMsgTxt("Unsupported array type");
break;
}
plhs[0] = out;
}
然后你必须弄清楚如何从你的 Matlab 代码中调用它。如果您正在编写所有代码,则可以在任何地方都调用“c_plus(a, b)”而不是“a + b”。或者,您可以创建自己的数字包装类,例如@cnumeric,它在其字段中保存一个 Matlab 数字数组并定义 plus() 和其他调用适当的 C 样式 MEX 函数的操作。
classdef cnumeric
properties
x % the underlying Matlab numeric array
end
methods
function obj = cnumeric(x)
obj.x = x;
end
function out = plus(a,b)
[a,b] = promote(a, b); % for convenience, and to mimic Matlab implicit promotion
if ~isequal(class(a.x), class(b.x))
error('inputs must have same wrapped type');
end
out_x = c_plus(a.x, b.x);
out = cnumeric(out_x);
end
% You'd have to define the math operations that you want normal
% Matlab behavior on, too
function out = minus(a,b)
[a,b] = promote(a, b);
out = cnumeric(a.x - b.x);
end
function display(obj)
fprintf('%s = \ncnumeric: %s\n', inputname(1), num2str(obj.x));
end
function [a,b] = promote(a,b)
%PROMOTE Implicit promotion of numeric to cnumeric and doubles to int
if isnumeric(a); a = cnumeric(a); end
if isnumeric(b); b = cnumeric(b); end
if isinteger(a.x) && isa(b.x, 'double')
b.x = cast(b.x, class(a.x));
end
if isinteger(b.x) && isa(a.x, 'double')
a.x = cast(a.x, class(b.x));
end
end
end
end
然后将您的数字包装在您想要 C 样式 int 行为的@cnumeric 中,并用它们进行数学运算。
>> cnumeric(int32(intmax))
ans =
cnumeric: 2147483647
>> cnumeric(int32(intmax)) - 1
ans =
cnumeric: 2147483646
>> cnumeric(int32(intmax)) + 1
ans =
cnumeric: -2147483648
>> cnumeric(int16(intmax('int16')))
ans =
cnumeric: 32767
>> cnumeric(int16(intmax('int16'))) + 1
ans =
cnumeric: -32768
有你的 C 风格的溢出行为,与破坏原始 @int32 类型隔离。另外,您可以将 @cnumeric 对象传递给其他需要常规数字的函数,只要它们以多态方式处理其输入,它就会“工作”。
性能警告:因为这是一个对象, + 将具有较慢的方法分派速度而不是内置方法。如果您对大型数组的调用很少,这会很快,因为实际的数值运算在 C 中。对小型数组的大量调用可能会减慢速度,因为您为每个方法调用付出了很多开销。