summaryrefslogtreecommitdiff
path: root/macros/latex/exptl/graphicp/div16b.sty
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/exptl/graphicp/div16b.sty
Initial commit
Diffstat (limited to 'macros/latex/exptl/graphicp/div16b.sty')
-rw-r--r--macros/latex/exptl/graphicp/div16b.sty490
1 files changed, 490 insertions, 0 deletions
diff --git a/macros/latex/exptl/graphicp/div16b.sty b/macros/latex/exptl/graphicp/div16b.sty
new file mode 100644
index 0000000000..523fa75026
--- /dev/null
+++ b/macros/latex/exptl/graphicp/div16b.sty
@@ -0,0 +1,490 @@
+%
+% div16.tex -- perform 16.16 bit fixed point division
+% by pts@fazekas.hu at Fri Dec 27 22:40:52 CET 2002 --- ...
+%
+% This .tex file contains TeX macros for double precision multiplication,
+% division of integer and real numbers and image size scaling. The most
+% remarkable macro in this file is \@@muldivletposdim (see the comments in
+% front of it for detailed documentation).
+%
+% If you process this file with
+% Plain TeX, the unit regression testsuite will be run, and the results of
+% the operations issued at the end of this file will be printed to the
+% terminal and into the .log file.
+%
+% The documentation of this macro package is scattered through this file as
+% embedded TeX comments.
+%
+% History
+% ~~~~~~~
+% started at Fri Dec 27 22:40:52 CET 2002
+% --- Sat Dec 28 01:26:52 CET 2002
+% 31.31 bit arithmetic: Tue Jan 7 18:12:53 CET 2003
+% skippable, partial \@@muldivpos at Tue Jan 7 21:00:17 CET 2003
+% skippable, finished, doesn't work at Tue Jan 7 21:43:25 CET 2003
+% first successful test case at Tue Jan 7 22:34:32 CET 2003
+% all test cases OK at Tue Jan 7 23:30:32 CET 2003
+% Fri Jan 24 12:56:23 CET 2003
+% uses laemu.sty
+%
+
+\expandafter\ifx\csname ifLaTeX\endcsname\relax\input laemu.sty\relax\fi%
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{div16b}[2003/01/24 v0.0 high precision div and mul]
+
+%
+% SUXX: `\count0=2\count1' and `\advance\count0 by 2\count1' disallowed
+% Dat: `\count0=-\count1' and `\advance\count0 by -\count1' OK
+%
+% Imp: @@ namespace
+%
+
+% \def\@empty{} % from laemu.sty
+% \catcode`\@=11 % \makeatletter
+
+%\def\loop#1\repeat{%
+% \def\iterate{#1\relax\expandafter\iterate\fi}%
+% \iterate \let\iterate\relax%
+%}%
+%\let\repeat\fi%
+
+% vvv so we can nest a \@@loop inside \loop or vica versa
+\def\@@loop#1\@@repeat{%
+ \def\@@iterate{#1\relax\expandafter\@@iterate\fi}%
+ \@@iterate \let\@@iterate\relax%
+}%
+\let\@@repeat\fi%
+
+%\repeat
+%alma
+%\iftrue
+%korte
+%\loop
+
+\def\@@gobbleend#1\end{}%
+
+%** `\@@aftergroupbegin ... \end' types `...' token-by-token \aftergroup
+%** Argument of \@@aftergroupbegin must not contain \end, {, or }
+\def\@@aftergroupbegin#1{%
+ \ifx#1\end%
+ %\message{done}
+ \else%
+ %\message{\string#1}%
+ \aftergroup#1%
+ \expandafter\@@aftergroupbegin%
+ \fi%
+}%
+
+%** Doesn't make a \global assignment to #1, but keeps its value after the
+%** the next `}'.
+%** @param #1 name of a \count, \dimen or \skip register (i.e \count0 or
+%** \jot)
+\def\@@noresetaftergroup#1{%
+ \@@aftergroupbegin#1=\end%
+ \expandafter\@@aftergroupbegin\the#1 \end%
+ % ^^^ The space before \end is required, because in LaTeX, \end is expandable
+ \aftergroup\relax% finish assignment
+}%
+%** Doesn't work if the definition of #1 contains strange tokens
+%** @param #1 a macro \cs name
+\def\@@keepdefaftergroup#1{%
+ \aftergroup\def%
+ \aftergroup#1%
+ \aftergroup{%
+ \expandafter\@@aftergroupbegin#1\end%
+ \aftergroup}%
+}%
+
+%** Performs the `#1 := #2' assignment, avoids `Dimension too large' error if
+%** both #1 and #2 are \counts.
+%** @param #1 a \count or \dimen register specification
+%** @param #2 a \count or \dimen register specification, an integer, a real
+%** number or a dimension. Numbers are assumed to have unit `sp'.
+\def\@@letdimcount#1#2{{%
+ \afterassignment\@@letdimcount@a\count0=#2 \end%
+ % Dat: now \@@letdimcount@c contains any of "", "sp", ".45", ".45pt"
+ \afterassignment\@@gobbleend\dimen0=1\@@letdimcount@c sp \end% "1", "1sp" "1.45sp" "1.45pt"
+ % Dat: 1.99999999sp == 1sp
+ \ifdim\dimen0=1sp%
+ %\showthe\count0 \message{\the\count0-sp}%
+ \afterassignment\@@gobbleend#1=\count0 sp \end%
+ \else%
+ \afterassignment\@@gobbleend\dimen0=#2 sp \end%
+ \afterassignment\@@gobbleend#1=\dimen0 sp \end%
+ \fi%
+ \@@noresetaftergroup{#1}% return(\T)
+}}%
+\def\@@letdimcount@a#1\end{\def\@@letdimcount@c{#1}}%
+%** Performs the `#1 := #2' assignment, doesn't avoid `Dimension too large'
+%** error if both #1 and #2 are \counts.
+%** `\@@letdimcount#1#2' is the same as `\@@letdimcountany#1#2{sp}', but
+%** \@@letdimcount avoids the error.
+%** @param #1 a \count or \dimen register specification
+%** @param #2 a \count or \dimen register specification, an integer, a real
+%** number or a dimension. Numbers are assumed to have unit `#3'.
+%** @param #3 default metric unit
+\def\@@letdimcountany#1#2#3{{%
+ \afterassignment\@@letdimcount@a\dimen0=#2 #3 bp\end%
+ #1=\dimen0%
+ \@@noresetaftergroup{#1}% return(\T)
+}}%
+
+\iffalse
+% Regression test for \@@letdimcount:
+\@@letdimcount{\count0}{2147483647} \message{\the\count0}
+\@@letdimcount{\count0}{2147483647sp} \message{\the\count0}
+\@@letdimcount{\count0}{2147483647.0sp} \message{\the\count0}
+\@@letdimcount{\count0}{2147483647.999999sp} \message{\the\count0}
+\@@letdimcount{\count0}{16383.99999pt} \message{\the\count0}
+\@@letdimcount{\dimen0}{16383.99999pt} \message{\the\dimen0}
+%\@@letdimcount{\count0}{16384pt} % Dimension too large.
+%\@@letdimcount{\dimen0}{2000000000} % Dimension too large.
+\@@letdimcount{\dimen0}{\count0} \message{\the\dimen0}
+\fi
+
+% ---
+
+% !! why no \space in \write?
+%** Performs the assignment `#1 := \dimen0 / \dimen1',
+%** @param #1 is a name of a TeX dimen/count register (i.e \jot or \count7).
+%** If dimen, then it contains quotient in dimension `pt' (i.e 1in / 1cm
+%** is 2.54pt). If count, then its value divided by 65536 is the quotient
+%** (so this is 16.16 bit fixed-point notation).
+%** \dimen0 must not be negative. \dimen1 must be positive.
+%** Overwrites \dimen2.
+\def\@@divletpos#1{%
+ \dimen2=1pt\relax%
+ \multiply#1 0% `#1 := 0' works for both \dimen and \count registers
+ \loop\ifdim\dimen0>0pt%
+ \immediate\write16{0 a=\the\dimen0:b=\the\dimen1:m=\the\dimen2:q=\the#1}
+ \@@loop\ifdim\dimen1<0.5\dimen0%
+ \advance\dimen1\dimen1%
+ \advance\dimen2\dimen2%
+ % ^^^ this is the only statement where an arithmetic overflow can occur.
+ % an arithmetic overflow means that the divisor is zero is very
+ % small positive, so the result will be a ``dimen too large''
+ \@@repeat%
+ \immediate\write16{1 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1}
+ \@@loop\ifdim\dimen1>\dimen0%
+ \divide\dimen1 2%
+ \divide\dimen2 2%
+ \ifdim\dimen2=0pt%
+ \dimen0\dimen2%
+ \dimen1\dimen2%
+ \fi%
+ \@@repeat%
+ \immediate\write16{2 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1}
+ \ifdim\dimen0>0pt%
+ \@@loop\ifdim\dimen0<8192pt%
+ \multiply\dimen0 2%
+ \multiply\dimen1 2%
+ \@@repeat%
+ \fi%
+ \immediate\write16{3 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1}
+ \advance\dimen0-\dimen1%
+ \advance#1\dimen2%
+ % ^^^ Dat: because of this, \dimen2 must be a dimen (and not a count)
+ \immediate\write16{4 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1}
+ \repeat%
+ %\ifdim\dimen0>0pt \message{SUXX}\fi%
+}%
+
+%** The same as \@@divletpos, except for #2 and #3 may be either positive or
+%** negative, and they might be either dimen or count registers. (A count is
+%** measured in sp.)
+%** Please don't pass \dimen0, \dimen1 or \dimen2 as argument.
+%** @param #1 is a name of a TeX dimen/count register (i.e \jot or \count7).
+%** If dimen, then it contains quotient in dimension `pt' (i.e 1in / 1cm
+%** is 2.54pt). If count, then its value divided by 65536 is the quotient
+%** (so this is 16.16 bit fixed-point notation).
+%** @param #2 and #3 are token lists
+%** containing a _positive_ integer or floating point value
+%** (measured in sp, must be specified explicitly), or a dimen such as `2.54cm'.
+\def\@@divletdim#1#2#3{{%
+ \afterassignment\@@gobbleend\dimen0=#2 sp\end% \dimen0 := #1, convert count -> sp
+ \afterassignment\@@gobbleend\dimen1=#3 sp\end%
+ \ifdim\dimen1=0pt%
+ \divide\dimen0 by0% trigger a TeX division-by-zero error
+ \else%
+ \ifdim\dimen1<0pt%
+ \dimen1-\dimen1%
+ \ifdim\dimen0<0pt%
+ \dimen0-\dimen0%
+ \@@divletpos{#1}%
+ \else
+ \@@divletpos{#1}%
+ #1-#1%
+ \fi%
+ \else%
+ \ifdim\dimen0<0pt%
+ \dimen0-\dimen0%
+ \@@divletpos{#1}%
+ #1-#1%
+ \else
+ \@@divletpos{#1}%
+ \fi%
+ \fi%
+ \fi%
+ % Imp: round to nearest integer
+ \@@noresetaftergroup{#1}%
+}}%
+
+% --- Dobule (high) precision multiplication and division.
+
+% The type co31.31 denotes two \count registers, representing a nonnegative
+% value in 31.31 bit fixed point notation. The sign bits of the registers
+% are unused.
+
+%** Subtracts #3#4 from #1#2, modifies #1#2 in place
+%** @param #1 \control-sequence on less
+%** @param #2 \control-sequence on greater-or-equal
+%** @param #3#4 co31.31
+%** @param #5#6 co31.31
+\def\@@dolt#1#2#3#4#5#6{%
+ \ifnum#3<#5%
+ \expandafter#1%
+ \else%
+ \ifnum#3>#5%
+ \expandafter#2%
+ \else%
+ \ifnum#4<#6%
+ \expandafter#1%
+ \else%
+ \expandafter#2%
+ \fi%
+ \fi%
+ \fi%
+}%
+
+%** Subtracts #3#4 from #1#2, modifies #1#2 in place
+%** @param #1#2 co31.31
+%** @param #3#4 co31.31
+\def\@@letsub#1#2#3#4#5{%
+ \ifnum#2<#4%
+ \advance#1-1%
+ \advance#2-#4%
+ \advance#2-#5% #2 += 0x80000000
+ \else%
+ \advance#2-#4%
+ \fi%
+ \advance#1-#3%
+}%
+
+%** Adds #3#4 to #1#2, modifies #1#2 in place
+%** @param #1#2 co31.31
+%** @param #3#4 co31.31
+%** @param #5 \countx, whose value is -0x80000000 (-2147483648)
+\def\@@letadd#1#2#3#4#5{%
+ % \message{add:\the#3:\the#4}%
+ \advance#2#5% #2 -= 0x80000000
+ \ifnum#2<-#4% orig#2-0x80000000<-#4 <=> orig#2+#4 < 0x80000000
+ \advance#2-#5% #2 += 0x80000000
+ \else%
+ \advance#1 1%
+ \fi%
+ \advance#2#4%
+ \advance#1#3%
+}%
+
+%** Multiplies #1#2 by two, modifies #1#2 in place
+%** @param #1#2 co31.31
+\def\@@lettwice#1#2{%
+ \advance#1#1%
+ \ifnum#2>1073741823%
+ \advance#1 1%
+ \advance#2-1073741824%
+ \fi%
+ \advance#2#2%
+}%
+
+%** Divides #1#2 by two, discards LSB, modifies #1#2 in place
+%** @param #1#2 co31.31
+\def\@@lethalf#1#2{%
+ \divide#2 2%
+ \ifodd#1%
+ \advance#2 1073741824%
+ \fi%
+ \divide#1 2%
+}%
+
+% vvv SUXX: \newif is `\outer'
+\newif\ifLOOP
+% \def\x{ \expandafter\newif\csname ifLOOP\endcsname}%
+
+%** `\@@muldivletposdim#1#2#3#4' performs the assignment `#1 := #2 * #3 / #4'.
+%** `\@@muldivletposdim#1{1pt}#3#4' performs the assignment `#1 := #3 / #4'.
+%** `\@@muldivletposdim#1#2#3{1pt}' performs the assignment `#1 := #2 * #3'.
+%**
+%** All source arguments (#2, #3, #4) can be valid TeX dimen/count values, or
+%** \dimen / \count register specifications. Input values may be negative or
+%** positive or zero.
+%**
+%** -- Before each multiplication and division, the arguments are converted
+%** to `pt' (if the argument is a bare number or a \count register, it is
+%** treated as being a dimension in `sp'), the operation is performed on
+%** the numbers, and `pt' is added
+%** to the resulting number, so the result will be a dimension.
+%** -- The default unit of measure is `sp'. That is, all bare numbers and
+%** \count registers are treated as being a dimension in `sp'. This
+%** applies to both source and target argument. (You may notice that 1pt
+%** == 65536sp. So the operations are performed in a fixed-point
+%** arithmetic with 16 bits in the fraction.)
+%** -- The multiplication is performed exactly (i.e without loss of
+%** precision). However, the division and the 31.31 -> 15.16 rounding
+%** after the division may degrade precision. Internal calculations are
+%** performed in fixed-point arithmetic with 31 bits in the fraction.
+%** -- The following constants are valid source arguments, and represent the
+%** same number (one and a half): `1.5pt', `98304sp', `98304 sp',
+%** `98304', `98304.1sp', `98304.9sp'.
+%** -- To specify the real number `1.5', please specify `1.5 pt'.
+%** -- To specify the integer `42', please specify `42 pt'.
+%** -- If you do only division, set #2 := `1pt'. In that special case you may
+%** specify bare integers (or `... sp') for _both_ #3 and #4.
+%** -- The following are valid arguments: `\count0',
+%** `\dimen7', `\jot', `\interdisplaylinepenalty'
+%** -- Due to a limitation of TeX's fixed-precision arithmetic, it is
+%** impossible to specify exactly `1.5pt' in inches. `0.02075958251953in'
+%** is `1.49974pt', and `0.02075958251954in' is `1.50084pt'. (Of course,
+%** `1.5pt' is `1.5pt'.) That's because TeX converts the real constant
+%** 0.02075958251953 to the fraction `1360/65536' and
+%** 0.02075958251954 to the fraction `1361/65536', before multiplying.
+%** -- If you specify >=2 of \dimen0, \dimen1 and \dimen2 as input, please
+%** specify them in this order.
+%**
+%** @param #1 target, must be a \dimen or \count register
+%** specification (including `\count0' and `\jot'). If a \dimen register,
+%** its maximum will be 1073741823sp. If a \count register, its maximum
+%** will be 2147483647.
+%** @param #2 must be >=0
+%** @param #3 must be >=0
+%** @param #4 must be >0
+%**
+\def\@@muldivletposdim#1#2#3#4{{%
+ %\afterassignment\@@gobbleend\dimen0=#2 sp\end% \dimen0 := #1, convert count -> sp
+ %\afterassignment\@@gobbleend\dimen1=#3 sp\end%
+ %\afterassignment\@@gobbleend\dimen2=#4 sp\end%
+ \countdef\Y 2 \@@letdimcount\Y{#4}%
+ \countdef\F 14 \ifnum\Y<0 \Y-\Y \F-1 \else \F1 \fi%
+% \showthe\Y%
+ \ifnum0=\Y % SUXX: \ifnum\Y=0 doesn't work
+ \divide\Y0% trigger a TeX division-by-zero error (`arithmetic overflow')
+ \else%
+ % vvv declare my input arguments as local variables
+ \countdef\XA 0 \@@letdimcount\XA{#2}% treat dimen as in `sp'
+ \ifnum\XA<0 \XA-\XA \F-\F\fi%
+ \countdef\XB 1 \@@letdimcount\XB{#3}%
+ \ifnum\XB<0 \XB-\XB \F-\F\fi%
+ %\countdef\XA 0 \XA\dimen0% treat dimen as in `sp'
+ %\countdef\XB 1 \XB\dimen1%
+ %\countdef\Y 2 \Y \dimen2%
+ % vvv declare local variables
+ \countdef\C 3%
+ \countdef\B 4%
+ \countdef\R 5%
+ \countdef\S 6%
+ \countdef\T 7%
+ \countdef\U 8%
+ \countdef\D 9%
+ \countdef\A 10%
+ \countdef\L 11%
+ \countdef\M 12%
+ % vvv ++++ comment out the line below to get rid of the error ++++
+ \countdef\G 13 \relax \G-1073741824 \advance\G\G% G := -0x80000000
+ %
+ % Imp: support negative numbers here
+ \ifnum\XB=\Y% shortcut
+ \T\XA%
+ \else%
+ \ifnum\XA=\Y% shortcut
+ \T\XB%
+ \else% really multiply and divide
+ \@@muldivpos%
+ %
+ % vvv convert (round) \T\U: co31.31 -> \T: dimen15.16
+ % return (\U>=0x7fffc000) ? ((\T+1)<<16) : (\T<<16)+((\U+0x4000)>>15)
+ \multiply\T65536% result too large
+ \ifnum\U<2147467264% 0x80000000-0x4000
+ \advance\U16384%
+ \divide\U32768%
+ \advance\T\U%
+ \else%
+ \advance\T65536%
+ \fi%
+ \fi%
+ \fi%
+ \ifnum\F<0 \T-\T\fi%
+ %\afterassignment\@@gobbleend#1=\T sp\end% works if #1 is a dimen/count
+ \@@letdimcount{#1}\T%
+ \@@noresetaftergroup{#1}% return(\T)
+ \fi% else of division-by-zero
+}}%
+
+%** Performs the assignment `\T\U := \XA * \XB / \Y'. Destroys contents of
+%** \XA \XB \Y \C \B \R \S \T \U \D \A \L and \M during operations. All
+%** control sequences mentioned in this paragraph must be predefined \count
+%** registers.
+%** Assumes \newif\LOOP, sets \LOOPfalse upon return
+%** Inputs are: \XA \XB \Y and \G. \XA \XB \Y must be in 15.16 bit
+%** fixed-point notation (i.e dimension in `pt' converted to a \count).
+%** \G must be -0x80000000.
+%** Outputs are \T and \U. \T\U is a real number in 31.31 bit fixed-point
+%** notation (the sign bits are unused).
+%** This is helper routine called by \@@muldivletposdim.
+\def\@@muldivpos{%
+ %\message{A}%
+ \R\XA \divide\R65536 \S-\R \multiply\S65536 \advance\S\XA% my(\R,\S)=(( \XA >>16), \XA &0xffff);
+ %\message{A.S=\the\S,R=\the\XA}%
+ \T\XB \divide\T65536 \U-\T \multiply\U65536 \advance\U\XB% my(\T,\U)=(( \XB >>16), \XB &0xffff);
+ \D0 \A\Y \divide\A65536 \multiply\A32768 % my (\D,\A)=(0, ((( \Y >>16)&0xffff)<<15)); % round() final result
+ \L\R \advance\L\L \multiply\L\T \M0 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), ((\R*\T)<<1, 0)
+ \L\R \multiply\L\U \M\L \divide\L32768 \multiply\L32768 \advance\M-\L \divide\L32768 \multiply\M65536 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), ((\R*\U)>>15, ((\R*\U)&0x7fff)<<16)
+ \L\S \multiply\L\T \M\L \divide\L32768 \multiply\L32768 \advance\M-\L \divide\L32768 \multiply\M65536 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), ((\S*\T)>>15, ((\S*\T)&0x7fff)<<16)
+ \ifnum\S>32767 %
+ \L0 \M\U \multiply\M32768 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), (0, \U<<15)
+ \advance\S-32768%
+ \fi%
+ %\message{B.S=\the\S,U=\the\U}%
+ \L0 \M\S \multiply\M\U \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), (0, \S*\U)
+ \C\Y \divide\C 32768 \B-\C \multiply\B32768 \advance\B\Y \multiply\B65536 % my(\C,\B)=(( \Y >>15),(( \Y &0x7fff)<<16));
+ \L1 \M0 \T0 \U0% my (\L,\M)=(1,0); (\T,\U)=(0,0);
+ %\showthe\D \showthe\A \showthe\C \showthe\B
+ %\message{C}%
+ \loop% vvv while (\D!=0 or \A!=0) % DA != 0 % \D!=0 <=> \D>0
+ %\message{if}%
+ \LOOPfalse%
+ \ifnum\D>0 \LOOPtrue \fi% Dat: must have a space after `>0'
+ \ifnum\A>0 \LOOPtrue \fi%
+ \ifLOOP% loop condition
+ \R\D \S\A \@@lethalf\R\S% (\R,\S)=(\D,\A); _Half(\R,\S);
+ \@@loop% vvv while (_lt((\C,\B),(\R,\S))) % while (CB<DA/2)
+ %\message{ina}%
+ \@@dolt\LOOPtrue\LOOPfalse\C\B\R\S%
+ \ifLOOP% loop condition
+ \@@lettwice\C\B%
+ \ifnum\L=1073741824% Dat: \L\M is a power of 2
+ \divide\L0% die "overflow or division by 0" if \L<0
+ \fi%
+ \@@lettwice\L\M%
+ \@@repeat%
+ \@@loop% vvv while (_lt((\D,\A),(\C,\B)))
+ %\immediate\write16{D=\the\D:A=\the\A:C=\the\C:B=\the\B}%
+ %\message{inb}%
+ \@@dolt\LOOPtrue\LOOPfalse\D\A\C\B%
+ \ifLOOP% loop condition
+ \ifnum\D<1073741824 \@@lettwice\D\A \else \@@lethalf\C\B \fi%
+ \@@lethalf\L\M%
+ \ifnum0=\L \ifnum0=\M %
+ \D0 \A0% (\D,\A)=(0,0) if \L==0 and \M==0;
+ \B0 \C0%
+ \fi\fi%
+ \@@repeat%
+ \@@letsub\D\A\C\B\G%
+ \@@letadd\T\U\L\M\G%
+ \repeat%
+ \ifnum\T>32767\divide\T0\fi% die "overflow2 or division by 0" if \T>=0x8000
+ % ^^^ !! Imp: more meaningful overflow error message (here and at other places)
+ % return value: \T\U: co31.31
+ % to convert it to \dimen, do: (\U>=0x7fffc000) ? ((\T+1)<<16) : (\T<<16)+((\U+0x4000)>>15)
+}%
+
+\endinput%