Recent

Author Topic: View Byte as Bits matrix  (Read 2229 times)

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
View Byte as Bits matrix
« on: February 23, 2021, 08:23:42 pm »
Hi,

is there some neat way to access bits in a Byte in a two-dimensional matrix fashion, example:
Code: Pascal  [Select][+][-]
  1. program bitpackedArray(input, output, stdErr);
  2. type
  3.         x = (left, middle, right);
  4.         y = (up, down);
  5.         z = bitpacked array[x, y] of Boolean;
  6. begin
  7.         writeLn(   sizeOf(z):2, 'B':2);
  8.         writeLn(bitSizeOf(z):2, 'b':2);
  9. end.
But this reports a size of 3 Bytes. I actually wanted a single Byte quantity.

I thought of using a set, but that’d require me to name every single bit, it’d produce unnecessary redundancies.

Ideally, I’d like to avoid programming any additional function, just declare. Maybe there’s some solution I don’t see. Do you know something I could do?

Thanks for your replies.
Yours Sincerely
Kai Burghardt

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: View Byte as Bits matrix
« Reply #1 on: February 23, 2021, 08:56:45 pm »
Could we have a reality check please: I think you're actually talking about /packing/, not /viewing/.

I'm sure that somebody will be along shortly saying that you want to simulate the array using an object, which kinda misses the point and triggers one of my microrants: if you wanted to /simulate/ the structure you'd be doing it in Lisp or Smalltalk, not using a quasi-systems-programming language which in theory allows you to organise things efficiently in memory.

MarkMLl


MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: View Byte as Bits matrix
« Reply #2 on: February 23, 2021, 09:38:48 pm »
Hi!

Look how BITPACKING works:

If you stay inside one element of a structured type bitpacking works fine.
But the next element in a record or an array starts a byte bound - even if there are 7 bits left over from the elemen before.

So with 2 dimensions in a definition you will never use less than 2 bytes.

There are only workarounds: Put your definition into ONE type so you use 3 bitpacked bits.

TaType = (left, middle, right, up, down);

Let the logik do the rest.

Not such a nice solution, but if you insist "everything in one byte" then I see no other trick.

Winni

« Last Edit: February 23, 2021, 09:41:14 pm by winni »

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: View Byte as Bits matrix
« Reply #3 on: February 23, 2021, 10:06:40 pm »
Hi!

Perhaps on step further to your needs.
And a trip to the 8-bit-times.
And how we tortured the 6502 and the Z80

We reintroduce the Nibble also known as half-byte.

We define the Nibble and a variant record:

Code: Pascal  [Select][+][-]
  1. Type
  2.         nibble= 0..15;
  3.        
  4.       TRec = BitPacked Record case byte of
  5.         0: (By: byte);
  6.         1: (N: bitpacked array[0..1] of Nibble);
  7.         2: (Bi: bitpacked array[0..7] of boolean);
  8.         end;        
  9.  
  10.  

Now you can use the low nibble for the x values and the high nibble for the y values.

This can be done with casting.
Inside the nibble range 0..15 this should be no problem.

Winni



« Last Edit: February 23, 2021, 10:13:37 pm by winni »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: View Byte as Bits matrix
« Reply #4 on: February 23, 2021, 10:25:50 pm »
And a trip to the 8-bit-times.
And how we totured the 6502 and the Z80

We reintroduce the Nibble also known as half-byte.

There always has to be one: the Z80 was actually a 4-bit processor :-)

I suspect that this is one of those cases where a good macro-based preprocessor would be a lot of help, and where "we can replace the preprocessor with templates/generics" wouldn't.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: View Byte as Bits matrix
« Reply #5 on: February 24, 2021, 12:32:22 am »

There always has to be one: the Z80 was actually a 4-bit processor :-)

MarkMLl

Hi!

A half byte is not such a big trick - I think.
The magic starts if you show me a half bit.
Especially the "true" half ........

Winni

speter

  • Sr. Member
  • ****
  • Posts: 345
Re: View Byte as Bits matrix
« Reply #6 on: February 24, 2021, 12:46:31 am »
I think the OP should consider encoding the information into a byte and decoding as needed.

This is a bit ;) kludgy but it works:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.CheckGroup1ItemClick(Sender: TObject; Index: integer);
  2. var
  3.   k : byte;
  4. begin
  5.   k := 1 shl index;
  6.   if checkgroup1.checked[index] then
  7.     inc(num,k)
  8.   else
  9.     dec(num,k);
  10.  
  11.   memo1.append(format('index = %d = %s = %s'+slinebreak+'num = %d'+slinebreak+
  12.                       '%d-%d-%d'+slinebreak+'%d-%d-%d',
  13.                       [index, checkgroup1.items[index],
  14.                        offon[checkgroup1.checked[index]], num,
  15.                        ord(num and 1 > 0),
  16.                        ord(num and (1 shl 1) > 0),
  17.                        ord(num and (1 shl 2) > 0),
  18.                        ord(num and (1 shl 3) > 0),
  19.                        ord(num and (1 shl 4) > 0),
  20.                        ord(num and (1 shl 5) > 0)]));
  21. end;

cheers
S.
I climbed mighty mountains, and saw that they were actually tiny foothills. :)

speter

  • Sr. Member
  • ****
  • Posts: 345
Re: View Byte as Bits matrix
« Reply #7 on: February 24, 2021, 01:32:17 am »
Further to my earlier post, you could write a function to return a boolean...

Code: Pascal  [Select][+][-]
  1. function TForm1.v(x,y : byte) : boolean;
  2. begin
  3.   result := num and (1 shl (y*3 + x)) > 0;
  4. end;

which comes close to allowing something like v[x,y] being v(x,y).

cheers
S.
« Last Edit: February 24, 2021, 01:34:28 am by speter »
I climbed mighty mountains, and saw that they were actually tiny foothills. :)

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: View Byte as Bits matrix
« Reply #8 on: February 24, 2021, 04:36:40 am »
Further to my earlier post, you could write a function to return a boolean... [etc]

Your code would work better as a type helper for Byte; you could then use something like AByteVar.Bit(x,y).

But then, Byte already has a type helper (in sysUtils) with operations over individual bits: SetBit, ClearBit, ToggleBit, TestBit, ... 
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: View Byte as Bits matrix
« Reply #9 on: February 24, 2021, 07:36:58 pm »
Hi!

As I showed above there is no need for low level operations.
Or some helpers.

Because we got Pascal.
Perhaps Kay can use it.

Code: Pascal  [Select][+][-]
  1. type
  2.         Thor = (xleft, xmiddle, xright);
  3.         Tvert = (yup, ydown);
  4.  
  5.         nibble= 0..15;
  6.  
  7.         TRec = BitPacked Record case byte of
  8.         0: (By: byte);
  9.         1: (N: bitpacked array[0..1]of Nibble);
  10.         2: (Bi: bitpacked array[0..7] of boolean);
  11.         end;
  12.  
  13.  
  14.      procedure SetHor(X : Thor; var MagicByte:TRec);
  15.      begin
  16.          MagicByte.N[0] :=  byte(X);
  17.      end;
  18.  
  19.      procedure SetVert (y: Tvert; var MagicByte:  TRec);
  20.      begin
  21.       MagicByte.N[1] :=byte(y);
  22.      end;
  23.  
  24.      procedure GetXY (MagicByte : Trec; var x: THor; var y: TVert);
  25.      begin
  26.      x := THor (MagicByte.N[0]);
  27.      y := TVert (MagicByte.N[1]);
  28.      end;
  29.    
  30.  
  31.  


Winni

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
Re: View Byte as Bits matrix
« Reply #10 on: February 24, 2021, 10:32:21 pm »
Could we have a reality check please: I think you're actually talking about /packing/, not /viewing/.
Sorry about using the wrong verb. I meant to do this:
Code: Text  [Select][+][-]
  1.          R   M   L
  2.  ┄┄┄┄┄┄┌───┬───┬───┐
  3.  7 │ 6 │ 5 │ 4 │ 3 │ Dn
  4.  ┄┄┄┄┄┄├───┼───┼───┤
  5.        │ 2 │ 1 │ 0 │ Up
  6.        └───┴───┴───┘
For me, the bits are already (bit)packed, but I want to “believe”, think (“view”) they were arranged in a matrix.

[…] This can be done with casting. […]
Thanks for your suggestion, but I’d like to avoid casting if I had to it every time I access the bit matrix.

Code: Pascal  [Select][+][-]
  1. function TForm1.v(x,y : byte) : boolean;
  2. begin
  3.   result := num and (1 shl (y*3 + x)) > 0;
  4. end;
which comes close to allowing something like v[x,y] being v(x,y).
Wow, that’s concise. Any idea how I could avoid having to specify the function name? I mean, properties (in the context of type helpers), but then still I had specify the property name.



In reminiscence of the ole pack and unpack I think I’m actually gonna define and utilize implicit operator overloads:
Code: Pascal  [Select][+][-]
  1. {$mode objFPC}
  2. program bitpackedArray(input, output, stdErr);
  3. type
  4.         xAxis = (left, middle, right);
  5.         yAxis = (up, down);
  6.         z = type Byte; // this may not be an array data type
  7.         zUnpacked = array[xAxis, yAxis] of Boolean;
  8.  
  9. // otherwise these operator overloads will horribly go wrong
  10. {$optimization regVar+}
  11. operator := (const bits: z): zUnpacked;
  12. var
  13.         v: bitpacked array[1..6] of Boolean absolute bits;
  14. begin
  15.         result[left, up] := v[1];
  16.         result[middle, up] := v[2];
  17.         result[right, up] := v[3];
  18.         result[left, down] := v[4];
  19.         result[middle, down] := v[5];
  20.         result[right, down] := v[6];
  21. end;
  22.  
  23. operator := (const unpacked: zUnpacked): z;
  24. var
  25.         v: bitpacked array[1..6] of Boolean absolute result;
  26. begin
  27.         v[1] := unpacked[left, up];
  28.         v[2] := unpacked[middle, up];
  29.         v[3] := unpacked[right, up];
  30.         v[4] := unpacked[left, down];
  31.         v[5] := unpacked[middle, down];
  32.         v[6] := unpacked[right, down];
  33. end;
  34.  
  35. function foobar(const given: z): zUnpacked;
  36. begin
  37.         foobar := given; // implicit operator z → unpacked
  38.         foobar[left, up] := true;
  39. end;
  40.  
  41. var
  42.         data: z;
  43. begin
  44.         data := default(z);
  45.         data := foobar(data); // implicit operator unpacked → z
  46.         writeLn(data);
  47. end.
It’s of course a trade-off between fast and convenient access versus introducing unnecessary overhead. Alas, using the RTL’s pack/unpack wouldn’t work, because the arrays would have to have same dimension specifications and since the bitpacked array has the wrong size, I have to do it manually as show above.
Yours Sincerely
Kai Burghardt

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: View Byte as Bits matrix
« Reply #11 on: February 25, 2021, 05:52:14 am »
Instead of:
Code: Pascal  [Select][+][-]
  1.   yAxis=(Up,Down);

I think this:
Code: Pascal  [Select][+][-]
  1.   yAxis=(Up,Down=3);

would make finding the index of a bit a simple addition. Using a default property gets you what you want, using the variable as an array. And of course a couple simple operators:

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$ModeSwitch advancedrecords}
  3.  
  4. uses
  5.   SysUtils;
  6.  
  7. type
  8.   yAxis=(Up,Down=3);
  9.   xAxis=(Left,Middle,Right);
  10.  
  11.   { z }
  12.  
  13.   z=bitpacked record
  14.   private
  15.     procedure SetBit(V: yAxis; H: xAxis; AValue: boolean);inline;
  16.     function GetBit(V: yAxis; H: xAxis):boolean;inline;
  17.   public
  18.     AsByte: Byte;
  19.     property AsArray[V: yAxis; H: xAxis]:boolean Read GetBit Write SetBit; default;
  20.   end;
  21.  
  22. procedure z.SetBit(V: yAxis; H: xAxis; AValue: boolean);
  23. begin
  24.   if AValue then
  25.     AsByte := AsByte.SetBit(byte(h)+byte(v))
  26.   else
  27.     AsByte := AsByte.ClearBit(byte(h)+byte(v));
  28. end;
  29.  
  30. function z.GetBit(V:yAxis; H:xAxis):Boolean;
  31. begin
  32.   Result := AsByte.TestBit(byte(h) + byte(v));
  33. end;
  34.  
  35. operator := (AByte:Byte):z;inline;
  36. begin
  37.   Result.AsByte := AByte;
  38. end;
  39.  
  40. operator := (AZ:z):Byte;inline;
  41. begin
  42.   Result := AZ.AsByte;
  43. end;

A small test:
Code: Pascal  [Select][+][-]
  1. var
  2.   a:z;
  3.  
  4. procedure Test(v:yAxis; b:boolean);
  5. var
  6.   h: xAxis;
  7. begin
  8.   for h in xAxis do
  9.   begin
  10.     a[V,H]:=b;
  11.     WriteLn(V:7,H:7,b:7,a.AsByte.ToBinString:10);
  12.   end;
  13. end;
  14.  
  15. begin
  16.   a := 0;
  17.   WriteLn('':21,a.AsByte.ToBinString:10);
  18.  
  19.   Test(Up,True);
  20.   Test(Down,True);
  21.   Test(Up,False);
  22.   Test(Down,False);
  23.  
  24.   a := $55;
  25.   WriteLn('':21,a.AsByte.ToBinString:10);
  26.   a := $AA;
  27.   WriteLn('':21,a.AsByte.ToBinString:10);
  28.  
  29.   ReadLn;
  30. end.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: View Byte as Bits matrix
« Reply #12 on: February 25, 2021, 08:51:47 am »
Code: Pascal  [Select][+][-]
  1. function TForm1.v(x,y : byte) : boolean;
  2. begin
  3.   result := num and (1 shl (y*3 + x)) > 0;
  4. end;
which comes close to allowing something like v[x,y] being v(x,y).
Wow, that’s concise. Any idea how I could avoid having to specify the function name? I mean, properties (in the context of type helpers), but then still I had specify the property name.

Ideally it would work to use a type helper with a default indexed property, however it seems that this does not work yet... :-[

Code: Pascal  [Select][+][-]
  1. {$modeswitch typehelpers}
  2.  
  3. type
  4.   TByteHelper = type helper for Byte
  5.   private
  6.     function GetBit(aX, aY: Byte): Boolean;
  7.   public
  8.     property Bit[X, Y: Byte]: Boolean read GetBit; default;
  9.   end;
  10.  
  11. function TByteHelper.GetBit(aX, aY: Byte): Boolean;
  12. begin
  13.   Result := Self and (1 shl (aY*3 + aX)) > 0;
  14. end;
  15.  
  16. var
  17.   b: Byte;
  18. begin
  19.   b := 42;
  20.   Writeln(b[1, 2]);
  21. end.

 

TinyPortal © 2005-2018