diff options
author | Karl Berry <karl@freefriends.org> | 2021-11-03 20:48:42 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-11-03 20:48:42 +0000 |
commit | d8d54b2f11fbd0b283af6c46782927b3f5778373 (patch) | |
tree | 502f8ac1354ec54d832e1afcb9f33e94270d812b /Master/texmf-dist | |
parent | 57eeaa0c416fd9cd99918ca2ae7fdd2cc348e0a7 (diff) |
texdimens (3nov21)
git-svn-id: svn://tug.org/texlive/trunk@60934 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r-- | Master/texmf-dist/doc/generic/texdimens/README.md | 168 | ||||
-rw-r--r-- | Master/texmf-dist/tex/generic/texdimens/texdimens.sty | 2 | ||||
-rw-r--r-- | Master/texmf-dist/tex/generic/texdimens/texdimens.tex | 49 |
3 files changed, 160 insertions, 59 deletions
diff --git a/Master/texmf-dist/doc/generic/texdimens/README.md b/Master/texmf-dist/doc/generic/texdimens/README.md index d574ae2ae68..ecd86311931 100644 --- a/Master/texmf-dist/doc/generic/texdimens/README.md +++ b/Master/texmf-dist/doc/generic/texdimens/README.md @@ -10,7 +10,7 @@ LPPL 1.3c. See file LICENSE.md. Development: https://github.com/jfbu/texdimens -Release: `0.9 2021/07/21` +Release: `0.99 2021/11/02` ## Aim of this package @@ -21,11 +21,6 @@ The aim of this package is to address the issue of expressing dimensions (or dimension expressions evaluated by `\dimexpr`) in the various TeX units, to the extent possible. -The descriptions that follow do not explain the details of the exact -internal TeX procedures of parsing dimensional input, they only describe -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 `<dim. expr.>` in the macro descriptions refers to a *dimensional expression* as accepted by `\dimexpr`. The syntax has some @@ -37,7 +32,7 @@ Notice that this is WIP and inaccuracies may exist even relative to descriptions of TeX handlings due to limited time available for the project. -## TeX points and scaled points +## Quick review of basics: TeX points and scaled points TeX dimensions are represented internally by a signed integer which is in absolute value at most `0x3FFFFFFF`, i.e. `1073741823`. The @@ -51,10 +46,10 @@ If `\foo` is a dimen register: - inside `\numexpr`, `\foo` is replaced by `N`, - `\the\foo` produces a decimal `D` (with at most five places) followed -with `pt` (catcode 12 tokens) and this output `Dpt` can serve as input -in a dimen assignment to produce the same dimension as `\foo`. One can -also use the catcode 11 characters `pt` for this. Digits and decimal -mark must have their standard catcode 12. + with `pt` (catcode 12 tokens) and this output `Dpt` can serve as input + in a dimen assignment to produce the same dimension as `\foo`. One can + also use the catcode 11 characters `pt` for this. Digits and decimal + mark must have their standard catcode 12. When TeX encounters a dimen denotation of the type `Dpt` it will compute `N` in a way equivalent to `N = round(65536 D)` where ties are @@ -72,15 +67,30 @@ TeX understands on input further units: `bp`, `cm`, `mm`, `in`, `pc`, `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`, `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). - -TeX associates to each such unit `uu` a fraction `phi` which is a conversion -factor. It is always `>1`: +The `ex`, `em`, and `px` units are handled somewhat differently by (pdf)TeX than +`bp`, `cm`, `mm`, `in`, `pc`, `cc`, `nc`, `dd` and `nd` units. For the former +(let's use the generic notation `uu`), the exact same dimensions are obtained +from an input `D uu` where `D` is some decimal or from `D <dimen>` where `<dimen>` +stands for some dimension register which records `1uu` or `\dimexpr1uu\relax`. In +contrast, among the latter, i.e. the core TeX units, this is false except for the +`pc` unit. + +The explanation is as follows (in this discussion `sp` is kept aside). + +TeX associates (explicitly for the core units, implicitly for the units corresponding +to internal dimensions) to each unit `uu` a fraction `phi` which is a conversion +factor. For the internal dimensions `ex`, `em`, `px` or in the case of multiplying +a dimension by a decimal, this `phi` is morally `f/65536` where `f` is the integer +such that `1 uu=f sp`. For core units however, the hard-coded ratio `n/d` never has a +denominator `d` whici is a power of `2`, except for the `pc` whose associated ratio +factor is `12/1` (and arguably for the `sp` for which morally `phi` is `1/65536` but +we keep it separate from the general discussion). + +As a result the value of `1 uu` as `f sp` is at best irrelevant +or at worst misleading regarding the way TeX parses `D uu`. Notice for example +that `1.00375` is the exact value of the `phi` factor for the `bp` unit but +that `1.00375pt>1bp` ... +Here is a table with the hard-coded conversion factors: uu phi reduced real approximation 1uu in sp= x=[65536phi]/65536 \the<1uu> (Python output) [65536phi] (real approximation) @@ -96,26 +106,28 @@ factor. It is always `>1`: in 7227/100 same 72.27 4736286 72.26998901367188 72.26999pt When TeX parses an assignment `U uu` with a decimal `U` and a unit `uu`, -among those listed above, it first handles `U` as with the `pt` unit. +be it a core unit, or a unit corresponding to an internal dimension, +it first handles `U` as with the `pt` unit. This means that it computes `N = round(65536*U)`. It then multiplies this `N` by the conversion factor `phi` and truncates towards zero the mathematically exact result to obtain an integer `T`: `T=trunc(N*phi)`. The assignment `Uuu` is concluded by defining the value of the dimension to be `Tsp`. -Attention that although the mnemotic is `phi=1uu/1pt`, this formula -definitely does not apply with numerator and denominator interpreted as -TeX dimensions. See the above table. Also, the last column looks like -`round(.,5)` is applied to the previous one, but `\the\dimexpr1dd\relax` -is an exception (in the table `[x]` is the integer part, aka for -non-negative values, the `\trunc()` function). Notice also that -`1.00375` is the exact value of the `phi` factor for the `bp` unit but -`1.00375pt>1bp` (`65782>65781`). - -As `phi>1` (and is not exceedingly close to `1`), the increasing -sequence `0<=trunc(phi)<=trunc(2phi)<=...` is *strictly increasing* and -**it has jumps**: not all TeX dimensions can be obtained from an -assignment not using the `pt` unit. +Regarding the core units, we always have `phi>1`. +The increasing +sequence `0<=trunc(phi)<=trunc(2phi)<=...` is thus *strictly increasing* +and, as `phi` is never astronomically close to `1`, +**it always has jumps**: not all TeX dimensions can be obtained from an +assignment using a core unit distinct from the `pt` (and `sp` of course, +but we already said it was kept out of the discussion here). + +On the other hand when `phi<1`, then the sequence `trunc(N phi)` is not +strictly increasing, already because `trunc(phi)=0` and besides here +`phi=f/65536`, so the `65536` integers `0..65535` are mapped to `f` +integers `0..(f-1)` inducing non one-to-oneness. But +all integers in the `0..(2**30-1)` range will be attained for some input, +so there is surjectivity. The "worst" unit is the largest i.e. the `in` whose conversion factor is `72.27`. The simplest unit to understand is the `pc` as it corresponds @@ -127,14 +139,13 @@ 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 -[Extras?] section the closest dimension attainable both via `in` and via -`cm`. +`12sp` it is impossible to adjust +either the `in` side or the `cm` side to obtain equality. 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`! +`100in==254cm`... (it is already true that `50in==127cm`). 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 @@ -149,7 +160,7 @@ In particular `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 in `sp` unit are given in +other core 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 @@ -170,23 +181,49 @@ Perhaps for these various peculiarities with dimensional units, TeX does not provide an output facility for them similar to what `\the` achieves for the `pt`. -## Macros of this package +## Macros of this package (summary) -The macros defined by the package are expandable, and will expand -completely in an `\edef`, or in a `\dimexpr...\relax` construct. -As they parse their inputs via `\dimexpr` they can be nested (with -the suitable dimension unit added as postfix to nested macro). +This package provides expandable (most are f-expandable, see the code) +macros (they can be nested as they parse their inputs via `\dimexpr`): -Apart from the `\texdimen<uu>up` in case of a negative input, they will -even expand completely under f-expansion. +- `\texdimenpt`, +- `\texdimenUU`, `\texdimenUUup` and + `\texdimenUUdown` with `UU` standing for one of `bp`, `cm`, `mm`, `in`, + `pc`, `cc`, `nc`, `dd` and `nd`, +- `\texdimenbothincm` (and relatives not listed here, see below), +- and `\texdimenwithunit`, added at `0.99`. + +For example `\texdimenbp` takes on input some dimension or dimension +expression and produces on output a decimal `D` such that `D bp` is +guaranteed to be the same dimension as the input, if that one admits any +representation as `E bp`; else it will be either the closest match from +above or from below. The `\texdimenbpup` and `\texdimenbpdown` allow to +choose the direction of approximation. + +`\texdimenwithunit{<dimen1>}{<dimen2>}` produces a decimal `D` such +that `D \dimexpr dimen2\relax` is represented internally the same as +`dimen1` if at all possible, else is a closest match, but one does not +know if from below or above. If `dimen2<1pt` all TeX dimensions `dimen1` +are attainable. If `dimen2>1pt` not all `dimen1` are attainable. 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"). +Do not confuse `\texdimenwithunit{dim}{1bp}` with +`\texdimenbp{dim}`. The former produces a decimal `D` such that +`D\dimexpr 1bp\relax` is represented internally as is `dim` if at all +possible, whereas the latter produces a decimal `D` such that `D bp` is +the one aiming at being the same as `dim`. Using `D\dimexpr 1bp\relax` +implies a conversion factor equal to `65781/65536`, whereas `D bp` +involves the `803/800` conversion factor. + + +## Macros of this package (full list) + 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 + (i.e. all core units except `pt`, `bp` and `nd`), the output `D` of the "up" macros `\texdimen<uu>up{X}`, if used as `Duu` in a dimension assignment or expression, will (naturally) trigger a "Dimension too large" error. @@ -198,6 +235,12 @@ at last step the sign (if result is not zero) is applied (so "down" means 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`. +4. With `\texdimenwithunit{dimen1}{dimen2}` and if `\maxdimen` + is not representable exactly by `dimen2` used as a base dimension, + (which may happen only if `dimen2>1pt`) it might + be that the decimal `D` produced from `\maxdimen` or nearby dimensions + will trigger "Dimension too large" if an attempt to use `D <dimen2>` is + made. `\texdimenpt{<dim. expr.>}` @@ -407,20 +450,20 @@ at last step the sign (if result is not zero) is applied (so "down" means > represents the dimension exactly if possible. If not possible it > will be smallest representable dimension larger than the original one. -`\texdimenbothcmin{<dim. expr.>}` (new with `0.9dev`) +`\texdimenbothcmin{<dim. expr.>}` > Produces a decimal (with up to five decimal places) `D` such that `Din` > is the largest dimension smaller than the original one and > exactly representable both in the `in` and `cm` units. -`\texdimenbothincm{<dim. expr.>}` (new with `0.9dev`) +`\texdimenbothincm{<dim. expr.>}` > Produces a decimal (with up to five decimal places) `D` such that `Dcm` > is the largest dimension smaller than the original one and > exactly representable both in the `in` and `cm` units. It thus represents > the same dimension as `\texdimenbothcmin{<dim. expr.>}in`. -`\texdimenbothcminpt{<dim. expr.>}` (new with `0.9dev`) +`\texdimenbothcminpt{<dim. expr.>}` > Produces a decimal (with up to five decimal places) `D` such that `Dpt` > is the largest dimension smaller than the original one and @@ -428,20 +471,26 @@ at last step the sign (if result is not zero) is applied (so "down" means > the same dimension as the one provided by `\texdimenbothcmin` and > `\texdimenbothincm`. -`\texdimenbothincmpt{<dim. expr.>}` (new with `0.9dev`) +`\texdimenbothincmpt{<dim. expr.>}` > Same as `\texdimenbothcminpt`. -`\texdimenbothcminsp{<dim. expr.>}` (new with `0.9dev`) +`\texdimenbothcminsp{<dim. expr.>}` > Produces an integer (explicit digit tokens) `N` such that `Nsp` > is the largest dimension smaller than the original one and > exactly representable both in the `in` and `cm` units. -`\texdimenbothincmsp{<dim. expr.>}` (new with `0.9dev`) +`\texdimenbothincmsp{<dim. expr.>}` > Same as `\texdimenbothcminsp`. +`\texdimenwithunit{<dim. expr. 1>}{<dim expr. 2>}` + +> Produces a decimal `D` such that `D\dimexpr <dim expr. 2>\relax` is +> considered by TeX the same as `<dim. expr. 1>` if at all possible. +> If not possible it will be a closest match either from above or below. + ## Extras? @@ -457,7 +506,7 @@ as input with the corresponding unit will be beyond `\maxdimen` if the latter is not attainable, i.e. for all units except `bp`, and `nd` (and `pt` but there is no "up" macro for it). -According to a reference on the web by an anonymous contributor the +The dimensions representable with both `in` and `cm` units have the shape `trunc(3613.5*k)sp` for some integer `k`. The largest one smaller than a given dimension will thus differ from it by at most about `0.055pt`, @@ -476,6 +525,13 @@ For the `1in` for example it would be `4737298sp`, i.e. `1.00021in` which differs from TeX's `1in` by `+1012sp` and is obtained also as `2.54054cm` and `72.28543pt`. +## Acknowledgements + +Thanks to Denis Bitouzé for raising an issue on the LaTeX3 tracker which +gave the initial motivation for this package. + +Thanks to Ruixi Zhang for reviving the topic about handling also +the `ex` and `em` cases, which led to `\texdimenwithunit`. <!-- --> diff --git a/Master/texmf-dist/tex/generic/texdimens/texdimens.sty b/Master/texmf-dist/tex/generic/texdimens/texdimens.sty index 8467e69a6f0..1b41c47d68e 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/07/21 v0.9 conversion of TeX dimensions to decimals (JFB)] +\ProvidesPackage{texdimens}[2021/11/02 v0.99 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 8103bef1cd0..d8bf99e0bc4 100644 --- a/Master/texmf-dist/tex/generic/texdimens/texdimens.tex +++ b/Master/texmf-dist/tex/generic/texdimens/texdimens.tex @@ -1,6 +1,6 @@ % 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/07/21 v0.9 +% 2021/11/02 v0.99 % All macros from 0.9delta release have changed names: \texdimen prefix % has replaced \texdimin. \edef\texdimensendinput{\endlinechar\the\endlinechar\catcode`\noexpand _=\the\catcode`\_\relax\noexpand\endinput}% @@ -10,6 +10,12 @@ % Mathematics ("down" and "up" macros) % =========== % +% In the entire discussion here, "uu" stands for some core unit, +% or some unit corresponding to a dimension > 1pt. For the case +% of a unit corresponding to a dimension < 1pt, i.e. to +% \texdimenwithunit macro added at 0.99, refer to the +% comments of issue #2 on the tracker site. +% % Is T sp attainable from unit "uu"?. % If not, what is largest dimension < Tsp which is attainable? % Here we suppose T>0. @@ -325,7 +331,7 @@ % there is ample room for 7227k+1 using \numexpr. % % But this step, as well as initial step to get kmax will require to separate -% hangdling of negative input from positive one. +% handling of negative input from positive one. % % Alternative % ----------- @@ -368,4 +374,43 @@ \def\texdimenbothsp_neg#1#2-#3;{#1-\numexpr(((2*#3-3612)/7227)*7227+1)/2-1\relax\relax}% % \let\texdimenbothcminsp\texdimenbothincmsp +% (\texdimenwithunit, added at 0.99) +% Mathematics +% =========== +% +% <comments to be added> (see discussion #2) +% +% Implementation +% ============== +% +% <comments to be added> (see discussion #2) +% #2 is unit, assumed positive. We will need to branch whether +% #2 is <1pt or >1pt. +% pre-multiplication of #1 by 2 here +\def\texdimenwithunit#1#2{\expandafter\texdimenwithunit_ + \the\numexpr\dimexpr#2\expandafter;\the\numexpr2*\dimexpr#1;}% +\def\texdimenwithunit_#1;#2{\ifnum#1>65535 + \expandafter\texdimenwithunit_A\else\expandafter\texdimenwithunit_B\fi + #2#1;% +}% +% unit>=1pt, handle this as for bp +\def\texdimenwithunit_A#1#2;#3;{\expandafter\texdimenstrippt + \the\dimexpr\numexpr(#1#3+\if-#1-\fi1)*32768/#2sp\relax +}% +% unit<1pt +% if dim1<0, simply negate result for dim1>0 as it can not be 0.0 +\def\texdimenwithunit_B#1{\if-#1\expandafter\texdimenwithunit_Bneg\fi\texdimenwithunit_Ba#1}% +\def\texdimenwithunit_Ba#1#2;#3;{\expandafter\texdimenwithunit_Bb\the\numexpr#1#3+1;#2;}% +\def\texdimenwithunit_Bb#1;#2;{\expandafter\texdimenwithunit_Bc\the\numexpr(#1-#2)/(2*#2);#1;#2;}% +% not adding f-expandability slight overhead here +% oh well, let's do \the\numexpr..+0.ddddd which does the trick and allows +% recycling strippt here with no need of another utility +% (thinking about it it means we could do this for unit >1pt as this method +% works even for \the\dimexpr producing 1pt or more... (as TeX outputs 1.0pt, not 1pt +% so the dot remains to stop the \numexpr scan) +\def\texdimenwithunit_Bc#1;#2;#3;{\the\numexpr#1+\expandafter\texdimenstrippt + \the\dimexpr\numexpr(#2-#1*2*#3)*32768/#3sp\relax}% +% definitly not caring about f-expandability here +\def\texdimenwithunit_Bneg\texdimenwithunit_Ba-#1;#2;% + {-\expandafter\texdimenwithunit_Bb\the\numexpr#2+1;#1;}% \texdimensendinput |