* Bug #14640 fixed: median(int8([10 60 80 100])) returned -58 instead of 70 29/18329/11
Samuel GOUGEON [Thu, 30 Jun 2016 04:50:47 +0000 (06:50 +0200)]
  http://bugzilla.scilab.org/14640

Change-Id: Iee08a16879eff4fbe408302afb1dfa1594c9a0aa

scilab/CHANGES.md
scilab/modules/statistics/macros/median.sci
scilab/modules/statistics/tests/nonreg_tests/bug_14640.dia.ref [new file with mode: 0644]
scilab/modules/statistics/tests/nonreg_tests/bug_14640.tst [new file with mode: 0644]

index 23cc807..71ff6ab 100644 (file)
@@ -258,6 +258,7 @@ Bug Fixes
 * [Bug #14590](http://bugzilla.scilab.org/show_bug.cgi?id=14590) fixed - Help pages in pt_BR directories had a wrong xml:lang="en" tag.
 * [Bug #14593](http://bugzilla.scilab.org/show_bug.cgi?id=14593) fixed - Signs are no more drawn in BIGSOM and PRODUCT components.
 * [Bug #14602](http://bugzilla.scilab.org/show_bug.cgi?id=14602) fixed - WRITEC_f block didn't work for x86 machines.
+* [Bug #14640](http://bugzilla.scilab.org/show_bug.cgi?id=14640) fixed - `median(int8([10 60 80 100]))` returned -58 instead of 70 due to overflow when interpolating (60+80)>128
 * [Bug #14648](http://bugzilla.scilab.org/show_bug.cgi?id=14648) fixed - `isinf` returned `%F` for complex numbers with both real and imag infinite parts.
 * [Bug #14662](http://bugzilla.scilab.org/show_bug.cgi?id=14662) fixed - Matrix of strings concatenation with single quote led to a parser error.
 * [Bug #14681](http://bugzilla.scilab.org/show_bug.cgi?id=14681) fixed - Short-circuited AND operation was not possible with double matrices in if and while clauses
index 819adf5..d003790 100644 (file)
@@ -1,6 +1,7 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) 1999 - INRIA - Carlos Klimann
 // Copyright (C) 2012 - Scilab Enterprises - Adeline CARNIS
+// Copyright (C) 2016 - Samuel GOUGEON
 //
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
 //
 // along with this program.
 //
 
-
-function y=median(x,orient)
+function y = median(x,orient)
     //
     // NOTES
     //    - modified by farid.belahcene:the case when x is an hypermatrix
     //    - new syntaxes: median(x,'m') and median(x,dim)
+    //    S. Gougeon 2016:
+    //     - Fixes overflow issues with encoded integers when interpolating
+    //       http://bugzilla.scilab.org/14640
 
+    // CHECKING ARGUMENTS
+    // ==================
     [lhs, rhs] = argn(0);
 
     if rhs == 0 then
-        error(msprintf(gettext("%s: Wrong number of input argument(s): %d or %d expected.\n"),"median",1,2));
+        msg = _("%s: Wrong number of input argument(s): %d or %d expected.\n")
+        error(msprintf(msg, "median", 1, 2))
     end
 
-    if argn(2)<2 then
-        orient=0;
+    if rhs<2 then
+        orient = 0
     else
         if orient=="r" then
-            orient=1
+            orient = 1
         elseif orient=="c" then
-            orient=2
+            orient = 2
         elseif orient=="*" then
-            orient=0
+            orient = 0
         elseif orient=="m" then
-            orient=find(size(x)>1,1)
-            if orient==[] then orient=1,end
+            orient = find(size(x)>1,1)
+            if orient==[] then
+                orient = 1
+            end
         else
             if type(orient)<>1|size(orient,"*")<>1|~isreal(orient)|orient<=0 then
-                error(msprintf(gettext("%s: Wrong value for input argument #%d: ''%s'', ''%s'',''%s'' or a positive number expected.\n"),"median",2,"r","c","m")),
+                msg = _("%s: Wrong value for input argument #%d: ''%s'', ''%s'',''%s'' or a positive number expected.\n")
+                error(msprintf(msg, "median",2,"r","c","m"))
             end
         end
     end
 
+    // PROCESSING
+    // ==========
+    // median on all components
+    // ------------------------
     if orient==0 then
-        if x==[] then y=%nan,return,end
-        n=size(x,"*");
-        x=gsort(x(:),"g","i")
+        if x==[] then
+            y = %nan
+            return
+        end
+        n = size(x,"*");
+        x = gsort(x(:),"g","i")
         if 2*int(n/2)==n then
-            y = (x(n/2)+x(n/2+1))/2;
+            // avoid overflow: http://bugzilla.scilab.org/14640
+            a = x(n/2)
+            b = x(n/2+1)
+            y = a/2 + b/2 + ((a-(a/2)*2) + (b-(b/2)*2))/2
         else
             y = x((n+1)/2);
         end
+
+    // Projection along a given direction / dimension
+    // ----------------------------------------------
     else
-        if x==[] then y=[],return,end
-        if orient>ndims(x) then y=x; return;  end
-        xsize=size(x);
-        if xsize(orient)==1 then  y=x; return;  end
-        orient_above_size=xsize(orient+1:$);N=prod(orient_above_size)
-        orient_below_size=xsize(1:orient-1);M=prod(orient_below_size)
-        orient_size=xsize(1:orient);P=prod(orient_size)
-        y=[];
-        n=xsize(orient)
-        for k=1:N
-            for i=1:M
-                ytemp=gsort(x(i+(0:n-1)*M+(k-1)*P),"r","i"); ytemp = ytemp(:);
+        if x==[] then
+            y = []
+            return
+        end
+        if orient>ndims(x) then
+            y = x
+            return
+        end
+        xsize = size(x);
+        if xsize(orient)==1 then
+            y = x
+            return
+        end
+        orient_above_size = xsize(orient+1:$);
+        N = prod(orient_above_size)
+        orient_below_size = xsize(1:orient-1);
+        M = prod(orient_below_size)
+        orient_size = xsize(1:orient);
+        P = prod(orient_size)
+        y = [];
+        n = xsize(orient)
+        for k = 1:N
+            for i = 1:M
+                ytemp = gsort(x(i+(0:n-1)*M+(k-1)*P),"r","i")
                 if 2*int(n/2)==n then
-                    y = [y (ytemp(n/2,:)+ytemp(n/2+1,:))/2];
+                    // avoid overflow: http://bugzilla.scilab.org/14640
+                    a = ytemp(n/2)
+                    b = ytemp(n/2+1)
+                    y = [ y ; a/2 + b/2 + ((a-(a/2)*2) + (b-(b/2)*2))/2]
                 else
-                    y = [y ytemp((n+1)/2,:)];
+                    y = [ y ; ytemp((n+1)/2)]
                 end
             end
         end
-        xsize(orient)=1;
-        y=matrix(y,xsize);
+        xsize(orient) = 1
+        y = matrix(y, xsize)
     end
-
 endfunction
diff --git a/scilab/modules/statistics/tests/nonreg_tests/bug_14640.dia.ref b/scilab/modules/statistics/tests/nonreg_tests/bug_14640.dia.ref
new file mode 100644 (file)
index 0000000..ae39e57
--- /dev/null
@@ -0,0 +1,57 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2016 - Samuel GOUGEON
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+// <-- CLI SHELL MODE -->
+// <-- Non-regression test for bug 14640 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/14640
+//
+// <-- Short Description -->
+// median(int8([10 60 80 100])) returned -58 instead of 70 due to (60+80)>128 overflow
+x = int8([ 10    60   80  100
+          -10   -60  -80 -100
+          -120 -122 -124 -126
+          -122 -122 -126 -126
+         ]);
+assert_checkequal(median(x), int8(-110));
+assert_checkequal(median(x,"c"), int8([70 -70 -123 -124]'));
+assert_checkequal(median(x,"r"), int8([-65 -91 -102 -113]));
+
+// with hypermatrices
+clear x
+x(:,:,1) = int8([
+    10    60   80  100
+   -10   -60  -80 -100
+   ]);
+x(:,:,2) = int8([
+   -120 -122 -124 -126
+   -122 -122 -126 -126
+    ]);
+expected = int8(matrix([0 0 0 0 -121 -122 -125 -126],1,4,-1));
+assert_checkequal(median(x,1), expected);
+clear expected
+expected = int8(matrix([70 -70 -123 -124],2,1,2));
+assert_checkequal(median(x,2), expected);
+clear expected
+expected = int8([
+ -55 -31 -22 -13
+ -66 -91 -103 -113
+ ]);
+assert_checkequal(median(x,3), expected);
+
+//
+//see http://bugzilla.scilab.org/14647
+//b = int64(2)^62;
+//x = b + ..
+//    int64([10    60   80  100
+//          -10   -60  -80 -100
+//          -120 -122 -124 -126
+//          -122 -122 -126 -126
+//         ]);
+//assert_checkequal(median(x), b + int64(-110));
+//assert_checkequal(median(x,"c"), b + int64([70 -70 -123 -124]'));
+//assert_checkequal(median(x,"r"), b + int64([-65 -91 -102 -113]));
diff --git a/scilab/modules/statistics/tests/nonreg_tests/bug_14640.tst b/scilab/modules/statistics/tests/nonreg_tests/bug_14640.tst
new file mode 100644 (file)
index 0000000..ae39e57
--- /dev/null
@@ -0,0 +1,57 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2016 - Samuel GOUGEON
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+// <-- CLI SHELL MODE -->
+// <-- Non-regression test for bug 14640 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/14640
+//
+// <-- Short Description -->
+// median(int8([10 60 80 100])) returned -58 instead of 70 due to (60+80)>128 overflow
+x = int8([ 10    60   80  100
+          -10   -60  -80 -100
+          -120 -122 -124 -126
+          -122 -122 -126 -126
+         ]);
+assert_checkequal(median(x), int8(-110));
+assert_checkequal(median(x,"c"), int8([70 -70 -123 -124]'));
+assert_checkequal(median(x,"r"), int8([-65 -91 -102 -113]));
+
+// with hypermatrices
+clear x
+x(:,:,1) = int8([
+    10    60   80  100
+   -10   -60  -80 -100
+   ]);
+x(:,:,2) = int8([
+   -120 -122 -124 -126
+   -122 -122 -126 -126
+    ]);
+expected = int8(matrix([0 0 0 0 -121 -122 -125 -126],1,4,-1));
+assert_checkequal(median(x,1), expected);
+clear expected
+expected = int8(matrix([70 -70 -123 -124],2,1,2));
+assert_checkequal(median(x,2), expected);
+clear expected
+expected = int8([
+ -55 -31 -22 -13
+ -66 -91 -103 -113
+ ]);
+assert_checkequal(median(x,3), expected);
+
+//
+//see http://bugzilla.scilab.org/14647
+//b = int64(2)^62;
+//x = b + ..
+//    int64([10    60   80  100
+//          -10   -60  -80 -100
+//          -120 -122 -124 -126
+//          -122 -122 -126 -126
+//         ]);
+//assert_checkequal(median(x), b + int64(-110));
+//assert_checkequal(median(x,"c"), b + int64([70 -70 -123 -124]'));
+//assert_checkequal(median(x,"r"), b + int64([-65 -91 -102 -113]));