diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/texdimens/texdimens.tex')
-rw-r--r-- | Master/texmf-dist/tex/generic/texdimens/texdimens.tex | 387 |
1 files changed, 202 insertions, 185 deletions
diff --git a/Master/texmf-dist/tex/generic/texdimens/texdimens.tex b/Master/texmf-dist/tex/generic/texdimens/texdimens.tex index de6f20e58fe..c3aa10fc73b 100644 --- a/Master/texmf-dist/tex/generic/texdimens/texdimens.tex +++ b/Master/texmf-dist/tex/generic/texdimens/texdimens.tex @@ -1,27 +1,38 @@ % 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/10 v1.0 +% 2021/11/17 v1.1 \edef\texdimensendinput{\endlinechar\the\endlinechar% \catcode`\noexpand _=\the\catcode`\_% \catcode`\noexpand @=\the\catcode`\@\relax\noexpand\endinput}% \endlinechar13\relax% -\catcode`\_=11 \catcode`\@=11 % only for using \p@ (also \z@ now) of Plain. Check exists? +% only for using \p@ (also \z@ now) of Plain. Check if \p@, \z@ exists? +\catcode`\_=11 \catcode`\@=11 +% so tempted to do \input xintkernel.sty to have some utilities... +% not even a \@gobble in Plain... +\def\texdimenfirstofone#1{#1}% +\def\texdimengobtilminus#1-{}% +\def\texdimenzerominusfork #10-#2#3\krof {#2}% % -% Mathematics (the challenge of the "down" and "up" macros) -% =========== +% \texdimenuu, \texdimenuudown, \texdimenuuup +% =========================================== +% +% Mathematics +% ----------- % % In the entire discussion here, "uu" stands for some core unit, % or some unit corresponding to an internal dimension > 1pt. % -% Is T sp attainable from unit "uu"?. -% If not, what is largest dimension < Tsp which is attainable? -% Here we suppose T>0. +% Main question at the origin of this file was: +% Is T sp attainable from unit "uu"?. +% If not, what is largest dimension < Tsp which is? +% +% Here we suppose T>0. TeX parsing of D uu is equivalent to: % % D uu --> N = round(D * 65536) --> T = trunc (N * phi) % % phi>1 is the conversion factor associated to "uu" % psi=1/phi, psi<1. Define U(N, phi) = trunc (N * phi) -% +% % U(N,phi) is thus the strictly increasing sequence, % indexed by non-negative integers, of non-negative % attainable dimensions. (in sp unit) @@ -35,23 +46,16 @@ % % - the largest attainable dimension not exceeding T sp % is obtained via the integer "Zd = ceil((T+1)psi) - 1 = N", -% (i.e. find D with Zd=round(65536 D) then "D uu" is "down" approximation) +% (i.e. find D with Zd=round(65536 D) then "D uu" is "down" +% approximation) % % - the smallest attainable dimension at least equal to T sp % is obtained from the integer "Zu = ceil(T psi) = M + 1" % % - the two "Z"'s are either equal (i.e. T is attained) or Zu=Zd+1. % -% The round((T+0.5)*psi) based approach (basis of the "\texdimenUU" macros) -% ------------------------------------- -% -% Recall in all of this T > 0. And phi>1, psi=1/phi<1. -% -% Let's return to our analysis of the -% -% U(N)<= T < U(N+1) and U(M)< T <= U(M+1) -% -% equations. We will also use the N=Zd, and M+1=Zu notations. +% \texdimenUU macros use round((T+0.5)*psi) +% ----------------------------------------- % % case1: M = N, i.e. Zd<Zu, i.e. T is not attainable: % M=N=Zd < T psi < (T+1) psi <= N+1=Zu @@ -61,8 +65,8 @@ % and check if it is < T or > T. % % As will be explained later trunc(R phi) can be computed very -% easily by hijacking TeX's handling of dimensions, we don't -% have to launch into \numexpr evaluations for that. +% easily by hijacking TeX's handling of dimensions, no \numexpr +% chains is needed. % % case2: M = N - 1, i.e. T = Zd = Zu is attained: % T psi <= N < (T+1) psi, T = trunc(N phi) @@ -76,38 +80,38 @@ % % - compute R = round((T+0.5) psi) % -% - if T is attained, then T = trunc(R * phi) +% - if T is attained, then T = trunc(R * phi) % -% - if T is not attained then either { Zd = R and Zu = R+1 } or -% {Zd = R-1 and Zu = R}. +% - if T is not attained then either { Zd = R and Zu = R+1 } or +% {Zd = R-1 and Zu = R}. % -% How do we check if R = Zd or Zu? We need to evaluate trunc(R phi) and -% compare it with T. This trunc(R phi) can be computed the following way: +% How do we check if R = Zd or Zu? We need to evaluate trunc(R phi) and +% compare it with T. This trunc(R phi) can be computed the following way: % -% - obtain D pt from \the\dimexpr R sp. Knuth's algorithm guarantees +% - obtain D pt from \the\dimexpr R sp. Knuth's algorithm guarantees % that R = round(D * 65536) % -% - then D uu where uu is the unit with conversion factor phi is -% converted by TeX into "trunc(R phi) sp", i.e. trunc(R phi) = -% \number\dimexpr Duu\relax, where D pt = \the\dimexpr Rsp\relax. +% - then D uu where uu is the unit with conversion factor phi is +% converted by TeX into "trunc(R phi) sp", i.e. trunc(R phi) = +% \number\dimexpr Duu\relax, where D pt = \the\dimexpr Rsp\relax. % % Conclusion: % % 1. the macro \texdimenuu does the one-liner R=round((T+0.5) psi) -% then \the\dimexpr Rsp\relax and strips the "pt" unit +% then \the\dimexpr Rsp\relax gives "Dpt", the "pt" is removed, +% we have a decimal D such that "Duu" does what one wants. % -% 2. macros \texdimenuuup and \texdimenuudown go further and check -% which one of Zd or Zu is R, obtaining thus Zd or Zu. -% [update: this describes the macros prior to 1.0 release] +% 2. to get Zd (resp. Zu) one can use the D obtained in 1. and check +% if "D uu" is at most (or at least) the user input dimension. % % For units with conversion factor phi>2, a simplification is possible. -% In that case let X = round(T psi) (it has the advantage compared to +% In that case let X = round(T psi) (it has the advantage compared to % R that we can apply the formula without checking the sign of T). % % Going back to our earlier analyis, now with psi < 0.5 (1uu>2pt) % % case1: T is not attainable -% M=N=Zd < T psi < (T+1) psi <= N+1=Zu +% M=N=Zd < T psi < (T+1) psi <= N+1=Zu % As Zd < T psi < Zu, we have round(T psi) = Zd or Zu % % case2: T is attained, i.e. T psi <= N < (T+1) psi. @@ -153,8 +157,8 @@ % This made all usable even with \maxdimen input and besided, proved % on average slightly faster. % -% Overcoming the ceil() stumbling block (i.e. the 1.0 manner for "up/down") -% ------------------------------------- +% Overcoming the ceil() stumbling block for \texdimenUU{up,down} +% -------------------------------------------------------------- % % I will in what follows refer to trunc(), floor() or ceil() only for % positive arguments, obtained as ratios x/y or sometimes as a numexpr @@ -182,7 +186,7 @@ % with x = n*100/7227, and n = 1+r, so 0<n<=7227 % % Here we have a nice situation 0 < x <= 100. Then: -% +% % ceil(x) = 100 - floor(100 - x) % = 100 - (round(100 - x + 0.5) - 1) % = 101 - round(100 * (1 - n/7227) + 0.5) @@ -203,10 +207,6 @@ % Zu = ceil(T*100/7227) and for all core TeX units. See the comments % below for all obtained formulae and some additional details. % -% Implementation -% ============== -% -\def\texdimenfirstofone#1{#1}% {\catcode`p 12\catcode`t 12 \csname expandafter\endcsname\gdef\csname texdimenstrippt\endcsname#1pt{#1}}% % @@ -216,24 +216,22 @@ % % bp 7227/7200 = 803/800 % -\def\texdimenbp#1{\expandafter\texdimenbp_\the\numexpr\dimexpr#1;}% -\def\texdimenbp_#1#2;{% - \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*400/803sp\relax -}% +\def\texdimenbp#1{\expandafter\texdimenstrippt\the\dimexpr\numexpr(% + \expandafter\texdimen_bpnddd_signcheck + \the\numexpr2*\dimexpr#1\relax\relax)*400/803sp\relax}% +\def\texdimen_bpnddd_signcheck#1{\texdimengobtilminus#1-1+#1}% % % nd 685/642 % -\def\texdimennd#1{\expandafter\texdimennd_\the\numexpr\dimexpr#1;}% -\def\texdimennd_#1#2;{% - \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*321/685sp\relax -}% +\def\texdimennd#1{\expandafter\texdimenstrippt\the\dimexpr\numexpr(% + \expandafter\texdimen_bpnddd_signcheck + \the\numexpr2*\dimexpr#1\relax\relax)*321/685sp\relax}% % % dd 1238/1157 % -\def\texdimendd#1{\expandafter\texdimendd_\the\numexpr\dimexpr#1;}% -\def\texdimendd_#1#2;{% - \expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*1157/2476sp\relax -}% +\def\texdimendd#1{\expandafter\texdimenstrippt\the\dimexpr\numexpr(% + \expandafter\texdimen_bpnddd_signcheck + \the\numexpr2*\dimexpr#1\relax\relax)*1157/2476sp\relax}% % % mm 7227/2540 phi now >2, use from here on the X = round(T psi) approach % @@ -259,8 +257,8 @@ % \def\texdimenin#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*100/7227\relax}% % -% "no test" ceil()-based approach to up and down macros (release 1.0) -% ===================================================== +% "up and down macros" +% -------------------- % % The notation <u/v> means u/v in numexpr, which does rounding % away from zero. It is essential that the argument be >-0.5 else <x+1> @@ -523,8 +521,11 @@ \def\texdimeninup_c#1;#2;{\expandafter\texdimeninup_d\the\numexpr#2-7227*#1;#1;}% \def\texdimeninup_d#1;#2;{\numexpr#200+101-(1452627-2*#100)/14454sp\relax}% % -% Mathematics ("both in and cm", added at release 0.9) -% =========== +% "both in and cm" +% ================ +% +% Mathematics +% ----------- % % Let a and b be two non-negative integers such that U = floor(a 7227/100) = % floor(b 7227/254). It can be proven that a=50k, b=127k for some integer k. @@ -548,7 +549,7 @@ % avoiding overflow. % % Implementation -% ============== +% -------------- % % Regarding the output in pt or sp, we seem to need floor(k 7227/2). % The computation of floor(k 7227/2) as <(7227 k - 1)/2> would require to @@ -566,43 +567,33 @@ % else if U > T, replace it by U - 3614. This is alternative road to the maximal % floor(k 7227/2) at most equal to T. % -% There is some slight under-efficiency to share macros across the 3 end targets -% as I added one layer of parentheses. \def\texdimenbothincm#1{\expandafter\texdimenstrippt\the\dimexpr - \expandafter\texdimenboth_a\the\numexpr\dimexpr#1;127);}% + \expandafter\texdimenboth_a + \the\numexpr\dimexpr#1\relax\relax-3612)/7227)*127sp\relax}% \def\texdimenbothcmin#1{\expandafter\texdimenstrippt\the\dimexpr - \expandafter\texdimenboth_a\the\numexpr\dimexpr#1;50);}% + \expandafter\texdimenboth_a + \the\numexpr\dimexpr#1\relax\relax-3612)/7227)*50sp\relax}% +\def\texdimenboth_a#1{\texdimengobtilminus#1\texdimenboth_neg-\numexpr((2*#1}% +\def\texdimenboth_neg-\numexpr((2*-{-\numexpr((2*}% +% +\def\texdimenbothincmsp#1{\number + \expandafter\texdimenbothsp_a\the\numexpr\dimexpr#1\relax\relax + -3612)/7227)*7227+1)/2-1\relax}% \def\texdimenbothincmpt#1{\expandafter\texdimenstrippt\the\dimexpr - \expandafter\texdimenboth_a\the\numexpr\dimexpr#1;7227+1)/2-1;}% -\let\texdimenbothcminpt\texdimenbothincmpt -\def\texdimenboth_a#1{\if-#1\texdimenboth_neg\fi\texdimenboth_b#1}% -% The opening parenthesis ( is closed in #2, it was added to share "pt" output -% with the two others -\def\texdimenboth_b#1;#2;{\numexpr(((2*#1-3612)/7227)*#2sp\relax}% -% negative branch. This is expanded in a \dimexpr so we can insert the - -% in front of the \numexpr. -% #1 is \fi here and #2 is \texdimenboth_b -\def\texdimenboth_neg#1#2-#3;#4;{#1-\numexpr(((2*#3-3612)/7227)*#4sp\relax}% -% -% \texdimenbothincmsp is done separately as I found no easy way to share -% its macros with the others; alternative would have been to make it the -% core, and derive the others from it, (\texdimencm{\texdimenbothincmsp{...}sp}) -% but then they would be less efficient than their current versions. -% (it is a bit ironical to worry about not creating too many macros -% in such a small package, by the way) -\def\texdimenbothincmsp#1{\the\numexpr\expandafter\texdimenbothsp_a\the\numexpr\dimexpr#1;}% -\def\texdimenbothsp_a#1{\if-#1\texdimenbothsp_neg\fi\texdimenbothsp_b#1}% -\def\texdimenbothsp_b#1;{(((2*#1-3612)/7227)*7227+1)/2-1\relax}% -% #1 is \fi -% we need to regrab here or to add a \numexpr..\relax layer to -% \texdimenbothsp_b (parentheses could do but using 0-(...) syntax) -% finally doing the job of \texdimenbothsp_b directly -\def\texdimenbothsp_neg#1#2-#3;{#1-\numexpr(((2*#3-3612)/7227)*7227+1)/2-1\relax\relax}% + \expandafter\texdimenbothsp_a\the\numexpr\dimexpr#1\relax\relax + -3612)/7227)*7227+1)/2-1sp\relax}% +\def\texdimenbothsp_a#1{\texdimengobtilminus#1\texdimenbothsp_neg-\numexpr(((2*#1}% +\def\texdimenbothsp_neg-\numexpr(((2*-{-\numexpr(((2*}% % +\let\texdimenbothcminpt\texdimenbothincmpt \let\texdimenbothcminsp\texdimenbothincmsp % -% Mathematics and Algorithm ("both mm and bp", added at release 1.0) -% ========================= +% "both mm and bp" +% ================ +% +% Mathematics and Algorithm +% ------------------------- +% % We start from a dimension expressed in sp unit, "T sp". Assume T positive. % We know how to get largest "X sp <= T sp" which is exactly expressible % in mm unit @@ -640,7 +631,6 @@ % via an already positioned \dimexpr waiting to output final result. \def\texdimenbothbpmm#1{\expandafter\texdimenstrippt\the\dimexpr \expandafter\texdimenbothbpmm_fork\the\numexpr\dimexpr#1;}% -% the \texdimenzerominusfork is defined in the \texdimenwithunit section \def\texdimenbothbpmm_fork#1{\texdimenzerominusfork #1-\texdimenbothbpmm_zero 0#1\texdimenbothbpmm_neg @@ -693,9 +683,8 @@ % now the lazy way for \texdimenbothmmbp \def\texdimenbothmmbp#1{\expandafter\texdimenstrippt\the\dimexpr \expandafter\texdimenbothmmbp_a\the\numexpr\dimexpr\texdimenbothbpmm{#1}mm;}% -% or remove the + and do \if-#1-\else+\fi1 ? % If zero at this stage, we will correctly get 0.0 in the end -\def\texdimenbothmmbp_a#1#2;{\numexpr(2*#1#2+\if-#1-\fi1)*400/803sp\relax}% +\def\texdimenbothmmbp_a#1#2;{\numexpr(2*#1#2+\texdimengobtilminus#1-1)*400/803sp\relax}% % \texdimenbothbpmmpt and its alias \texdimenbothmmbppt \def\texdimenbothbpmmpt#1{\texdimenpt{\texdimenbothbpmm{#1}mm}}% \let\texdimenbothmmbppt\texdimenbothbpmmpt @@ -703,12 +692,15 @@ \def\texdimenbothbpmmsp#1{\the\numexpr\dimexpr\texdimenbothbpmm{#1}mm\relax\relax}% \let\texdimenbothmmbpsp\texdimenbothbpmmsp % -% Mathematics (\texdimenwithunit, added at release 0.99, modified at 1.0) -% =========== +% \texdimenwithunit +% ================= +% +% Mathematics +% ----------- +% +% The ex and em units are handled by TeX as if multiplying by a +% conversion factor f/65536 (here f sp = 1ex resp. = 1em). % -% 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 @@ -732,7 +724,7 @@ % 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. +% T/phi <= N< (T+1)/phi. % % This is equivalent to ceil(T/phi)<= N < ceil((T+1)/phi) % @@ -749,7 +741,7 @@ % It is not obvious to compute this ceil(T/phi) without overflow. % % Implementation -% ============== +% -------------- % % \texdimenwithunit{dim1}{dim2} % @@ -769,61 +761,98 @@ % or f<=65536. % We will also need to check the sign of T (dim1=T sp). % f>65536: we compute round((2T+1)*32768/f) -% f=65536: merged with f<65536 branch -% f<65536: we compute ceil(T*65536/f) +% f=65536: merged with f<65536 branch (as it works and avoids checking for it) +% f<65536: 0.99 release used the round((2T+1)*32768/f) formula +% (it is funny that it works for all f except for f=65536) % -% rationale: round((2T+1)*32768/f) which was used at 0.99 -% would be ok [if f<65536 not f=65536 ! cf #3, #4] -% also for this branch -% -% BUT it diverges noticeably from naive expectation -% dim1/dim2 "=" T*65536/f the more so when f is small. +% But the output then diverges noticeably from mathematical +% dim1/dim2 "=" T*65536/f, the more so the smaller the dim2. % See issue #16 and also the discussion at #13. % -% As was explained in comments to issue #2 which asked for a -% \texdimenwithunit the ceil(T*65536/f) is the smallest -% allowable choice +% 1.0 release thus opted for the ceil(T*65536/f) formula, as it is the +% smallest allowable choice, hence the closest to naive dim1/dim2. % % To avoid arithmetic overflow issues we first do the euclidean -% division T = k f + r, 0<= r < f +% division T = k f + r, 0<= r < f, 0<= k +% +% The final result in "sp" unit would be k*65536 + C with +% C = ceil(r * 65536/f). % -% The final result in sp units will be k*65536 + ceil(r * 65536/f) -% We don't do this k*65536 explicitly as it may overflow -% but output the decimal k + E where E is the conversion -% to a decimal 0.ddddd or 1.0 of "ceil(r * 65536/f) sp" -% (which is at most 65536sp=1pt so E is at most 1.0). +% We don't do this k*65536 explicitly as it may overflow and is +% anyhow unneeded: the output will be the integer k concatenated with +% the decimal E given by TeX from \the\dimexpr C sp, i.e. such that +% E pt = C sp, with C = ceil(r*65536/f). +% +% As r is at most f-1, r*65536/f is at most 65536-65536/f, and as +% 65536>=f (we use this branch also for f=65536), C<=65535. Hence +% E is never 1.0 but always "0.<some digits>" % % To compute the Euclidean quotient k in \numexpr we use there -% (2T-f)/(2f) i.e. round((2T-f)/2f) = trunc(T/f) -% as we are careful to never have T=0 inthere... +% <(2T-f)/(2f)> i.e. round((2T-f)/2f) = trunc(T/f) +% as we are careful to never have T=0 in-there... % % Computing C = ceil(r * 65536/f) in \numexpr is the delicate -% part, as r can be as large as f-1 hence 65535 and r*65536 would -% overflow. We could compute R=round(r*65536/f) ("scaling operation") -% then C=R+1 if R*f-65536*r<0, else C=R. +% part, as r can be as large as f-1 hence 65535 and 65535*65536 would +% overflow. Let's try anyhow to see how to compute ceil() with round(): +% +% C = 65536 - floor(65536 * (1 - r/f)) +% = 65536 - round(65536*(f-r)/f - 0.5) (as r<f so no "round(-0.5)=-1") +% = 65536 - <(2*65536*(f-r) - f)/(2f)> +% +% Here the problem is with small r, and large f, and naive implementation +% of this formula can overflow... +% Let's thus retreat to eTeX scaling operation <r*65536/f> as it +% operates with temporary double precision. +% +% R=round(r*65536/f)=<r*65536/f> is either C-1 or C +% Let x = mathematical exact r*65536/f: +% - if R < x, C=R+1. +% - if R >= x, C=R. +% +% C=ceil(r*65536/f) is the smallest integer such that +% trunc(C*f/65536)>=r, or more precisely (as f<=65536) the +% smallest integer with trunc(C*f/65536)=r. So trunc(R*f/65536) +% will be either r (then R=C), or r-1, then R=C-1. +% +% Method from release 1.0: let's TeX compute P=trunc(R*f/65536) itself! +% Via P sp = E <f sp> where E is a decimal such that E pt = R sp. +% So +% - if P>=r (it is then equal to r in fact) then C=R +% - if P<r (it is then equal to r-1), then C=R+1. +% +% New method: overflow-free pure \numexpr way to get the sign of R-x. +% +% Write R=4*S+t, with say S=<R/4>=round(R/4), so t=-2,-1,0,+1. +% +% Then R*f-65536*r = 4*(S*f-16384*r)+t*f % -% The problem is then: how to get the sign of R*f-65536*r without -% overflow? I considered various ways. +% We know that R<=C<65536, so <R/4> <= 16384 and 16384*f +% is at worst 2**(14+16)=\maxdimen+1 but we will be in \numexpr, +% so no overflow! +% And r<f<=65536 so also 16384*r can not overflow. +% As |R - r*65536/f|<= 0.5, then |R*f-65536*r|<= f/2, so +% 4*|S*f-16384*r| <= 2.5*f is very far from overflow risk % -% But in the end, opted for simply this: -% - get R=round(r*65536/f) as \the\numexpr r*65536/f ("scaling" no overflow) -% - hence get E pt=\the\dimexpr R sp -% - let TeX compute E<f sp>: if it turns out < r sp, -% then C=R+1, -% else C=R. Done. +% T>0, 0<f<=65536 +% k = <(2*T-f)/(2*f)> +% r = T - k*f +% R=<r*65536/f> +% S=<R/4> +% t=R-4*S +% +% IF: 4*(S*f-16384*r)+t*f < 0 THEN C=R+1 ELSE C=R. +% +% Ept=\the\dimexpr Csp, E=0.d...d +% +% End expansion with the contatenation k.d...d % \def\texdimenwithunit#1#2{\expandafter\texdimenwithunit_i % no premultiplication of dim1 by 2 as was done for technical % reasons when dim2<1pt branch used round((2T+1)*32768/f) - \the\numexpr\dimexpr#2\expandafter;\the\numexpr\dimexpr#1;}% -% -% so tempted to do \input xintkernel.sty to have some utilities... -% not even a \@gobble in Plain... -\let\texdimenorthat\texdimenfirstofone -\def\texdimendothis#1#2\texdimenorthat#3{\fi#1}% -\def\texdimengobtominus#1-{}% + \the\numexpr\dimexpr#2\expandafter;\the\numexpr\dimexpr#1;% +}% \def\texdimenwithunit_i#1{% - \texdimengobtominus#1\texdimenwithunit_switchsigns-% + \texdimengobtilminus#1\texdimenwithunit_switchsigns-% \texdimenwithunit_j#1% }% \def\texdimenwithunit_switchsigns-\texdimenwithunit_j-#1;#2% @@ -831,7 +860,7 @@ % due to \texdimenwithunit_Bneg we can not simply prefix dim1 % with -, as -0 is bad there. So let's check also if #2 is 0 \texdimenzerominusfork - #2-\texdimenwithunit_Bzero % abusive double usage + #2-\texdimenwithunit_Bzero % also used in \texdimenwithunit_B 0#2\texdimenwithunit_j % abusive shortcut 0-{\texdimenwithunit_ic#2}% \krof @@ -839,19 +868,14 @@ }% \def\texdimenwithunit_ic#1#2;{\texdimenwithunit_j#2;-#1}% \def\texdimenwithunit_j#1;#2{% - % \ifnum#1=\p@\texdimendothis\texdimenwithunit_p@\fi - \ifnum#1>\p@\texdimendothis\texdimenwithunit_A\fi - \texdimenorthat\texdimenwithunit_B#2#1;% + \ifnum#1>\p@\texdimenwithunit_A\fi + \texdimenwithunit_B#2#1;% }% -% not needed, as the "ceil" branch is fine to use for f = 65536 -% \def\texdimenwithunit_p@#1#2;#3;{% -% \expandafter\texdimenstrippt\the\dimexpr#1#3sp/2\relax -% }% -% unit>1pt, handle this as for bp. Attention it would be wrong for -% unit=1pt! -\def\texdimenwithunit_A#1#2;#3;{% +% unit>1pt, handle this as for bp. +% Attention it would be wrong for unit=1pt! +\def\texdimenwithunit_A\fi\texdimenwithunit_B#1#2;#3;{\fi \expandafter\texdimenstrippt - \the\dimexpr\numexpr(2*#1#3+\if-#1-\fi1)*32768/#2sp\relax + \the\dimexpr\numexpr(2*#1#3+\texdimengobtilminus#1-1)*32768/#2sp\relax % - fine if dim1>0, <0, or =0 % - with *\p@ better but an early doubled dim2 would complicate 1pt % test and not sure if doing \p@/(2*#2) here advantageous @@ -862,47 +886,40 @@ % will even be at least 2 if f<65536). % The dim1=0 case must get filtered out due to way of calculating the % "ceil" in \numexpr -\def\texdimenzerominusfork #10-#2#3\krof {#2}% \def\texdimenwithunit_B#1{\texdimenzerominusfork #1-\texdimenwithunit_Bzero 0#1\texdimenwithunit_Bneg - 0-\texdimenwithunit_Ba + 0-\texdimenwithunit_Ba \krof#1}% +\def\texdimenwithunit_Bzero#1;#2;{0.0}% \def\texdimenwithunit_Ba#1#2;#3;{% - % no overflow possible from 2*#1#3=2*dim1 - \expandafter\texdimenwithunit_Bb\the\numexpr(2*#1#3-#2)/(2*#2);#1#3;#2;% -}% -% now k;T;f;. Get the remainder r=T-k*f + % no overflow possible from 2*#1#3 in \numexpr + \expanded{\expandafter\texdimenwithunit_Bb + \the\numexpr(2*#1#3-#2)/(2*#2);#1#3;#2;}% +}% +% I could have inserted \expanded\bgroup in \texdimenwithunit_B +% but then needed to modify _Bzero (used also by \texdimenwithunit_switchsigns) +% so easiest is to simply defined Bneg explicitly here rather than +% insisting on deriving it from _Ba +\def\texdimenwithunit_Bneg-#1;#2;{% + \expanded{-\expandafter\texdimenwithunit_Bb + \the\numexpr(2*#2-#1)/(2*#1);#2;#1;}% +}% +% now k;T;f;. Get the remainder r=T-k*f, and abandon k in the token stream. +% the earlier \expanded maintains f-expandability \def\texdimenwithunit_Bb#1;#2;#3;{% - \expandafter\texdimenwithunit_Bc\the\numexpr#2-#1*#3;#1;#3;% + #1\expandafter\texdimenwithunit_Bc\the\numexpr#2-#1*#3;#3;% }% -% now r;k;f;. We can start \the\numexpr k+ .... -% and there we will need to get R=round(r*65536/f), Ept=Rsp, -% check if E"f sp"<"r sp", if yes replace R by R+1 else keep E etc. -\def\texdimenwithunit_Bc#1;#2;#3;{% -% \the\numexpr k+0.ddddd is handy because it can well be actually -% \the\numexpr k+1.0, now that we use ceil approach in this branch - \the\numexpr#2+\expandafter\texdimenwithunit_Bd - \the\numexpr #1*\p@/#3;#1;#3;% +% now r;f;. Get R=<r*65536/f> +\def\texdimenwithunit_Bc#1;#2;{% + \expandafter\texdimenwithunit_Bd\the\numexpr #1*\p@/#2;#1;#2;% }% -% R;r;f; -\def\texdimenwithunit_Bd#1;{% - \expandafter\texdimenwithunit_Be\the\dimexpr#1sp;#1;% +% R;r;f; Is 4*(S*f-16384*r)+t*f < 0 ? with S=<R/4>, t=R-4S +\def\texdimenwithunit_Bd#1;#2;#3;{% + \expandafter\texdimenwithunitstripzeroandpt + \the\dimexpr\numexpr#1% + \ifnum\numexpr 4*((#1/4)*#3-16384*#2)<\numexpr(4*(#1/4)-#1)*#3\relax + +1\fi sp\relax }% -% Ept;R;r;f; -% #1=0.ddd... or 1.0 but has no end marker hence the -% \texdimenfirstofone{#1} as in \texdimendown_d and \texdimenup_d -{\catcode`P 12\catcode`T 12 -\lowercase{\gdef\texdimenwithunit_Be#1PT};#2;#3;#4;{% - \ifdim#1\dimexpr#4sp<#3sp \texdimenwithunit_Bf{#2}\fi - \texdimenfirstofone{#1}% - }% -}% -% #2 is \fi. Add a dimen storage \onesp for 1sp? -\def\texdimenwithunit_Bf#1#2\texdimenfirstofone#3{#2% - \expandafter\texdimenstrippt\the\dimexpr#1sp+1sp\relax -}% -% Here definitely not caring about f-expandability. Or efficiency. -\def\texdimenwithunit_Bneg-{-\texdimenwithunit_Ba{}}% -\def\texdimenwithunit_Bzero#1;#2;{0.0}% +{\catcode`P12\catcode`T12\lowercase{\gdef\texdimenwithunitstripzeroandpt0#1PT}{#1}}% \texdimensendinput |