From 44e933e35901329b69a607da2dc65d10b1420c86 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 15 Jul 2021 19:58:54 +0000 Subject: texdimens (15jul21) git-svn-id: svn://tug.org/texlive/trunk@59939 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/generic/texdimens/README.md | 317 ++++++++++++--------- .../texmf-dist/tex/generic/texdimens/texdimens.sty | 2 +- .../texmf-dist/tex/generic/texdimens/texdimens.tex | 278 ++++++++++++++---- 3 files changed, 403 insertions(+), 194 deletions(-) diff --git a/Master/texmf-dist/doc/generic/texdimens/README.md b/Master/texmf-dist/doc/generic/texdimens/README.md index 54f5a530dc9..4f028fe6895 100644 --- a/Master/texmf-dist/doc/generic/texdimens/README.md +++ b/Master/texmf-dist/doc/generic/texdimens/README.md @@ -10,10 +10,12 @@ LPPL 1.3c. See file LICENSE.md. Development: https://github.com/jfbu/texdimens +Release: `0.9delta 2021/07/15` + ## Aim of this package Utilities and documentation related to TeX dimensional units, usable -both with Plain (\input texdimens) and with LaTeX (\usepackage{texdimens}). +both with Plain (`\input texdimens`) and with LaTeX (`\usepackage{texdimens}`). The aim of this package is to address the issue of expressing dimensions (or dimension expressions evaluated by `\dimexpr`) in the various TeX @@ -25,9 +27,15 @@ in a faithful manner the exact outcome of those internal procedures. The reader is supposed to be familiar with TeX basics. This project requires the e-TeX extensions `\dimexpr` and `\numexpr`. +The notation `` in the macro descriptions refers to a +*dimensional expression* as accepted by `\dimexpr`. The syntax has some +peculiarities: among them the fact that `-(...)` (for example `-(3pt)`) +is illegal, one must use alternatives such as `0pt-(...)` or a +sub-expression `-\dimexpr...\relax` for example. Notice that this is WIP and inaccuracies may exist even relative to -descriptions of TeX handlings due to limited time available for the project. +descriptions of TeX handlings due to limited time available for the +project. ## TeX points and scaled points @@ -57,17 +65,16 @@ When `\foo` has been assigned as `D pt`, `\the\foo` will produce some `E pt` where `E` is not necessarily the same as `D`. But it is guaranteed that `E pt` defines the same dimension as `D pt̀`. - ## Further units known to TeX on input TeX understands on input further units: `bp`, `cm`, `mm`, `in`, `pc`, -`cc`, `dd` and `nd`. It also understands font-dependent units `ex` and +`cc`, `nc`, `dd` and `nd`. It also understands font-dependent units `ex` and `em`, and PDFTeX adds the `px` dimension unit. Japanese engines also add specific units. `ex`, `em`, `px` and other engine-dependent units, are all currently excluded from consideration in this project and the rest of this -documentation is only for the `bp`, `cm`, `mm`, `in`, `pc`, `cc`, `dd` +documentation is only for the `bp`, `cm`, `mm`, `in`, `pc`, `cc`, `nc`, `dd` and `nd` units. When we say "unit" we mean one of those or the `pt` (the `sp` is a special case and will be included or not tacitly in the "unit" denomination depending on the case). @@ -76,7 +83,7 @@ TeX associates to each such unit `uu` a fraction `phi` which is a conversion factor. It is always `>1`: uu phi reduced real approximation 1uu in sp= x=[65536phi]/65536 \the<1uu> - [65536phi] (real approximation) + (Python output) [65536phi] (real approximation) -- ---------- ------- ------------------ --------- -------------------- ---------- bp 7227/7200 803/800 1.00375 65781 1.0037384033203125 1.00374pt nd 685/642 same 1.0669781931464175 69925 1.0669708251953125 1.06697pt @@ -116,11 +123,18 @@ to an integer ratio `12`: only dimensions which in scaled points are multiple of `12` are exactly representable in the `pc` unit. This also means that some dimensions expressible in one unit may not be -available with another unit. For example, it turns out that `0.6in` can -not be expressed as `D cm`, whatever the `D`. More surprisingly perhaps -is that `1in==2.54cm` is **false** in TeX! But it is true that -`100in==254cm`! It is also false that `10in==25.4cm` but it is true that -`10in==254mm`! It is false though that `1in==25.4mm`! +available with another unit. For example, and perhaps surprisingly, +there is no decimal `D` which would achieve `1in==Dcm`: the "step" +between attainable dimensions is `72--73sp` for the `in` and `28--29sp` +for the `cm`, and as `1in` differs internally from `2.54cm` by only +`12sp` (see below the `xintsession` verbatim) it is impossible to adjust +either the `in` side or the `cm` side to obtain equality. See in the +[TODO] section the closest dimension attainable both via `in` and via +`cm`. + +In particular `1in==2.54cm` is **false** in TeX, but it is true that +`100in==254cm`... It is also false that `10in==25.4cm` but it is true that +`10in==254mm`... It is false though that `1in==25.4mm`! >>> (\dimexpr1in, \dimexpr2.54cm); @_1 4736286, 4736274 @@ -135,17 +149,22 @@ is that `1in==2.54cm` is **false** in TeX! But it is true that @_5 47362867, 47362867 `\maxdimen` can be expressed only with `pt`, `bp`, and `nd`. For the -other units the maximal attainable dimensions are given in this table: - - 16322.78954 bp (\maxdimen = 1073741823 sp) - 15355.51532 nd (\maxdimen = 1073741823 sp) - 15312.02583 dd (1073741822 sp) - 5758.31741 mm (1073741822 sp) - 1365.33333 pc (1073741820 sp) - 1279.62627 nc (1073741814 sp) - 1276.00215 cc (1073741821 sp) - 575.83174 cm (1073741822 sp) - 226.7054 in (1073741768 sp) +other units the maximal attainable dimensions in `sp` unit are given in +the middle column of the next table. + + maximal allowed the corresponding minimal TeX dimen denotation + (with 5 places) maximal attainable dim. causing "Dimension too large" + --------------- -------------------------- -------------------------- + 16383.99999 pt 1073741823 sp (=\maxdimen) 16383.99999237060546875 pt + 16322.78954 bp 1073741823 sp (=\maxdimen) 16322.78954315185546875 bp + 15355.51532 nd 1073741823 sp (=\maxdimen) 15355.51532745361328125 nd + 15312.02584 dd 1073741822 sp 15312.02584075927734375 dd + 5758.31742 mm 1073741822 sp 5758.31742095947265625 mm + 1365.33333 pc 1073741820 sp 1365.33333587646484375 pc + 1279.62627 nc 1073741814 sp 1279.62627410888671875 nc + 1276.00215 cc 1073741821 sp 1276.00215911865234375 cc + 575.83174 cm 1073741822 sp 575.83174896240234375 cm + 226.70540 in 1073741768 sp 226.70540618896484375 in Perhaps for these various peculiarities with dimensional units, TeX does not provide an output facility for them similar to what `\the` achieves for @@ -153,34 +172,32 @@ the `pt`. ## Macros of this package -All macros are expandable. At time of writing they may not be -f-expandable, but (perhaps) in future final versions will expand fully -in two steps. This refinement is anyhow not really important as TeX -engines now support the `\expanded` primitive. - -All macros handle negative dimensions via their absolute value then -taking the opposite. - -1. At time of writing only the `\texdimin` macros are implemented, -The envisioned "down" and "up" variants are not done yet. - -2. For `dd`, `nc` and `in`, input equal to (or sufficiently close to) -`\maxdimen` will produce also with `\texdimin` an output `D` -representing the next "attainable" dimension above `\maxdimen` hence -using `Duu` will trigger "Dimension too large error". - -3. (not yet) For input equal to (or sufficiently close to) `\maxdimen` and those -units `uu` for which `\maxdimen` is not exactly representable, i.e. all -units except `pt`, `bp` and `nd`, the output `D` of the "up" variants -`\texdiminu` if used as `Duu` in a dimension assignment or -expression will (naturally) trigger "Dimension too large" error. - -4. (not yet) For some units the "down" and "up" macros may trigger "Dimension too -large" during their execution if used with an input too close to -`\maxdimen`. "Safe" variants which are guaranteed never to trigger this -error but have some extra overhead to filter out inputs too close to -`\maxdimen` will *perhaps* be provided. But see 2. and 3. regarding the -usability of the output anyhow. +The macros defined by the package are expandable, and will expand +completely in an `\edef`, or in a `\dimexpr...\relax` construc. +As they parse their inputs via `\dimexpr` they can be nested (with +suitable postfix dimension unit added to inner macro). + +Apart for the `\texdiminup` in case of a negative input, they will +even expand completely under f-expansion. + +Negative dimensions behave as if replaced by their absolute value, then +at last step the sign (if result is not zero) is applied (so "down" means +"towards zero", and "up" means "away from zero"). + +1. For input `X` equal to (or sufficiently close to) `\maxdimen` and + those units `uu` for which `\maxdimen` is not exactly representable + (i.e. all units except `pt`, `bp` and `nd`), the output `D` of the + "up" macros `\texdiminup{X}`, if used as `Duu` in a dimension + assignment or expression, will (naturally) trigger a "Dimension too + large" error. +2. For `dd`, `nc` and `in`, and input `X` equal to (or sufficiently + close to) `\maxdimen` it turns out that `\texdimin{X}` produces + an output `D` such that `Duu` is the first "virtually attainable" TeX + dimension *beyond* `\maxdimen`. Hence `Duu` will trigger on use + "Dimension too large error". +3. Again for the `dd`, `nc` and `in` units, both the "down" and "up" macros + will trigger "Dimension too large" during their execution if used + with an input equal to (or sufficiently close to `\maxdimen`. `\texdiminpt{}` @@ -188,73 +205,73 @@ usability of the output anyhow. `\texdiminbp{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> bp` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D bp` +> represents the dimension exactly if possible. If not possible it > will differ by `1sp` from the original dimension, but it is not > known in advance if it will be above or below. > `\maxdimen` on input produces `16322.78954` and indeed is realized as `16322.78954bp`. -`\texdiminbpd{}` NOT YET +`\texdiminbpdown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> bp` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D bp` +> represents the dimension exactly if possible. If not possible it > will be smaller by `1sp` from the original dimension. -`\texdiminbpu{}` NOT YET +`\texdiminbpup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> bp` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D bp` +> represents the dimension exactly if possible. If not possible it > will be larger by `1sp` from the original dimension. `\texdiminnd{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> nd` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D nd` +> represents the dimension exactly if possible. If not possible it > will differ by `1sp` from the original dimension, but it is not > known in advance if it will be above or below. > `\maxdimen` on input produces `15355.51532` and indeed is realized as `15355.51532nd`. -`\texdiminndd{}` NOT YET +`\texdiminnddown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> nd` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D nd` +> represents the dimension exactly if possible. If not possible it > will be smaller by `1sp` from the original dimension. -`\texdiminndu{}` NOT YET +`\texdiminndup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> nd` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D nd` +> represents the dimension exactly if possible. If not possible it > will be larger by `1sp` from the original dimension. `\texdimindd{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> dd` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D dd` +> represents the dimension exactly if possible. If not possible it > will differ by `1sp` from the original dimension, but it is not > known in advance if it will be above or below. > Warning: the output for `\maxdimen` is `15312.02585` but `15312.02585dd` > will trigger "Dimension too large" error. -> `\maxdimen-1sp` is atteignable via `15312.02583dd`. +> `\maxdimen-1sp` is attainable via `15312.02584dd`. -`\texdiminddd{}` NOT YET +`\texdimindddown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> dd` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D dd` +> represents the dimension exactly if possible. If not possible it > will be smaller by `1sp` from the original dimension. -`\texdiminddu{}` NOT YET +`\texdiminddup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> dd` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D dd` +> represents the dimension exactly if possible. If not possible it > will be larger by `1sp` from the original dimension. `\texdiminmm{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> mm` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D mm` +> represents the dimension exactly if possible. If not possible it > will either be the closest from below or from above, but it is not > known in advance which one (and it is not known if the other choice > would have been closer). @@ -262,44 +279,44 @@ usability of the output anyhow. > `\maxdimen` as input produces on output `5758.31741` and indeed the > maximal attainable dimension is `5758.31741mm` (`1073741822sp`). -`\texdiminmmd{}` NOT YET +`\texdiminmmdown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> mm` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D mm` +> represents the dimension exactly if possible. If not possible it > will be largest representable dimension smaller than the original one. -`\texdiminmmu{}` NOT YET +`\texdiminmmup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> mm` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D mm` +> represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. `\texdiminpc{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> pc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D pc` +> represents the dimension exactly if possible. If not possible it > will be the closest representable one (in case of tie, the approximant > from above is chosen). > `\maxdimen` as input produces on output `1365.33333` and indeed the > maximal attainable dimension is `1365.33333pc` (`1073741820sp`). -`\texdiminpcd{}` NOT YET +`\texdiminpcdown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> pc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D pc` +> represents the dimension exactly if possible. If not possible it > will be largest representable dimension smaller than the original one. -`\texdiminpcu{}` NOT YET +`\texdiminpcup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> pc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D pc` +> represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. `\texdiminnc{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> nc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D nc` +> represents the dimension exactly if possible. If not possible it > will either be the closest from below or from above, but it is not > known in advance which one (and it is not known if the other choice > would have been closer). @@ -308,45 +325,45 @@ usability of the output anyhow. > will trigger "Dimension too large" error. > `\maxdimen-9sp` is attainable via `1279.62627nc`. -`\texdiminncd{}` NOT YET +`\texdiminncdown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> nc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D nc` +> represents the dimension exactly if possible. If not possible it > will be largest representable dimension smaller than the original one. -`\texdiminncu{}` NOT YET +`\texdiminncup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> nc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D nc` +> represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. `\texdimincc{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> cc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D cc` +> represents the dimension exactly if possible. If not possible it > will either be the closest from below or from above, but it is not -> known in advacce which one (and it is not known if the other choice +> known in advance which one (and it is not known if the other choice > would have been closer). > `\maxdimen` as input produces on output `1276.00215` and indeed the > maximal attainable dimension is `1276.00215cc` (`1073741821sp`). -`\texdiminccd{}` NOT YET +`\texdiminccdown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> cc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D cc` +> represents the dimension exactly if possible. If not possible it > will be largest representable dimension smaller than the original one. -`\texdiminccu{}` NOT YET +`\texdiminccup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> cc` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D cc` +> represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. `\texdimincm{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> cm` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D cm` +> represents the dimension exactly if possible. If not possible it > will either be the closest from below or from above, but it is not > known in advance which one (and it is not known if the other choice > would have been closer). @@ -354,22 +371,22 @@ usability of the output anyhow. > `\maxdimen` as input produces on output `575.83174` and indeed the > maximal attainable dimension is `575.83174cm` (`1073741822sp`). -`\texdimincmd{}` NOT YET +`\texdimincmdown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> cm` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D cm` +> represents the dimension exactly if possible. If not possible it > will be largest representable dimension smaller than the original one. -`\texdimincmu{}` NOT YET +`\texdimincmup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> cm` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D cm` +> represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. `\texdiminin{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> in` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D in` +> represents the dimension exactly if possible. If not possible it > will either be the closest from below or from above, but it is not > known in advance which one (and it is not known if the other choice > would have been closer). @@ -378,31 +395,67 @@ usability of the output anyhow. > will trigger "Dimension too large" error. > `\maxdimen-55sp` is maximal attainable dimension (via `226.7054in`). -`\texdiminind{}` NOT YET +`\texdiminindown{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> in` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D in` +> represents the dimension exactly if possible. If not possible it > will be largest representable dimension smaller than the original one. -`\texdimininu{}` NOT YET +`\texdimininup{}` -> Produces a decimal (with up to five decimal places) `D` such that `D -> in` represents the dimension exactly if possible. If not possible it +> Produces a decimal (with up to five decimal places) `D` such that `D in` +> represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. +## Extras? + +As already stated the "up" and also the "down" macros for the `dd`, `nc` +and `in` units will trigger "Dimension too large" if used with inputs +equal to or very near `\maxdimen`. "Safe" variants which are guaranteed +never to trigger this error but have some extra overhead to filter out +inputs very close to `\maxdimen` will *perhaps* be provided if there is +some demand for it. -## TODO +But of course anyhow the output from the "up" macros if used +as input with the corresponding unit will be beyond `\maxdimen` if the +latter is not atteignable, i.e. for all units except `bp`, and `nd` +(and `pt` but there is no "up" macro for it). -Implement the "up" and "down" variants. +Provide a macro `\texdimforbothincm{}` which would output +the nearest dimension simultaneously representable both in `in` and in +`cm`? -Provide a macro `\texdimnearest{in,cm}{}` which provides the -nearest dimension simultaneously representable both in `in` and in `cm`? According to a reference on the web by an anonymous contributor the -available positive dimensions in scaled points have the shape -`floor(3613.5*k) sp` for some integer `k`. So we basically may have a +dimensions representable with both `in` and `cm` units have the shape +`trunc(3613.5*k) sp` for some integer `k`. So we basically may have a delta up to about `1800sp` which is about `0.0275pt` and is still small -(less than one hundredth of a millimeter), so perhaps such a utility for -"safe dimensions" may be useful. Simpler however and more efficient +(less than one hundredth of a millimeter, i.e. less than ten micron), +so perhaps such a utility for +"safe dimensions" may be useful. Here are for example the dimensions +nearest to `1in` and realizable both in `in` and `cm` units: + + >>> \input texdimens.tex\relax + (executing \input texdimens.tex\relax in background) + (./texdimens.tex) + >>> &exact + exact mode (floating point evaluations use 16 digits) + >>> (\texdiminin{4737298sp}); + @_10 1.00021 + >>> (\texdimincm{4737298sp}); + @_11 2.54054 + >>> (\dimexpr1.00021in, \dimexpr2.54054cm); + @_12 4737298, 4737298 + >>> (\texdiminin{4733685sp}); + @_13 0.99945 + >>> (\texdimincm{4733685sp}); + @_14 2.5386 + >>> (\dimexpr0.99945in, \dimexpr2.5386cm); + @_15 4733685, 4733685 + +As promised, one of them, the upper approximation, is at less than +one hundredth of millimeter from the two nearby targets. + +Simpler however and more efficient would be for people to finally adopt the French revolution Système Métrique (rather than setting up giant financial paradises). diff --git a/Master/texmf-dist/tex/generic/texdimens/texdimens.sty b/Master/texmf-dist/tex/generic/texdimens/texdimens.sty index c29f1458e0b..dbf39c72f80 100644 --- a/Master/texmf-dist/tex/generic/texdimens/texdimens.sty +++ b/Master/texmf-dist/tex/generic/texdimens/texdimens.sty @@ -1,5 +1,5 @@ % This is file texdimens.tex, part of texdimens package, which % is distributed under the LPPL 1.3c. Copyright (c) 2021 Jean-François Burnol -\ProvidesPackage{texdimens}[2021/06/30 v0.9beta conversion of TeX dimensions to decimals (JFB)] +\ProvidesPackage{texdimens}[2021/07/15 v0.9delta conversion of TeX dimensions to decimals (JFB)] \@@input texdimens.tex\relax \endinput \ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/texdimens/texdimens.tex b/Master/texmf-dist/tex/generic/texdimens/texdimens.tex index 471a07f807d..189caca95d0 100644 --- a/Master/texmf-dist/tex/generic/texdimens/texdimens.tex +++ b/Master/texmf-dist/tex/generic/texdimens/texdimens.tex @@ -1,101 +1,257 @@ % This is file texdimens.tex, part of texdimens package, which % is distributed under the LPPL 1.3c. Copyright (c) 2021 Jean-François Burnol -% 2021/06/30 v0.9beta +% 2021/07/15 v0.9delta \edef\texdimensendinput{\endlinechar\the\endlinechar\catcode`\noexpand _=\the\catcode`\_\relax\noexpand\endinput}% \endlinechar13\relax% \catcode`\_=11 +% +% Mathematics +% =========== +% % Is T sp attainable from unit "uu"?. Here we suppose T>0. % phi>1, psi=1/phi, psi<1 -% U(N,phi)=floor(N phi) is strictly increasing +% U(N,phi)=trunc(N phi) is strictly increasing % U(N)<= T < U(N+1) iff N = ceil((T+1)psi) - 1 % U(M)< T <= U(M+1) iff M = ceil(T psi) - 1 % Either: -% - M = N, i.e. T is not attainable, M=N < T psi < (T+1) psi <= N+1 -% - M = N - 1, i.e. T is attained, T psi <= N < (T+1) psi, T = floor(N phi) +% case1: M = N, i.e. T is not attainable, M=N < T psi < (T+1) psi <= N+1 +% case2: M = N - 1, i.e. T is attained, T psi <= N < (T+1) psi, T = floor(N phi) % -% In the latter case: -% - as psi<1, |N - (T+0.5) psi| < 0.5, hence N = R := round((T+0.5) psi). -% Also works for T=0 but T<0 would need -0.5. +% Let X = round(T psi). And let Y = trunc(X phi). % -% - if psi<1/2, then N = round(T psi) is simpler formula which works -% also for attainable T<0. +% case1: X can be N or N+1. It will be N+1 iff Y > T. +% case2: X can be N or N-1. It will be N iff trunc((X+1)phi)>T. % -% This R=round((T+0.5) psi) can always be computed via \numexpr because 2T+1 -% will not trigger arithmetic overflow. +% This is not convenient: if Y <= T it might still be that we are in case 2 +% and we must check then if trunc((X+1) phi) > T or not. +% +% If psi < 0.5 +% ------------ +% +% The situation then simplifies: % -% If Tsp>0 is not attainable, this R can produce either N or N+1 (=M+1). +% case1: X can be N or N+1. It will be N+1 iff Y = trunc(X phi) > T. +% case2: X is necessarily N. % -% If we try computing ceil(x) via round(x+0.5) (\numexpr rounds up) -% this means for N, we need round((T+1)psi + 0.5), for example with -% psi = 100/7227 for "in", this gives round((((T+1)200)+7227)/14454) -% feasible via \numexpr only for (circa) 100 T less than \maxdimen. +% Thus: +% a) compute X = round(T psi) +% b) compute Y = trunc(X phi) and test if Y > T. If true, we +% were in case 1, replace X by X - 1, else we were either +% in case 1 or case 2, but we can leave X as is. +% We have thus found N. % -% We could rather compute round(T psi) but we don't know if it gives -% N or N+1. We know it is N if round(T psi)< round((T+1) psi) -% but if the two are the same we don't know if they are both N or -% both N+1. +% The operation Y = trunc(X phi) can be achieved this way: +% i) use \the\dimexpr to convert X sp into D pt, +% ii) use \the\numexpr\dimexpr to convert "D uu" into sp. +% These steps give Y. % -% It is slightly less costly to compute X = round(T psi) than R, -% but if we then realize that X uu < T sp we do not yet know -% if (X+1) uu = T sp or is > Tsp, except if psi<1/2, because -% if T sp is attainable then X = round(T psi) is then necessarily N -% so if X uu < T sp we now that T sp was not attainable. +% This way we find the maximal dimension at most T sp exactly +% representable in "uu" unit. % -% We decide with some hesitation to not split whether psi<1/2 or -% psi>1/2. Reverted! Currently following done only for psi>1/2, -% i.e. bp, nd, dd. +% The computations of X and Y can be done independently of sign of T. +% But the final test has to be changed to Y < T if T < 0 and then +% one must replace X by X+1. So we must filter sign. % -% 1. compute R = round((T+0.5) psi) in \numexpr. This forces -% to check for negative T because then we would want here (T-0.5)psi +% If the goal is only to find a decimal D such that "D uu" is +% exactly T sp in the case this is possible, then things are simpler +% because from X = round(T psi) we get D such as X sp is same as D pt +% and "D uu" will work. +% We don't have to take sign into account for this computation. +% But if T sp was not atteignable we don't know if this X will give +% a D such that D uu < T sp or D uu > T sp. % -% 2. check for the "up" and "down" variants whether R uu is <, =, or > T sp. -% But we have to choose here what "up" and "down" mean for T<0. -% Also, computation of R uu -% may trigger Dimension too large if T sp is not attainable, -% close to \maxdimen, and \maxdimen itself is not attainable. +% If psi > 0.5 +% ------------ % -% For the envisioned "safe versions" we would tabulate first per unit -% what is Rmax such that Rmax uu <= \maxdimen. Then the "safe" versions -% would have an extra check of R. But for \texdimeninuuu it will -% then not be compliant to its definition for inputs close to -% non-attainable \maxdimen. +% For example unit "bp" has phi=803/800. +% +% It is then not true that if T sp is atteignable, the X = round(T psi) +% will always work. +% +% But it is true that R = round((T + 0.5) psi) will always work. +% Here we must use -0.5 if T < 0, though. +% +% This R=round((T+0.5) psi) can always be computed via \numexpr because 2T+1 +% will not trigger arithmetic overflow. +% +% So this gives an approach to find a D such that "D uu" is exactly +% T sp when this is possible. +% +% If Tsp (positive) is not attainable, this R however can produce +% either N or N+1. +% +% But we can decide what happened by computing Z = trunc(R phi). +% If and only if Z > T this means R was N+1. +% +% It is slightly less costly to compute X = round(T psi) than +% R = round((T + 0.5) psi), +% but if we then realize that trunc(X phi) < T we do not yet know +% if trunc((X+1) phi) = T or is > T. +% +% To recapitulate: we have our algorithm for all units to find out +% maximal dimension exactly atteignable in "uu" unit and at most equal +% to (positive) T sp. +% +% Unfortunately the check that Y (in case psi < 0.5) or Z (in case psi > +% 0.5) may trigger a Dimension too large error if T sp was near +% non-atteignable \maxdimen. +% +% For additional envisioned "safe versions" we would tabulate first per unit +% what is the integer Rmax such that trunc(Rmax phi) <= \maxdimen. Then +% the "safe" versions would have an extra check of X or R before +% proceeding further. But the "up macros" supposed to give the next +% dimension above Tsp and exactly atteignable in "uu" unit, if compliant +% to their description can not avoid "Dimension too large" for inputs +% close to non-attainable \maxdimen. % % After having written the macros we will tabulate what is for each unit % the maximal attainable dimension. % -% Hesitation about whether using simpler round(T psi) approach -% for units > 2pt and the \texdimin macros. +% About the macros such as \texdiminbp whose constraints are: +% - give a decimal D such that "Duu" = "T sp" for TeX if possible +% - else give nearest from below or above without knowing +% which one, +% +% there was some hesitation about whether or not using the simpler +% round(T psi) approach for units > 2pt and the \texdimin macros. +% Testing showed that this did not change the output for \maxdimen +% with the units "nc" and "in": still N+1 is returned... +% +% As it has great +% advantage to not have to check the sign of the input, the +% "simpler" approach was chosen for those units to which it +% applies, i.e. the units uu > 2pt (phi>2, psi<1/2), i.e. +% all units except bp, nd and dd. +% +% Implementation +% ============== +% +\def\texdimenfirstofone#1{#1}% +{\catcode`p 12\catcode`t 12 + \csname expandafter\endcsname\gdef\csname texdimenstrippt\endcsname#1pt{#1}}% % -% Testing shows that this would not change output for \maxdimen -% with "nc" and "in": still N+1 is returned... but it has great -% advantage to not have to check the sign. +% down macros: +% for units with phi < 2: +\def\texdimendown_A#1{\if-#1\texdimendown_neg\fi\texdimendown_B#1}% +\def\texdimendown_B#1;#2;{\expandafter\texdimendown_c\the\numexpr(2*#1+1)#2;#1;}% +% for units with phi > 2: +\def\texdimendown_a#1{\if-#1\texdimendown_neg\fi\texdimendown_b#1}% +\def\texdimendown_b#1;#2;{\expandafter\texdimendown_c\the\numexpr#1#2;#1;}% +% shared macros: +\def\texdimendown_c#1;{\expandafter\texdimendown_d\the\dimexpr#1sp;#1;}% +{\catcode`P 12\catcode`T 12\lowercase{\gdef\texdimendown_d#1PT};#2;#3;#4;% + {\ifdim#1#4>#3sp \texdimendown_e{#2}\fi\texdimenfirstofone{#1}}% +}% +% this #2 will be \fi +\def\texdimendown_e#1#2#3#4{#2\expandafter\texdimenstrippt\the\dimexpr\numexpr#1-1sp\relax}% +% negative branch: +% The problem here is that if input very small, output can be 0.0, and we +% do not want -0.0 as output. +% So let's do this somewhat brutally and non-efficiently. +% Anyhow, negative inputs are not our priority. +% #1 is \fi here and #2 is \texdimendown_b or _B: +\def\texdimendown_neg#1#2-#3;#4;#5;{#1\expandafter\texdimenstrippt\the\dimexpr-#2#3;#4;#5;pt\relax}% +% +% up macros: +\def\texdimenup_A#1{\if-#1\texdimenup_neg\fi\texdimenup_B#1}% +\def\texdimenup_B#1;#2;{\expandafter\texdimenup_c\the\numexpr(2*#1+1)#2;#1;}% +\def\texdimenup_a#1{\if-#1\texdimenup_neg\fi\texdimenup_b#1}% +\def\texdimenup_b#1;#2;{\expandafter\texdimenup_c\the\numexpr#1#2;#1;}% +\def\texdimenup_c#1;{\expandafter\texdimenup_d\the\dimexpr#1sp;#1;}% +{\catcode`P 12\catcode`T 12\lowercase{\gdef\texdimenup_d#1PT};#2;#3;#4;% + {\ifdim#1#4<#3sp \texdimenup_e{#2}\fi\texdimenfirstofone{#1}}% +}% +% this #2 will be \fi +\def\texdimenup_e#1#2#3#4{#2\expandafter\texdimenstrippt\the\dimexpr\numexpr#1+1sp\relax}% +% negative branch: +% Here we can me more expeditive than for the "down" macros. +% But this breaks f-expandability. +% #1 will be \fi and #2 is \texdimenup_b or _B: +\def\texdimenup_neg#1#2-{#1-#2}% +% +% pt +% +\def\texdiminpt#1{\expandafter\texdimenstrippt\the\dimexpr#1\relax}% % -% OK let's do this, -% especially as I don't know if I will ever implement "up" and "down". -\def\texdiminpt#1{\expandafter\texdiminpt_\the\dimexpr#1\relax}% -{\catcode`p 12\catcode`t 12\csname expandafter\endcsname\gdef\csname texdiminpt_\endcsname#1pt{#1}}% % bp 7227/7200 = 803/800 -% complications and annoying overhead caused by sign -% and we don't want to evaluate #1 twice in a \dimexpr; if #1 was -% restricted to be a dimen register, we would avoid "\the and re-grab" step. +% \def\texdiminbp#1{\expandafter\texdiminbp_\the\numexpr\dimexpr#1;}% -\def\texdiminbp_#1#2;{\texdiminpt{\numexpr(2*#1#2+\if-#1-\fi1)*400/803sp}}% +\def\texdiminbp_#1#2;{% + \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*400/803sp\relax +}% +% \texdiminbpdown: maximal dim exactly expressible in bp and at most equal to input +\def\texdiminbpdown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*400/803;bp;}% +% \texdiminbpup: minimal dim exactly expressible in bp and at least equal to input +\def\texdiminbpup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*400/803;bp;}% +% % nd 685/642 +% \def\texdiminnd#1{\expandafter\texdiminnd_\the\numexpr\dimexpr#1;}% -\def\texdiminnd_#1#2;{\texdiminpt{\numexpr(2*#1#2+\if-#1-\fi1)*321/685sp}}% +\def\texdiminnd_#1#2;{% + \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*321/685sp\relax +}% +% \texdiminnddown: maximal dim exactly expressible in nd and at most equal to input +\def\texdiminnddown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*321/685;nd;}% +% \texdiminndup: minimal dim exactly expressible in nd and at least equal to input +\def\texdiminndup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*321/685;nd;}% +% % dd 1238/1157 +% \def\texdimindd#1{\expandafter\texdimindd_\the\numexpr\dimexpr#1;}% -\def\texdimindd_#1#2;{\texdiminpt{\numexpr(2*#1#2+\if-#1-\fi1)*1157/2476sp}}% +\def\texdimindd_#1#2;{% + \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*1157/2476sp\relax +}% +% \texdimindddown: maximal dim exactly expressible in dd and at most equal to input +\def\texdimindddown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*1157/2476;dd;}% +% \texdiminddup: minimal dim exactly expressible in dd and at least equal to input +\def\texdiminddup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*1157/2476;dd;}% +% % mm 7227/2540 phi now >2, use from here on the simpler approach -\def\texdiminmm#1{\texdiminpt{(#1)*2540/7227}}% +% +\def\texdiminmm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*2540/7227\relax}% +% \texdiminmmdown: maximal dim exactly expressible in mm and at most equal to input +\def\texdiminmmdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*2540/7227;mm;}% +% \texdiminmmup: minimal dim exactly expressible in mm and at least equal to input +\def\texdiminmmup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*2540/7227;mm;}% +% % pc 12/1 -\def\texdiminpc#1{\texdiminpt{(#1)/12}}% +% +\def\texdiminpc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)/12\relax}% +% \texdiminpcdown: maximal dim exactly expressible in pc and at most equal to input +\def\texdiminpcdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;/12;pc;}% +% \texdiminpcup: minimal dim exactly expressible in pc and at least equal to input +\def\texdiminpcup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;/12;pc;}% +% % nc 1370/107 -\def\texdiminnc#1{\texdiminpt{(#1)*107/1370}}% +% +\def\texdiminnc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*107/1370\relax}% +% \texdiminncdown: maximal dim exactly expressible in nc and at most equal to input +\def\texdiminncdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*107/1370;nc;}% +% \texdiminncup: minimal dim exactly expressible in nc and at least equal to input +\def\texdiminncup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*107/1370;nc;}% +% % cc 14856/1157 -\def\texdimincc#1{\texdiminpt{(#1)*1157/14856}}% +% +\def\texdimincc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*1157/14856\relax}% +% \texdiminccdown: maximal dim exactly expressible in cc and at most equal to input +\def\texdiminccdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*1157/14856;cc;}% +% \texdiminccup: minimal dim exactly expressible in cc and at least equal to input +\def\texdiminccup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*1157/14856;cc;}% +% % cm 7227/254 -\def\texdimincm#1{\texdiminpt{(#1)*254/7227}}% +% +\def\texdimincm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*254/7227\relax}% +% \texdimincmdown: maximal dim exactly expressible in cm and at most equal to input +\def\texdimincmdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*254/7227;cm;}% +% \texdimincmup: minimal dim exactly expressible in cm and at least equal to input +\def\texdimincmup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*254/7227;cm;}% +% % in 7227/100 -\def\texdiminin#1{\texdiminpt{(#1)*100/7227}}% +% +\def\texdiminin#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*100/7227\relax}% +% \texdiminindown: maximal dim exactly expressible in in and at most equal to input +\def\texdiminindown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*100/7227;in;}% +% \texdimininup: minimal dim exactly expressible in in and at least equal to input +\def\texdimininup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*100/7227;in;}% +% \texdimensendinput -- cgit v1.2.3