diff options
author | Karl Berry <karl@freefriends.org> | 2007-08-20 12:55:15 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2007-08-20 12:55:15 +0000 |
commit | a5b418efaeb33e9ffe036ba3b54fa12397ac7705 (patch) | |
tree | 80f29affef80ea1ea042e7f87e8c77c99c1ac4d9 /Master/texmf-dist/source/generic | |
parent | 2a71f2106a4a2b9758de9beda1917445bd95e399 (diff) |
fltpoint generic (luecking 23 Jul 2007 13:47:15)
git-svn-id: svn://tug.org/texlive/trunk@4776 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/generic')
-rw-r--r-- | Master/texmf-dist/source/generic/fltpoint/fltpoint.dtx | 1791 | ||||
-rw-r--r-- | Master/texmf-dist/source/generic/fltpoint/fltpoint.ins | 8 |
2 files changed, 1799 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/generic/fltpoint/fltpoint.dtx b/Master/texmf-dist/source/generic/fltpoint/fltpoint.dtx new file mode 100644 index 00000000000..e2cd2ed5af8 --- /dev/null +++ b/Master/texmf-dist/source/generic/fltpoint/fltpoint.dtx @@ -0,0 +1,1791 @@ +% \iffalse META-COMMENT +% +% The fltpoint package for use with TeX / LaTeX +% Current Version: 1.1b, dated 2004/11/12 +% Copyright 2000-2004 +% Eckhart Guthoehrlein +% e-mail <e_w_g@web.de> +% +% This program may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.2 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.2 or later is part of all distributions of LaTeX +% version 1999/12/01 or later. +% +% This program consists of the files 'fltpoint.dtx', 'fltpoint.ins' +% and 'README_fltpoint.txt'. +% +% The package provides simple arithmetic with TeX. It should work with +% all formats and has been tested with plain TeX and LaTeX. +% +% Run TeX over fltpoint.ins to produce the docstripped version +% of the file. The documentation can be typeset by running +% LaTeX over fltpoint.dtx. +% +% Comments and bug-reports are welcome under the above +% e-mail address. +% +% \fi ^^A end meta-comment +% \CheckSum{1150} +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \DoNotIndex{\def,\edef,\xdef,\gdef,\let,\global,\the,^^A +% \newcount,\if,\ifx,\else,\fi,\ifnum,\catcode,^^A +% \@,\expandafter,\csname,\endcsname,\number^^A +% \relax,\end,\advance,\multiply,\divide,\endinput^^A +% \iterate,\body,\repeat,\iiterate,\ibody,\irepeat,^^A +% \xiterate,\xbody,\xrepeat. +% \,,\active,\AlsoImplementation,\AtBegin\Document, +% \begin,\CodelineIndex,\CommaCheck,\CommaOrdinary, +% \CommaPunct,\DeclareOption,\DisableCrossrefs, +% \DocInput,\documentclass,\EnableCrossrefs,\endinput, +% \futurelet,\long,\mathchardef,\mathcode,\mbox, +% \NeedsTeXFormat,\newcommand,\noexpand,\number, +% \obeyspaces,\OnlyDescription,\ProcessOptions, +% \ProvidesPackage,\RecordChanges,\rightarrow, +% \space,\tt,\usepackage} +% +% \MakeShortVerb{\"} +% +% \changes{v1.0a}{2000/08/23}{First public release} +% \changes{v1.0b}{2000/08/25}{Some spaces sneaked into the output. +% Fixed.} +% \changes{v1.0c}{2000/09/05}{Changes necessary for +% the \texttt{rccol} package.} +% \changes{v1.1}{2001/11/17}{Cleanup to freeze development.} +% \changes{v1.1b}{2004/11/12}{Some more freezing cleanup.} +% \GetFileInfo{fltpoint.sty} +% \title{The \texttt{fltpoint} package\thanks{This +% file has version number \fileversion{} dated \filedate.}} +% \author{Eckhart Guth\"ohrlein\thanks{Send comments +% or bug-reports to the author via e-mail +% \texttt{<e\_w\_g@web.de>}.}} +% \date{Printed \today} +% \maketitle +% +% \begin{abstract} +% This package provides commands for simple +% arithmetic with generic \TeX. At the moment, there is support for the +% basic operations addition, subtraction, multiplication and division as +% well as for rounding numbers to a given precision. +% \end{abstract} +% +% \newif\ifmulticols +% \IfFileExists{multicol.sty}{\multicolstrue}{} +% \ifmulticols +% \addtocontents{toc}{\protect\begin{multicols}{2}} +% \fi +% ^^A{\parskip0mm\tableofcontents} +% +% \section{Introduction} +% The need for calculations inside \TeX\ was encountered when working on +% some macros to convert positions on a linear scale into angle values, +% since integer values proved not to be sufficiently exact. Although +% the capabilities of this package are currently rather limited, +% they may be of some use if you do not need more than the +% provided functions. The \texttt{rccol} package may serve as an +% example application; it uses the rounding facilities of this package. +% +% \section{User interface} +% The user commands are divided into two categories: +% the normal and the register commands. Each command +% is available in those two variants, as decribed below. +% At first, we have to agree about the syntax for floating +% point numbers. +% +% \subsection{Syntax of floating point numbers} +% In the syntax descriptions below, \meta{fp number} +% will be used to denote a number according to the following +% syntax. +% \begin{flushleft} +% $\mbox{\meta{fp number}}:=\mbox{\meta{opt signs}} +% \mbox{\meta{opt digits}}\mbox{\meta{opt dot}} +% \mbox{\meta{opt digits}}$ +% \end{flushleft} +% \meta{opt signs} may be any number of `"+"' and/or `"-"' +% characters, where each `"-"' toggles the sign of +% the number. \meta{opt digits} may be any number +% of characters `"0"'\dots `"9"', and \meta{opt dot} +% is the optional decimal sign. For example, the +% following inputs for \meta{fp number} are valid, +% resulting into the specified numbers. +% \fpexample{100}, \fpexample{010,98700}, \fpexample{-,99}, +% \fpexample{-+-+0001,}, \fpexample{}, \fpexample{---,50}. +% As you can see, leading and trailing zeros are removed +% as far as possible, and an `empty number' (omitting anything +% optional) is understood as zero. +% +% There is no syntax checking, so if you do not obey the +% rules above, you are likely to encounter strange error +% messages, as well as everything might work properly in +% some cases. +% Of course, it is also possible to +% use a macro as \meta{fp number} if it expands to a +% string satisfying the syntax rules. +% +% \subsection{Standard operations} +% \DescribeMacro\fpAdd\DescribeMacro\fpSub +% \DescribeMacro\fpMul\DescribeMacro\fpDiv +% The standard commands for binary operations have the following +% common syntax: +% \begin{flushleft} +% "\fp"\meta{bOp}"{"\meta{command sequence}"}{"\meta{fp number}"}"^^A +% "{"\meta{fp number}"}". +% \end{flushleft} +% This will perform the operation specified by \meta{bOp} +% with the two given numbers, saving the result in +% \meta{command sequence}. Possibilities for +% \meta{bOp} are `"Add"', `"Sub"', `"Mul"' and `"Div"', +% specifying addition, subtraction, multiplication, +% and division. Example: +% \begin{flushleft} +% "\fpAdd{\exmplsum}{100,0}{-99,1}"\\ +% "\fpMul{\exmplprod}{5}{\exmplsum}" +% \end{flushleft} +% \fpAdd{\exmplsum}{100,0}{-99,1}^^A +% \fpMul{\exmplprod}{5}{\exmplsum}^^A +% After this, the results of the computations will +% be stored in the macros "\exmplsum" and "\exmplprod", +% expanding to \exmplsum\ and \exmplprod. +% +% \DescribeMacro\fpNeg\DescribeMacro\fpAbs +% Similar to the binary operations, the unary operations +% share the common syntax +% \begin{flushleft} +% "\fp"\meta{uOp}"{"\meta{command sequence}"}{"\meta{fp number}"}". +% \end{flushleft} +% Possibilities for \meta{uOp} are `"Abs"' and `"Neg"', +% meaning absolute amount and negation. +% +% \DescribeMacro\fpRound +% With "\fpRound{"\meta{command sequence}"}{"\meta{fp number}^^A +% "}{"\meta{precision}"}", +% a number can be rounded to the desired precision (a power of ten). +% The result +% is saved in \meta{command sequence} as usual. +% +% \subsection{Register operations} +% You may use register variants of all operations, +% which means that you perform the operation on +% a register which contains a number. A register is +% referred to using its name; the name may +% contain any characters including digits. +% +% \DescribeMacro\fpRegSet\DescribeMacro\fpRegGet +% Registers are initialized by assigning them values, +% using "\fpRegSet". They can be read out into +% command sequences using "\fpRegGet". +% \begin{flushleft} +% "\fpRegSet{"\meta{reg name}"}{"\meta{fp number}"}"\\ +% "\fpRegGet{"\meta{reg name}"}{"\meta{command sequence}"}" +% \end{flushleft} +% +% \DescribeMacro\fpRegAdd\DescribeMacro\fpRegSub +% \DescribeMacro\fpRegMul\DescribeMacro\fpRegDiv +% The binary operations need two register names. +% After execution, the first register will hold +% the result of the specified computation, +% performed with its former value and the +% value of the second register. +% \begin{flushleft} +% "\fp"\meta{bOp}"{"\meta{reg name 1}"}{"\meta{reg name 2}"}" +% \end{flushleft} +% \DescribeMacro\fpRegAbs\DescribeMacro\fpRegNeg +% Consequently, the unary operations only need +% the name of the register. +% \begin{flushleft} +% "\fp"\meta{uOp}"{"\meta{reg name}"}" +% \end{flushleft} +% \DescribeMacro\fpRegRound +% Rounding of registers is also possible. +% \begin{flushleft} +% "\fpRegRound{"\meta{reg name}"}{"\meta{precision}"}" +% \end{flushleft} +% \DescribeMacro\fpRegCopy +% Furthermore, there is one binary operation only available for +% registers, this is "\fpRegCopy" which assigns the +% value of \meta{reg name 2} to register \meta{reg name 1}. +% +% For example, consider the following statements. +% \begin{flushleft} +% "\fpRegSet{test1}{36} \fpRegSet{test2}{-3}"\\ +% "\fpRegDiv{test1}{test2} \fpRegMul{test1}{test1}"\\ +% "\fpRegGet{test1}{\fpresult}" +% \end{flushleft} +% \fpRegSet{test1}{36}\fpRegSet{test2}{-3}^^A +% \fpRegDiv{test1}{test2}\fpRegMul{test1}{test1}^^A +% \fpRegGet{test1}{\fpresult}^^A +% After this, "test1" will hold the value \fpresult, which +% "\fpresult" will expand to. +% +% +% \subsection{Configuration and Parameters} +% +% \DescribeMacro\fpAccuracy +% The macro "\fpAccuracy" takes one argument (a number), +% determining the number of digits after the decimal sign, +% i.\,e., the accuracy of the computations. +% The default value is five. +% At the moment, the name promises too much. +% The command only affects "\fpDiv" and "\fpRegDiv". +% +% \DescribeMacro\fpDecimalSign +% With "\fpDecimalSign{"\meta{character}"}" you can chose any character +% for use as the decimal sign. Normally, this will be either +% a point or a comma; the default is a comma. +% You can furthermore use the package options +% \texttt{comma} or \texttt{point}. +% The support for options like \texttt{english} or \texttt{german} +% has been removed. It will not be added again, and there will be no +% detection of packages like \texttt{babel} or \texttt{german}. +% In my view, a comma is the better choice regardless of the language +% in question (and it is the \textsc{iso} standard). On the other hand, +% many people think that a point should be used even in German texts. +% So, you have to make an explicit decision. +% +% \section{Final Remarks} +% After the first release, I intended to include the features listed +% below in the near future. +% Unfortunately, I didn't have time to do so, and maybe I will +% never have, since I am currently not interested in extending this +% package. If I continued the development some day, the +% first extensions might be what is listed here. +% \begin{itemize} +% \item Extend syntax to support numbers like $1,7\mathrm{E}{-}1$ or +% $2,765\cdot 10^5$ in input and output. +% \item Formatted, customizable output. +% \item User access to the comparison of registers. +% \item A better concept for chosing the accuracy of the computations. +% \item More operations like $\mathrm{e}^x$, $\sqrt{x}$, $\sin x$, +% $\ln x$\ldots +% \end{itemize} +% +% Some users have pointed out that the terminus \lq floating-point\rq\ +% is not strictly correct for what is provided by the package. Alas! I +% happily stick to the package name. +% +% If you encounter needs not satisfied by this package, you may +% wait for the unlikely event of an extension from my part, or you can +% have a look at the following packages and see if they do what you want: +% \begin{itemize} +% \item {\tt fp} by Michael Mehlich for calculations, +% \item {\tt numprint} by Harald Harders for formatted printing of +% numbers. +% \end{itemize} +% Finally, the license of this package is LPPL, so feel free to do +% it yourself. +% +% \StopEventually{% +% \ifmulticols +% \addtocontents{toc}{\protect\end{multicols}} +% \fi} +% \section{Implementation} +% +% \subsection{General ideas} +% The main idea was to represent numbers internally by storing their +% digits in an array/record-like construction (to be referred to as +% an array or as a register from now on) whose numbering +% reflects the decimal position factor of the digit, with +% some information about the range of the numbering +% and the sign of the number. +% An array consists of a couple of command sequences, +% sharing a common name followed by an element number. +% E.\,g., `$120.3$' means $1\cdot 10^2+2\cdot 10^1+ +% 0\cdot 10^0+3\cdot 10^{-1}$. So, if the number is to be stored +% in the array "\exmpl", the command sequences +% "\exmpl@2", "\exmpl@1", "\exmpl@0" and "\exmpl@-1" +% will be defined as `"1"', `"2"', `"0"' and `"3"', respectively. +% The sign information `"+"' will be stored in "\exmpl@sig". +% "\exmpl@ul" (`upper limit') will be `"2"', "\exmpl@ll" (`lower +% limit') will be `"-1"'. +% +% The computations are performed as +% you do it with paper and pencil. +% E.\,g., for an addition, all corresponding digits +% are summed, taking over anything +% exceeding ten to the next pair of digits. +% Thus, there is no limit to the range of numbers or to the +% number of digits after the decimal sign, except +% \TeX's memory and, probably the limiting factor, your patience. +% +% Initially, the computations were not performed inside of +% groups, and side-effects were avoided using more +% counters and constructions like "\xloop" etc. +% This may make more efficient use of \TeX, as far as speed +% and save stack usage is concerned, but I think that further +% extensions will be much simpler now without the +% need to worry about possible side-effects and the surprising +% result when, once again, something happens you simply +% did not think of. Furthermore, this provides +% a simple mechanism of removing temporary stuff +% from the memory. +% +% But now, let's reveal the code\dots +% +% +% \subsection{Driver file} +% The driver file can be generated from \texttt{fltpoint.dtx} +% and then be used to produce the documentation (if you don't like +% to run \LaTeX\ directly over the \texttt{dtx}-file). +% \begin{macrocode} +%<*deccomma> +\mathchardef\CommaOrdinary="013B +\mathchardef\CommaPunct ="613B +\mathcode`,="8000 +{\catcode`\,=\active + \gdef ,{\obeyspaces\futurelet\next\CommaCheck}} +\def\CommaCheck{\if\space\next\CommaPunct\else\CommaOrdinary\fi} +%</deccomma> +%<*driver> +\documentclass{ltxdoc} +\usepackage{deccomma,fltpoint} +%\OnlyDescription +\AlsoImplementation +\EnableCrossrefs % disable if index is ready +\CodelineIndex +\RecordChanges +%\DisableCrossrefs +\newcommand{\fpexample}[1]{% + \fpRegSet{fptemp}{#1}% + \fpRegGet{fptemp}{\fptemp}% + $\mbox{\tt`#1'}\rightarrow\fptemp$} +\begin{document} + \DocInput{fltpoint.dtx} +\end{document} +%</driver> +% \end{macrocode} +% +% +% \subsection{\LaTeX\ package definitions} +% If used as a \LaTeX\ package, the usual \LaTeX\ preliminaries +% and some option declarations are necessary. +% \begin{macrocode} +%<*package> +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{fltpoint}[2004/11/12 v1.1b floating point arithmetic] +\DeclareOption{comma}{\AtBeginDocument{\fpDecimalSign,}} +\DeclareOption{point}{\AtBeginDocument{\fpDecimalSign.}} +\ProcessOptions*\relax +\input{fltpoint} +%</package> +% \end{macrocode} +% +% \iffalse +%<*fltmain> +% \fi +% \subsection{Private letters} +% +% \begin{macro}{\atcatcode} +% `"@"' is used for private command sequences. Its catcode is saved +% in "\atcatcode" to be restored just before "\endinput". +% \begin{macrocode} +\edef\atcatcode{\the\catcode`\@} +\catcode`\@=11 +% \end{macrocode} +% \end{macro} +% +% +% \subsection{\LaTeX\ or not?} +% +% Check for \LaTeX, otherwise provide the "\@ifnextchar" mechanism +% copied from the \LaTeX\ source, see there for explanation. +% \begin{macrocode} +\ifx\documentclass\relax +\long\def\@ifnextchar#1#2#3{% + \let\reserved@d=#1% + \def\reserved@a{#2}% + \def\reserved@b{#3}% + \futurelet\@let@token\@ifnch} +\def\@ifnch{% + \ifx\@let@token\@sptoken + \let\reserved@c\@xifnch + \else + \ifx\@let@token\reserved@d + \let\reserved@c\reserved@a + \else + \let\reserved@c\reserved@b + \fi + \fi + \reserved@c} +\def\:{\let\@sptoken= } \: +\def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch} +\fi +% \end{macrocode} +% \subsection{Additional loop structures} +% +% \begin{macro}{\iloop} +% \begin{macro}{\xloop} +% To be able to nest loop structures without the need for +% hiding the inner loop(s) in grouped blocks, the constructions +% "\iloop...\irepeat" and "\xloop...\xrepeat" are defined +% analogously to \PlainTeX's "\loop...\repeat". +% "\iloop" will be used `internally' by macros which are +% to be used in ordinary "\loop"s or in "\xloop"s. +% "\xloop" will be used +% `externally', surrounding ordinary "\loop"s. +% \begin{macrocode} +\def\iloop#1\irepeat{\def\ibody{#1}\iiterate} +\def\iiterate{\ibody\let\inext=\iiterate\else\let\inext=\relax\fi + \inext} +\def\xloop#1\xrepeat{\def\xbody{#1}\xiterate} +\def\xiterate{\xbody\let\xnext\xiterate\else\let\xnext\relax\fi\xnext} +% \end{macrocode} +% The following assignments are necessary to make +% "\loop"\dots"\if"\dots"\repeat" +% constructions skippable inside another "\if". +% \begin{macrocode} +\let\repeat\fi +\let\irepeat\fi +\let\xrepeat\fi +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsection{Allocation of registers} +% +% \begin{macro}{\fp@loopcount} +% \begin{macro}{\fp@loopcountii} +% \begin{macro}{\fp@result} +% \begin{macro}{\fp@carryover} +% \begin{macro}{\fp@tempcount} +% \begin{macro}{\fp@tempcountii} +% Several count registers are needed. I have tried to keep this +% number small, which means that, at some points, I may have chosen a +% less logical or less readable usage of counts. +% Nevertheless, I do not claim to have minimized the number +% as far as possible\dots +% +% "\fp@loopcount" and "\fp@loopcountii" are often, but not always, used +% for "\loop"s, "\fp@loopcountii" sometimes just stores the finishing +% number. "\fp@result" and "\fp@carryover" +% are used to store the intermediate results of computations. +% "\fp@tempcount" and "\fp@tempcountii" are scratch registers +% whose values should not be considered to be the same +% after the use of any macro, except the simple array +% accession abbreviations starting whith "\ar@", as explained below. +% \begin{macrocode} +\newcount\fp@loopcount +\newcount\fp@loopcountii +\newcount\fp@result +\newcount\fp@carryover +\newcount\fp@tempcount +\newcount\fp@tempcountii +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Communication between macros and groups} +% +% \begin{macro}{\fp@setparam} +% \begin{macro}{\fp@param} +% To pass information from one macro to another, or from +% inside a group to the outer world, the construction +% "\fp@setparam{"\meta{information}"}" is used. It saves +% \meta{information} globally in the command sequence "\fp@param". +% This mechanism is used, e.\,g., by "\fp@regcomp", +% "\fp@getdigit" to pass their result to the calling macro, +% or by "\fp@regadd" etc.\ to make \meta{information} survive the end +% of the current group. Since "\xdef" is used, \meta{information} +% will be fully expanded. +% \begin{macrocode} +\def\fp@setparam#1{\xdef\fp@param{#1}}% +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Array accession} +% +% \begin{macro}{\ar@set} +% \begin{macro}{\ar@get} +% \begin{macro}{\ar@setsig} +% \begin{macro}{\ar@getsig} +% \begin{macro}{\ar@setul} +% \begin{macro}{\ar@getul} +% \begin{macro}{\ar@setll} +% \begin{macro}{\ar@getll} +% The idea of arrays using command sequences like +% "\exmpl@-1" means typing a lot of unreadable +% "\expandafter"s and "\csname"s, so the following +% abbreviations were introduced. They take the base name of +% the array as the first argument, if needed followed by +% an element number, for the "set"-commands followed by +% the third argument to be the (new) value. +% No checks are performed if the element number +% is inside the boundaries of the array, nor anything +% else to ensure the validity of the operation. +% +% "\ar@set" is used to save digits. +% "\ar@setsig", "\ar@setul" and "\ar@setll" set sign, +% upper and lower limit of the array. +% "\ar@get", "\ar@getsig", "\ar@getul" and "\ar@getll" +% are used to access the respective command sequences. +% \begin{macrocode} +\def\ar@set#1#2#3{\expandafter\edef\csname#1@\number#2\endcsname{% + \number#3}} +\def\ar@get#1#2{\csname#1@\number#2\endcsname} +\def\ar@setsig#1#2{\expandafter\edef\csname#1@sig\endcsname{#2}} +\def\ar@getsig#1{\csname#1@sig\endcsname} +\def\ar@getul#1{\csname#1@ul\endcsname} +\def\ar@getll#1{\csname#1@ll\endcsname} +\def\ar@setul#1#2{\expandafter\edef\csname#1@ul\endcsname{\number#2}} +\def\ar@setll#1#2{\expandafter\edef\csname#1@ll\endcsname{\number#2}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Miscellaneous} +% +% \begin{macro}{\fp@settomax} +% The macro "\fp@settomax" assigns the maximum of the two +% numbers given as "#2" and "#3" to the counter "#1". +% \begin{macrocode} +\def\fp@settomax#1#2#3{% + \ifnum#2<#3\relax + #1=#3\relax + \else + #1=#2\relax + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@settomin} +% The macro "\fp@settomin" does the same with the minimum. +% \begin{macrocode} +\def\fp@settomin#1#2#3{% + \ifnum#2<#3\relax + #1=#2\relax + \else + #1=#3\relax + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@modulo} +% The macro "\fp@modulo" computes the result of $\mbox{\#1}\bmod +% \mbox{\#2}$ and saves it in "\fp@param". +% \begin{macrocode} +\def\fp@modulo#1#2{% + \fp@tempcount=#1\relax + \fp@tempcountii=#1\relax + \divide\fp@tempcountii#2\relax + \multiply\fp@tempcountii#2\relax + \advance\fp@tempcount-\fp@tempcountii + \edef\fp@param{\number\fp@tempcount}} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Setting and getting register contents} +% +% \begin{macro}{\fp@regread} +% \begin{macro}{\fp@regread@raw} +% The macro "\fp@regread" reads the string or command sequence +% (after expansion) given as "#2" into register "#1". +% The main work is done by the subroutine +% "\fp@readchars", where "\fp@tempcount" is used to indicate +% the current position. "\fp@arrayname" is used to pass +% "#1" to "\fp@readchars". +% \begin{macrocode} +\def\fp@regread#1#2{% + \fp@regread@raw{#1}{#2}% + \fp@cleanreg{#1}} +\def\fp@regread@raw#1#2{% +% \end{macrocode} +% Initialize "\fp@tempcount". +% Initialize "\fp@arrayname". +% Make "#1" positive by default. +% \begin{macrocode} + \fp@tempcount=0 + \edef\fp@arrayname{#1}% + \ar@setsig{#1}{+}% +% \end{macrocode} +% Now call "\fp@readchars" with "#2" fully expanded, +% followed by a decimal sign. The decimal sign is necessary because +% "\fp@readchars" expects at least one decimal sign to occur in the +% given string, so if "#2" is, say, "100", this will make it +% readable. On the other hand, a superficial decimal sign at the end +% of a number like $1.34$ will be ignored. +% \begin{macrocode} + \edef\fp@scratch{#2\fp@decimalsign}% + \expandafter\fp@readchars\fp@scratch\end +% \end{macrocode} +% If the first character of "#2" has been a decimal sign, the upper +% limit will be wrong, no pre-point digits will be present. +% This does not conform the internal syntax and is +% corrected now. +% \begin{macrocode} + \ifnum\ar@getul{#1}=-1 + \ar@setul{#1}{0}% + \ar@set{#1}{0}{0}% + \fi +% \end{macrocode} +% The $n$ digits before the decimal sign (if any) have been +% read in from left to right, assigning positions from +% $0\ldots n$, so they have to be swapped to +% their correct positions. This is done with two counters, +% one starting as $0$, the other as $n$, using +% "\fp@scratch" for temporary storage. +% \begin{macrocode} + \fp@tempcount=0 + \fp@tempcountii=\ar@getul{#1}\relax + \iloop + \ifnum\fp@tempcount<\fp@tempcountii + \edef\fp@scratch{\ar@get{#1}{\fp@tempcountii}}% + \ar@set{#1}{\fp@tempcountii}{\ar@get{#1}{\fp@tempcount}}% + \ar@set{#1}{\fp@tempcount}{\fp@scratch}% + \advance\fp@tempcount by 1 + \advance\fp@tempcountii by -1 + \irepeat +}% end \fp@regread@raw +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp@readchars} +% As mentioned above, this subroutine is called by +% "\fp@regread" to do the actual work of reading +% the given number character after character into the register +% passed using "\fp@arrayname". It will stop if it sees +% an \fbox{\tt end} token. +% \begin{macrocode} +\def\fp@readchars#1{% + \ifx#1\end +% \end{macrocode} +% If the condition is true, the token read before has been the final +% one. So at the end, do not call "\fp@readchars" any more, and use +% the current value of "\fp@tempcount" to assign the correct +% lower limit to the register. +% \begin{macrocode} + \let\inext=\relax + \ifnum\fp@tempcount<0 + \advance\fp@tempcount by 1 + \ar@setll{\fp@arrayname}{\fp@tempcount}% + \else + \ar@setll{\fp@arrayname}{0}% + \fi + \else % \ifx#1\end +% \end{macrocode} +% If the condition is false, further characters will +% follow, so "\fp@readchars" will have to be called +% again after finishing this character. +% \begin{macrocode} + \let\inext=\fp@readchars +% \end{macrocode} +% Now check the character and perform the respective actions. +% \begin{macrocode} + \ifx#1+% +% \end{macrocode} +% An optional `"+"' has been encountered, nothing to do. +% \begin{macrocode} + \else + \ifx#1-% +% \end{macrocode} +% `"-"' sign, toggle sign. +% \begin{macrocode} + \if\ar@getsig{\fp@arrayname}-% + \ar@setsig{\fp@arrayname}{+}% + \else + \ar@setsig{\fp@arrayname}{-}% + \fi + \else + \if\noexpand#1\fp@decimalsign% +% \end{macrocode} +% A decimal sign has been encountered. So, if it is the first +% one, switch to reading afterpoint digits, otherwise ignore it. +% \begin{macrocode} + \ifnum\fp@tempcount>-1 + \advance\fp@tempcount by -1 + \ar@setul{\fp@arrayname}{\fp@tempcount}% + \fp@tempcount=-1 + \fi + \else +% \end{macrocode} +% None of the above characters was encountered, so assume +% a digit, and read it into the current position. Then step +% "\fp@tempcount" by $+1$ if prepoint digits are read in, +% or by $-1$ if the decimal sign has already been seen. +% \begin{macrocode} + \ar@set{\fp@arrayname}{\fp@tempcount}{#1}% + \ifnum\fp@tempcount<0 + \advance\fp@tempcount by -1 + \else + \advance\fp@tempcount by 1 + \fi + \fi% end \if\noexpand#1\fp@decimalsign + \fi% end \ifx#1- + \fi% end \ifx#1+ + \fi% end \ifx#1\end +% \end{macrocode} +% That's all, call "\inext". +% \begin{macrocode} + \inext +}% end \fp@readchars +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regget} +% The macro "\fp@regget" is used to read the contents of the +% register "#1" into the command sequence "#2". +% \begin{macrocode} +\def\fp@regget#1#2{% +% \end{macrocode} +% First, we get the sign of the number. If negative, +% "#2" is initialized as `"-"', otherwise as empty. +% \begin{macrocode} + \if\ar@getsig{#1}-% + \def#2{-}% + \else + \def#2{}% + \fi +% \end{macrocode} +% Then we set up "\fp@tempcount" as the counter for an "\iloop", +% starting at the upper limit of "#1". +% \begin{macrocode} + \fp@tempcount=\ar@getul{#1}\relax + \iloop +% \end{macrocode} +% If the "\fp@tempcount" is $-1$, we have to append a decimal sign. +% \begin{macrocode} + \ifnum\fp@tempcount=-1 + \edef#2{#2\fp@decimalsign}% + \fi +% \end{macrocode} +% Now append the corresponding digit. +% \begin{macrocode} + \edef#2{#2\ar@get{#1}{\fp@tempcount}}% +% \end{macrocode} +% And repeat if the lower limit of "#1" is not yet reached. +% \begin{macrocode} + \ifnum\fp@tempcount>\ar@getll{#1}\relax + \advance\fp@tempcount by -1 + \irepeat +}% end \def\fp@regget +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@cleanreg} +% The macro "\fp@cleanreg" will clean up the given register. +% This means that leading and trailing zeros will be +% removed, and that $-0$ will be turned into $+0$ +% to be recognised as equal later on. +% \begin{macrocode} +\def\fp@cleanreg#1{% +% \end{macrocode} +% First, we will iterate until all leading zeros +% have been removed, except for digit $0$ that it is +% expected to be `"0"' for all numbers $n$ with $-1<n<1$. +% \begin{macrocode} + \fp@tempcount=\ar@getul{#1}\relax + \iloop + \ifnum\fp@tempcount>0 + \ifnum\ar@get{#1}{\fp@tempcount}=0 +% \end{macrocode} +% If this is true, the first digit is a zero and is `removed' +% by changing the upper limit. It is not necessary to +% erase it by setting the array element to "\empty" or something +% like that, because it will not be looked at any more. +% \begin{macrocode} + \advance\fp@tempcount by -1 + \ar@setul{#1}{\fp@tempcount}% + \else +% \end{macrocode} +% So the condition is false, the first digit is not a zero +% and the following ones need not to be looked at. +% \begin{macrocode} + \fp@tempcount=0 + \fi + \irepeat +% \end{macrocode} +% Similarly, the trailing zeros are removed. +% \begin{macrocode} + \fp@tempcount=\ar@getll{#1}\relax + \iloop + \ifnum\fp@tempcount<0 + \ifnum\ar@get{#1}{\fp@tempcount}=0 + \advance\fp@tempcount by 1 + \ar@setll{#1}{\fp@tempcount}% + \else + \fp@tempcount=0 + \fi + \irepeat +% \end{macrocode} +% Now check if the number is zero, using +% $(\mbox{x@ll}=\mbox{x@ul})\wedge(\mbox{x@0}=0)\Longleftrightarrow +% \rm x=0$, and set the sign to `"+"' if this is the case. +% \begin{macrocode} + \ifnum\ar@getll{#1}=\ar@getul{#1}\relax + \ifnum\ar@get{#1}{0}=0\relax + \ar@setsig{#1}{+}% + \fi + \fi +}% end \fp@regclean +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@getdigit} +% The macro "\fp@getdigit" will return the digit number "#2" of +% register "#1" using "\fp@setparam". If "#2" is outside the +% boundaries of the array, `"0"' is returned. (Which is not only +% sensible, but also mathematically correct.) +% \begin{macrocode} +\def\fp@getdigit#1#2{% + \ifnum#2<\ar@getll{#1}\relax + \fp@setparam0% + \else + \ifnum#2>\ar@getul{#1}\relax + \fp@setparam0% + \else + \fp@setparam{\ar@get{#1}{#2}}% + \fi + \fi +}% end \fp@getdigit +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@shiftright} +% The macro "\fp@shiftright" takes register "#1" and shifts the decimal +% sign "#2" digits to the right ("#2" may be negative or zero, too, +% so there is no need for a "\fp@shiftleft"). +% The digits are read into "\fp@shiftnum", inserting the decimal +% sign at the new place. Then, "\fp@shiftnum" is read +% into "#1" via "\fp@regread". +% \begin{macrocode} +\def\fp@shiftright#1#2{% +% \end{macrocode} +% First, save the value of "#2" in "\fp@shiftamount". +% This makes it possible to say, e.\,g., +% "\fpshiftright{exmpl}{\fp@tempcount}" without side-effects. +% \begin{macrocode} + \edef\fp@shiftamount{\number#2}% +% \end{macrocode} +% Now, determine the start position. +% The maximum of the upper limit and "-\fp@shiftamount" is used +% in order to allow the decimal sign of, e.\,g., +% $1.1$ to be shifted $-5$ digits to the right. +% \begin{macrocode} + \fp@settomax{\fp@tempcount}{\ar@getul{#1}}{-\fp@shiftamount}% +% \end{macrocode} +% Similarly, determine the stop position. +% \begin{macrocode} + \fp@settomin{\fp@tempcountii}{\ar@getll{#1}}{-\fp@shiftamount}% +% \end{macrocode} +% Now, initialize "\fp@shiftnum" and begin the "\iloop". +% Read digit after digit using "\fp@getdigit", therefore +% getting a `"0"' outside the boundaries. Insert the +% decimal sign at the new position given by +% "-\fp@shiftamount". +% \begin{macrocode} + \def\fp@shiftnum{}% + \iloop + \fp@getdigit{#1}{\fp@tempcount}% + \edef\fp@shiftnum{\fp@shiftnum\fp@param}% + \ifnum\fp@tempcount=-\fp@shiftamount\relax + \edef\fp@shiftnum{\fp@shiftnum\fp@decimalsign}% + \fi + \ifnum\fp@tempcount>\fp@tempcountii + \advance\fp@tempcount by -1 + \irepeat +% \end{macrocode} +% Finally, assign the value to "#1". +% \begin{macrocode} + \fp@regread{#1}{\fp@shiftnum}% +}% end \fp@shiftright +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@firstnonzero} +% The macro "\fp@firstnonzero" returns the first non-zero +% digit of register "#1" via "\fp@setparam". +% \begin{macrocode} +\def\fp@firstnonzero#1{% +% \end{macrocode} +% If "#1" is zero, the "\iloop" below will run infinitely, +% so this case has to be checked separately by comparing +% "#1" to the internal register "@0" which holds zero. +% `"0"' is returned if "#1" is zero. +% \begin{macrocode} + \fp@regcomp{#1}{@0}% + \if\fp@param=% + \fp@setparam0% +% \end{macrocode} +% Otherwise, each digit is checked, starting at the upper limit, +% and the position of first digit differing from zero is +% returned in "\fp@param". +% \begin{macrocode} + \else + \fp@tempcount=\ar@getul{#1}\relax% + \fp@tempcountii=\ar@getll{#1}\relax% + \iloop + \ifnum\ar@get{#1}{\fp@tempcount}>0 + \fp@setparam{\number\fp@tempcount}% + \fp@tempcount=\fp@tempcountii + \fi + \ifnum\fp@tempcount>\fp@tempcountii + \advance\fp@tempcount by -1 + \irepeat + \fi +}% end \fp@firstnonzero +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Comparison of registers} +% +% \begin{macro}{\fp@regcomp} +% The macro "\fp@regcomp" compares the two specified registers. +% It saves the result of the comparison (either `"<"', `">"', +% or `"="') in "\fp@param". First, it checks whether the +% two numbers have the same sign or not. If not, +% the comparison is very easy, otherwise "\fp@regcomp@main" +% is called to do the work. +% \begin{macrocode} +\def\fp@regcomp#1#2{% + {% + \if\ar@getsig{#1}-% + \if\ar@getsig{#2}-% + \fp@regcomp@main{#1}{#2}<>% + \else + \fp@setparam{<}% + \fi + \else + \if\ar@getsig{#2}-% + \fp@setparam{>}% + \else + \fp@regcomp@main{#1}{#2}><% + \fi + \fi + }% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regcomp@main} +% The macro "\fp@regcomp@main" takes four parameters: +% The two registers to be compared, and two tokens +% to be used as result. This is needed because +% if, e.\,g., two numbers have the same sign and +% are equal for all positions greater than +% $10^2$, and number~1 has `"9"' at position $10^2$ and number~2 +% has `"5"', then the result must be `"<"' if $n_1<n_2<0$, +% but `">"' if $n_1>n_2>0$. +% +% First, the range of digits to compare is determined. +% Then, each pair of digits is compared. If different, +% "\fp@param" is set and the loop is terminated by +% setting the loop counter to the stop position. +% If the digits are equal and there are no more digits +% to compare, the numbers are equal. +% \begin{macrocode} +\def\fp@regcomp@main#1#2#3#4{% + \fp@settomax{\fp@loopcount}{\ar@getul{#1}}{\ar@getul{#2}}% + \fp@settomin{\fp@loopcountii}{\ar@getll{#1}}{\ar@getll{#2}}% + \loop + \fp@getdigit{#1}{\fp@loopcount}% + \fp@tempcount=\fp@param\relax + \fp@getdigit{#2}{\fp@loopcount}% + \fp@tempcountii=\fp@param\relax + \ifnum\fp@tempcount<\fp@tempcountii + \fp@setparam{#4}% + \fp@loopcount=\fp@loopcountii + \else + \ifnum\fp@tempcount>\fp@tempcountii + \fp@setparam{#3}% + \fp@loopcount=\fp@loopcountii + \else + \ifnum\fp@loopcount=\fp@loopcountii + \fp@setparam{=}% + \fi + \fi + \fi + \ifnum\fp@loopcount>\fp@loopcountii + \advance\fp@loopcount by -1 + \repeat +}% end \fp@regcomp@main +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Unary Operations} +% +% \begin{macro}{\fp@regabs} +% The macro "\fp@regabs" turns register "#1" into its amount. +% This is rather trivial: just set the sign to `"+"'. +% \begin{macrocode} +\def\fp@regabs#1{% + \ar@setsig{#1}{+}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regneg} +% The macro "\fp@regneg" negates register "#1". It checks +% whether the actual sign is `"+"' or `"-"' and sets it +% to its opposite, except that nothing is done if the +% number is zero. +% \begin{macrocode} +\def\fp@regneg#1{% + \if\ar@getsig{#1}-% + \ar@setsig{#1}{+}% + \else + \fp@regcomp{#1}{@0}% + \if\fp@param=% + \else + \ar@setsig{#1}{-}% + \fi + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@reground} +% The macro "\fp@reground" rounds register "#1" with a target accuracy +% given as "#2" (as a power of ten). +% \begin{macrocode} +\def\fp@reground#1#2{% +% \end{macrocode} +% Fist, if the desired accuracy is smaller than the lower limit of +% "#1", nothing has to be done. +% \begin{macrocode} + \ifnum#2>\ar@getll{#1}\relax + {% +% \end{macrocode} +% Otherwise, we check the following digit. If it is greater than four, +% we have to advance digit "#2" before truncating the number. This +% means adding $10^{\mathtt{\#2}}$ for positive "#1" and subtracting +% $10^{\mathtt{\#2}}$ for negative "#1". +% \begin{macrocode} + \fp@tempcount=#2\relax + \advance\fp@tempcount by -1 + \fp@getdigit{#1}{\fp@tempcount}% + \ifnum\fp@param>4 + \fp@regcopy{fp@temp}{@1}% + \fp@shiftright{fp@temp}{#2}% + \fp@regcomp{#1}{@0}% + \if\fp@param<% + \fp@regneg{fp@temp}% + \fi + \fp@regadd{#1}{fp@temp}% + \fi +% \end{macrocode} +% Afterwards, we set the lower limit to "#2". If "#2" is greater than +% zero, +% we set the lower limit and all digits~$n$ with $0\leq n<\texttt{\#2}$ +% to zero. Then we read the number using +% "\fp@regget", make it globally available and read it into "#1" +% after finishing the local group. +% \begin{macrocode} + \ifnum#2>0 + \fp@loopcount=#2\relax + \iloop + \ifnum\fp@loopcount>0 + \advance\fp@loopcount by -1 + \ar@set{#1}{\fp@loopcount}{0}% + \irepeat + \ar@setll{#1}{0}% + \else + \ar@setll{#1}{#2}% + \fi + \fp@regget{#1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \fp@regread{#1}{\fp@param}% + \fi +} % end \fp@reground +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Binary operations} +% +% \begin{macro}{\fp@regcopy} +% The macro "\fp@regcopy" assigns the value of register +% "#2" to register "#1". This is done simply by reading +% register "#2" into a scratch control sequence +% and then reading this into register "#1". +% \begin{macrocode} +\def\fp@regcopy#1#2{% + \fp@regget{#2}{\fp@scratch}% + \fp@regread{#1}{\fp@scratch}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regadd} +% The macro "\fp@regadd" adds the value of register "#2" to +% register "#1". +% \begin{macrocode} +\def\fp@regadd#1#2{% + {% +% \end{macrocode} +% First, check whether the two numbers have the same sign. +% \begin{macrocode} + \if\ar@getsig{#1}\ar@getsig{#2}% +% \end{macrocode} +% If the two numbers have the same sign, the addition can be +% done by adding each two corresponding digits and a possible +% carryover, starting at $\min(\mbox{ll1},\mbox{ll2})$, +% ending at $\max(\mbox{ul1},\mbox{ul2})$. Those values +% are saved in "\fp@add@start" and "\fp@add@finish". +% \begin{macrocode} + \fp@settomin{\fp@loopcount}{\ar@getll{#1}}{\ar@getll{#2}}% + \edef\fp@add@start{\number\fp@loopcount}% + \fp@settomax{\fp@tempcount}{\ar@getul{#1}}{\ar@getul{#2}}% + \edef\fp@add@finish{\number\fp@tempcount}% +% \end{macrocode} +% Initialize "\fp@carryover". +% \begin{macrocode} + \fp@carryover=0 +% \end{macrocode} +% Now start the main loop. Each digit is computed +% in counter "\fp@result" as the +% sum of the corresponding digits plus the carryover from +% the previous pair. If the sum is greater than 10, +% it is reduced by 10 and "\fp@carryover" is set to 1. +% (No sum greater than 19 is possible.) +% \begin{macrocode} + \loop + \fp@getdigit{#1}{\fp@loopcount}% + \fp@result=\fp@param\relax + \fp@getdigit{#2}{\fp@loopcount}% + \advance\fp@result by \fp@param\relax + \advance\fp@result by \fp@carryover + \ifnum\fp@result>9 + \fp@carryover=1 + \advance\fp@result by -10 + \else + \fp@carryover=0 + \fi + \ar@set{#1}{\fp@loopcount}{\fp@result}% + \ifnum\fp@loopcount<\fp@add@finish\relax + \advance\fp@loopcount by 1 + \repeat +% \end{macrocode} +% If the last pair had a carryover, take it into account. +% Then adjust the lower and upper limit of the result. +% \begin{macrocode} + \ifnum\fp@carryover>0 + \advance\fp@loopcount by 1 + \ar@set{#1}{\fp@loopcount}{\fp@carryover}% + \fi + \ar@setll{#1}{\fp@add@start}% + \ar@setul{#1}{\fp@loopcount}% +% \end{macrocode} +% Finally, save the result in "\fp@param" to make it survive +% the endgroup character after "\fi". +% \begin{macrocode} + \fp@regget{#1}{\fp@scratch}% + \fp@setparam\fp@scratch +% \end{macrocode} +% That's it. But if the two numbers have different signs, +% the situation is a bit more complicated. In this case, +% the amounts of "#1" and "#2" are saved in two temporary registers +% ("fp@tempi" and "fp@tempii"). The smaller one is subtracted +% from the larger one, and the sign of the result is +% adjusted according to the sign of "#1" and "#2". +% This is done by the subroutine "\fp@regadd@sub", which also takes +% care of saving the result in "\fp@param". +% \begin{macrocode} + \else % \if sign + \fp@regcopy{fp@tempi}{#1}% + \fp@regcopy{fp@tempii}{#2}% + \fp@regabs{fp@tempi}% + \fp@regabs{fp@tempii}% + \fp@regcomp{fp@tempi}{fp@tempii}% + \if\fp@param>% + \fp@regadd@sub{#1}{fp@tempi}{fp@tempii}% + \else + \fp@regadd@sub{#2}{fp@tempii}{fp@tempi}% + \fi + \fi % end \if sign +% \end{macrocode} +% Now end the group to keep everything local, and read +% the result in "\fp@param" into register "#1". +% \begin{macrocode} + }% + \fp@regread{#1}{\fp@param}% +}% end \fp@regadd +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regadd@sub} +% The macro "\fp@regadd@sub" is a subroutine of +% "\fp@regadd". +% \begin{macrocode} +\def\fp@regadd@sub#1#2#3{% +% \end{macrocode} +% First, subtract "#3" from "#2". The restriction $\mbox{\tt\#2}> +% \mbox{\tt\#3}$ is ensured by the calling "\fp@regadd". +% \begin{macrocode} + \fp@regsub@restricted{#2}{#3}% +% \end{macrocode} +% "#1" is the original number of which "#2" is the amount. +% So, if it is negative, the final result also has to be negative. +% This is done by the following four lines. +% \begin{macrocode} + \fp@regcomp{#1}{@0}% + \if\fp@param<% + \fp@regneg{#2}% + \fi +% \end{macrocode} +% Now, the final result is stored in "#2". Make it +% globally available using "\fp@setparam". +% \begin{macrocode} + \fp@regget{#2}{\fp@scratch}% + \fp@setparam\fp@scratch +}% end \fp@regadd@sub +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regsub@restricted} +% The macro "\fp@regsub@restricted" does the actual +% work of subtracting "#2" from "#1", provided that +% "#1" is greater than "#2". It is called by +% "\fp@regadd@sub" and by "\fp@regdiv". +% \begin{macrocode} +\def\fp@regsub@restricted#1#2{% +% \end{macrocode} +% First, we start a group to keep counters etc.\ local. +% Then, we determine the start and end position for the +% loop, as above for "\fp@regadd". +% \begin{macrocode} + {% + \fp@settomin{\fp@loopcount}{\ar@getll{#1}}{\ar@getll{#2}}% + \edef\fp@lowermin{\number\fp@loopcount}% + \fp@settomax{\fp@tempcount}{\ar@getul{#1}}{\ar@getul{#2}}% + \edef\fp@uppermin{\number\fp@tempcount}% +% \end{macrocode} +% Now subtract the corresponding digits, taking into +% account a possible carryover. +% \begin{macrocode} + \fp@carryover=0 + \loop + \fp@getdigit{#1}{\fp@loopcount}% + \fp@result=\fp@param\relax + \fp@getdigit{#2}{\fp@loopcount}% + \advance\fp@result by -\fp@param\relax + \advance\fp@result by \fp@carryover +% \end{macrocode} +% If the result is $<0$, add 10 to the result +% and set the carryover to $-1$. +% \begin{macrocode} + \ifnum\fp@result<0 + \fp@carryover=-1 + \advance\fp@result by 10 + \else + \fp@carryover=0 + \fi +% \end{macrocode} +% Now save the result and repeat if there are further +% digits. +% \begin{macrocode} + \ar@set{#1}{\fp@loopcount}{\fp@result}% + \ifnum\fp@loopcount<\fp@uppermin\relax + \advance\fp@loopcount by 1 + \repeat +% \end{macrocode} +% If there is a carryover for the last two digits, +% take it into account. +% \begin{macrocode} + \ifnum\fp@carryover=-1 + \advance\fp@loopcount by 1 + \ar@set{#1}{\fp@loopcount}{-1}% + \fi +% \end{macrocode} +% Now adjust the upper and lower limit of the result, +% and save it in "\fp@param". +% \begin{macrocode} + \ar@setll{#1}{\fp@lowermin}% + \ar@setul{#1}{\fp@loopcount}% + \fp@regget{#1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% +% \end{macrocode} +% Finally, assign the result to "#1" inside the current group. +% \begin{macrocode} + \fp@regread{#1}{\fp@param}% +}% end \fp@regsub@restricted +% \end{macrocode} +% \end{macro} +% \begin{macro}{\fp@regsub} +% The macro "\fp@regsub" subtracts register "#2" from +% register "#1". This is done by negating "#2" inside +% a group and calling "\fp@regadd". +% \begin{macrocode} +\def\fp@regsub#1#2{% + {% + \fp@regneg{#2}% + \fp@regadd{#1}{#2}% + \fp@regget{#1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \fp@regread{#1}{\fp@param}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regmul} +% The macro "\fp@regmul" multiplies the value +% of register "#1" with the value of register "#2". +% \begin{macrocode} +\def\fp@regmul#1#2{% + {% +% \end{macrocode} +% First, we initialize the temporary register "fp@temp1" +% as zero; it will be used to hold the results so far. +% Then we start the outer "\xloop" which will +% run through all digits of "#2", beginning at the lower limit. +% \begin{macrocode} + \fp@regcopy{fp@temp1}{@0}% + \fp@loopcountii=\ar@getll{#2}\relax + \xloop +% \end{macrocode} +% Then we initialize the inner loop, which multplies the +% current digit of "#2" with "#1" digit after digit, +% saving the result in "\fp@newnum". +% \begin{macrocode} + \fp@loopcount=\ar@getll{#1}\relax + \fp@carryover=0 + \def\fp@newnum{}% + \loop + \fp@result=\ar@get{#2}{\fp@loopcountii}\relax + \multiply\fp@result by \ar@get{#1}{\fp@loopcount}\relax + \advance\fp@result by \fp@carryover +% \end{macrocode} +% If the result is greater than~9, we set the carryover +% as $(\mbox{\tt\bslash fp@result}\bmod 10)$ and +% the result to $(\mbox{\tt\bslash fp@result}\mathop{\mbox{div}}10)$. +% \begin{macrocode} + \ifnum\fp@result>9 + \fp@carryover=\fp@result + \divide\fp@carryover by 10 + \fp@tempcount=\fp@carryover + \multiply\fp@tempcount by 10 + \advance\fp@result by -\fp@tempcount + \else + \fp@carryover=0 + \fi + \edef\fp@newnum{\number\fp@result\fp@newnum}% + \ifnum\fp@loopcount<\ar@getul{#1}\relax + \advance\fp@loopcount by 1 + \repeat + \edef\fp@newnum{\number\fp@carryover\fp@newnum}% + \fp@regread{fp@temp2}{\fp@newnum}% +% \end{macrocode} +% Now "fp@temp2" holds the partial result for this digit of +% "#2". We have to multiply it with $10^n$, if $n$ is the +% number of digits of "#2" completed so far. +% This is done by calling "\fp@shiftright" with $-n$ as +% second argument. +% \begin{macrocode} + \fp@tempcount=\fp@loopcountii + \advance\fp@tempcount by -\number\ar@getll{#2}\relax + \fp@shiftright{fp@temp2}{\fp@tempcount}% +% \end{macrocode} +% Now we add "fp@temp2" to the results so far and iterate +% if there are further digits. +% \begin{macrocode} + \fp@regadd{fp@temp1}{fp@temp2}% + \ifnum\fp@loopcountii<\ar@getul{#2}\relax + \advance\fp@loopcountii by 1 + \xrepeat +% \end{macrocode} +% The final result of the multiplication will have +% as much afterpoint digits as "#1" and "#2" have together. +% Adjust this. +% \begin{macrocode} + \fp@tempcount=\ar@getll{#1}\relax + \advance\fp@tempcount by \ar@getll{#2}\relax + \fp@shiftright{fp@temp1}{\fp@tempcount}% +% \end{macrocode} +% If "#1" and "#2" have different signs, the result is negative, +% otherwise positive. +% \begin{macrocode} + \if\ar@getsig{#1}\ar@getsig{#2}% + \else + \fp@regneg{fp@temp1}% + \fi +% \end{macrocode} +% Finally, save the result via "\fp@setparam" and assign it +% to "#1" after the end of the group. +% \begin{macrocode} + \fp@regget{fp@temp1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \fp@regread{#1}{\fp@param}% +} % end \fp@regmul +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@regdiv} +% The macro "\fp@regdiv" divides register "#1" by register "#2". +% It works by repeated subtraction. +% \begin{macrocode} +\def\fp@regdiv#1#2{% + {% +% \end{macrocode} +% The amount of the two numbers is read into the two +% temporary registers "fp@temp1" and "fp@temp2". +% \begin{macrocode} + \fp@regcopy{fp@temp1}{#1}% + \fp@regcopy{fp@temp2}{#2}% + \fp@regabs{fp@temp1}% + \fp@regabs{fp@temp2}% +% \end{macrocode} +% First, we determine the initial shift for "fp@temp2". +% This is the shift which will make "fp@temp2" have as many +% digits before the decimal sign as "fp@temp1". +% "\fp@firstnonzero" is used, because the upper limit +% need not be the first non-zero digit. +% \begin{macrocode} + \fp@firstnonzero{fp@temp1}% + \fp@loopcountii=\fp@param\relax + \fp@firstnonzero{fp@temp2}% + \advance\fp@loopcountii by -\fp@param\relax + \fp@shiftright{fp@temp2}{\fp@loopcountii}% +% \end{macrocode} +% Now we initialize "\fp@divnum" which will hold the result. +% If "\fp@loopcountii" is smaller than zero, i.\,e., if +% the first digit of the result that will be computed +% is after the decimal sign, we have to +% initialize "\fp@divnum" with the decimal sign as well +% as with an appropriate number of zeros following it. +% \begin{macrocode} + \def\fp@divnum{}% + \ifnum\fp@loopcountii<0 + \fp@tempcount=\fp@loopcountii + \loop + \ifnum\fp@tempcount<-1 + \edef\fp@divnum{0\fp@divnum}% + \advance\fp@tempcount by 1 + \repeat + \edef\fp@divnum{\fp@decimalsign\fp@divnum}% + \fi +% \end{macrocode} +% The main loop follows. Each digit is determined by +% subtracting the divisor $n$ times from the dividend until +% the result is smaller than the divisor. +% This is done only if "\fp@loopcountii" plus one +% is greater than "-\fp@accuracy". +% If the divisor is equal to the dividend, the division is complete +% and the "\xloop" is terminated. Therefore, "\fp@accuracy" is locally +% set to `"0"', so that possibly following zeros are computed +% until the digit representing $10^0$. +% At the end, the divisor is divided +% by 10, and the next digit follows. +% \begin{macrocode} + \xloop + \fp@tempcount=\fp@loopcountii + \advance\fp@tempcount by 1 + \ifnum\fp@tempcount>-\fp@accuracy\relax + \fp@loopcount=0 + \loop + \fp@regcomp{fp@temp2}{fp@temp1}% + \if\fp@param=% + \def\fp@accuracy{0}% + \gdef\fp@param{<}% + \fi + \if\fp@param<% + \fp@regsub@restricted{fp@temp1}{fp@temp2}% + \advance\fp@loopcount by 1 + \repeat + \ifnum\fp@loopcountii=-1 + \edef\fp@divnum{\fp@divnum\fp@decimalsign}% + \fi + \edef\fp@divnum{\fp@divnum\number\fp@loopcount}% + \fp@shiftright{fp@temp2}{-1}% + \advance\fp@loopcountii by -1 + \xrepeat +% \end{macrocode} +% The sign of the result is set according to the +% signs of "#1" and "#2". +% \begin{macrocode} + \if\ar@getsig{#1}\ar@getsig{#2}% + \fp@regread{fp@temp1}{\fp@divnum}% + \else + \fp@regread{fp@temp1}{-\fp@divnum}% + \fi +% \end{macrocode} +% Now save the result in "\fp@param". After endgroup, +% read it into "#1". +% \begin{macrocode} + \fp@regget{fp@temp1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \fp@regread{#1}{\fp@param}% +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{User interface} +% +% \begin{macro}{\fp@call@bin} +% The macro "\fp@call@bin" is a common calling command +% used by the user commands for binary operations. It reads +% the values given in "#2" and "#3" into temporary registers, +% performs the operation specified in "#4", +% and finally assigns the result to the command sequence +% given as "#1". +% \begin{macrocode} +\def\fp@call@bin#1#2#3#4{% + {% + \fp@regread{fp@user1}{#2}% + \fp@regread{fp@user2}{#3}% + \csname fp@reg#4\endcsname{fp@user1}{fp@user2}% + \fp@regget{fp@user1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \edef#1{\fp@param}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpAdd} +% As described above, the main work is done by "\fp@call@bin", +% so this macro reduces to passing the parameters and +% specifying the desired operation. +% \begin{macrocode} +\def\fpAdd#1#2#3{\fp@call@bin{#1}{#2}{#3}{add}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpSub} +% Just like "\fpAdd". +% \begin{macrocode} +\def\fpSub#1#2#3{\fp@call@bin{#1}{#2}{#3}{sub}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpMul} +% Just like "\fpAdd". +% \begin{macrocode} +\def\fpMul#1#2#3{\fp@call@bin{#1}{#2}{#3}{mul}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpDiv} +% Just like "\fpAdd". +% \begin{macrocode} +\def\fpDiv#1#2#3{\fp@call@bin{#1}{#2}{#3}{div}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp@call@un} +% Similarly, the unary operations "\fpAbs" and "\fpNeg" +% refer to the common macro "\fp@call@un". +% \begin{macrocode} +\def\fp@call@un#1#2#3{% + {% + \fp@regread{fp@user1}{#2}% + \csname fp@reg#3\endcsname{fp@user1}% + \fp@regget{fp@user1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \edef#1{\fp@param}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpAbs} +% Pass the information and specify the action. +% \begin{macrocode} +\def\fpAbs#1#2{\fp@call@un{#1}{#2}{abs}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpNeg} +% Just like "\fpAbs". +% \begin{macrocode} +\def\fpNeg#1#2{\fp@call@un{#1}{#2}{neg}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRound} +% This macro does not fit into the scheme, so it has to be defined +% seperately. +% \begin{macrocode} +\def\fpRound#1#2#3{% + {% + \fpRegSet{fp@user1}{#2}% + \fpRegRound{fp@user1}{#3}% + \fpRegGet{fp@user1}{\fp@scratch}% + \fp@setparam\fp@scratch + }% + \edef#1{\fp@param}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegSet} +% The register operations "\fpRegSet", "\fpRegGet", +% "\fpRegAdd", "\fpRegSub", "\fpRegMul", "\fpRegDiv", +% "\fpRegAbs", "\fpRegNeg", "\fpRegCopy" and "\fpRegRound" +% have the same syntax as the internal variants, so their +% definitions reduce to passing the parameters. The register name +% is always given as the first parameter. +% \begin{macrocode} +\def\fpRegSet#1#2{\fp@regread{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegGet} +% As described above. +% \begin{macrocode} +\def\fpRegGet#1#2{\fp@regget{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegAdd} +% As described above. +% \begin{macrocode} +\def\fpRegAdd#1#2{\fp@regadd{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegSub} +% As described above. +% \begin{macrocode} +\def\fpRegSub#1#2{\fp@regsub{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegMul} +% As described above. +% \begin{macrocode} +\def\fpRegMul#1#2{\fp@regmul{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegDiv} +% As described above. +% \begin{macrocode} +\def\fpRegDiv#1#2{\fp@regdiv{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegAbs} +% As described above. +% \begin{macrocode} +\def\fpRegAbs#1{\fp@regabs{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegNeg} +% As described above. +% \begin{macrocode} +\def\fpRegNeg#1{\fp@regneg{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegCopy} +% As described above. +% \begin{macrocode} +\def\fpRegCopy#1#2{\fp@regcopy{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpRegRound} +% As described above. +% \begin{macrocode} +\def\fpRegRound#1#2{\fp@reground{#1}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fpAccuracy} +% \begin{macro}{\fp@accuracy} +% The user command "\fpAccuracy" "\edef"s the internal +% parameter "\fp@accuracy", which stores the maximum +% number of digits after the decimal sign, i.\,e., +% the minimum for the lower limit of fp numbers. +% At the moment, "\fp@accuracy" does not affect the accuracy +% of any operation except "\fp@regdiv". In fact, it was +% introduced when the definition of a termination condition +% for the loop was not possible without an externally given limit. +% "\fp@accuracy" is initialized to `"5"' digits after +% the decimal sign. +% \begin{macrocode} +\def\fpAccuracy#1{\edef\fp@accuracy{#1}} +\fpAccuracy{5} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fpDecimalSign} +% \begin{macro}{\fp@decimalsign} +% The command "\fpDecimalSign" allows the user to select any character +% for use as the decimal sign. The character is stored in +% "\fp@decimalsign". Normally, the decimal sign will be either `"."' or +% `","'; a comma is the default. (Take a look at ISO~31-0, part 3.3.2, +% if you dislike this.) +% \begin{macrocode} +\def\fpDecimalSign#1{\edef\fp@decimalsign{#1}} +\fpDecimalSign{,} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fpThousandsep} +% \begin{macro}{\fp@thousandsep} +% Those macros are used to define and store a thousand seperator +% used by "\fp@regoutput". By default, there is none. +% \begin{macrocode} +\def\fpThousandSep#1{\edef\fp@thousandsep{#1}} +\fpThousandSep{} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Constants} +% +% \begin{macro}{@0} +% \begin{macro}{@1} +% The number zero ist stored +% in register "@0", the number one in register "@1". +% \begin{macrocode} +\fp@regread{@0}{0} +\fp@regread{@1}{1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsection{Finish} +% Finally, restore the catcode of `"@"' and "\endinput". +% \begin{macrocode} +\catcode`\@=\atcatcode\relax +\endinput +%</fltmain> +% \end{macrocode} +% \Finale +% \PrintIndex +% \PrintChanges diff --git a/Master/texmf-dist/source/generic/fltpoint/fltpoint.ins b/Master/texmf-dist/source/generic/fltpoint/fltpoint.ins new file mode 100644 index 00000000000..f8e4203913f --- /dev/null +++ b/Master/texmf-dist/source/generic/fltpoint/fltpoint.ins @@ -0,0 +1,8 @@ +\input docstrip
+\keepsilent
+\usedir{tex/latex/fltpoint}
+\generate{\file{deccomma.sty}{\from{fltpoint.dtx}{deccomma}}}
+\generate{\file{fltpoint.sty}{\from{fltpoint.dtx}{package}}}
+\usedir{tex/generic/fltpoint}
+\generate{\file{fltpoint.tex}{\from{fltpoint.dtx}{fltmain}}}
+\endbatchfile
|