Page 2 of 3
Re: BitGet/BitSet/BitOff
Posted: Wed Feb 10, 2016 12:24 am
by Lunasole
idle wrote:It's probably better to use macros with the assembly instructions BTS, BTR, BTC and a procedure for BT
Thanks for interesting example, but your code cannot be used like that
Code: Select all
Define.i A, B
BitSet (A, 2)
B = BitSet(A, 1) ; B will have 1 and 2 bits set, A only 2nd
Or used inside other expressions, with IF or some else:
Code: Select all
Debug BitSet (0, 1) | BitSet (0, 2); = 3
This is important thing and one of reasons why my macro made like they are. For my macro the only limit is that they cannot be surrounded by some high-priority operators (~,<<,>>,%,!), until code inside of BitSet/BitOff is not taken to ( ).
Also using procedure call for BitGet looks expensive against inline bit operations, as there are arguments pushed, local variables assigned and returned (but in my get macro CBool is called, though, cause using "~~" sequence unfortunately has some minuses).
Re: BitGet/BitSet/BitOff
Posted: Wed Feb 10, 2016 12:27 am
by Lunasole
@Idle
Also don't know why, but your BitSet macro constantly shows 3x slower execution time than my variant on my AMD with that code running w/o debugger:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EnableExplicit
Macro BitSet(bitfield,bit)
EnableASM
bts bitfield , bit
DisableASM
EndMacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Macro BitSetA (Value, Bit)
Value | (1 << (Bit - 1)) ;
EndMacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Define A
Define B
Define Time
Define Count = 100000000 ; 100 billions iterations
Time = ElapsedMilliseconds()
For B = 1 To Count
A = 0
;BitSet(A, 0)
BitSetA(A, 1)
Next B
MessageRequester("BitSet:ASM", Str(ElapsedMilliseconds() - Time))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Time = ElapsedMilliseconds()
For B = 1 To Count
A = 0
;BitSetA(A, 1)
BitSet(A, 0)
Next B
MessageRequester("BitSet", Str(ElapsedMilliseconds() - Time))
I guess other macro too, didn't tested. This is strange enough.
Re: BitGet/BitSet/BitOff
Posted: Wed Feb 10, 2016 3:39 am
by idle
I don't notice any difference between them, the latency of BTS is 8 and "shift and or" should add up to 7 or 8
depending how it's done.
Re: BitGet/BitSet/BitOff
Posted: Wed Feb 10, 2016 8:02 am
by wilbert
idle wrote:I don't notice any difference between them, the latency of BTS is 8 and "shift and or" should add up to 7 or 8
depending how it's done.
PureBasic probably replaces the entire
(1 << (Bit - 1)) part with a constant so the difference would be like
bts [v_A], 0 vs
or [v_A], 1 and the
or instruction is faster.
Re: BitGet/BitSet/BitOff
Posted: Wed Feb 10, 2016 5:06 pm
by Little John
Keya wrote:Code: Select all
Macro BitGet(bitnum, value=0)
(value & (1<<bitnum))
EndMacro
Macro BitSet(bitnum, value=0)
(value | (1<<bitnum))
EndMacro
Macro BitUnset(bitnum, value=0)
(value ! (1<<bitnum))
EndMacro
Hello Keya,
it occurred to me that there is probably a mistake in your code.
According to my limited knowledge of the English language, I think the name "BitUnset" shall denote that the macro sets the wanted bit to 0, right?
But that macro uses XOR, and so the regarding bit is toggled.
I suggest to write the macros as follows:
Code: Select all
Macro BitGet(value, bitnum)
(value & (1<<bitnum))
EndMacro
Macro BitSet(value, bitnum)
(value | (1<<bitnum))
EndMacro
Macro BitToggle(value, bitnum)
(value ! (1<<bitnum))
EndMacro
Macro BitUnset(value, bitnum)
(value & ~(1<<bitnum))
EndMacro
; -- Demo
a = BitSet(0, 16)
If BitGet(a, 16)
Debug "on: " + Bin(a, #PB_Long)
EndIf
a = BitUnset(a, 16)
If Not BitGet(a, 16)
Debug "off: " + Bin(a, #PB_Long)
EndIf
a = BitToggle(a, 16)
Debug "toggle on: " + Bin(a, #PB_Long)
a = BitToggle(a, 16)
Debug "toggle off: " + Bin(a, #PB_Long)
Re: BitGet/BitSet/BitOff
Posted: Wed Feb 10, 2016 6:30 pm
by Lunasole
wilbert wrote:idle wrote:I don't notice any difference between them, the latency of BTS is 8 and "shift and or" should add up to 7 or 8
depending how it's done.
PureBasic probably replaces the entire
(1 << (Bit - 1)) part with a constant so the difference would be like
bts [v_A], 0 vs
or [v_A], 1 and the
or instruction is faster.
Yes, I posted example of this previously.
But anyway my variant of macro looks as MOV, OR, MOV, 3 instructions against one BTS. It seems that BTS itself is slower, at least on my AMD.
Re: BitGet/BitSet/BitOff
Posted: Wed Jun 22, 2016 4:54 am
by Blue
idle wrote:
Code: Select all
[...]
Global mybit.l
BitSet(mybit,16)
If BitGet(mybit,16)
Debug "on: " + Bin(mybit,#PB_Long)
EndIf
BitReset(mybit,16)
If Not BitGet(mybit,16)
Debug "off: " + Bin(mybit,#PB_Long)
EndIf
BitToggle(mybit,16)
Debug "toggle on: " + Bin(mybit,#PB_Long)
BitToggle(mybit,16)
Debug "toggle off: " + Bin(mybit,#PB_Long)
[...]
If, working from your example, i use a variable instead of a literal value to specify which bit to modify, as in the following
Code: Select all
[...]
Global mybit.l
define b
b = 16
BitSet(mybit, b)
If BitGet(mybit,b)
Debug "on: " + Bin(mybit,#PB_Long)
EndIf
[...]
I get this error message (which I totally don't understand !

).
---------------------------
PureBasic - Assembler error
---------------------------
PureBasic.asm [135]:
bts dword [v_mybit],dword [v_b]
error: invalid operand.
---------------------------
OK
I guess it has to do with the bug Little John pointed out.
So how would i solve that ?
You mention
"aliasing the registers", but how is that done ?
(using PB 5.42 x86 in Windows 10 x64)
Re: BitGet/BitSet/BitOff
Posted: Wed Jun 22, 2016 5:35 am
by Blue
@LunaSole : I like your macros very much.
Very good idea, + excellent and simple implementation.
Bravo !
However, I'll use them by counting up from 0.
As Little John suggested, i think it's better to stick to some standards sometimes.
I'd also like to point out that, while you explain that
'Value' is bitmask, it is actually a
bitfield.
A
bitmask is a
pattern used to filter out or isolate specific bits in a bitfield.
Thank you for your very useful macros.
--------------------------------------------------
Addendum :
I think there is a mistake in your
BitOFF() macro.
You are using an XOR operation to turn the bit OFF,
which works if the bit is ON, but fails if it is already OFF !
Try this out.
Code: Select all
; using Lunasole's irregular 1-based position counting scheme
Macro BitOFF (Value, bit)
Value ! (1 << (bit-1)) ;; a zero bit will be turned on with this !
EndMacro
A = 15
Debug "A = " + Bin(A, #PB_Long)
A = BitOFF(A,1)
Debug " BitOFF(A,1) A = " + Bin(A, #PB_Long)
Debug ""
Debug "That bit #1 went from ON to OFF. OK."
Debug "Even though it's OFF, let's turn it OFF once more :"
Debug ""
A = BitOFF(A,1)
Debug " BitOFF(A,1) A = " + Bin(A, #PB_Long)
Debug ""
Debug "That bit #1 went from OFF to ON."
Debug "Not the expected result..."
Debug ""
Now,
INVERTING the bit and then
ANDing it against the bitfield works perfectly :
Code: Select all
; using Lunasole's irregular 1-based position counting scheme
Macro BitOFF (Value, bit)
Value & ~(1 << (bit-1))
EndMacro
A = 15
Debug "A = " + Bin(A, #PB_Long)
A = BitOFF(A,1)
Debug " BitOFF(A,1) A = " + Bin(A, #PB_Long)
Debug ""
Debug "That bit #1 went from ON to OFF. OK."
Debug "So it's OFF, but let's turn it OFF again anyway :"
Debug ""
A = BitOFF(A,1)
Debug " BitOFF(A,1) A = " + Bin(A, #PB_Long)
Debug ""
Debug "And bit #1 stayed OFF, as we wanted..."
Debug ""
Re: BitGet/BitSet/BitOff
Posted: Wed Jun 22, 2016 10:05 am
by Lunasole
@Blue, thanks for your response. I've updated first post and also set starting index to 0 at last

However 1 anyway looks better in many cases when starting from 0 is not crucial.
Re: BitGet/BitSet/BitOff
Posted: Wed Jun 22, 2016 1:25 pm
by Blue
Lunasole wrote:@Blue, thanks for your response. I've updated first post and also set starting index to 0 at last

However 1 anyway looks better in many cases when starting from 0 is not crucial.
I agree with you that indexing items with 1 for the first item of a suite is a lot more natural and logical for regular humans
(
That's you and me, brother. It, ipso facto, excludes propeller heads like Little John, Idle, and a bunch of others! 
)
The insistance on pointing your unorthodox (
NOT abnormal) indexing method was not to force you to change, only to draw to it to the attention of those irregular humans called
programmers. I certainly didn't want you to feel that you need to apologize in any way, nor even to change it.
Your idea is still top notch, and your macros, very useful and intelligent.
Stick to your guns : you like indexing from 1, just do it (plus the way you implement it is perfect.)
You say that you updated the first post. But what actually needs updating is NOT your indexing approach, but
the method used in BitOFF(), since it fails with bits already zeroed. That point is very important, since, most often, programmers do not know in advance whether the bit of interest is off or not.
Re: BitGet/BitSet/BitOff
Posted: Wed Jun 22, 2016 6:58 pm
by Keya
Little John wrote:Hello Keya,
it occurred to me that there is probably a mistake in your code.
According to my limited knowledge of the English language, I think the name "BitUnset" shall denote that the macro sets the wanted bit to 0, right?
But that macro uses XOR, and so the regarding bit is toggled.
I suggest to write the macros as follows:
Code: Select all
Macro BitGet(value, bitnum)
(value & (1<<bitnum))
EndMacro
Macro BitSet(value, bitnum)
(value | (1<<bitnum))
EndMacro
Macro BitToggle(value, bitnum)
(value ! (1<<bitnum))
EndMacro
Macro BitUnset(value, bitnum)
(value & ~(1<<bitnum))
EndMacro
well spotted and i agree with your changes, thanks!

Re: BitGet/BitSet/BitOff
Posted: Wed Jun 22, 2016 9:24 pm
by idle
Blue wrote:
If, working from your example, i use a variable instead of a literal value to specify which bit to modify, as in the following
I get this error message (which I totally don't understand !

).
---------------------------
PureBasic - Assembler error
---------------------------
PureBasic.asm [135]:
bts dword [v_mybit],dword [v_b]
error: invalid operand.
---------------------------
OK
I guess it has to do with the bug Little John pointed out.
So how would i solve that ?
You mention
"aliasing the registers", but how is that done ?
(using PB 5.42 x86 in Windows 10 x64)
Sorry didn't pay attention to the questions asked earlier, the macro's only supported immediate values
you can use this with either an immediate or a variable but only with integer types.
Code: Select all
CompilerIf SizeOf(Integer) = 8
Macro ecx : rcx : EndMacro
Macro eax : rax : EndMacro
CompilerEndIf
Macro BitSet(bitfield,bit)
EnableASM
mov eax, bit
bts bitfield, eax
!xor eax,eax
DisableASM
EndMacro
Macro BitReset(bitfield,bit)
EnableASM
mov eax, bit
btr bitfield,eax
!xor eax,eax
DisableASM
EndMacro
Macro BitToggle(bitfield,bit)
EnableASM
mov eax, bit
btc bitfield,eax
!xor eax,eax
DisableASM
EndMacro
Procedure BitGet(bitfield, bit)
!movzx eax, byte [p.v_bit]
!bt [p.v_bitfield], eax
!setc al
ProcedureReturn
EndProcedure
Global mybit.i,a.i
For a = 0 To 16 Step 2
BitSet(mybit,a)
Debug RSet(Bin(mybit,#PB_Long),16,"0")
Next
For a = 0 To 16 Step 2
If BitGet(mybit,a)
Debug "on: " + Str(a)
EndIf
Next
For a = 0 To 16 Step 2
BitReset(mybit,a)
If Not BitGet(mybit,a)
Debug Str(a) + " off: " + RSet(Bin(mybit,#PB_Long),16,"0")
EndIf
Next
BitToggle(mybit,16)
Debug "toggle on: " + RSet(Bin(mybit,#PB_Long),16,"0")
BitToggle(mybit,16)
Debug "toggle off: " + RSet(Bin(mybit,#PB_Long),16,"0")
Re: BitGet/BitSet/BitOff
Posted: Thu Jun 23, 2016 5:53 am
by wilbert
idle wrote:Code: Select all
Procedure BitGet(bitfield.i,bit.i)
EnableASM
!mov ecx, [p.v_bit]
!bt [p.v_bitfield],ecx
DisableASM
!jnb lbitget
ProcedureReturn 1
!lbitget:
!xor eax,eax
ProcedureReturn
EndProcedure
There's no need to use branches for this.
The same can be done without a conditional jump.
Code: Select all
Procedure BitGet(bitfield, bit)
!movzx eax, byte [p.v_bit]
!bt [p.v_bitfield], eax
!setc al
ProcedureReturn
EndProcedure
Re: BitGet/BitSet/BitOff
Posted: Thu Jun 23, 2016 6:02 am
by idle
wilbert wrote:
There's no need to use branches for this.
The same can be done without a conditional jump.
Code: Select all
Procedure BitGet(bitfield, bit)
!movzx eax, byte [p.v_bit]
!bt [p.v_bitfield], eax
!setc al
ProcedureReturn
EndProcedure
Yes that's better. thanks!
Re: BitGet/BitSet/BitOff
Posted: Thu Jun 23, 2016 6:20 am
by Lunasole
Blue wrote:
The insistance on pointing your unorthodox (NOT abnormal) indexing method was not to force you to change, only to draw to it to the attention of those irregular humans called programmers. I certainly didn't want you to feel that you need to apologize in any way, nor even to change it.
Stick to your guns : you like indexing from 1, just do it (plus the way you implement it is perfect.)
It's all OK man, I'm still using 1-based in my stuff (when it is more handy than 0), only posted here sample starting from 0
Blue wrote:
You say that you updated the first post. But what actually needs updating is NOT your indexing approach, but the method used in BitOFF(), since it fails with bits already zeroed.
Funny, yesterday I changed this in my own template but posted another one here without this fix. Well, updated first post-II ^^