diff options
author | Norbert Preining <norbert@preining.info> | 2021-11-05 03:01:04 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-11-05 03:01:04 +0000 |
commit | c628b1aa9cf528de739c1de45acf3739561619ed (patch) | |
tree | 07c7fadd26f7d7fb71c242459b79759c42e71274 /macros/generic/texdimens/texdimens.tex | |
parent | e9894be38f76d67f7c8b8e5d16f16e8b14b96f40 (diff) |
CTAN sync 202111050301
Diffstat (limited to 'macros/generic/texdimens/texdimens.tex')
-rw-r--r-- | macros/generic/texdimens/texdimens.tex | 137 |
1 files changed, 110 insertions, 27 deletions
diff --git a/macros/generic/texdimens/texdimens.tex b/macros/generic/texdimens/texdimens.tex index d8bf99e0bc..61086d138d 100644 --- a/macros/generic/texdimens/texdimens.tex +++ b/macros/generic/texdimens/texdimens.tex @@ -1,18 +1,18 @@ % 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/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}% +% 2021/11/04 v0.99d +\edef\texdimensendinput{\endlinechar\the\endlinechar% +\catcode`\noexpand _=\the\catcode`\_% +\catcode`\noexpand @=\the\catcode`\@\relax\noexpand\endinput}% \endlinechar13\relax% -\catcode`\_=11 +\catcode`\_=11 \catcode`\@=11 % only for using \p@ of Plain. Check exists? % % 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 +% 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. % @@ -378,39 +378,122 @@ % Mathematics % =========== % -% <comments to be added> (see discussion #2) -% +% As explained in the README.md, the ex and em units are +% handled by TeX as if multiplying by a conversion factor f/65536 +% (here f sp = 1ex resp. = 1em). +% In particular, for any decimal D, input "D em" is handled the exact +% same way as input "D\dimexpr 1em\relax"; this is not +% the case for the core units except for pt and pc (and sp), whose +% conversion factors are the sole ones with a power of 2 denominator +% (respectively 1, 1, and 65536). The further difference is that +% for the core units apart from sp, the conversion factor is >1. +% +% We assume for this discussion T is non-negative. +% If f/65536 > 1, the analysis is as above : some dimensions T sp +% are not attainable as D uu, but the formula +% N=round((2T+1)*32768/f) +% will give a suitable decimal D via \the\dimexpr N sp\relax. +% (if T=0, we get N=0 as 32768/f<0.5) +% This D will let TeX convert D uu into T sp, if the dimension +% is attainable else it will be a closest match +% either from above or below (not necessarily nearest overall). +% +% If f/65536=1, attention that above formula would give N=1 for +% T=0 (was bug #4). +% +% If f/65536<1, all dimensions Tsp are attainable as D uu. Indeed +% D uu is parsed by TeX via N=round(D*65536), then T=trunc(N*phi), +% with phi=f/65536. Starting from T we need to find an N such that +% T/phi <= N< (T+1)/phi. We first consider v=(T+0.5)/phi. As its +% distance to the extremities is 0.5/phi>0.5,(*) its rounding M +% to an integer verifies automatically T/phi < M < (T+1)/phi, so +% is a candidate. The TeX core conversion of Msp to a Dpt with +% D a decimal of at most 5 fractional digits will provide a D +% such that indeed M=round(D*65536). +% +% (*) attention that this fails if phi=1, we definitely can not +% use the N=round((2T+1)*32768/f) formula for f=65536, it gives +% N=T+1 in place of N=T... It is funny the formula works for all +% f apart from f=65536... +% +% Attention that if T=0, the M=round(0.5/phi) will be at least 1, +% so the produced decimal D will not be 0.0, although it will +% be true that D \dimexpr f sp\relax produces the zero dimension, +% the above analysis being correct even for T=0. +% % Implementation % ============== % -% <comments to be added> (see discussion #2) -% #2 is unit, assumed positive. We will need to branch whether -% #2 is <1pt or >1pt. +% \texdimenwithunit{dim1}{dim2}. dim2>0 assumed. +% We first get f from dim2 and branch according to whether f>65536, +% f=65536 or f<65536. +% We will also need to check the sign of T (dim1=T sp). +% We then compute in both branches round((2T+1)*32768/f), but +% in an indirect way in the f<65536 branch to avoid overflow. +% We will need also to intercept T=0 to avoid producing a non +% pleasing positive D in that case (still correct for f<65536; +% this is issue #3). +% +% In the f<65536 branch we first do the Euclidean division +% 2T+1 = k*2*f + R with 0<=R<2f. The k is obtained as round((2T+1-f)/(2f)) +% which can be computed in a numexpr (and never gives -1 even for T=0) +% Then (2T+1)*32768/f=65536*k + R*32768/f +% Then R*32768/f<=65536-32768/f<65536-32768/65536=65536-0.5 +% Hence the numexpr evaluation gives an integer B<65536. +% +% N.B.: if f>=65536, we still have R*32768/f<65536 as R<2f +% so the only difference is that the B could be here 65536 +% +% From \the\dimexpr Bsp, we get a decimal E < 1, so E=0.ddddd +% (or less digits) and the looked for D will be the contatenation +% k.ddddd with k as obtained earlier. This procedure has no possible +% arithmetic overflow. +% +% #2 is assumed positive. The case #2=1pt=65536sp is special, and +% must be filtered out (issues #4, #6). % 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;% +\let\texdimenorthat\texdimenfirstofone +\def\texdimendothis#1#2\texdimenorthat#3{\fi#1}% +\def\texdimenwithunit_#1;#2{% + \ifnum#1=\p@\texdimendothis\texdimenwithunit_p@\fi + \ifnum#1>\p@\texdimendothis\texdimenwithunit_A\fi + \texdimenorthat\texdimenwithunit_B#2#1;% }% -% unit>=1pt, handle this as for bp +% we premultiplied the first argument by 2... must be undone now! +% and we must avoid overflow. Very underoptimal, but user is not +% supposed to do something as silly as actually using this unit=1pt case! +\def\texdimenwithunit_p@#1#2;#3;{\expandafter\texdimenstrippt\the\dimexpr\numexpr#1#3/2sp\relax}% +% unit>1pt, handle this as for bp. Attention it would be wrong for unit=1pt! \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}% +% unit<1pt. Attention it would be wrong for unit=1pt! +% if dim1<0, simply negate result for dim1>0 as it can not possibly be 0.0 +% Indeed (2T+1)*32768/f will be at least 3*32768/f so its rounding at least 2. +% Add a check for dim1=0 to fix issue #3 +\def\texdimenzerominusfork #10-#2#3\krof {#2}% +\def\texdimenwithunit_B#1{\texdimenzerominusfork + #1-\texdimenwithunit_Bzero + 0#1\texdimenwithunit_Bneg + 0-\texdimenwithunit_Ba + \krof#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) +% I was hesitating between leaving k in the stream (breaking f-expandability) +% and then remove the "0" and trailing "pt" from 0.ddddd pt, but opted +% finally for doing \the\numexpr..+0.ddddd which is f-expandable and allows +% recycling strippt here with no need of another utility. +% +% This means (see the nota bene above) that we could apply this procedure +% also for f>65536, because at worst we will get a \the\numexprk+1.0, which +% gives the correct result. I tested and found about 39% longer execution time +% if dim2>1pt does same calculations as for dim2<1pt, and at the same time +% dim2<1pt was improved about 11% from skipping the conditional \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;}% +% Here, definitely not caring about f-expandability. Or efficiency. +\def\texdimenwithunit_Bneg-{-\texdimenwithunit_Ba{}}% +\def\texdimenwithunit_Bzero#1;#2;{0.0}% \texdimensendinput |