bugGNU Octave - Bugs: bug #67592, bitget() does not work for sign...

 
 

bug #67592: bitget() does not work for sign bit of signed integers

Submitter:  Rik <rik5>
Submitted:  Wed 08 Oct 2025 01:51:30 PM UTC
   
 
Category:  Octave Function Severity:  5 - Blocker
Priority:  5 - Normal Item Group:  Incorrect Result
Status:  Confirmed Assigned to:  None
Originator Name:  Open/Closed:  * Open
Release:  * stable Operating System:  * Any
Fixed Release:  11.1.0 (current default) Planned Release:  11.1.0 (current default)
* Mandatory Fields

Post a Comment

Add a New Comment Rich Markup
   

Discussion

Jump to the original submission

Thu 09 Oct 2025 07:48:54 AM UTC, comment #8: 

I stumbled across this problem while looking at bug #53458.  I think for stable we should do a quick fix just to stop Octave giving obviously incorrect results.

On dev brach, it's probably time to rewrite all of the bit functions.  They should do broadcasting for Matlab compatibility, they should return the same type as the input for compatibility, probably other things as well.

Rik <rik5>
Group administrator
Wed 08 Oct 2025 05:00:00 PM UTC, comment #7: 

Unfortunately changing return type breaks bunch of other stuff.
I guess we just would need to fix those.

Summary:

  PASS                            20044
  FAIL                               51


Dmitri.
--

Dmitri A. Sergatskov <dasergatskov>
Wed 08 Oct 2025 04:01:34 PM UTC, comment #6: 

Changed a little bit (avoid `feval`).

(file bug67592_1.diff)

Dmitri.
--


(file #57705)

Dmitri A. Sergatskov <dasergatskov>
Wed 08 Oct 2025 03:48:10 PM UTC, comment #5: 

Here is a diff that works for me and passes tests (which needed to be adjusted for the correct return types).

$ hg diff
diff -r 76914cc2c680 scripts/general/bitget.m
--- a/scripts/general/bitget.m  Wed Oct 08 11:04:08 2025 +0200
+++ b/scripts/general/bitget.m  Wed Oct 08 11:43:44 2025 -0400
@@ -47,60 +47,61 @@
     print_usage ();
   endif

-  if (isa (A, "double"))
-    Amax = ceil (log2 (flintmax));
-    _conv = @double;
-  elseif (isa (A, "single"))
-    Amax = ceil (log2 (flintmax ("single")));
-    _conv = @single;
-  else
-    if (isa (A, "uint8"))
+  ## Save original class for final output
+  orig_class = class (A);
+
+  ## Determine Amax and _conv based on current class
+  switch (class (A))
+    case "double"
+      Amax = ceil (log2 (flintmax));
+    case "single"
+      Amax = ceil (log2 (flintmax ("single")));
+    case {"int8", "uint8"}
       Amax = 8;
-      _conv = @uint8;
-    elseif (isa (A, "uint16"))
+    case {"int16", "uint16"}
       Amax = 16;
-      _conv = @uint16;
-    elseif (isa (A, "uint32"))
+    case {"int32", "uint32"}
       Amax = 32;
-      _conv = @uint32;
-    elseif (isa (A, "uint64"))
+    case {"int64", "uint64"}
       Amax = 64;
-      _conv = @uint64;
-    elseif (isa (A, "int8"))
-      Amax = 8;
-      _conv = @int8;
-    elseif (isa (A, "int16"))
-      Amax = 16;
-      _conv = @int16;
-    elseif (isa (A, "int32"))
-      Amax = 32;
-      _conv = @int32;
-    elseif (isa (A, "int64"))
-      Amax = 64;
-      _conv = @int64;
-    else
+    otherwise
       error ("bitget: invalid class %s", class (A));
-    endif
+  endswitch
+
+  ## Reinterpret signed integers as unsigned for bit operations
+  if (isinteger (A))
+    switch (class (A))
+      case 'int8',   A = typecast (A, 'uint8');
+      case 'int16',  A = typecast (A, 'uint16');
+      case 'int32',  A = typecast (A, 'uint32');
+      case 'int64',  A = typecast (A, 'uint64');
+    endswitch
   endif

+  ## Set _conv to working type (after typecast)
+  _conv = str2func (class (A));
+
   m = double (n(:));
   if (any (m < 1) || any (m > Amax))
     error ("bitget: N must be in the range [1,%d]", Amax);
   endif

-  b = bitand (A, bitshift (_conv (1), uint8 (n) - uint8 (1))) != _conv (0);
+  b = _conv (bitand (A, bitshift (_conv (1), uint8 (n) - uint8 (1))) != 0);
+
+  ## Convert result back to original type
+  b = feval (str2func (orig_class), b);

 endfunction


 %!test
-%! assert (bitget ([4, 14], [3, 3]), logical ([1, 1]));
-%! assert (bitget (single ([4, 14]), [3, 3]), logical ([1, 1]));
+%! assert (bitget ([4, 14], [3, 3]),  ([1, 1]));
+%! assert (bitget (single ([4, 14]), [3, 3]), single ([1, 1]));
 %! pfx = {"", "u"};
 %! for i = 1:2
 %!   for prec = [8, 16, 32, 64]
 %!     fcn = str2func (sprintf ("%sint%d", pfx{i}, prec));
-%!     assert (bitget (fcn ([4, 14]), [3, 3]), logical ([1, 1]));
+%!     assert (bitget (fcn ([4, 14]), [3, 3]),  fcn ([1, 1]));
 %!   endfor
 %! endfor


Dmitri.
--

Dmitri A. Sergatskov <dasergatskov>
Wed 08 Oct 2025 03:23:11 PM UTC, comment #4: 

The typecast should be inside `bitget.m`

Also to return the correct type "b" should probably changed to:


 b = _conv (bitand (A, bitshift (_conv (1), uint8 (n) - uint8 (1))) != 0);


I also do not quite understand why `_conv` is setup there.
Could we just do  "_conv = str2func (class (A));"  once?

Dmitri.
--



Dmitri A. Sergatskov <dasergatskov>
Wed 08 Oct 2025 03:10:49 PM UTC, comment #3: 

Fwiw, in MATLAB R2025b:

>> I = intmin ('int8')

I =

  int8

   -128

>> s = dec2bin (I)

s =

    '10000000'

>> b = bitget (I, 8:-1:1)

b =

  1×8 int8 row vector

   1   0   0   0   0   0   0   0

>>


(No need to typecast.)

Markus Mützel <mmuetzel>
Group administrator
Wed 08 Oct 2025 02:40:57 PM UTC, comment #2: 

I noticed that `bitget` returns `logical`.

In Matlab it:

"Bit value at bit, returned as an array of 0s and 1s. b is the same data type as A."

Dmitri.
--

Dmitri A. Sergatskov <dasergatskov>
Wed 08 Oct 2025 02:33:47 PM UTC, comment #1: 

Typecast "A" to unsigned int?


if (isinteger (A))
  switch class (A)
    case 'int8',   A = typecast (A, 'uint8');
    case 'int16',  A = typecast (A, 'uint16');
    case 'int32',  A = typecast (A, 'uint32');
    case 'int64',  A = typecast (A, 'uint64');
  endswitch
endif


Seems to wor for me.

Dmitri.
--

Dmitri A. Sergatskov <dasergatskov>
Wed 08 Oct 2025 01:51:30 PM UTC, original submission:  

The bitget() function returns the wrong value for the sign bit.  This seems pretty important, and it's unclear how long this has been the case.

octave:47> I = intmin ('int8')
I = -128
octave:48> s = dec2bin (I)
s = 10000000
octave:49> b = bitget (I, 8:-1:1)
b =

  0  0  0  0  0  0  0  0



Rik <rik5>
Group administrator

 

Attached Files

Attached Files
file #57705:  bug67592_1.diff added by dasergatskov (2.6KiB - text/x-patch)

(Note: upload size limit is set to 16MiB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

 

Dependencies

This item does not depend on any other items.

No items depend on this one.

 

Mail Notification Carbon-Copy List

Carbon-Copy List
  • -email is unavailable- added by mmuetzel (Posted a comment)
  • -email is unavailable- added by dasergatskov (Posted a comment)
  • -email is unavailable- added by rik5 (Submitted the item)
  •  

    Votes

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    History

    Follow 4 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2025-10-28 rik5 Fixed ReleaseNone 11.1.0 (current default)
        Planned Release10.3.0 11.1.0 (current default)
    2025-10-28 rik5 Severity4 - Important 5 - Blocker
    2025-10-08 dasergatskov Attached File- Added bug67592_1.diff, #57705

    Back to the top

    Powered by Savane 3.16.
    Corresponding source code