From: Skybuck Flying on
Cool and handy too ! ;) =D, I shall add this method of yours as number 4.

1. (Skybuck) Mask := not word(65535 shl BitCount); // not 1111000 =
0000111

2. (Michael Vinther) Mask := (1 shl BitCount)-1; // 10000-1 = 09999 = 01111
;) :)

3. (Skamradt) (Mask := ($FFFF shl BitCount) xor $FFFF; // 1111000 xor
1111111 = 0000111

4. (MitchAlsup) Mask := not word((not 0) shl BitCount); // not((not 0 =
1111111) shl 3 = 1111000) = 0000111

So far it seems method 2 is the best/shortest at least in Delphi 2007
compiler.
Method 2 works well for functions and inlining as well, some of the others
seem to become bigger when inlined ?!?
(Actual speed is yet to be determined ;) :))

It could be interesting to see how a C compiler compiles it...

For now here is the Delphi 2007 test program, and the assemblies of inlined
vs non-inlined:

// *** Begin of Test Program ***

program TestProgram;

{$APPTYPE CONSOLE}

{

TestProgram to test and analyze calculation for BitMasks.

version 0.01 created on 25 may 2010 by Skybuck Flying.

When the functions are not inlined all versions use 5 instructions.
(including the return).

However when inline directive happens something interesting happens.

Some versions will be 4 instructions and some 5 some maybe even more.

I guess it depends on how the Delphi 2007 compiler inlines it... ?!?

Re-ordering the code didn't really help...

Mask2MichaelVinther seems to be the best one so far,

Shortest in both modes, uses the least ammount of "instruction bytes".

Actual speed is yet to be determined ! ;) :)

}

uses
SysUtils;

function Mask1Skybuck( ParaBitCount : byte ) : word; inline;
begin
result := not word(65535 shl ParaBitCount);
end;

function Mask2MichaelVinther( ParaBitCount : byte ) : word; inline;
begin
result := (1 shl ParaBitCount)-1;
end;

function Mask3Skamradt( ParaBitCount : byte ) : word; inline;
begin
result := word($FFFF shl ParaBitCount) xor $FFFF;
end;

function Mask4MitchAlsup( ParaBitCount : byte ) : word; inline;
begin
result := not word((not 0) shl ParaBitCount);
end;

procedure Main;
var
vMask : word;
vBitCount : word;
begin
vBitCount := 16;

vMask := Mask1Skybuck( vBitCount );
writeln( vMask );

vMask := Mask2MichaelVinther( vBitCount );
writeln( vMask );

vMask := Mask3Skamradt( vBitCount );
writeln( vMask );

vMask := Mask4MitchAlsup( vBitCount );
writeln( vMask );
end;

begin
try
{ TODO -oUser -cConsole Main : Insert code here }
Main;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
ReadLn;
end.


{
Inlined version:

TestProgram.dpr.51: begin
00408E44 53 push ebx
00408E45 56 push esi
00408E46 57 push edi
TestProgram.dpr.52: vBitCount := 16;
00408E47 66BE1000 mov si,$0010
TestProgram.dpr.54: vMask := Mask1Skybuck( vBitCount );
00408E4B 8BDE mov ebx,esi
00408E4D 8BCB mov ecx,ebx
00408E4F 66BFFFFF mov di,$ffff
00408E53 66D3E7 shl di,cl
00408E56 66F7D7 not di
TestProgram.dpr.55: writeln( vMask );
00408E59 0FB7D7 movzx edx,di
00408E5C A1F0A94000 mov eax,[$0040a9f0]
00408E61 E8CEA8FFFF call @Write0Long
00408E66 E801A9FFFF call @WriteLn
00408E6B E86C9FFFFF call @_IOTest
TestProgram.dpr.57: vMask := Mask2MichaelVinther( vBitCount );
00408E70 8BCB mov ecx,ebx
00408E72 66BF0100 mov di,$0001
00408E76 66D3E7 shl di,cl
00408E79 4F dec edi
TestProgram.dpr.58: writeln( vMask );
00408E7A 0FB7D7 movzx edx,di
00408E7D A1F0A94000 mov eax,[$0040a9f0]
00408E82 E8ADA8FFFF call @Write0Long
00408E87 E8E0A8FFFF call @WriteLn
00408E8C E84B9FFFFF call @_IOTest
TestProgram.dpr.60: vMask := Mask3Skamradt( vBitCount );
00408E91 8BCE mov ecx,esi
00408E93 66BFFFFF mov di,$ffff
00408E97 66D3E7 shl di,cl
00408E9A 6681F7FFFF xor di,$ffff
TestProgram.dpr.61: writeln( vMask );
00408E9F 0FB7D7 movzx edx,di
00408EA2 A1F0A94000 mov eax,[$0040a9f0]
00408EA7 E888A8FFFF call @Write0Long
00408EAC E8BBA8FFFF call @WriteLn
00408EB1 E8269FFFFF call @_IOTest
TestProgram.dpr.63: vMask := Mask4MitchAlsup( vBitCount );
00408EB6 8BCE mov ecx,esi
00408EB8 66BFFFFF mov di,$ffff
00408EBC 66D3E7 shl di,cl
00408EBF 66F7D7 not di
TestProgram.dpr.64: writeln( vMask );
00408EC2 0FB7D7 movzx edx,di
00408EC5 A1F0A94000 mov eax,[$0040a9f0]
00408ECA E865A8FFFF call @Write0Long
00408ECF E898A8FFFF call @WriteLn
00408ED4 E8039FFFFF call @_IOTest
TestProgram.dpr.65: end;
00408ED9 5F pop edi
00408EDA 5E pop esi
00408EDB 5B pop ebx
00408EDC C3 ret

}

{

Non-inlined/function version:

TestProgram.dpr.29: result := not word(65535 shl ParaBitCount);
00408E44 8BC8 mov ecx,eax
00408E46 66B8FFFF mov ax,$ffff
00408E4A 66D3E0 shl ax,cl
00408E4D 66F7D0 not ax
TestProgram.dpr.30: end;
00408E50 C3 ret
00408E51 8D4000 lea eax,[eax+$00] // ignored/filling
TestProgram.dpr.34: result := (1 shl ParaBitCount)-1;
00408E54 8BC8 mov ecx,eax
00408E56 66B80100 mov ax,$0001
00408E5A 66D3E0 shl ax,cl
00408E5D 48 dec eax
TestProgram.dpr.35: end;
00408E5E C3 ret
00408E5F 90 nop // ignored/filling
TestProgram.dpr.39: result := word($FFFF shl ParaBitCount) xor $FFFF;
00408E60 8BC8 mov ecx,eax
00408E62 66B8FFFF mov ax,$ffff
00408E66 66D3E0 shl ax,cl
00408E69 6635FFFF xor ax,$ffff
TestProgram.dpr.40: end;
00408E6D C3 ret
00408E6E 8BC0 mov eax,eax // ignored/filling
TestProgram.dpr.44: result := not word((not 0) shl ParaBitCount);
00408E70 8BC8 mov ecx,eax
00408E72 66B8FFFF mov ax,$ffff
00408E76 66D3E0 shl ax,cl
00408E79 66F7D0 not ax
TestProgram.dpr.45: end;
00408E7C C3 ret
00408E7D 8D4000 lea eax,[eax+$00]
TestProgram.dpr.51: begin
00408E80 53 push ebx
00408E81 56 push esi
00408E82 57 push edi
TestProgram.dpr.52: vBitCount := 16;
00408E83 66BE1000 mov si,$0010
TestProgram.dpr.54: vMask := Mask1Skybuck( vBitCount );
00408E87 8BDE mov ebx,esi
00408E89 8BC3 mov eax,ebx
00408E8B E8B4FFFFFF call Mask1Skybuck
00408E90 8BF8 mov edi,eax
TestProgram.dpr.55: writeln( vMask );
00408E92 0FB7D7 movzx edx,di
00408E95 A1F0A94000 mov eax,[$0040a9f0]
00408E9A E895A8FFFF call @Write0Long
00408E9F E8C8A8FFFF call @WriteLn
00408EA4 E8339FFFFF call @_IOTest
TestProgram.dpr.57: vMask := Mask2MichaelVinther( vBitCount );
00408EA9 8BC3 mov eax,ebx
00408EAB E8A4FFFFFF call Mask2MichaelVinther
00408EB0 8BF8 mov edi,eax
TestProgram.dpr.58: writeln( vMask );
00408EB2 0FB7D7 movzx edx,di
00408EB5 A1F0A94000 mov eax,[$0040a9f0]
00408EBA E875A8FFFF call @Write0Long
00408EBF E8A8A8FFFF call @WriteLn
00408EC4 E8139FFFFF call @_IOTest
TestProgram.dpr.60: vMask := Mask3Skamradt( vBitCount );
00408EC9 8BC3 mov eax,ebx
00408ECB E890FFFFFF call Mask3Skamradt
00408ED0 8BF8 mov edi,eax
TestProgram.dpr.61: writeln( vMask );
00408ED2 0FB7D7 movzx edx,di
00408ED5 A1F0A94000 mov eax,[$0040a9f0]
00408EDA E855A8FFFF call @Write0Long
00408EDF E888A8FFFF call @WriteLn
00408EE4 E8F39EFFFF call @_IOTest
TestProgram.dpr.63: vMask := Mask4MitchAlsup( vBitCount );
00408EE9 8BC3 mov eax,ebx
00408EEB E880FFFFFF call Mask4MitchAlsup
00408EF0 8BF8 mov edi,eax
TestProgram.dpr.64: writeln( vMask );
00408EF2 0FB7D7 movzx edx,di
00408EF5 A1F0A94000 mov eax,[$0040a9f0]
00408EFA E835A8FFFF call @Write0Long
00408EFF E868A8FFFF call @WriteLn
00408F04 E8D39EFFFF call @_IOTest
TestProgram.dpr.65: end;
00408F09 5F pop edi
00408F0A 5E pop esi
00408F0B 5B pop ebx
00408F0C C3 ret


}

// *** End of Test Program ***

Bye,
Skybuck.


From: Skybuck Flying on
The other methods have problems too ofcourse, that's why I added the "word"
typecasts... though when leaving out the "word" typecast not all problems
are detected by Delphi's range checking capabilities.

Therefore it's worth bitching about Delphi not being able to detect
problems:

> 1. (Skybuck) Mask := not word(65535 shl BitCount); // not 1111000 =
> 0000111

This method without the typecast should have raised an exception since 65535
is being shifted out and becomes to large for a word...

Therefore in 16 bit it will work but in 32 bit it will still bug out, a
typecast for longword will fix it again.

All methods have this problem, therefore all methods require a typecast to
be on the safe side if range/overflow checking is to be enabled.

>
> 2. (Michael Vinther) Mask := (1 shl BitCount)-1; // 10000-1 = 09999 =
> 01111 ;) :)
>
> 3. (Skamradt) (Mask := ($FFFF shl BitCount) xor $FFFF; // 1111000 xor
> 1111111 = 0000111
>
> 4. (MitchAlsup) Mask := not word((not 0) shl BitCount); // not((not 0 =
> 1111111) shl 3 = 1111000) = 0000111

Moral of the story:

Code designed will work in 16 bit in Delphi but would present problems in 32
bit.

The typecasts were added because I already had experience with 32 bit
problems/versions.

Bye,
Skybuck.


From: Skybuck Flying on
Wow when the bit count changes from 16 to 15 then suddenly my method starts
to trip range checking exceptions as well !

Totally funny ! =D

This is some fun code we have here ladies and gentlemen ! ;) :)

Bye,
Skybuck =D


From: Skybuck Flying on
Wow method 1 even trips for a BitCount of 0 ?!?

How is that possible ?

Seems like Delphi compiler has some real issue's with this code and it's
range checking capabilities ?! :)

Bye,
Skybuck.


From: Skybuck Flying on
Method 3 does work for BitCount of 0 and starts to trip at BitCount 1 !

Most amuzing ! =D

Bye,
Skybuck =D