evenmore-bitwise.tex /size: 7987 b    last modification: 2021-10-28 13:50
1% language=us runpath=texruns:manuals/evenmore
2
3\environment evenmore-style
4
5\startcomponent evenmore-bitwise
6
7\startchapter[title={Bitwise operations}]
8
9Occasionally we use a bit set to pass (or store) options and one way of doing
10that is to add up some constants. However, what you would like to do is to set a
11specific bit. Of course one can write macros for that but performance wise one
12can wonder if there are other ways. One solution is to extend the engine but that
13has its own pitfalls. For instance, I played with additions to \type {\numexpr}
14and although they worked okay and brought now performance degradation, I decided
15to remove that experiment. One problem is that we have no real 32 bit cardinals
16(unsigned integers) in \TEX\ and the engine makes sure that we never exceed the
17minima and maxima. Another problem is that in expressions we then need either
18verbose \type {and}, \type {or}, \type {xor}, \type {not} and other verbose
19operators, if only because the usual symbols can have catcodes that are
20unsuitable.
21
22So in the end I decided to come up with a set of primitive like commands that
23do the job. It is no problem to have a set of dedicated verbose commands and we
24can extend the repertoire if needed. So this is what we have now:
25
26\starttabulate[||i2c||]
27\NC command                    \NC operator equivalent  \NC optional     \NC \NR
28\NC \type {\bitwiseset      a} \NC \type {a}            \NC              \NC \NR
29\NC \type {\bitwisenot      a} \NC \type {~a}           \NC              \NC \NR
30\NC \type {\bitwisenil   a  b} \NC \type {a & (~ b)}    \NC \type {with} \NC \NR
31\NC \type {\bitwiseand   a  b} \NC \type {a & b}        \NC \type {with} \NC \NR
32\NC \type {\bitwiseor    a  b} \NC \type {a | b}        \NC \type {with} \NC \NR
33\NC \type {\bitwisexor   a  b} \NC \type {a ~ b}        \NC \type {with} \NC \NR
34\NC \type {\bitwiseshift a  b} \NC \type {a >> b}       \NC \type {by}   \NC \NR
35\NC \type {\bitwiseshift a -b} \NC \type {a << b}       \NC \type {by}   \NC \NR
36\NC \type {\ifbitwiseand a  b} \NC \type {(a & b) ~= 0} \NC              \NC \NR
37\stoptabulate
38
39Here a some examples:
40
41\startbuffer
42\scratchcounter = \bitwiseand "01      "02 \uchexnumbers{\scratchcounter} \quad
43\scratchcounter = \bitwiseand "01 with "02 \uchexnumbers{\scratchcounter} \quad
44\scratchcounter = \bitwiseand "03      "02 \uchexnumbers{\scratchcounter} \qquad
45\scratchcounter = \bitwiseor  "01      "02 \uchexnumbers{\scratchcounter} \quad
46\scratchcounter = \bitwiseor  "01 with "02 \uchexnumbers{\scratchcounter} \quad
47\scratchcounter = \bitwiseor  "03      "02 \uchexnumbers{\scratchcounter} \qquad
48\scratchcounter = \bitwisexor "01      "02 \uchexnumbers{\scratchcounter} \quad
49\scratchcounter = \bitwisexor "01 with "02 \uchexnumbers{\scratchcounter} \quad
50\scratchcounter = \bitwisexor "03      "02 \uchexnumbers{\scratchcounter}
51\stopbuffer
52
53\typebuffer
54
55This gives the nine values:
56
57{\tt\getbuffer}
58
59Because they are numeric operations you can chain them, as in:
60
61\starttyping
62\scratchcounter = \bitwisenil \bitwisenil "0F      "02      "01 \relax
63\scratchcounter = \bitwisenil \bitwisenil "0F with "02 with "01 \relax
64\stoptyping
65
66We try as good as possible to support all bits in the range from zero upto \type
67{0xFFFFFFFF};
68
69\startbuffer
70\scratchcounter \bitwiseset "FFFFFFFF
71
72\ifbitwiseand \scratchcounter "80000000 YES \else NOP \fi
73\ifbitwiseand \scratchcounter "F0000000 YES \else NOP \fi
74\ifbitwiseand \scratchcounter "10000000 YES \else NOP \fi
75
76\scratchcounter \bitwisenot \scratchcounter
77
78\ifbitwiseand \scratchcounter "80000000 YES \else NOP \fi
79\ifbitwiseand \scratchcounter "F0000000 YES \else NOP \fi
80\ifbitwiseand \scratchcounter "10000000 YES \else NOP \fi
81\stopbuffer
82
83\typebuffer
84
85and we get:
86
87\startpacked \tt \getbuffer \stoppacked
88
89Of course you can just use normal counters and \TEX\ integers but using the bit
90commands have the advantage that they do some checking and can do real \type {or}
91etc operations. Here is some food for thought:
92
93\startbuffer
94\scratchcounter \bitwiseand "01 "02
95\scratchcounter \numexpr    "01+"02\relax
96
97\ifcase      \bitwiseand \scratchcounterone \plusone \else \fi
98\ifbitwiseand            \scratchcounterone \plusone \else \fi
99\ifnum                   \scratchcounterone=\plusone \else \fi
100\stopbuffer
101
102\typebuffer
103
104and we get:
105
106\startpacked \tt \getbuffer \stoppacked
107
108You can also go real binary, but we only provide a combined setter|/|getter for
109that, but you can mix that one with the other commands:
110
111\startbuffer
112\scratchcounterone   = \bitwise 1101
113\scratchcountertwo   = \bitwise 11011101110111011101110111011101
114\scratchcounterthree = \bitwiseor \bitwise 0001 \bitwise 1100
115
116{0x\uchexnumber{\scratchcounterone}   \bitwise\scratchcounterone  }\par
117{0x\uchexnumber{\scratchcountertwo}   \bitwise\scratchcountertwo  }\par
118{0x\uchexnumber{\scratchcounterthree} \bitwise\scratchcounterthree}\par
119\stopbuffer
120
121\typebuffer
122
123We get bits back:
124
125\startpacked \tt \getbuffer \stoppacked
126
127The above commands are typical for the things we can do with \LUAMETATEX\ and
128\LMTX\ and are unlikely to become available in \MKIV.
129
130There is a special command for (re)setting a bit in a register:
131
132\startbuffer
133             \scratchcounter  0
134\bitwiseflip \scratchcounter  1 [\the\scratchcounter]
135\bitwiseflip \scratchcounter  4 [\the\scratchcounter]
136\bitwiseflip \scratchcounter  8 [\the\scratchcounter]
137\bitwiseflip \scratchcounter -5 [\the\scratchcounter]
138\stopbuffer
139
140\typebuffer
141
142This gives: \inlinebuffer. Of course a global assignment works too:
143
144\startbuffer
145 \global              \globalscratchcounter  0
146{\global \bitwiseflip \globalscratchcounter  2 } [\the\globalscratchcounter]
147{\global \bitwiseflip \globalscratchcounter  4 } [\the\globalscratchcounter]
148{\global \bitwiseflip \globalscratchcounter  8 } [\the\globalscratchcounter]
149{\global \bitwiseflip \globalscratchcounter -6 } [\the\globalscratchcounter]
150\stopbuffer
151
152\typebuffer
153
154Here we get: \inlinebuffer. A side effect of it being an number makes that
155this is also valid:
156
157\starttyping
158\scratchcounterone\bitwiseflip \scratchcountertwo -16
159\stoptyping
160
161\stopchapter
162
163\stopcomponent
164
165% (\scratchcounterone \bitwiseset "F        \uchexnumber{\scratchcounterone})\par
166% (\scratchcounterone \bitwiseset "FF       \uchexnumber{\scratchcounterone})\par
167% (\scratchcounterone \bitwiseset "FFF      \uchexnumber{\scratchcounterone})\par
168% (\scratchcounterone \bitwiseset "FFFF     \uchexnumber{\scratchcounterone})\par
169% (\scratchcounterone \bitwiseset "FFFFF    \uchexnumber{\scratchcounterone})\par
170% (\scratchcounterone \bitwiseset "FFFFFF   \uchexnumber{\scratchcounterone})\par
171% (\scratchcounterone \bitwiseset "FFFFFFF  \uchexnumber{\scratchcounterone})\par
172% (\scratchcounterone \bitwiseset "FFFFFFFF \uchexnumber{\scratchcounterone})\par
173%
174% (\scratchcounterone \bitwiseset       "0000FFFF
175%  \scratchcounterone \bitwiseshift     \scratchcounterone  -16
176%  \uchexnumber{\scratchcounterone})\par
177%
178% \scratchcounterone \bitwiseset "FFFFFFFF
179% \scratchcountertwo \bitwiseset "FFFFFFFE
180%
181% \the\scratchcounterone : \uchexnumber{\scratchcounterone}\par
182% \the\scratchcountertwo : \uchexnumber{\scratchcountertwo}\par
183
184% I need to check this on the garden run as it looks like that server is some 50%
185% faster than my (in terms of computers) old laptop.
186
187% \testfeatureonce{10000}{\scratchcounter \bitwiseand "01 "02      }                \elapsedtime\par
188% \testfeatureonce{10000}{\scratchcounter \numexpr    "01+"02\relax}                \elapsedtime\par
189% \testfeatureonce{10000}{\ifcase\bitwiseand \scratchcounterone \plusone \else \fi} \elapsedtime\par
190% \testfeatureonce{10000}{\ifbitwiseand      \scratchcounterone \plusone \else \fi} \elapsedtime\par
191% %testfeatureonce{10000}{\ifnum             \scratchcounterone=\plusone \else \fi} \elapsedtime\par
192%
193% \testfeatureonce{100000}{\scratchcounter = \bitwise 1101 } \elapsedtime\par
194% \testfeatureonce{100000}{\scratchcounter = \bitwise 11011101110111011101110111011101 } \elapsedtime\par
195