summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/evenmore/evenmore-numbers.tex
blob: 9b8e10a5601821171592dda14653631b9a769fa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
% language=us

\startcomponent evenmore-numbers

\environment evenmore-style

\startchapter[title={Numbers}]

% \startsection[title={Introduction}]

A few decades of programming in the \TEX\ language can make one wish for certain
features. It will therefore be no surprise that in \LUATEX\ (and even more in
\LUAMETATEX) we have some additional functionality. However, I have to admit that
some of these are not used that much in \CONTEXT\ \MKIV\ and \LMTX. The reason is
that some wishes date from \MKII\ times and because we now have \LUA\ we actually
don't need that many new fancy features. Also, it makes no sense to rewrite
mechanisms that are already working well. However, in order to fully exploit the
possibilities that \LUA\ gives, there are some additions that relate to the way
this language can communicate with \TEX. Of course there's also the issue of a
potentially enhanced performance, but there is not much to gain in that
department.

A side effect of adding features, of which some are just there to complete the
picture, or, as mentioned, because they were supposed to make sense, is that I
make examples. Here I show the result of one of these experiments. I have no clue
how useful this is, but I've learned not to underestimate users in their demands
and creativity.

Internally, \TEX\ does all in 32 bit integers. When you say:

\starttyping
\scratchcounter 123
\scratchdimen   123pt
\stoptyping

the \type {123} gets assigned to a count register and the \type {123pt} is
assigned to a dimen register but actually that is then also an integer: the
internal unit of a dimen is a scaled point (sp) and only when its value is shown
to the user, a real number can show up, followed by the \type {pt} unit. The
precision is limited, so you can expect about four decimal positions precision
here. There is no concept of a floating point number in \TEX, and the only case
where a float gets used is in the final calculations of glue and even that only
comes into play in the backend.

So, although I don't really have an application for it in \CONTEXT\ (otherwise
I'd already added a float data type to the engine), it sounded like a good idea
to see if we could emulate float support. In the following examples the numbers
are managed in \LUA\ and therefore they are global. I could make a local variant
but why complicate matters. These macros start with \type {\lua} to make clear
that they are not managed by \TEX.

\startbuffer
\luacardinal bar  123
\luainteger  bar -456
\luafloat    bar  123.456E-3
\stopbuffer

\typebuffer \getbuffer

We define \type {bar} three times. Each type gets its own hash, so from the
perspective of \LUA\ its nature is kept: integer or double.

\startbuffer
\the\luacardinal bar \quad
\the\luainteger  bar \quad
\the\luafloat    bar
\stopbuffer

\typebuffer \getbuffer

Instead of decimal values, you can also use hexadecimal values (watch the \type
{p} for exponents):

\startbuffer
\luacardinal bar  0x123
\luainteger  bar -0x456
\luafloat    bar  0x123.456p-3
\stopbuffer

\typebuffer \getbuffer

So, now we get:

\startbuffer
\the\luacardinal bar \quad
\the\luainteger  bar \quad
\the\luafloat    bar
\stopbuffer

\getbuffer

From these examples you see two kind of usage: setting a value, and using it. It
is that property that makes them special. Because the macros are implemented
using \LUA\ calls it means that at the \LUA\ end we know what usage is expected.
And it is that dualistic property that I wanted to explore but that in the end
only makes sense it a very few cases, but sometimes those few are important. We
could of course two macros, a setter and a getter, but using one kind of its in.

The setters accept an optional equal sign, as in:

\startbuffer
\luainteger gnu=  123456   \luafloat gnu=  123.456e12
\luainteger gnu = 123456   \luafloat gnu = 123.456e12
\luainteger gnu  =123456   \luafloat gnu  =123.456e12
\stopbuffer

\typebuffer

Although \LUA\ is involved in picking up the value, storing it someplace, and
retrieving it on demand, performance is pretty good. You probably won't notice
the overhead anyway.

The values that \type{\the} returns are serialized numbers. However, sometimes
you want what \TEX\ sees as a numeric token, For that we have these variants

\startbuffer
\luadimen test 100pt
\scratchdimen = .25 \luadimen test
\the\scratchdimen
\stopbuffer

\typebuffer

Which produces the expected value: {\tttf \inlinebuffer}, something that depends
on the fact that the dimension is not a serialized. Talking of serialization,
there are several ways that \LUA\ can do that so let's give some examples. We
start with some definitions. Beware, floats and cardinals are stored
independently!

\startbuffer
\luacardinal x = -123
\luacardinal y =  456

\luafloat    x =  123.123
\luafloat    y = -456.456
\stopbuffer

\typebuffer \getbuffer

We have a macro \type {\luaexpression} (not to be confused with \type {\luaexpr}) that
takes an optional keyword:

\startbuffer
- : \luaexpression          {n.x + 2*n.y}
f : \luaexpression float    {n.x + 2*n.y}
i : \luaexpression integer  {n.x + 2*n.y}
c : \luaexpression cardinal {n.x + 2*n.y}
b : \luaexpression boolean  {n.x + 2*n.y}
l : \luaexpression lua      {n.x + 2*n.y}
\stopbuffer

\typebuffer

The serialization can be different for these cases:

\startlines
\tt \getbuffer
\stoplines

The \type {numbers} namespace resolves to a float, integer or cardinal (in that
order) and calculations take place as in \LUA. If you only use integers then
normally \LUA\ will also serialize them as such.

Here is another teaser. Say that we set the \type {scratchdimen} register to
a value:

\startbuffer
\scratchdimen 123.456pt
\stopbuffer

\typebuffer \getbuffer

We now introduce the \type {\nodimen} macro, that can be used this way:

\startbuffer
[\the\scratchdimen] [\the\nodimen\scratchdimen]
\stopbuffer

\typebuffer \getbuffer

which is not that spectacular. Nor is this:

\startbuffer
\nodimen\scratchdimen = 654.321pt
\stopbuffer

\typebuffer \getbuffer

But how about this:

\starttabulate[|T|T|]
\NC \type {\the\nodimen bp \scratchdimen} \NC \the\nodimen bp \scratchdimen \NC \NR
\NC \type {\the\nodimen cc \scratchdimen} \NC \the\nodimen cc \scratchdimen \NC \NR
\NC \type {\the\nodimen cm \scratchdimen} \NC \the\nodimen cm \scratchdimen \NC \NR
\NC \type {\the\nodimen dd \scratchdimen} \NC \the\nodimen dd \scratchdimen \NC \NR
\NC \type {\the\nodimen in \scratchdimen} \NC \the\nodimen in \scratchdimen \NC \NR
\NC \type {\the\nodimen mm \scratchdimen} \NC \the\nodimen mm \scratchdimen \NC \NR
\NC \type {\the\nodimen nc \scratchdimen} \NC \the\nodimen nc \scratchdimen \NC \NR
\NC \type {\the\nodimen nd \scratchdimen} \NC \the\nodimen nd \scratchdimen \NC \NR
\NC \type {\the\nodimen pt \scratchdimen} \NC \the\nodimen pt \scratchdimen \NC \NR
\NC \type {\the\nodimen sp \scratchdimen} \NC \the\nodimen sp \scratchdimen \NC \NR
\stoptabulate

So here we have a curious mix of setter and getter. The setting part is not that
interesting but we just provide it as convenience (and demo). Of course we can
have 10 specific macros instead. Keep in mind that this is a low level macro, so
it doesn't use the normal \CONTEXT\ user interface.

A bit more complex are one or two dimensional arrays. Again this is an example
implementation where users can come up with more ideas.

\startbuffer
\newarray name integers   type integer   nx 2 ny 2
\newarray name booleans   type boolean   nx 2 ny 2
\newarray name floats     type float     nx 2 ny 2
\newarray name dimensions type dimension nx 4
\stopbuffer

\typebuffer \getbuffer

Here we define three two|-|dimensional assays and one one|-|dimensional
array. The type determines the initialization as well as the scanner and
serializer.  Values can be set as follows:

\startbuffer
\arrayvalue integers   1 2 4        \arrayvalue integers   2 1 8
\arrayvalue booleans   1 2 true     \arrayvalue booleans   2 1 true
\arrayvalue floats     1 2 12.34    \arrayvalue floats     2 1 34.12
\arrayvalue dimensions 1   12.34pt  \arrayvalue dimensions 3   34.12pt
\stopbuffer

\typebuffer \getbuffer

If you want to check an array on the console, you can say:

\starttyping
\showarray integers
\stoptyping

We now access some values. Apart from the float these are (sort of) native data
types.

\startbuffer
[\the\arrayvalue integers   1 2]
[\the\arrayvalue booleans   1 2]
[\the\arrayvalue floats     1 2]
[\the\arrayvalue dimensions 1  ]\crlf
[\the\arrayvalue integers   2 1]
[\the\arrayvalue booleans   2 1]
[\the\arrayvalue floats     2 1]
[\the\arrayvalue dimensions   3]
\stopbuffer

\typebuffer

This produces:

\getbuffer

You can of course use these values in many ways:

\startbuffer
\dostepwiserecurse{1}{4}{1}{
    [\the\arrayvalue dimensions #1 :
     \luaexpression dimen {math.sind(30) * a.dimensions[#1]}]
}
\stopbuffer

\typebuffer

This gives:

\getbuffer

In addition to the already seen integer and dimension variables fed back into
\TEX, we also have booleans. These are just integers with the value zero or one.
In order to make their use easier there is a new \type {\ifboolean} primitive
that takes such a bit:

\startbuffer
slot 1 is \ifboolean\arrayequals dimensions 1 0pt zero \else not zero \fi
slot 2 is \ifboolean\arrayequals dimensions 2 0pt zero \else not zero \fi
\stopbuffer

\typebuffer

We get:

\startlines
\getbuffer
\stoplines

A variant is a comparison macro. Of course we can use the dimen comparison
conditional instead:

\startbuffer
slot 1: \ifcase\arraycompare dimensions 1 3pt lt \or eq \else gt \fi zero
slot 2: \ifcase\arraycompare dimensions 2 3pt lt \or eq \else gt \fi zero
slot 3: \ifcase\arraycompare dimensions 3 3pt lt \or eq \else gt \fi zero
slot 4: \ifcase\arraycompare dimensions 4 3pt lt \or eq \else gt \fi zero

slot 1: \ifcmpdim\arrayvalue dimensions 1 3pt lt \or eq \else gt \fi zero
slot 2: \ifcmpdim\arrayvalue dimensions 2 3pt lt \or eq \else gt \fi zero
slot 3: \ifcmpdim\arrayvalue dimensions 3 3pt lt \or eq \else gt \fi zero
slot 4: \ifcmpdim\arrayvalue dimensions 4 3pt lt \or eq \else gt \fi zero
\stopbuffer

\typebuffer

We get:

\startlines
\getbuffer
\stoplines

Anyway, the question is: do we need this kind of trickery, and if so, what more
is needed? But beware: we do have \LUA\ anyway, so there is no need for a complex
user interface at the \TEX\ end just for the sake of it looking more \TEX. The
above shows a bit what is possible.

It is too soon to discuss the low level interface because it still evolves. After
some initial experiments, I decided to follow a slightly different route, and
often the third implementation starts to look what I like more.

% \newarray name whatever type integer nx 100 ny 100
%
% \testfeatureonce{1}{
%     \dorecurse {100} {
%         \dorecurse {100} {
%             \scratchcounter \arrayvalue whatever ##1 ####1 \relax
%         }
%     }
% } \elapsedtime

% \startluacode
% local whatever = { foo = true, bar = true }
%
% interfaces.implement {
%     name      = "MyMatch",
%     public    = true,
%     value     = true,
%     actions   = function(b)
%         -- we gobble spaces
%         return
%             tokens.functionvalues.boolean,
%             whatever[tokens.scanners.word(true)] or false
%     end,
% }
% \stopluacode
%
% [\ifboolean\MyMatch foo YES\else NOP\fi]
% [\ifboolean\MyMatch rab YES\else NOP\fi]
% [\ifboolean\MyMatch bar YES\else NOP\fi]
% [\ifboolean\MyMatch oof YES\else NOP\fi]
%
% \def\Matched#1{\ifboolean\MyMatch #1 }
%
% [\ifcondition\Matched{oof}YES\else NOP\fi]
% [\ifcondition\Matched{foo}YES\else NOP\fi]

% \stopsection

\stopchapter

\stopcomponent