%% 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, witch catches the result. %% String or macro witch expands to a value in the range %% from -2147483647.999999999 to 2147483647.999999999 %% 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 Addition \def\Radd#1#2#3{\@callc\@Radd#1{#2}{#3}} %% \Rsub 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 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 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 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 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 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 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 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 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 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 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 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