Bits

BlitzMax Forums/BlitzMax Beginners Area/Bits

nrsteel(Posted 2007) [#1]
Is there any way to store information as bits, not bytes?

In other words is it possible to write just a 1 or 0 (in binary) to some sort of file, and if so, how?


grable(Posted 2007) [#2]
You need to use Shl Shr & | for that kind of thing

feks like this, where each next bit is a multiple of the last value
Const BIT_1:Int = 1
Const BIT_2:Int = 2
Const BIT_3:Int = 4
Const BIT_4:Int = 8

Local bits:Int

bits =  BIT_1 | BIT_3
Print "BIT_1 " + ((bits & BIT_1) <> 0)
Print "BIT_2 " + ((bits & BIT_2) <> 0)
Print "BIT_3 " + ((bits & BIT_3) <> 0)
Print "BIT_4 " + ((bits & BIT_4) <> 0)
Print
bits :Shl 1
Print "BIT_1 " + ((bits & BIT_1) <> 0)
Print "BIT_2 " + ((bits & BIT_2) <> 0)
Print "BIT_3 " + ((bits & BIT_3) <> 0)
Print "BIT_4 " + ((bits & BIT_4) <> 0)



Jesse(Posted 2007) [#3]
in case you don't know anything about binary numbers
1 decimal = 1 binary
2 decimal = 10 binary
4 decimal = 100 binary
8 decimal = 1000 binary

if you shift left by 1 is the same as multiplying by 2
if you shift right by 1 is the same as divide by 2

to operate on two binary numbers :

"and" symbol "&". say 4 & 8 = 00:

0100 -> 4
1000 -> 8
------
0000 ->00 result


"or " symbol "|". say 4 | 8 = 12:

0100 -> 4 
1000 -> 8
------ 
1100 -> 12 result


exclusiveor symbol "~". say 5~9

0101 -> 5
1001 -> 9
------
1100 ->12 

if you want to find out if a certain bit in a variable is on or off then you would compare it with an "&". Say you don't know the third bit in x is on or of. then you would compare it with 4. If it is on, it will return 4 else it will return 0.
example 1:
if x = 13
x & 4 =

1101  ->  x  and is equal 13
0100  ->  4  
------
0100  ->  answer is 4



if you shift all the bits right by 2 then you get:
answer shr 2 = 0001 or 1 decimal

example 2:

if x = 13
x & 2 =

1101 -> x and is equal 13
0010 -> 2 
------
0000 ->  answer is 0

then shift answer 2:
answer shr 2 = 0000 -abvious answer.

if you want to extract more than 1 bit. say the third and second.

if x = 13

1101 -> x = 13
0110 -> 6
--------
0100 -> 8 answer

answer shr 1 = 4

<note> keep in mind this only works with integer variables. integers in bmax are 32 bits long (I believe). Both operands may be variables.


xlsior(Posted 2007) [#4]
Also, depending on what you are trying to accomplish: if memory size is not an immediate concern, it's probably going to be faster to just use a plain integer to store your 0 or 1 rather than juggle individual bits around.


H&K(Posted 2007) [#5]
it's probably going to be faster to just....
Hes right, but to what level of faster.

Let say for example you wnat to know if a farm (for example), has been built or not. Which is bit 3
Method HasFarm:True/False()

If (self.data & 4)
   return true
else
   Return False
endif

end method

or
Method HasFarm:True/False()

If self.data 
   return true
else
   Return False
endif

end method



nrsteel(Posted 2007) [#6]
Thanks, this helps a lot.


nrsteel(Posted 2007) [#7]
Alright, here's something I just came up with.

Does anyone have any sugestions, or a way to make each part simpler & more compact?

'----------------------------------

SuperStrict

Global Bit:Int[] = [%1,%10,%100,%1000,%10000,%100000,%1000000,%10000000]

Global n:Byte = Bit[0] | Bit[1] | Bit[2] | Bit[3] | Bit[4] | Bit[5] | Bit[6] | Bit[7]

Global CBit:Int[8]

Local x:Byte, cln:Byte

Print n

' Opening & Writing a Byte to a File
'-------------------------------------------------
Local file:TStream = OpenFile("binary1.bin")
WriteByte(file, n)
CloseStream file


' Opening & Reading a Byte from a File & Taking apart a Byte
'-------------------------------------------------
file:TStream = OpenFile("binary1.bin")
cln = ReadByte(file)

For x = 0 To 7
CBit[x] = (cln & Bit[x] <> 0)
Print CBit[x]
Next

CloseStream file


ImaginaryHuman(Posted 2007) [#8]
If you're going to store and change lots of bits it is not going to be faster to store, say, 32 int's, compared to 1 int containing 32 bits. 32 times the amount of memory access is in no way going to make up for the very fast and's/or's/shifts that you need to extract/set bits.


Who was John Galt?(Posted 2007) [#9]
What AngelDaniel said, plus if you're doing bit access for speed you're unlikely to write OO style getters and setters which will probably nullify any speed advantage.


SculptureOfSoul(Posted 2007) [#10]
I'd get rid of the global bit array. Global access is slow.

Then, modify the last piece of code to the following:
file:TStream = OpenFile("binary1.bin")
cln = ReadByte(file)

For x = 0 To 7
CBit[x] = (cln & 1 )
cln = cln shr 1
Print CBit[x]
Next

CloseStream file 


Of course, like AngelDaniel said, you'd be better off not disassembling the byte but instead using ands and ors on a single byte or int or whatever.

I'd be able to give better advice if I knew exactly what you were trying to accomplish with the code.


nrsteel(Posted 2007) [#11]
I was thinking of using this code for storing and reading map information.

For example, collisions on a 8x8 tile map.

With something like this, I could simply write 8 bytes to a file, with each 0 or 1 in the byte telling whether the tile is passable.


ImaginaryHuman(Posted 2007) [#12]
Are you saying you have a tilemap where the tiles are 8x8 in size, and that this produces a lot of tile data hence your concern, or are you saying you have a map that is only 8 tiles across by 8 tiles down? If the latter, just store all the bits in one Long. If the former, I probably would use Longs or Ints as the container for the bits and then use set or test each bit.

'To set a bit:
MyLong:|($1 Shl Bit) 'use or to combine new bit with old bits

'To clear a bit:
MyLong:&(~($1 Shl Bit)) 'use and to mask off a bit

'To test a bit:
If (MyLong & ($1 Shl Bit)) Then BitIsSet 'mask off bit and find status

Storing data as Long is usually faster to read/write than Int's (less overhead), so you should start on the left of the visible map area and do a whole row in sequence so you read a sequence of Longs for that row. Read the Long once and then go through each individual bit that you need to test while you have it read in. Don't read the Long 64 times if you can help it! Read it into a Local variable then do the changes to it then write it back out if you need to (after finished all changes to all bits in it).

For a 640x480 screen where you have 8x8 size tiles that's 5600 tiles in view at a time (or more if you need to scroll), so you can store those bits in 88 Longs. So that's about 704 bytes per screen, compared to 5600 bytes per screen if you store a byte for each tile - 8 times as much!


nrsteel(Posted 2007) [#13]
I meant that the map size was 8 x 8, with 8 tiles down & 8 tiles across. But that is just a test map.

Most of the maps that I'm going to make are going to be bigger than that, of course:
16 x 32
32 x 64
64 x 128


ImaginaryHuman(Posted 2007) [#14]
Well, these are still small maps, I think I would just use a byte as a flag for each tile. 64x128 is only 8 kilobytes.


H&K(Posted 2007) [#15]
?

If you are going for map sizes that small, you might as well just store the maps as "Images", so that you can just plot and point to them.

Come on Mr steel, most people have textures twice as big as that.


nrsteel(Posted 2007) [#16]
That sounds like good idea - I'll try that and see how it turns out.