diff options
Diffstat (limited to 'doc/context/sources/general/manuals/evenmore/evenmore-numbers.tex')
-rw-r--r-- | doc/context/sources/general/manuals/evenmore/evenmore-numbers.tex | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/doc/context/sources/general/manuals/evenmore/evenmore-numbers.tex b/doc/context/sources/general/manuals/evenmore/evenmore-numbers.tex new file mode 100644 index 000000000..9b8e10a56 --- /dev/null +++ b/doc/context/sources/general/manuals/evenmore/evenmore-numbers.tex @@ -0,0 +1,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 |