* Bug 16609 fixed: bitcmp() upgraded for Scilab 6
[scilab.git] / scilab / modules / elementary_functions / macros / bitcmp.sci
index b09731c..c482ee7 100644 (file)
@@ -1,8 +1,8 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) ???? - INRIA - Farid BELAHCENE
 // Copyright (C) 2008 - INRIA - Pierre MARECHAL
-//
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
+// Copyright (C) 2020 - Samuel GOUGEON
 //
 // This file is hereby licensed under the terms of the GNU GPL v2.0,
 // pursuant to article 5.3.4 of the CeCILL v.2.1.
 // For more information, see the COPYING file which you should have received
 // along with this program.
 
-function y = bitcmp(x,n)
+function y = bitcmp(x, n)
 
-    // BITCMP function
-    //
-    // Given an unsigned integer x, this function returns the unsigned integer
-    // which is the integer corresponding to the complementary of the binary
-    // form of x
-    //
-    // If the bits number of the x binary representation is less than the
-    // bitmax number (8,16 or 32) then the bits '1' are added to the
-    // complementary in order to have bitmax number (8, 16 or 32) for the
-    // complementary
-    //
-    // for example for the type uint8 (bitmax=8), the complementary of '1101' is not '0010' but '11110010'
-    // The integer n sets the bits max number
-    // -Inputs :
-    //  x : an unsigned integer
-    //  n : a positive integer between 1 and the bitmax of the x type
-    //
-    // -Output :
-    //  y : an unsigned integer
+    // BITCMP function: bitwise complement of integers
     //
-    // P. Marechal, 5 Feb 2008
-    //   - Add argument check
+    // P. Marechal, 2008 : Add argument check
+    // S. Gougeon, 2020 :
+    //   * Entension to 64 bit integers.
+    //   * Extension to all signed integers.
+    //   * Decimal positive integers > 2^52 up to 2^1024 = number_properties("huge")
+    //      can now be processed, with bitnum up to 1024 instead of 52.
+    //   * bitnum is now optional as well for input decimal integers.
+    //     It can actually be an array.
 
-    // check number input argument
     rhs = argn(2);
 
-    if rhs == 0 then
-        error(msprintf(gettext("%s: Wrong number of input argument(s): At least %d expected.\n"),"bitcmp",1));
-    elseif (type(x) == 1) & (rhs == 1) then
-        error(msprintf(gettext("%s: Wrong number of input argument(s): %d expected.\n"),"bitcmp",2));
+    // CHECK INPUT ARGUMENTS
+    // =========================================================================
+    if rhs < 1 | rhs > 2 then
+        msg = gettext("%s: Wrong number of input arguments: %d or %d expected.\n")
+        error(msprintf(msg, "bitcmp", 1, 2));
     end
 
-    // check type
-
-    if    (type(x)==1  & (x-floor(x)<>0 | x<0)) ..
-        | (type(x)==8  & (inttype(x)<10)) ..
-        | (type(x)<>1  & type(x)<>8) then
 
-        error(msprintf(gettext("%s: Wrong input argument #%d: Scalar/matrix of unsigned integers expected.\n"),"bitcmp",1));
+    // Check types
+    if and(type(x)<>[1 8]) | (type(x)==1 & ~isreal(x))
+        msg = gettext("%s: Argument #%d: Decimal or encoded integers expected.\n");
+        error(msprintf(msg, "bitcmp",1))
     end
-
-    if  (rhs == 2) & ( ..
-        (type(n)==1  & (n-floor(n)<>0 | x<0)) ..
-        | (type(n)==8  & (inttype(n)<10)) ..
-        | (type(n)<>1  & type(n)<>8) ..
-        | (size(n,"*")<>1) ) then
-
-        error(msprintf(gettext("%s: Wrong input argument #%d: An unsigned integer expected.\n"),"bitcmp",2));
+    if x==[] then
+        y = []
+        return
+    end
+    if type(x)==1 & (or(x-floor(x)<>0) | or(x<0)) then
+        msg = gettext("%s: Argument #%d: Positive decimal integers expected.\n");
+        error(msprintf(msg, "bitcmp",1))
     end
-
-    // check n value
-
     select inttype(x)
-    case 0  then nmax = 52;
-    case 11 then nmax = 8;
-    case 12 then nmax = 16;
-    case 14 then nmax = 32;
+    case 0  then
+        nmax = 1024
+        p = int(log2(x)) + 1
+    case 1 then nmax = 8
+    case 2 then nmax = 16
+    case 4 then nmax = 32
+    case 8 then nmax = 64
+    case 11 then nmax = 8
+    case 12 then nmax = 16
+    case 14 then nmax = 32
+    case 18 then nmax = 64
     end
 
-    if rhs>1 then
-
-        if (n>nmax) | (n<1) then
-            error(msprintf(gettext("%s: Wrong value for input argument #%d: Must be between %d and %d.\n"),"bitcmp",2,1,nmax));
+    if rhs == 2
+        if size(n,"*")<>1 & or(size(n)<>size(x))
+            msg = gettext("%s: Argument #%d: Wrong size.\n")
+            error(msprintf(msg, "bitcmp", 2))
+        end
+        if and(type(n)<>[1 8]) | n<>int(n) | (type(n)==1 & ~isreal(n))
+            msg = gettext("%s: Argument #%d: Real or encoded integer expected.\n")
+            error(msprintf(msg, "bitcmp", 2))
+        end
+        if n > nmax | n<1 then
+            msg = gettext("%s: Argument #%d: Must be in the interval [%d, %d].\n")
+            error(msprintf(msg, "bitcmp", 2, 1, nmax));
         end
-
     else
-        n = nmax;
+        if type(x)==8
+            n = nmax
+        else
+            n = ones(x)*53
+            k = abs(x) > 1/%eps
+            n(k) = p(k)
+        end
     end
 
-    // Algorithm
+    // PROCESSING
     // =========================================================================
-
-    // empty matrix shortcut
-
-    if isempty(x) then
-        y = [];
-        return;
-    end
-
-    // unit8, uint16 and uint32 shortcut
-
+    // Encoded integers
     if type(x)==8 then
-        y = ~x;
+        y = ~x
+        // Canceling bits > n:
         if rhs > 1 then
-            select inttype(x)
-            case 11 then y = y & uint8(  2^n - 1);
-            case 12 then y = y & uint16( 2^n - 1);
-            case 14 then y = y & uint32( 2^n - 1);
-            end
-        end
-        return;
-    end
-
-    n = ones(x)*n;
-
-    if type(x) == 1 then
-
-        a     = 2^32;
-
-        y_LSB = uint32( x - double(uint32(x/a)) * a ); // LSB Less Significant Bits
-        y_MSB = uint32( x/a );                         // MSB Most Significant Bits
-
-        y_LSB = ~y_LSB;
-        y_MSB = ~y_MSB;
-
-        if n <= 32 then
-            y_LSB = y_LSB & uint32( 2^n - 1);
-            y_MSB = uint32(0);
-        else
-            y_MSB = y_MSB & uint32( 2^(n-32) - 1);
+            it = inttype(x)
+            y = y & (iconvert(2,it)^n - 1)
         end
 
-        y = double( a * y_MSB + y_LSB );
+    else
+    // Decimal integers
+        y = x
+        mask = 2.^n - (2.^max(0,n-52))
+        k = n < p
+        y(k) = bitand(y(k), mask)
+        y = bitxor(y, mask)
     end
 
 endfunction