Si desea obtener operaciones numéricas estilo C, puede utilizar una función MEX a llamar directamente a los operadores de C, y por definición que funcionarán como tipos de datos C.
Este método es una mucho más trabajo que las anulaciones de gnovice, pero debe integrarse mejor en una gran base de código y es más seguro que la alteración de la definición de los tipos predefinidos, así que creo que debe ser mencionado para la integridad.
Aquí hay un archivo MEX que realiza la operación C "+" en una matriz de Matlab. Haga uno de estos para cada operador en el que desee el comportamiento estilo 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;
}
Luego tiene que averiguar cómo invocarlo desde su código de Matlab. Si está escribiendo todo el código, puede simplemente llamar "c_plus (a, b)" en lugar de "a + b" en todas partes. Alternativamente, puede crear su propia clase contenedora numérica, p. @cnumeric, que contiene una matriz numérica Matlab en su campo y define más() y otras operaciones que invocan la función MEX de estilo C apropiada.
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
Luego ajuste sus números en @cnumeric donde desea el comportamiento int de estilo C y haga cálculos matemáticos con ellos.
>> 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
Tiene su comportamiento de desbordamiento estilo C, aislado de romper el tipo primitivo @ int32.Además, puede pasar un objeto @cnumeric a otras funciones que esperan números regulares y "funcionará" siempre que traten sus entradas de forma polimórfica.
Advertencia de rendimiento: como se trata de un objeto, + tendrá la velocidad más lenta de un envío de método en lugar de una función incorporada. Si tiene pocas llamadas en arreglos grandes, esto será rápido, porque las operaciones numéricas reales están en C. Muchas llamadas en arreglos pequeños, podrían ralentizar las cosas, porque está pagando mucho por la sobrecarga por llamada al método.
+1 para dar con la sobrecarga de operadores! – Jonas
+1 Eficaz pero aterrador. Creo que esto debería venir con la advertencia de que reemplazar operadores en tipos estándar podría interactuar mal con otras bibliotecas o funciones de Matlab que están esperando el comportamiento "+" normal de Matlab en ellas. (Incluso si MathWorks lo recomienda en el doco.) Potente para soluciones únicas, problemáticas para grandes bases de código. –
@Andrew: Haces un buen punto. Imagino que este tipo de solución solo se usa para la herramienta específica que está creando el OP, pero podría ser fácil olvidarse de volver al antiguo método 'int32' una vez que la herramienta haya terminado de ejecutarse. Para usar esto solo para un fragmento específico de código, tendría un comando al principio de ese código que agregaba la carpeta principal de la carpeta '@ int32' a la ruta, y luego la eliminaba de la ruta cuando terminaba de ejecutarse. – gnovice