]> git.donarmstrong.com Git - lib.git/blobdiff - texmf/realcalc.tex
add missing realcalc
[lib.git] / texmf / realcalc.tex
diff --git a/texmf/realcalc.tex b/texmf/realcalc.tex
new file mode 100644 (file)
index 0000000..be46167
--- /dev/null
@@ -0,0 +1,581 @@
+%% realcalc.tex
+%%
+%% (C) Frank Buchholz, Jan. 1993
+%% e-mail: buchholz@lusty.informatik.uni-dortmund.de
+%  User documentation: All lines starting with two %
+%  Try grep to extract these lines.
+%%
+%% Real arithmetic with big values and high precision.
+%% Calculations are done with 9 decimal digits.
+%% Usable with TeX and LaTeX.
+%%
+%% Parameter:
+%%
+%%     <macro> Macro, witch catches the result.
+%%     <value> String or macro witch expands to a value in the range 
+%%                 from -2147483647.999999999 to 2147483647.999999999
+%%     <precision> Number from 0 to 9
+%%
+%% Functions:
+%%
+
+% Don't read this file twice
+\ifx\Radd\undefined \else \endinput \fi
+
+% Make "@" be a letters
+\chardef\catamp=\the\catcode`\@
+\catcode`@=11
+\def\@Rversion{Version 1.0, Jan. 1993}
+\message{`Real arithmetic', \@Rversion (C) Frank Buchholz}
+
+% Allocation of temporary registers
+\newcount\@ta
+\newcount\@tb
+%
+\newcount\@xs  % Sign of 1st value
+\newcount\@xi  % Integer part of 1st value
+\newcount\@xf  % Fractional part of 1st value
+%
+\newcount\@ys  % Sign of 2nd value
+\newcount\@yi  % Integer part of 2nd value
+\newcount\@yf  % Fractional part of 2nd value
+%
+\newcount\@mil \@mil=1000000000        % 10^9
+%
+\countdef\@xa240
+\countdef\@xb241
+\countdef\@xc242
+\countdef\@xd243
+\countdef\@xe244
+\countdef\@ya245
+\countdef\@yb246
+\countdef\@yc247
+\countdef\@yd248
+\countdef\@ye249
+\let\@f=\@tb
+\let\@product=\@ta
+
+\chardef\@zero=0
+
+%%     \Radd<macro><value><value>              Addition
+\def\Radd#1#2#3{\@callc\@Radd#1{#2}{#3}}
+
+%%     \Rsub<macro><value><value>              Subtraction
+\def\Rsub#1#2#3{\@callc\@Radd#1{#2}{-#3}}
+
+\def\@Radd#1#2.#3.#4\relax#5.#6.#7\relax{%
+  % #1 Macro, witch gets the result
+  % #2 integer part of 1st value 
+  % #3 fractional part of 1st value
+  % #4 dummy to swallow everthing after the 2nd '.'
+  % #5 integer part of 2nd value 
+  % #6 fractional part of 2nd value
+  % #7 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#2}{#3}%
+  \@readvalue\@ys\@yi\@yf{#5}{#6}%
+  %
+  % Add integer parts
+  \@ta=\@xi \advance\@ta\@yi%
+  %
+  % Add fractional parts if they are not zero
+  \ifnum\@xf=\@zero%
+    \ifnum\@yf=\@zero%
+      \@tb=\@zero%
+    \else%
+      \@longadd%
+    \fi%
+  \else%
+    \@longadd%
+  \fi%
+  %
+  % Store result
+  \@store#1\@ta\@tb%
+}
+
+\def\@longadd{%
+    % Propagate sign to fractional parts
+    \multiply\@xf\@xs \multiply\@yf\@ys%
+    %
+    % Add fractional parts
+    \@tb=\@xf \advance\@tb\@yf%
+    %
+    % Calculate carry
+    \ifnum\@tb<\@zero% 
+      \ifnum\@tb<-\@mil      \advance\@ta -\@ne \advance\@tb\@mil  \fi% 
+    \else% 
+      \ifnum\@tb<\@mil \else \advance\@ta \@ne \advance\@tb-\@mil \fi% 
+    \fi%
+} 
+
+%%     \Rmul<macro><value><value>              Multiplication
+\def\Rmul#1#2#3{\@callc\@Rmul#1{#2}{#3}}
+
+\def\@Rmul#1#2.#3.#4\relax#5.#6.#7\relax{%
+  % #1 Macro, witch gets the result
+  % #2 integer part of 1st value 
+  % #3 fractional part of 1st value
+  % #4 dummy to swallow everthing after the 2nd '.'
+  % #5 integer part of 2nd value 
+  % #6 fractional part of 2nd value
+  % #7 dummy to swallow everthing after the 2nd '.'
+  %
+  % How to do real multiplications:
+  % Split values in various parts
+  % x y = 1234 567890 . 123 456 789
+  % ->   xa   xb       xc  xd  xe
+  % ->   ya   yb       yc  yd  ye
+  % Do 21 (!) integer multiplications if there are any fractional parts
+  % r = x * Y
+  % -> r =   xi*yi
+  %       + (xa*yc + xa*yc                  )*10^3 
+  %       + (xa*yd + xd*ya                  )*10^-0 
+  %       + (xa*ye + xe*ya  +  xb*yc + xc*yb)*10^-3 
+  %       + (xb*yd + xd*yb  +  xc*yc        )*10^-6 
+  %       + (xb*ye + xe*yb  +  xc*yd + xd*yc)*10^-9 
+  %       + (xc*ye + xe*yc  +  xd*yd        )*10^-12 
+  %       + (xd*ye + xe*yd                  )*10^-15 
+  %       + (xe*ye                          )*10^-18
+  %
+  % -> r = ((((( xe*ye                              / 1000 
+  %            + xd*ye + xe*yd                   ) / 1000
+  %           + xc*ye + xe*yc  +  xd*yd         ) / 1000
+  %          + xb*ye + xe*yb  +  xc*yd + xd*yc ) / 1000
+  %         + xb*yd + xd*yb  +  xc*yc         ) / 1000
+  %        + xa*ye + ye*xa  +  xb*yc + xc*yb ) / 1000
+  %       + xa*yd + xd*ya + (xa*yc + ya*xc)*1000 + xi*yi
+  % The last three digigs are saved just before the divisions.
+  %
+  % Init 
+  %
+  \@readvalue\@xs\@xi\@xf{#2}{#3}%
+  \@readvalue\@ys\@yi\@yf{#5}{#6}%
+  %
+  % Sign
+  \multiply\@xi\@xs%
+  \multiply\@yi\@ys%
+  \multiply\@xs\@ys%
+  %
+  \@product=\@zero%
+  % 
+  \ifnum\@xf=\@zero%
+    \ifnum\@yf=\@zero%
+      % No fractional parts
+      \edef\@frac{000000000}   % digits of fractional part  
+    \else%
+      \@longmul                        % Long multiplication           
+    \fi%
+  \else%
+    \@longmul                  % Long multiplication           
+  \fi%
+  %
+  % Multiply integer parts
+  \count@=\@xi \multiply\count@\@yi%
+  \advance\@product\count@%
+  %
+  % Sign
+  \multiply\@product\@xs%
+  %
+  % Store result
+  \edef#1{\number\@product.\@frac}%
+}
+
+% Do long multiplication
+\def\@longmul{%
+    % Split values in pieces
+    \@f=1000000%
+    \count@=\@xi%              
+    \divide\count@\@f                                  \@xa=\count@%
+    \multiply\count@-\@f       \advance\count@\@xi     \@xb=\count@%
+    \count@=\@xf%              
+    \divide\count@\@f                                  \@xc=\count@%
+    \multiply\count@-\@f       \advance\count@\@xf%    
+    \@f=1000%
+    \@xe=\count@%
+    \divide\count@\@f                                  \@xd=\count@%
+    \multiply\count@-\@f       \advance\count@\@xe     \@xe=\count@%
+    % 
+    \@f=1000000%
+    \count@=\@yi%              
+    \divide\count@\@f                                  \@ya=\count@%
+    \multiply\count@-\@f       \advance\count@\@yi     \@yb=\count@%
+    \count@=\@yf%              
+    \divide\count@\@f                                  \@yc=\count@%
+    \multiply\count@-\@f       \advance\count@\@yf%    
+    \@f=1000%
+    \@ye=\count@%
+    \divide\count@\@f                                  \@yd=\count@%
+    \multiply\count@-\@f       \advance\count@\@ye     \@ye=\count@%
+    %
+    \edef\@frac{}                              % digits of fractional part
+    % 
+    \@mul ee         \relax\@shift             % 10^-18
+    \@mul de ed       \relax\@shift            % 10^-15
+    \@mul ce ec dd    \relax\@shift            % 10^-12
+    \@mul be eb cd dc \relax\@saveshift                % 10^-9
+    \@mul bd db cc    \relax\@saveshift                % 10^-6
+    \@mul ae ea bc cb \relax\@saveshift                % 10^-3
+    \multiply\@xa\@f  \multiply\@xc\@f         % 10^3
+    \@mul ad da ac ca \relax%                  
+}
+
+\def\@mul#1#2#3{%
+  \count@=\csname @x#1\endcsname%
+  \multiply\count@\csname @y#2\endcsname%
+  \advance\@product\count@%
+  %
+  \ifx#3\relax%
+    \let\next=\relax% 
+  \else%
+    \let\next=\@mul%
+  \fi%
+  \next#3%
+}
+
+\def\@shift{%
+  \divide\@product\@f%
+}
+
+\def\@saveshift{%
+  % Save rightmost digits 
+  \count@=\@product%
+  \divide\@product\@f%
+  \multiply\@product\@f%
+  \advance\count@-\@product%
+  \advance\count@\@f%
+  \edef\@frac{\expandafter\@ignorenext\number\count@\@frac}%
+  %
+  \divide\@product\@f%
+}
+
+%%     \Rdiv<macro><value><value>              Division
+\def\Rdiv#1#2#3{\@callc\@Radd#1{#2}{#3}}
+
+\def\@Rdiv#1#2.#3.#4\relax#5.#6.#7\relax{%
+  % #1 Macro, witch gets the result
+  % #2 integer part of 1st value 
+  % #3 fractional part of 1st value
+  % #4 dummy to swallow everthing after the 2nd '.'
+  % #5 integer part of 2nd value 
+  % #6 fractional part of 2nd value
+  % #7 dummy to swallow everthing after the 2nd '.'
+  %
+  \message{Error: Rdiv not ready}
+  %
+  \@readvalue\@xs\@xi\@xf{#2}{#3}%
+  \@readvalue\@ys\@yi\@yf{#5}{#6}%
+  %
+  \ifnum\@yi=\@zero
+    \@xi=\@zero
+  \else
+    \divide\@xi\@yi
+  \fi
+  %
+  \@store#1\@xi\@xf%
+}
+
+%%     \Rneg<macro><value>             Negation
+\def\Rneg#1#2{%
+  % Expand the value and split it into the integer and the fractional part
+  \edef\next{\noexpand\@Rneg\noexpand#1#2..\noexpand\relax}%
+  \next%
+}
+
+\def\@Rneg#1#2.#3.#4\relax{
+  % #1 Macro, witch gets the result
+  % #2 Integer part of value
+  % #3 Fractional part of value
+  % #4 Remaining tokens
+  %
+  \@readvalue\@xs\@xi\@xf{#2}{#3}%
+  %
+  % Change sign
+  \multiply\@xi-\@ne%
+  \multiply\@xf-\@xs%
+  % 
+  % Store result
+  \@store#1\@xi\@xf%
+}
+
+%%
+%%     \Rtrunc<macro><precision><value> Truncate value to specified precision
+\def\Rtrunc#1#2#3{%
+  % Expand parameter and split the value into the integer and fractional part 
+  \edef\next{\noexpand\@Rtrunc\noexpand#1#2#3..\noexpand\relax}%
+  \next%
+}
+
+\def\@Rtrunc#1#2#3.#4.#5\relax{%
+  % #1 Macro, witch gets the result
+  % #2 Number of decimal places
+  % #3 Integer part of value
+  % #4 Fractional part of value
+  % #5 dummy to swallow everthing after the 2nd '.'
+  %
+  \count@=#2%
+  \edef\next{\empty}%
+  \ifnum\count@>\@zero%
+    \expandafter\@@Rtrunc#4000000000\relax%
+  \fi%
+  \edef#1{#3\next}%
+}
+
+\def\@@Rtrunc#1#2#3#4#5#6#7#8#9{%
+  % #1...#9 fractional part, padded with trailing zeros
+  \edef\next{.#1%
+    \ifnum\count@>1 #2\fi%
+    \ifnum\count@>2 #3\fi%
+    \ifnum\count@>3 #4\fi%
+    \ifnum\count@>4 #5\fi%
+    \ifnum\count@>5 #6\fi%
+    \ifnum\count@>6 #7\fi%
+    \ifnum\count@>7 #8\fi%
+    \ifnum\count@>8 #9\fi%
+  }%
+  \@swallow%
+}
+
+%%
+%%     \Rifle<value><value>            Test v1 < v2
+\def\Rifle#1#2{\@callb\@Rifle{#1}{#2}}
+
+\def\@Rifle#1.#2.#3\relax#4.#5.#6\relax{%
+  % #1 integer part of 1st value 
+  % #2 fractional part of 1st value
+  % #3 dummy to swallow everthing after the 2nd '.'
+  % #4 integer part of 2nd value 
+  % #5 fractional part of 2nd value
+  % #6 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#1}{#2}%
+  \@readvalue\@ys\@yi\@yf{#4}{#5}%
+  %
+  \ifnum\@xs<\@ys% 
+    \Rtesttrue% 
+  \else%
+    \ifnum\@xs>\@ys% 
+      \Rtestfalse%
+    \else%
+      \Rtestfalse%
+      \ifnum\@xi<\@yi \Rtesttrue \fi%
+      \ifnum\@xi=\@yi%
+       \multiply\@xf\@xs \multiply\@yf\@ys%
+       \ifnum\@xf<\@yf \Rtesttrue \fi% 
+      \fi%
+    \fi%
+  \fi%
+  %
+  \ifRtest%
+}
+
+%%     \Rifeq<value><value>            Test v1 = v2
+\def\Rifeq#1#2{\@callb\@Rifeq{#1}{#2}}
+
+\def\@Rifeq#1.#2.#3\relax#4.#5.#6\relax{%
+  % #1 integer part of 1st value 
+  % #2 fractional part of 1st value
+  % #3 dummy to swallow everthing after the 2nd '.'
+  % #4 integer part of 2nd value 
+  % #5 fractional part of 2nd value
+  % #6 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#1}{#2}%
+  \@readvalue\@ys\@yi\@yf{#4}{#5}%
+  %
+  \Rtestfalse%
+  \ifnum\@xi=\@yi\ifnum\@xf=\@yf \Rtesttrue \fi\fi%
+  \ifRtest%
+}
+
+%%     \Rifgt<value><value>            Test v1 > v2
+\def\Rifgt#1#2{\@callb\@Rifgt{#1}{#2}}
+
+\def\@Rifgt#1.#2.#3\relax#4.#5.#6\relax{%
+  % #1 integer part of 1st value 
+  % #2 fractional part of 1st value
+  % #3 dummy to swallow everthing after the 2nd '.'
+  % #4 integer part of 2nd value 
+  % #5 fractional part of 2nd value
+  % #6 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#1}{#2}%
+  \@readvalue\@ys\@yi\@yf{#4}{#5}%
+  %
+  \ifnum\@xs>\@ys% 
+    \Rtesttrue% 
+  \else%
+    \ifnum\@xs<\@ys% 
+      \Rtestfalse% 
+    \else%
+      \Rtestfalse%
+      \ifnum\@xi>\@yi \Rtesttrue \fi%
+      \ifnum\@xi=\@yi% 
+       \multiply\@xf\@xs \multiply\@yf\@ys%
+       \ifnum\@xf>\@yf \Rtesttrue \fi% 
+      \fi%
+    \fi%
+  \fi%
+  %
+  \ifRtest%
+}
+
+%%     \Rifneg<value>                  Test v < 0
+\def\Rifneg#1{\@calla\@Rifneg{#1}}
+
+\def\@Rifneg#1.#2.#3\relax{%
+  % #1 Integer part of value
+  % #2 Fractional part of value
+  % #3 dummy to swallow everthing after the 2nd '.'
+   %
+   \@readvalue\@xs\@xi\@xf{#1}{#2}%
+   %
+   \ifnum\@xs<0 \Rtesttrue \else \Rtestfalse \fi%
+   \ifRtest%
+ }
+
+%%     \Rifzero<value>                 Test v = 0
+\def\Rifzero#1{\@calla\@Rifzero{#1}}
+
+\def\@Rifzero#1.#2.#3\relax{%
+  % #1 Integer part of value
+  % #2 Fractional part of value
+  % #3 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#1}{#2}%
+  %
+  \Rtestfalse%
+  \ifnum\@xi=\@zero \ifnum\@xf=\@zero \Rtesttrue \fi \fi%
+  \ifRtest%
+}
+
+%%     \Rifpos<value>                  Test v >= 0
+%%                                     Take care to have a corresponding \fi
+\def\Rifpos#1{\@calla\@Rifpos{#1}}
+
+\def\@Rifpos#1.#2.#3\relax{%
+  % #1 Integer part of value
+  % #2 Fractional part of value
+  % #3 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#1}{#2}%
+  %
+  \ifnum\@xs<0 \Rtestfalse \else \Rtesttrue \fi%
+  \ifRtest%
+}
+
+%%     \Rifint<value>                  Test v is an integer value
+%%                                     Take care to have a corresponding \fi
+\def\Rifint#1{\@calla\@Rifint{#1}}
+
+\def\@Rifint#1.#2.#3\relax{%
+  % #1 Integer part of value
+  % #2 Fractional part of value
+  % #3 dummy to swallow everthing after the 2nd '.'
+  %
+  \@readvalue\@xs\@xi\@xf{#1}{#2}%
+  %
+  \ifnum\@xf=0 \Rtesttrue \else \Rtestfalse \fi%
+  \ifRtest%
+}
+
+% Utility macros
+
+\def\@calla#1#2{%
+  % #1 Macro to call
+  % #2 Value
+  % Expand the value and split them into the integer and the fractional part
+  \edef\next{\noexpand#1#2..\noexpand\relax}%
+  \next%
+}
+
+\def\@callb#1#2#3{%
+  % #1 Macro to call
+  % #2 1st value
+  % #3 2nd value
+  % Expand the values and split them into the integer and the fractional parts 
+  \edef\next{\noexpand#1#2..\noexpand\relax#3..\noexpand\relax}%
+  \next%
+}
+
+\def\@callc#1#2#3#4{%
+  % #1 Macro to call
+  % #2 Macro, witch gets the result
+  % #3 1st value
+  % #4 2nd value
+  % Expand the values and split them into the integer and the fractional parts
+  \edef\next{\noexpand#1\noexpand#2#3..\noexpand\relax#4..\noexpand\relax}%
+  \next%
+}
+
+%%     \ifRtest ... \else ... \fi      Re-execute the last test
+\newif\ifRtest
+
+%
+% Read value
+%
+\def\@readvalue#1#2#3#4#5{%
+  % #1   macro to catch the sign ( -1 or 1 )
+  % #2   macro to catch the integer part (maybe negative)
+  % #3   macro to catch the fractional part (positive)
+  % #4.#5 value
+  %
+  % Regular expression [-...d]d...["."[d...]]
+  % Attention: There has to be at least one digit between "-" and "."!
+  %
+  % Integer part
+  \if !#4! #2=\@zero \else #2=#4 \fi%
+  %
+  % Sign
+  \ifnum#2<\@zero #1=-\@ne \else #1=\@ne \fi%
+  \ifnum#2=\@zero \ifnum #4#5<\@zero #1=-\@ne \fi \fi%
+  %
+  % Fractional part
+  \if !#5!% 
+    #3=\@zero%
+  \else%
+    \@@setcount@#5000000000\relax%
+    #3=\count@%
+  \fi%
+}
+
+% Set count@ to fractional part with trailing zeros
+\def\@@setcount@#1#2#3#4#5#6#7#8#9{%
+  % #1...#9 fractional part, padded with '0'
+  \count@=#1#2#3#4#5#6#7#8#9%
+  \@swallow%
+}
+
+% Swallow everything up to next \relax
+\def\@swallow#1\relax{}
+
+%
+% Store result 
+%
+\def\@store#1#2#3{%
+  % #1 marcro to catch the result
+  % #2 counter with integer part (maybe negative)
+  % #3 counter with fractional part (maybe negative}
+  % 
+  % Sign
+  \edef#1{}%
+  \count@=#3%
+  \ifnum\count@<\@zero% 
+    \count@=-\count@%
+    \ifnum#2=\@zero% 
+      \edef#1{-}%
+    \fi%
+  \fi%
+  %
+  % Pad fractional part with leading zeros
+  \advance\count@\@mil%
+  %
+  % Store result 
+  \edef#1{#1\number#2.\expandafter\@ignorenext\number\count@}%
+}
+
+% Ignore next token
+\def\@ignorenext#1{}
+
+% Restore catcode of "@"
+\catcode`\@=\catamp