How do I get real integer overflows in MATLAB/Octave?

后端 未结 6 1609
天涯浪人
天涯浪人 2020-11-28 14:31

I\'m working on a verification-tool for some VHDL-Code in MATLAB/Octave. Therefore I need data types which generate \"real\" overflows:

intmax(\'int32\') + 1         


        
6条回答
  •  佛祖请我去吃肉
    2020-11-28 14:53

    If you want to get C style numeric operations, you can use a MEX function to call the C operators directly, and by definition they'll work like C data types.

    This method is a lot more work than gnovice's overrides, but it should integrate better into a large codebase and is safer than altering the definition for built-in types, so I think it should be mentioned for completeness.

    Here's a MEX file which performs the C "+" operation on a Matlab array. Make one of these for each operator you want C-style behavior on.

    /* c_plus.c - MEX function: C-style (not Matlab-style) "+" operation */
    
    #include "mex.h"
    #include "matrix.h"
    #include 
    
    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

    Then you have to figure out how to invoke it from your Matlab code. If you're writing all the code, you could just call "c_plus(a, b)" instead of "a + b" everywhere. Alternately, you could create your own numeric wrapper class, e.g. @cnumeric, that holds a Matlab numeric array in its field and defines plus() and other operations that invoke the approprate C style MEX function.

    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
    

    Then wrap your numbers in the @cnumeric where you want C-style int behavior and do math with them.

    >> 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
    

    There's your C-style overflow behavior, isolated from breaking the primitive @int32 type. Plus, you can pass a @cnumeric object in to other functions that are expecting regular numerics and it'll "work" as long as they treat their inputs polymorphically.

    Performance caveat: because this is an object, + will have the slower speed of a method dispatch instead of a builtin. If you have few calls on large arrays, this'll be fast, because the actual numeric operations are in C. Lots of calls on small arrays, could slow things down, because you're paying the per method call overhead a lot.

提交回复
热议问题