summaryrefslogtreecommitdiff
path: root/macros/generic/texdimens/texdimens.tex
diff options
context:
space:
mode:
Diffstat (limited to 'macros/generic/texdimens/texdimens.tex')
-rw-r--r--macros/generic/texdimens/texdimens.tex387
1 files changed, 202 insertions, 185 deletions
diff --git a/macros/generic/texdimens/texdimens.tex b/macros/generic/texdimens/texdimens.tex
index de6f20e58f..c3aa10fc73 100644
--- a/macros/generic/texdimens/texdimens.tex
+++ b/macros/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