% -*- coding: utf-8; time-stamp-format: "%02d-%02m-%:y at %02H:%02M:%02S %Z" -*- % This file: xint-calx.dtx. Proudly produced by xint-dtxbuild.sh. % Run etex on this file to extract all xint*sty files. %<*dtx> \def\xintdtxtimestamp {Time-stamp: <05-11-2026 at 13:36:23 CET>} % % % To build xint-calx.pdf (with both user manual and commented source code), % the recommended way is: % % - step 1: etex xint-calx.dtx (stop here if you only need the xint*sty files) % - step 2: make --file=Makefile.mk xint-calx.pdf % % The above step 2 requires make + latexmk and uses latex + dvipdfmx. % % Other make targets are % - xintmanual.pdf (contains only the user documentation) % - xintsource.pdf (contains only the commented source code) % % Alternative for building xint-calx.pdf (and extracting the xint*sty files): % % Direct runs of pdflatex, xelatex or lualatex on xint-calx.dtx, % or (better) of latexmk -pdf (or -pdfxe, -pdflua) on xint-calx.dtx. % % (if using xelatex, it must be with -8bit option for extracted Makefile.mk % to be valid, but this has no impact on the xint*sty files and xint-calx.pdf). % %<*xintmandrv|xintsrcdrv|xintalldrv> %% --------------------------------------------------------------- \def\calxbndldate{2026/11/01} \def\calxbndlversion{2.0a1} \let\xintbndldate\calxbndldate \let\xintbndlversion\calxbndlversion % %<*!makefile> %% --------------------------------------------------------------- %% The xint bundle 2.0 2026/10/22 %% Copyright (C) 2013-2022, 2025, 2026 Jean-Francois Burnol %%% xint: Expandable operations on big integers %%% xintbinhex: Expandable radix conversions (2, 8, 10, and 16) %%% xintcfrac: Expandable continued fractions with xint package %%% xintcore: Expandable arithmetic on big integers %%% xintexpr: Expandable fp, bigint and fraction expression parsers %%% xintfrac: Expandable operations on fractions %%% xintgcd: Euclidean algorithm with xint package %%% xintkernel: Paraphernalia for the xint packages %%% xintseries: Expandable partial sums with xint package %%% xinttools: Expandable and non-expandable utilities %%% calx: Expandable fp and bigint expression parsers %%% calxcore: Expandable arithmetic on big integers %%% calxfp: Floating point unit P1 to P100 %%% calxint: Expandable operations on big integers %%% calxlog: log, exp, etc for xintexpr/calx %%% calxtrig: sin, cos, etc for xintexpr/calx %% --------------------------------------------------------------- % %<*dtx> \bgroup\catcode2 0 \catcode`\\ 12 ^^Biffalse % %<*dates>------------------------------------------------------- `2.0a1 (2026/11/01)` `1.4q (2026/10/31)` `1.4p (2026/03/01)` `1.4o (2025/09/06)` `1.4n (2025/09/05)` `1.4m (2022/06/10)` `1.4l (2022/05/29)` `1.4k (2022/05/18)` `1.4j (2021/07/13)` `1.4i (2021/06/11)` `1.4h (2021/05/27)` `1.4g (2021/05/25)` `1.4f (2021/05/10)` `1.4e (2021/05/05)` `1.4d (2021/03/29)` `1.4c (2021/02/20)` `1.4b (2020/02/25)` `1.4a (2020/02/19)` `1.4 (2020/01/31)` `1.3f (2019/09/10)` `1.3e (2019/04/05)` `1.3d (2019/01/06)` `1.3c (2018/06/17)` `1.3b (2018/05/18)` `1.3a (2018/03/07)` `1.3 (2018/03/01)` `1.2q (2018/02/06)` `1.2p (2017/12/05)` `1.2o (2017/08/29)` `1.2n (2017/08/06)` `1.2m (2017/07/31)` `1.2l (2017/07/26)` `1.2k (2017/01/06)` `1.2j (2016/12/22)` `1.2i (2016/12/13)` `1.2h (2016/11/20)` `1.2g (2016/03/19)` `1.2f (2016/03/12)` `1.2e (2015/11/22)` `1.2d (2015/11/18)` `1.2c (2015/11/16)` `1.2b (2015/10/29)` `1.2a (2015/10/19)` `1.2 (2015/10/10)` `1.1c (2015/09/12)` `1.1b (2015/08/31)` `1.1a (2014/11/07)` `1.1 (2014/10/28)` `1.09n (2014/04/01)` `1.09m (2014/02/26)` `1.09kb (2014/02/13)` `1.09k (2014/01/21)` `1.09j (2014/01/09)` `1.09i (2013/12/18)` `1.09h (2013/11/28)` `1.09g (2013/11/22)` `1.09f (2013/11/04)` `1.09e (2013/10/29)` `1.09d (2013/10/22)` `1.09c (2013/10/09)` `1.09b (2013/10/03)` `1.09a (2013/09/24)` `1.08b (2013/06/14)` `1.08a (2013/06/11)` `1.08 (2013/06/07)` `1.07 (2013/05/25)` `1.06b (2013/05/14)` `1.06 (2013/05/07)` `1.05 (2013/05/01)` `1.04 (2013/04/25)` `1.03 (2013/04/14)` `1.0 (2013/03/28)` %------------------------------------------------------ %<*makefile>------------------------------------------------------ # This file: Makefile.mk (generated from xint-calx.dtx) # "make --file=Makefile.mk help" # The 1.4p CTAN zip does not include an xint.tds.zip anymore # But the Makefile recipe is kept here in case of need. # A copy of README.md is not included in xint-calx.dtx anymore. # The 1.4n CTAN zip includes an xintchanges.md but no CHANGES.html # anymore. The xintchanges.md is not extracted from the dtx but # kept separate. # The 1.4n CTAN zip does not ship with a commodity Makefile anymore, # use -f Makefile.mk as above or rename it to Makefile. # Also it does not include CHANGES.html. It can be build via make # or checked at https://jfbu.github.io/xint/CHANGES.html. # With 1.4n also, sourcexint.pdf got renamed into xintsource.pdf # and xint.pdf became what was called xint-all.pdf, i.e. (as was also # the case originally) it contains both user manual and documented # source code. This allows to benefit from hyperlinks between the two, # which were added already in 2022. # Starting with xint 1.3c, Latexmk is used for easier compilation of # sourcexint.pdf as the latter then included indices. These indices # got removed at 1.3e but usage of Latexmk is maintained for the build. # Originally tested on Mac OS X Mavericks with GNU Make 3.81, # TeXLive 2014 and Pandoc 1.13.1. # Note to myself: I wanted to use .RECIPEPREFIX = > but it is # supported only with GNU Make 3.82 and later. # this crazyness is to circumvent a problem with docstrip generation # of the Makefile; we do not want two empty lines becoming only one nullstring := define newline $(nullstring) endef # will speed-up a little, I think. newline := $(newline) define helptext ==== INSTRUCTIONS It is recommended to work with xint-calx.dtx and Makefile moved to some otherwise empty temporary repertory. make help Display this help using the more pager. make helpless Display this help using the less pager. make doc Produce all documentation, requires Latexmk and Pandoc. make all Produce all documentation, then creates xint.tds.zip. make xint.tds.zip Same as "make all" make xintmanual.pdf Extract files and produce xintmanual.pdf (user manual), using latex and dvipdfmx. This requires Latexmk. make xintsource.pdf Extract files and produce xintsource.pdf (source code), using latex and dvipdfmx. This requires Latexmk. make xint-calx.pdf Extract files and produce xint-calx.pdf (manual + code), using latex and dvipdfmx. This requires Latexmk. make CHANGES.html This requires Pandoc. make clean Remove auxiliary files and repertories. make cleanmore Remove also PDFs and ZIP archives and a few more. ==== INSTALLING The following has been tested on a TeXLive installation: make installhome Create xint.tds.zip, and unzip it in make installlocal Create xint.tds.zip, unzip it in and then does texhash Depending on access rights "sudo make installlocal" might be needed. In case of doubt run first "make doc" then "make installlocal". If the latter fails, then try "sudo make installlocal". make uninstallhome Remove all xint files and repertories from make uninstalllocal Remove all xint files and repertories from and then does texhash Might need "sudo". endef # Quelques difficultés à trouver le bon choix de ' ou " et de \# # et l'utilisation des \ en fins de ligne pour que ça fonctionne. highlighting-css = ' body{margin: 0; margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 20px; font-family: serif; max-width: 100%; padding: 0; }\ pre {white-space: pre-wrap;}\ code {white-space: pre-wrap;}\ a:link { color: blue; }\ a:visited { color: green; }\ a:hover { text-decoration: underline; color: hotpink }\ a:active { color: brown; }\ \#TOC {float: right; position: relative; top: 100px; margin-bottom: 100px; margin-left: 20px;}' .PHONY: help helpless all doc clean cleanmore\ installhome uninstallhome installlocal uninstalllocal # for printf with subst and \n, got it from # http://stackoverflow.com/a/5887751 # I could do the trick with := here, for \n substitution, but this would add # tiny overhead to all other operations of make help: @printf '$(subst $(newline),\n,$(helptext))' | more helpless: @printf '$(subst $(newline),\n,$(helptext))' | less # RM = rm -f JF_tmpdir := $(shell mktemp -d TEMP_XINT_XXX) TEXMF_local = $(shell kpsewhich -var-value TEXMFLOCAL) TEXMF_home = $(shell kpsewhich -var-value TEXMFHOME) packages = xintkernel.sty xintcore.sty xint.sty xintfrac.sty xintexpr.sty\ xintgcd.sty xintbinhex.sty xintseries.sty xintcfrac.sty\ xinttools.sty\ calxcore.sty calxint.sty calxfp.sty calx.sty\ calxlog.tex calxlogdata.tex calxtrig.tex calxtrigdata.tex # Makefile.mk n'est pas mis dans $(extrated) pour éviter des messages # de make. Les sty (aussi extraits) sont dans $(packages). extracted = xintmanual.tex xintsource.tex xint-calx.tex xint-dates.txt filesfortex = $(packages) filesforsource = xint-calx.dtx filesfordoc = xint-calx.pdf README.md xintchanges.md auxiliaryfiles = xintmanual.dvi xintmanual.aux xintmanual.toc xintmanual.log\ xintsource.dvi xintsource.aux xintsource.toc xintsource.log\ xint-calx.dvi xint-calx.aux xint-calx.toc xint-calx.log all: $(packages) $(extracted) doc xint-calx.tds.zip @echo 'make all done.' $(packages): xint-calx.dtx etex xint-calx.dtx $(extracted): xint-calx.dtx etex xint-calx.dtx doc: xintmanual.pdf xintsource.pdf CHANGES.html @echo 'make doc done.' xintmanual.pdf: xint-calx.dtx xintmanual.tex latexmk xintmanual.tex dvipdfmx xintmanual.dvi xintsource.pdf: xint-calx.dtx xintsource.tex latexmk xintsource.tex dvipdfmx xintsource.dvi xint-calx.pdf: xint-calx.dtx xint-calx.tex latexmk xint-calx.tex dvipdfmx xint-calx.dvi CHANGES.html: xintchanges.md pandoc -o CHANGES.html -s --toc -V highlighting-css=$(highlighting-css) xintchanges.md xint.tds.zip: $(filesfordoc) $(filesforsource) $(filesfortex) rm -fr $(JF_tmpdir) mkdir -p $(JF_tmpdir)/doc/generic/xint mkdir -p $(JF_tmpdir)/source/generic/xint mkdir -p $(JF_tmpdir)/tex/generic/xint chmod -R ugo+rwx $(JF_tmpdir) cp -a $(filesfordoc) $(JF_tmpdir)/doc/generic/xint cp -a $(filesforsource) $(JF_tmpdir)/source/generic/xint cp -a $(filesfortex) $(JF_tmpdir)/tex/generic/xint cd $(JF_tmpdir); chmod -R ugo+r doc source tex umask 0022 && cd $(JF_tmpdir) &&\ zip -r xint.tds.zip doc source tex &&\ mv -f xint.tds.zip ../ rm -fr $(JF_tmpdir) @echo 'make xint.tds.zip done.' xint.zip: $(filesfordoc) $(filesforsource) $(filesfortex) mkdir -p $(JF_tmpdir)/xint chmod ugo+rwx $(JF_tmpdir)/xint cp -a $(filesfordoc) $(JF_tmpdir)/xint cp -a $(filesforsource) $(JF_tmpdir)/xint chmod -R ugo+r $(JF_tmpdir)/xint umask 0022 && cd $(JF_tmpdir) && zip -r xint.zip xint mv -f $(JF_tmpdir)/xint.zip ./ rm -fr $(JF_tmpdir) @echo 'make xint.zip done.' installhome: xint.tds.zip unzip xint.tds.zip -d $(TEXMF_home) uninstallhome: cd $(TEXMF_home) && rm -fr doc/generic/xint \ source/generic/xint \ tex/generic/xint # cf http://stackoverflow.com/a/1909390 # as kpsewhich is very slow (.5s) I want to evaluate once only. installlocal: xint.tds.zip $(eval $@_tmp := $(TEXMF_local)) unzip xint.tds.zip -d $($@_tmp) && texhash $($@_tmp) uninstalllocal: cd $(TEXMF_local) && rm -fr doc/generic/xint \ source/generic/xint \ tex/generic/xint && texhash . clean: rm -fr auto/ .auto/ TEMP*/ rm -f $(auxiliaryfiles)\ xintmanual.fls xintmanual.fdb_latexmk\ xintsource.fls xintsource.fdb_latexmk\ xint-calx.fls xint-calx.fdb_latexmk # 1.4p does not remove xintmanual.pdf and xintsource.pdf # because cleanmore is used at home for building zip for CTAN # and it does not include them anyhow. cleanmore: clean rm -f xint-calx.pdf xint.tds.zip xint.zip %$----------------------------------------------------- %<*xintmandrv>----------------------------------------------------------- %% To extract files: %% etex xint-calx.dtx %% %% Then execute: %% make --file=Makefile.mk xintmanual.pdf %% %% Alternative for build without `make': %% latexmk xintmanual.tex %% dvipdfmx xintmanual.dvi %% %% One can also tell latexmk to use pdflatex, lualatex or xelatex. %% Or use one of them directly enough times on xintmanual.tex. \NeedsTeXFormat{LaTeX2e} \ProvidesFile{xintmanual.tex}% [\xintbndldate\space v\xintbndlversion\space xint documentation (JFB)]% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl} \chardef\NoSourceCode 1 \input xint-calx.dtx %%% Local Variables: %%% mode: latex %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %----------------------------------------------------------- %<*xintsrcdrv>----------------------------------------------------------- %% To extract files: %% etex xint-calx.dtx %% %% Then execute: %% make --file=Makefile.mk xintsource.pdf %% %% Alternative for build without `make': %% latexmk xintsource.tex %% dvipdfmx xintsource.dvi %% %% One can also tell latexmk to use pdflatex, lualatex or xelatex. %% Or use one of them directly enough times on xintsource.tex. \NeedsTeXFormat{LaTeX2e} \ProvidesFile{xintsource.tex}% [\xintbndldate\space v\xintbndlversion\space xint commented code (JFB)]% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl} \chardef\NoSourceCode=0\chardef\doxintsource=1 \input xint-calx.dtx %%% Local Variables: %%% mode: latex %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %----------------------------------------------------------- %<*xintalldrv>----------------------------------------------------------- %% To extract files: (but this is probably already done as you read this) %% etex xint-calx.dtx %% %% Then execute: %% make --file=Makefile.mk xint-calx.pdf %% to obtain a PDF containing both user manual and source code. %% %% Alternative for build without `make': %% %% latexmk xint-calx.tex %% dvipdfmx xint-calx.dvi %% %% One can also use pdflatex/lualatex/xelatex directly on xint-calx.tex, %% (or better latexmk with suitable engine option). \NeedsTeXFormat{LaTeX2e} \ProvidesFile{xint-calx.tex}% [\xintbndldate\space v\xintbndlversion\space xint user plus source doc (JFB)]% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl} \chardef\NoSourceCode=0 \input xint-calx.dtx %%% Local Variables: %%% mode: latex %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %----------------------------------------------------------- %<*dtx>----------------------------------------------------------- ^^Bfi^^Begroup \chardef\noetex 0 \ifx\numexpr\undefined\chardef\noetex 1 \fi % changed 2021/05/30: do not extract files at all if not using etex \ifnum\noetex=1 \chardef\extractfiles 3 % no extract, no typeset \else \ifx\PassOptionsToClass\undefined \chardef\extractfiles 0 % no LaTeX2e: probably etex, xetex, ... on xint-calx.dtx \else \ifx\NoSourceCode\undefined % latex/pdflatex/xelatex/lualatex on xint-calx.dtx, we will extract all files \chardef\extractfiles 1 % 1 = extract and typeset, 2 = only typeset \chardef\NoSourceCode 0 % 0 = include source code, 1 = do not \NeedsTeXFormat{LaTeX2e}% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl}% \else % latex/pdflatex/xelatex/lualatex on xint{manual,source,}.tex \chardef\extractfiles 2 % no extractions, but typeset \fi \ProvidesFile{xint-calx.dtx}[Source of the xint-calx bundle \xintbndlversion \xintbndldate]% \fi \fi \ifnum\extractfiles<2 % extract files \def\MessageDeFin{\newlinechar10 \let\Msg\message \Msg{^^J}% \Msg{********************************************************************^^J}% \Msg{*^^J}% \Msg{* To finish the installation you have to move the following^^J}% \Msg{* files into a directory searched by TeX:^^J}% \Msg{*^^J}% \Msg{* \space\space\space\space xintkernel.sty^^J}% \Msg{* \space\space\space\space xintcore.sty^^J}% \Msg{* \space\space\space\space xint.sty^^J}% \Msg{* \space\space\space\space xintbinhex.sty^^J}% \Msg{* \space\space\space\space xintgcd.sty^^J}% \Msg{* \space\space\space\space xintfrac.sty^^J}% \Msg{* \space\space\space\space xintseries.sty^^J}% \Msg{* \space\space\space\space xintcfrac.sty^^J}% \Msg{* \space\space\space\space xintexpr.sty^^J}% \Msg{* \space\space\space\space xinttools.sty^^J}% \Msg{* \space\space\space\space calxcore.sty^^J}% \Msg{* \space\space\space\space calxint.sty^^J}% \Msg{* \space\space\space\space calxfp.sty^^J}% \Msg{* \space\space\space\space calx.sty^^J}% \Msg{* \space\space\space\space calxlog.tex^^J}% \Msg{* \space\space\space\space calxlogdata.tex^^J}% \Msg{* \space\space\space\space calxtrig.tex^^J}% \Msg{* \space\space\space\space calxtrigdata.tex^^J}% \Msg{*^^J}% \Msg{* Rename Makefile.mk to Makefile if the latter is absent^^J}% \Msg{* (or use --file=Makefile.mk option of "make")^^J}% \Msg{* then "make xint-calx.pdf" builds a PDF including both the user manual^^J}% \Msg{* and the commented source code.^^J}% \Msg{*^^J}% \Msg{* Building with "make" requires "Latexmk".^^J}% \Msg{* The target "CHANGES.html" requires "Pandoc".^^J}% \Msg{*^^J}% \Msg{* Instructions for building without "make" are in file xint-calx.tex.^^J}% \Msg{*^^J}% \Msg{* Happy TeXing!^^J}% \Msg{*^^J}% \Msg{********************************************************************^^J}% }% \ifx\XeTeXinterchartoks\undefined\else \expandafter\def\expandafter\MessageDeFin\expandafter{\MessageDeFin \Msg{* ATTENTION! extraction with xetex must be made with -8bit option.^^J}% \Msg{* Extracted file Makefile.mk is invalid if this was not the case.^^J}% \Msg{********************************************************************^^J}% }% \fi \begingroup \input docstrip.tex \askforoverwritefalse \catcode9 11 % do not kill TAB in producing Makefile.mk \generate{\nopreamble\nopostamble % 1.4p of September 2025 omits including README.md in dtx % 1.4n of September 2025 omits including (renamed) CHANGES.md in dtx \file{xint-dates.txt}{\from{xint-calx.dtx}{dates}} % pure tex will use ^^I notation for TAB character, don't want that. % anyway, since 2021/05/30, tex xint-calx.dtx has been made a no-op. % there is a problem with xelatex, it generates ^^I if not with -8bit \file{Makefile.mk}{\from{xint-calx.dtx}{makefile}} \usepreamble\defaultpreamble \usepostamble\defaultpostamble \file{xintmanual.tex}{\from{xint-calx.dtx}{xintmandrv}} \file{xintsource.tex}{\from{xint-calx.dtx}{xintsrcdrv}} \file{xint-calx.tex}{\from{xint-calx.dtx}{xintalldrv}} \file{xintkernel.sty}{\from{xint-calx.dtx}{xintkernel}} \file{xinttools.sty}{\from{xint-calx.dtx}{xinttools}} \file{xintcore.sty}{\from{xint-calx.dtx}{xintcore}} \file{xint.sty}{\from{xint-calx.dtx}{xint}} \file{xintbinhex.sty}{\from{xint-calx.dtx}{xintbinhex}} \file{xintgcd.sty}{\from{xint-calx.dtx}{xintgcd}} \file{xintfrac.sty}{\from{xint-calx.dtx}{xintfrac}} \file{xintseries.sty}{\from{xint-calx.dtx}{xintseries}} \file{xintcfrac.sty}{\from{xint-calx.dtx}{xintcfrac}} \file{xintexpr.sty}{\from{xint-calx.dtx}{xintexpr}} \file{calxcore.sty}{\from{xint-calx.dtx}{calxcore}} \file{calxint.sty}{\from{xint-calx.dtx}{calxint}} \file{calxfp.sty}{\from{xint-calx.dtx}{calxfp}} \file{calx.sty}{\from{xint-calx.dtx}{calx}} \file{calxlog.tex}{\from{xint-calx.dtx}{calxlog}} \file{calxlogdata.tex}{\from{xint-calx.dtx}{calxlogdata}} \file{calxtrig.tex}{\from{xint-calx.dtx}{calxtrig}} \file{calxtrigdata.tex}{\from{xint-calx.dtx}{calxtrigdata}}} \endgroup \fi % end of file extraction (from etex/latex/pdflatex/... run on xint-calx.dtx) \ifnum\extractfiles=0 % no LaTeX, files now extracted. Stop. \MessageDeFin\expandafter\end \fi \ifnum\extractfiles=1 % direct run on xint-calx.dtx \expandafter\def\expandafter\MessageDeFin\expandafter{\MessageDeFin \Msg{* Direct (*)latex run on xint-calx.dtx: repeat as necessary. *^^J}% \Msg{********************************************************************^^J}% }% \fi \ifnum\extractfiles=3 % \newlinechar10 \errhelp{Extraction must be done via an engine with e-TeX extensions.^^J% Please try again, using etex rather.^^J% (and if with xetex, you must use -8bit option).}% \errmessage{Extraction aborted (must be done with etex)}% \expandafter\end \fi % From this point on, run is necessarily with e-TeX. % Check if \MessageDeFin got defined, if yes put it at end of run. \ifdefined\MessageDeFin\AtEndDocument{\MessageDeFin}\fi %----------------------------------------------------------------- % \tracinglostchars3 \makeatletter % counts used in particular in the samples from the documentation of the % xintseries.sty package \newcount\cnta \newcount\cntb \newcount\cntc \ifdefined\doxintsource \chardef\NoSourceCode 0 \else \chardef\doxintsource 0 \fi % \doxintsource=1 means producing only source code. % It is set in xintsource.tex. Prior to 1.4l it was % set in the call with latexmk + \input syntax. % % \doxintsource=0 and \NoSourceCode=1 : include only user doc % \doxintsource=0 and \NoSourceCode=0 : combine user doc and source code % \doxintsource=1 and \NoSourceCode=1 : never happens but would mean to do % nothing! % default is to assume latex + dvipdfmx \chardef\Withdvipdfmx 1 \RequirePackage{iftex} \ifpdf \chardef\Withdvipdfmx 0 \fi \ifxetex\chardef\Withdvipdfmx 0 \fi % 2019/09/10 % Get rid of HARASSMENT by KOMA-Script % Must be located before \documentclass \def\class@shoulddisablepackagewarning@list{tocloft.} \ifnum\Withdvipdfmx=1 \def\pgfsysdriver{pgfsys-dvipdfm.def} \documentclass [dvipdfm, dvipdfmx]{scrartcl} \else \documentclass {scrartcl} \fi %%% START OF CUSTOM doc.sty LOADING (May 21, 2022) % % For some legacy reason (because I started like this and it % worked to my satisfaction) I had used scrdoc.cls all those % years, without in fact needing most of its features. % % It loads ltxdoc class, from which again I need very little. On % testing May 20, 2022 the upcoming LaTeX 2022-06-01 I had some % problems with ltxdoc not having suitable interface for rolling % back to doc=V2. % % I did experiment with indices for xintsource.pdf from 2018 to % 2019 but it made the build process significantly lengthier, % created heavy-sized PDF, had various issues in my context % (possibly the kind of issues doc V3 addresses about indexing % non-macro things, hyperlinks,...), and these indices basically % had not any real use as PDF search proves efficient enough, % and the structures of local tables of contents makes for % agreeable enough navigation via the input mark-up using % sectioning commands. % % Thus it turns out I need very little of doc.sty, and almost % nothing of ltxdoc.cls and scrdoc.cls. % % Let's load the doc=V2 version to avoid having to work around % hypdoc loading interfering with my use of hyperref and as said % above I don't need the hyperlinked cross-referencing as I have % it via my own mark-up to a sufficiently good enough extent, % and this holds for many many years. And I will not now change % my mark-up. \ifdefined\IfFormatAtLeastTF \IfFormatAtLeastTF{2022/06/01}% {% \IfFileExists{doc-2021-06-01.sty}% {\usepackage{doc}[=v2]}% % Why on earth do I lose my time doing this? {\GenericError {(xint build doc)\@spaces}% {xint build error: % Your LaTeX installation seems to be broken, format is\MessageBreak 2022-06-01 or later but `doc' package in its `v2' version\MessageBreak seems to not be available. \space Will try with `doc' but if\MessageBreak its `v3' is used there will be an option clash error\MessageBreak regarding hyperref.}% {}% {Please make sure `doc' package matches your LaTeX format.}% \usepackage{doc}% }% }% {\usepackage{doc}}% \else \usepackage{doc} \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MACROS OF doc.sty WILL BE HACKED (2022/06/06) FOR THE IMPLEMENTATION PART % % First we want to turn CodelineNo into a real LaTeX counter % This will spare defining an extra counter for the hyperlinks with \hyperref \begingroup\let\newcount\@gobble\@definecounter{CodelineNo}\endgroup %%% Next line is not needed because \theCodelineNo already got that definition %%% from doc-2021-06-01.sty, and \@definecounter does not overwrite it. % \def\theCodelineNo{\reset@font\scriptsize\arabic{CodelineNo}} % But as we will reset CodelineNo at each style file we need some unique id \def\theHCodelineNo{\the\value{section}.\the\value{CodelineNo}} % This is all for now. % The further hacks are to be found after the \StopEventually (i.e. a few % thousands lines down from here if you don't have access to the private % sources, which is probably the case if you are not the author). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % As explained above I was formerly using scrdoc hence ltxdoc indirectly. % Let's emulate here the little I appear to need from ltxdoc.cls and % srcdoc.cls. % \AtBeginDocument{\MakeShortVerb{\|}} \DeclareFontShape{OT1}{cmtt}{bx}{n}{<-> ssub * cmtt/m/n}{} \DeclareFontFamily{OMS}{cmtt}{\skewchar\font 48} % '60 \DeclareFontShape{OMS}{cmtt}{m}{n}{<-> ssub * cmsy/m/n}{} \DeclareFontShape{OMS}{cmtt}{bx}{n}{<-> ssub * cmsy/b/n}{} \DeclareFontShape{OT1}{cmss}{m}{it}{<->ssub*cmss/m/sl}{} \ifnum\NoSourceCode=1 \OnlyDescription \fi \CodelineNumbered \EnableCrossrefs % but this will be hacked % \setcounter{StandardModuleDepth}{1} % we don't use this mechanism currently \def\cmd#1{\cs{\expandafter\cmd@to@cs\string#1}} \def\cmd@to@cs#1#2{\char\number`#2\relax} % Here I am loading doc=v2 but formerly I was using ltxdoc via scrdoc % which I dropped at release 1.4l (2022-05-29) and without much % thinking I had kept this. \DeclareRobustCommand\cs[1]{\texttt{\bslash#1}} % As I may have the * active, or macro names with _ or ^, I should % add \detokenize. But see below for a redefinition anyhow. % % More urgent is that I am also using hyperref and this definition gives wrong % bookmarks if \cs is used in section titles. As I had very very few usags of % \cs in the whole of xint.dtx, it took me a while to realize the problem % here. Turns out that doc=v3 by default loads hypdoc which includes this % configuation for hyperref compatibility: \AtBeginDocument{% \pdfstringdefDisableCommands{\def\cs#1{\textbackslash\detokenize{#1}}}% }% % As I have not loaded hyperref yet I must delay it to AtBeginDocument. % Late May, early June 2022 I added to my custom \verb automated detection % of potential hyperlinks. So I decided to replace \cs ltxdoc definition % by suitable \verb usage. It is not important to be efficient here, % I can leave some \expandafter, in fact there are a handful of uses. \DeclareRobustCommand\cs[1]{\expandafter\verb\expandafter~\bslash#1~} % As my \verb does a verbatimizing \scantokens I don't need to worry % here about active characters but I need in the PDF string, hence % the \detokenize above. \providecommand\marg[1]{% {\ttfamily\char`\{}\meta{#1}{\ttfamily\char`\}}} \providecommand\oarg[1]{% {\ttfamily[}\meta{#1}{\ttfamily]}} \providecommand\parg[1]{% {\ttfamily(}\meta{#1}{\ttfamily)}} % \@addtoreset{CodelineNo}{part}% No need for this here % \def\partname{File}% \partname is "fixed" somewhere further down anyhow % No need for this, anyhow I don't build the indices (I did in 2018-2019 only). % \gdef\codeline@wrindex#1{\if@filesw % \begingroup % \let\protect\noexpand % \immediate\write\@indexfile % {\string\indexentry{#1}% % {\filesep\number\c@CodelineNo}}% % \endgroup\fi} % \let\filesep\@empty % There is very little we seem to need from the scrdoc extras: page geometry % is set by geometry package and a4paper option from xint.tex file. So it % seems I only need the hologo loading: \usepackage{hologo} \DeclareRobustCommand*{\eTeX}{\hologo{eTeX}}% \DeclareRobustCommand*{\PDFTeX}{PDF\TeX{}}% \DeclareRobustCommand*{\LuaTeX}{\hologo{LuaTeX}}% \DeclareRobustCommand*{\XeTeX}{\hologo{XeTeX}}% % %%% end of ltxdoc+srcdoc emulation. See after \StopEventually for doc.sty hacks. % Remove from sectioning commands insertion of marks, because we % will do it ourself. \usepackage{etoolbox} % At scrartcl 2026/02/02 v3.49.2 % (LaTeX 2025-11-01, hyperref 2026-01-29 v7.01p the patch below has to be applied % to \scr@sect not to \@sect. \patchcmd{\scr@sect}% {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% {}{}{\Error@CouldNotApplyFirstPatch@sect} \patchcmd{\scr@sect}% {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% {}{}{\Error@CouldNotApplySecondPatch@sect} % This one now needed too, Jeudi 30 janvier 2020 % \expandafter \ifx \csname #1mark\endcsname \@gobble \@mkboth {}{}\else % \csname #1mark\expandafter \endcsname \expandafter {\@currentheadentry }\fi % \@gobble est long donc simplement \def\partmark #1{}% \pagestyle{headings} \iftutex % ensure lualatex or xelatex can be used to build the pdf % xinttools is not yet loaded hence the \AtBeginDocument % 1.4p fixes a bug where formerly \lccode`~=\lccode`#1 was used % which failed with ≠. It also adds the ± which apparently was % overlooked and the © (which however does not make it to public pdf). \AtBeginDocument{% \xintForpair #1#2 in {(δ, \delta), (ξ, \xi), (π, \pi), (≠, \neq), (±, \pm), (α, \alpha), (τ, \tau), (λ, \lambda), (ν, \nu)} \do{\catcode`#1\active \begingroup\lccode`~=`#1 \lowercase{\endgroup\def~}{\ensuremath{#2}}% }% \catcode`©\active \begingroup\lccode`~=`© \lowercase{\endgroup\def~}{(c)}% }% \else \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} % (2016/03/02): \delta utilisé dans les commentaires de la division de xint.sty % (2017/01/03): \xi pour doc \xintnewdummy % (2019/03/31): \pi utilisé dans mes commentaires de xinttrig.sty % (2019/04/24): \neq utilisé dans un commentaire de xintlog.sty % (2025/08/30): \alpha, \tau, \lambda, \nu pour doc \xintnewdummy % As we now (2025/08/30) load lgrmath (farther below), we have to delay this % to at begin document. % (2026/03/01): [1.4p] Problems with ± et © which did not exist earlier or which % I had overlooked but show since perhaps 2024 (≠ was already handled). % For some reason which I have forgotten, this must be done at \begin{document} \AtBeginDocument{% \DeclareUnicodeCharacter{03B4}{\ensuremath{\delta}}% δ \DeclareUnicodeCharacter{03BE}{\ensuremath{\xi}}% ξ \DeclareUnicodeCharacter{03C0}{\ensuremath{\pi}}% π \DeclareUnicodeCharacter{2260}{\ensuremath{\neq}}% ≠ \DeclareUnicodeCharacter{03B1}{\ensuremath{\alpha}}% α \DeclareUnicodeCharacter{03C4}{\ensuremath{\tau}}% τ \DeclareUnicodeCharacter{03BB}{\ensuremath{\lambda}}% λ \DeclareUnicodeCharacter{03BD}{\ensuremath{\nu}}% ν \DeclareUnicodeCharacter{B1}{\ensuremath{\pm}}% ± % This happens only in some code comments which do not make it % to the public xint-all.pdf anyhow, so I do not waste effort on this. % or use fall-back font. \DeclareUnicodeCharacter{A9}{(c)}% © } \fi \usepackage{multicol} \usepackage[head=3\baselineskip]{geometry} \AtBeginDocument {\ttzfamily % package newtxtt is loaded in preamble \newgeometry{textwidth=\dimexpr92\fontcharwd\font`X\relax, vscale=0.75}} \unless\ifnum\doxintsource=1 \usepackage{xintexpr} % \usepackage{xintbinhex}% done automatically since 1.4n \usepackage{xintgcd} \usepackage{xintseries} \usepackage{xintcfrac} \usepackage{amsmath}% for \cfrac usage \DeclareMathOperator{\sinc}{sinc} \fi \usepackage{pifont}% for \ding{73} (hollow star) % needed also for build of xintsource.pdf \usepackage{xinttools} \usepackage{enumitem} \usepackage{varioref} \usepackage{xspace} \usepackage[para]{footmisc} %\usepackage{picture}% obsolèté par LaTeX 2025-11-01 \usepackage{graphicx} \usepackage[english]{babel} % 2022/06/05 % \usepackage{csquotes} \def\myenquote#1{{\sffamily\textquotedblleft}#1{\sffamily\textquotedblright}} % 2022/05/24, commenting out this at it appears to not be used anywhere now. % \usepackage[autolanguage,np]{numprint} % \AtBeginDocument{\npthousandsep{,\hskip .5pt plus .1pt minus .1pt}} % But surprisingly it is via numprint that I was loading array package % whose extended syntax for tabular preambles is required! \usepackage{array} \usepackage[dvipsnames,svgnames]{xcolor} %%% DEFINITIONS OF COLORS USED IN DOCUMENT % color for the \xintname, \xintexprname, etc macros \definecolor{xintnamecolor}{RGB}{228,57,0} \colorlet{XINTNAMECOLOR}{xintnamecolor} % color for their analogs \xintnameimp, etc... in implementation part \colorlet{xintnameimpcolor}{blue} \colorlet{XINTNAMEIMPCOLOR}{xintnameimpcolor} % colors for hyperref \definecolor{xinturlcolor}{RGB}{38,128,192} \colorlet{xintlinkcolor}{blue} % colors for custom \verb and everbatim/everbatim* environments % % the commented-out legacy colors used in xint.pdf for many years up to % xint 1.4j (2021/07/13) (I should retrieve since when exactly) % % \colorlet{verbcolor}{jfbrown} % \colorlet{verbsoftwrapiconcolor}{blue} % \colorlet{everbatimfgcolor}{Brown} % \colorlet{everbatimbgcolor}{yellow!5} % \colorlet{everbatimxfgcolor}{OrangeRed} % % https://contrast-ratio.com/#rgb%28165%2C100%2C10%29-on-white % says the contrast ratio on white is 4.74 and I do see the contrast % is less strong than % for the DarkBlue/Beige and Maroon/White combinations seen below % \colorlet{verbcolor}{jfbrown} % I will simply use also Maroon \colorlet{verbcolor}{Maroon} \colorlet{digitsttcolor}{verbcolor} \colorlet{verbsoftwrapiconcolor}{DarkBlue} \colorlet{everbatimfgcolor}{DarkBlue} % % According to % https://contrast-ratio.com/#rgb%2811%2C35%2C139%29-on-rgb%28245%2C244%2C220%29 % the DarkBlue on Beige % gives a contrast-ratio of 11.58 which confirmed my intuition it is not bad % "Passes AAA level for any size text and AA for user interface components and % graphical objects" % % memo: with Apple ColorPicker it seems one needs to select "sRVB" (I guess % "sRGB" in English) for values matching xcolor RGB input or the above html % page rgb(R,G,B) input, also this did not work % 100%, most probably due to the window transparency by default on my mac? \colorlet{everbatimbgcolor}{Beige} % % https://contrast-ratio.com/#rgb%28128%2C31%2C19%29-on-white % gives 9.89 contrast ratio which is a bit less but still AAA \colorlet{everbatimxfgcolor}{Maroon} % % colors for margin notes \colorlet{marginnotecolor}{PineGreen} \colorlet{marginwarningcolor}{Red} % colors for toc \colorlet{tocstylesectioncolor}{cyan} \colorlet{tocstylesectionimpcolor}{RoyalPurple} \colorlet{tocstylebundlesectioncolor}{xintnamecolor} % colors for macro code and comments \colorlet{privatecommentcolor}{cyan} \colorlet{macrocodecommentcolor}{gray} \colorlet{macrocodenewmacrocolor}{verbcolor} \colorlet{macrocodelinktouserdoccolor}{xintnamecolor}% and bold face \colorlet{macrocodelinktosectioncolor}{DarkBlue}% and bold face \colorlet{macrocodelinktocodelinecolor}{DarkBlue} \colorlet{macrocodenoncscolor}{Green} % colors for the implementation part and the modified macrocode macros % are to be found after \StopEventually \usepackage{eso-pic}% après xcolor sinon Option clash for package xcolor. \ifnum\doxintsource=1 \else % Dependency graph done using TikZ (manually) \usepackage{tikz} \usetikzlibrary{shapes,arrows.meta} \fi \usepackage{framed} %\usepackage{colorframed} % SNUGFRAMED % ========== \newenvironment{snugframed}{% \fboxsep \dimexpr2\fontcharwd\font`X\relax \advance\linewidth-2\fboxsep \advance\csname @totalleftmargin\endcsname \fboxsep \def\FrameCommand##1{\hskip\@totalleftmargin \hskip-\fboxsep \fbox{##1}\hskip-\fboxsep % There is no \@totalrightmargin, so: \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth}% \MakeFramed {\advance\hsize-\width \@totalleftmargin\z@ \linewidth\hsize \@setminipage}% }{\par\unskip\@minipagefalse\endMakeFramed} % HYPERREF % ======== \usepackage{hyperref} % 2022/06/10 reduce clutter in console and log output, there are already % enough messages telling we have to execute latex once more \catcode`_ 11 \def\perhapshyperref[#1]{\ifcsname r@#1\endcsname \xint_afterfi{\hyperref[#1]}\fi} \catcode`_ 8 \hypersetup{% linktoc=all,% breaklinks=true,% colorlinks=true,% urlcolor=xinturlcolor,% linkcolor=xintlinkcolor,% pdfauthor={Jean-Fran\c cois Burnol},% pdftitle={The xintexpr and allied packages},% pdfsubject={Arithmetic with TeX},% pdfkeywords={Expansion, arithmetic, TeX},% pdfstartview=FitH,% pdfpagemode=UseNone,% } \usepackage{hypcap} \ifnum\doxintsource=1 \hypersetup{pdftitle={The xintexpr and allied packages source code}} \fi \usepackage{bookmark} % This is for having similarly named labels to get hyperlinks either to the % user documentation or to the implementation part. From source mark-up with % \csbxint, \csbXINT, \csb, or automated ones from |...| and the custom \verb % However in the user manual I have so far (2022/06/11) used manually typed-in % \label's in contrast to the almost exclusively automated ones of the implementation % part. So for time being I keep an empty prefix here in place of something % reasonable such as usr-. \let\xintdoclabelprefix\empty \def\xintimplabelprefix{src-} % used by \csbxint etc... \let\xintlabelprefix\xintdoclabelprefix % FONTS % ===== \usepackage[zerostyle=d,straightquotes,scaled=0.95]{newtxtt} \usepackage{newtxmath} \input ts1newtxttz.fd % Update at 1.4p. % In ts1newtxttz.fd 2024/03/03 reference to newtcxttz are made % presumably tc = text companion but the fonts do not exist. I % need this for a few characters © ("A9), ≠ (U2260) and ± ("B1). % Formerly I needed it for \textasciigrave, but the straightquotes % option solved that. The problematic characters are handled % at begin document, see above, at the \iftutex conditional. \renewcommand\familydefault\ttdefault \usepackage[noendash]{mathastext}% pas de endash dans newtxtt % A (somewhat surprising a priori, at least to me) effect of % \DeclareFontEncoding{LGR}{}{} (which loads lgrenc.dfu) is that % it redeclares all UTF-8 Greek ! So for example ξ will expand to \textxi. % So we delayed our own \DeclareUnicodeCharacter's to \begin{document} \usepackage[style=up,font=cmss]{lgrmath} % 2024/01/15: upstream update by Michael Sharpe to newtxtt, % in particular a shorter "extra space" for the nomono font % I thus try again with \nonfrenchspacing. % \frenchspacing % sans-serif in footnotes, TOC, titles, etc... \renewcommand\familydefault\sfdefault % TABLES OF CONTENTS % ================== % Attention @ is letter \usepackage{tocloft} \usepackage{etoc} \let\orig@etoctoclineleaders\etoctoclineleaders \def\gobbletodot #1.{} \newif\ifinmanualmaintoc \ifnum\doxintsource=0 \inmanualmaintoctrue \fi \def\tocstylesectionbracedcolor{{tocstylesectioncolor}} \def\tocstyleMARGEPAGENO {1.5em}% changera pour la partie implémentation \def\tocstylesectionVSKIP{\vskip\bigskipamount} \etocsetstyle{section}{} {\normalfont} {\etociffirst{}{\tocstylesectionVSKIP}% \rightskip \tocstyleMARGEPAGENO\relax \parfillskip -\tocstyleMARGEPAGENO\relax \bfseries \leftskip \leftmarginii \noindent\llap % \llap {\makebox[\leftmarginii][l]% et \leftmargini le 12/10/2014 {\expandafter\textcolor\tocstylesectionbracedcolor{\etocnumber}}}% \strut\etocname \mdseries\nobreak\leaders\etoctoclineleaders\hfill\nobreak\strut \makebox[\tocstyleMARGEPAGENO][r]{\etocpage}\par \let\ETOCsectionnumber\etocthenumber }% {}% \newdimen\tocstyleLEFTMARGIN \AtBeginDocument{\tocstyleLEFTMARGIN \dimexpr 5\fontcharwd\font`X\relax} \etocsetstyle{subsection} {\begingroup\normalfont \setlength{\premulticols}{0pt}% \setlength{\multicolsep}{0pt}% \setlength{\columnsep}{\leftmarginii}% \setlength{\columnseprule}{.4pt}% n'influence pas séparation colonnes \parskip\z@skip \raggedcolumns \addvspace{\smallskipamount}% \begin{multicols}{2} \leftskip \tocstyleLEFTMARGIN % 12 octobre 2014 \ifinmanualmaintoc \rightskip \tocstyleMARGEPAGENO \else \rightskip \tocstyleMARGEPAGENO plus 2em minus 1em \fi \parfillskip -\tocstyleMARGEPAGENO\relax } {} {\noindent \etocifnumbered{\llap{\makebox[\tocstyleLEFTMARGIN][l]{\ttzfamily\bfseries\etoclink {\ifinmanualmaintoc\expandafter\textcolor\tocstylesectionbracedcolor {\normalfont\bfseries\ETOCsectionnumber}\fi .\expandafter\gobbletodot\etocthenumber}}}}{\kern-\tocstyleLEFTMARGIN}% \strut\etocname\nobreak \unless\ifinmanualmaintoc\leaders\etoctoclineleaders\fi \hfill\nobreak \strut\makebox[\tocstyleMARGEPAGENO][r]{\small\etocpage}\endgraf } {\end{multicols}\endgroup }% \etocsetstyle{subsubsection} {\begingroup\normalfont\small \leftskip\dimexpr\leftmargini+1em\relax } {} {\noindent \llap{\makebox[\dimexpr\leftmargini+1em\relax][l]% {\ttzfamily\bfseries\etoclink {\tocstylesubsubsectionHOOK.\expandafter\gobbletodot\etocthenumber}}}% \strut\etocname\nobreak \leaders\etoctoclineleaders \hfill\nobreak \strut\makebox[\tocstyleMARGEPAGENO][r]{\small\etocpage}\endgraf } {\endgroup }% % 2018/02/28 % quick hack to get style I want in "User defined functions" section of manual \let\tocstylesubsubsectionHOOK\empty \etocsetlevel{xinttable}{6}% formerly "table" was used, but forbidden since % etoc 1.2 of 2023/10/01 \addtocontents{toc}{\protect\hypersetup{hidelinks}} % ===================== % MISCELLANEOUS MARK-UP % ===================== \def\digitstt #1{\begingroup\color{digitsttcolor}#1\endgroup} \let\dtt\digitstt % \fexpan 22 octobre 2013 \newcommand\fexpan {\perhapshyperref[ssec:expansions]{\textit{f}-expan}} % \xexpan ajouté 28 mai 2022 \newcommand\xexpan {\perhapshyperref[ssec:expansions]{\textit{x}-expan}} % Septembre 2015 % Address updated to github repo's one, May 2018 % They did s/master/main/ already a few years back, May 2022 \def\liiibigint {\href{https://github.com/latex3/latex3/tree/main/l3trial/l3bigint}{l3bigint}} % May 2022 \def\liiistrformat % {\href{https://github.com/latex3/latex3/tree/main/l3experimental/l3str}{l3str}} {\href{https://ctan.org/pkg/l3experimental}{l3str-format}} %\def\liiistrformatnew % {\href{https://github.com/latex3/latex3/tree/main/l3trial/l3str-format-new}{l3str-format-new}} % Margin Notes % ============ % Nothing here can be used in vertical mode directly. \def\MyMarginNote {\@ifnextchar[\@MyMarginNote{\@MyMarginNote[]}}% \let\inmarg\MyMarginNote % \smash needs \hbox here since LaTeX 2018/12/01 % https://github.com/latex3/latex2e/issues/108 \def\@MyMarginNote [#1]#2{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\color{marginnotecolor}\normalfont\small \hsize 1.6cm\rightskip.5cm minus.5cm \hss\vtop{#2}\ $\to$#1\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\MyMarginNoteWithBrace #1#2{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\color{marginnotecolor}%\normalfont\small \hss #1\ $\bigg\{$#2}}}% \vskip\dp\strutbox }\strut\@esphack} \def\IMPORTANT {\MyMarginNoteWithBrace {\raisebox{-.5\height}{\resizebox{2\width}{!}{\ding{43}}}}{\ }} \def\IMPORTANTf {\MyMarginNoteWithBrace {\raisebox{-.5\height}{\resizebox{2\width}{!}{\ding{43}}}}% {\kern\dimexpr\FrameSep+\FrameRule\relax\ }} \newcommand\cautionsign[1][10pt]{% \resizebox{!}{#1}{\ooalign{$\mathcolor{red}{\triangle}$\cr \kern2.07pt{\raise0.75pt\hbox{\resizebox{!}{3pt}{!}}}}}% } \def\etype #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \itshape \xintListWithSep{\,}{#1}\ $\star$\quad }}}% \vskip\dp\strutbox }\strut\@esphack} \def\xtype #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \itshape \xintListWithSep{\,}{#1}\ \ding{73}\quad }}}% \vskip\dp\strutbox }\strut\@esphack} \def\ntype #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \itshape \xintListWithSep{\,}{#1}\quad }}}% \vskip\dp\strutbox }\strut\@esphack} % \def\Numf {{\vbox{\halign{\hfil##\hfil\cr \footnotesize \upshape Num\cr \noalign{\hrule height 0pt \vskip1pt\relax} \itshape f\cr}}}} \def\Ff {{\vbox{\halign{\hfil##\hfil\cr \footnotesize \upshape Frac\cr \noalign{\hrule height 0pt \vskip1pt\relax} \itshape f\cr}}}} \def\numx {{\vbox{\halign{\hfil##\hfil\cr \footnotesize \upshape num\cr \noalign{\hrule height 0pt \vskip1pt\relax} \itshape x\cr}}}} % \def\NewWith #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent NEW WITH #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} % \def\CHANGED #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent CHANGED AT #1!}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\DNU#1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent DO NOT USE! #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\UNSTABLE#1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent UNSTABLE! #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\unstable#1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent Unstable? #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\DEPRECATED #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \normalfont\small\bfseries \hsize 2cm\rightskip.5cm minus.5cm \vtop{\noindent DEPRECATED! (#1)}\ }}}% \vskip\dp\strutbox }\strut\@esphack} % \def\CHANGEDf #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent CHANGED AT #1!}\ \kern\dimexpr\FrameSep+\FrameRule\relax}}}% \vskip\dp\strutbox }\strut\@esphack} % \def\NewWithf #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \normalfont\small\bfseries \hsize 1.7cm\rightskip.7cm minus.5cm \vtop{\noindent NEW WITH #1}\ \kern\dimexpr\FrameSep+\FrameRule\relax}}}% \vskip\dp\strutbox }\strut\@esphack} % \centeredline: OUR OWN LITTLE MACRO FOR CENTERING LINES % ======================================================= % 7 mars 2013 % Note (2020): now a package \usepackage{centeredline} % \leftedline % =========== % 12 octobre 2014 % Note (2020): somewhat obsoleted for many years by my usage of % everbatim and everbatim* environments. \newif\ifinlefted \newcommand*\leftedline {% \ifhmode \\\relax \def\leftedline@{\hss\egroup\hskip\z@skip\ignorespaces }% \else \def\leftedline@{\hss\egroup }% \fi \afterassignment\@leftedline \let\next=} \def\@leftedline {\hbox to \linewidth \bgroup \inleftedtrue \everbatimeverypar \bgroup \aftergroup\leftedline@ } % verbatim macros and environments % ================================ % % June 2013, then October 2014. % ----------------------------- % \catcode`_ 11 % some of my verbatim environments do not make the space active (\lverb e.g.). Then % \do@noligs must be modified, \char`#1 must be followed by a space token, else, % the `#1 expansion will swallow one space. \def\do@noligs #1{% \catcode`#1\active \begingroup \lccode`~`#1\relax \lowercase{% \endgroup\def~{\leavevmode\kern\z@\char`#1 }}% } % \lowast \def\lowast{\raisebox{-.25\height}{*}} \catcode`* 13 \def\makestarlowast {\let*\lowast\catcode`\*\active}% \catcode`* 12 % \verb % ===== % Initially, June 2013, then Sep 9, 2014, and Oct 9-12 2014 % % Initial motivation was simply that doc.sty and related classes \verb % macro is with a hard-coded \ttfamily. There were further issues. % % 1. With |stuff with space|, paragraph reformatting in the Emacs/AUCTeX % buffer caused havoc. Thus I wanted the input to accept linebreaks in % its contents. % % 2. Hence I did not want to have obeyed spaces obeyed, (Emacs reflowing % of paragraph in certain contexts often adds spaces at beginning of a line) % % 3. Also I wanted to allow hyphenated output, at least at some % locations. I did a first version which treated spaces, \, {, and } % specially. % % 4. At some point I wanted to add some colored background (I have % dropped that since due to pdf file size increase). % % 5. And also I got fed up from the non-compatibility with footnotes due % to catcode freeze. % % Because of 5. I opted for a \scantokens approach, hence for a macro % with delimited argument. Here is what I do now, this is compatible % with short verbs. \def\verbcolorcmd{\color{verbcolor}} \def\verbsoftwrapiconcolorcmd{\color{verbsoftwrapiconcolor}} \def\restoreMicroFont {\def\MicroFont {\ttfamily\makestarlowast \ifinlefted\else\verbcolorcmd\fi }} \restoreMicroFont \def\verb {% \relax \ifmmode\else\leavevmode\null\fi \bgroup \let\do\@makeother \dospecials \@ifstar{\@sverb}% \verb* is used in the index (obsolete: no indices at 1.3e), % leave it using ambient font {\MicroFont % used to change font (\ttfamily), color, % will make * active via \makestarlowast \catcode 32 10 \endlinechar 32 % allows to fetch across line breaks \frenchspacing % since 2024/01/15 not done globally in document \@@jfverb}% }% % Note (Oct 12, 2014): in the improbable situation a newlinechar is % found in the ##1, \scantokens will convert this to an end of line in % its "write" phase, which will be then ignored in its "read" phase due % to \endlinechar-1. This also avoids possible creation of \par which % would defeat \@@jfverb@@. Thus it is good. \def\@@jfverb #1{% \ifcat\noexpand#1\noexpand~\catcode`#1\active\fi % No problem with the EOL for the line where the short verb delimiter stands. \def\next ##1#1{% % 2022/06/04 % automated hyperlink detection % - \detokenize needed due to * \active from \makestarlowast in \MicroFont % - gobbling first char rather than checking if it is backslash % (and there is an \@empty first so gobbling two tokens) % mark-up using \csbxint is better way as it allow hyphenation after xint % Usage of \xintlabelprefix to modify behaviour in implementation part. % This will NOT WORK if the catcodes were already frozen... \ifcsname r@\xintlabelprefix\detokenize\expandafter{\xint_gobble_ii##1}\endcsname \hyperref[\xintlabelprefix\detokenize\expandafter{\xint_gobble_ii##1}]{##1}% \egroup \else % this will add \discretionary's for wrapping at end of line \@vobeyspaces\everyeof{\relax}\endlinechar\m@ne \expandafter\@@jfverb_a\scantokens\expandafter{##1}% \fi}% % hack with \@empty to prevent brace stripping if catcodes have been % frozen earlier, like in footnotes. \next \@empty } % We don't want a \discretionary at the very start. % But then an empty argument is forbidden! \def\@@jfverb_a #1{#1\@@jfverb_b } \def\@@jfverb_b #1{\ifx\relax #1% \egroup \else % \penalty\z@, or rather (Oct 11, 2014) but I then adjust the textwidth % precisely: \discretionary{\copy\SoftWrapIconA}{\copy\SoftWrapIconB}{}% #1\expandafter\@@jfverb_b\fi } \DeclareFontFamily{U}{MdSymbolC}{} \DeclareFontShape {U}{MdSymbolC}{m}{n}{<-> MdSymbolC-Regular}{} \newbox\SoftWrapIconA \newbox\SoftWrapIconB \usepackage{accsupp} \def\SetSoftWrapIcons{% \setbox\SoftWrapIconA\hb@xt@\z@ {\kern-1ex \smash{\lower5pt \hbox{% \BeginAccSupp{ActualText={}}% \verbsoftwrapiconcolorcmd\usefont{U}{MdSymbolC}{m}{n}\char 154 \EndAccSupp{}% }% }% \hss}% \setbox\SoftWrapIconB\hb@xt@\z@ {\hss \smash{%\lower1.5pt \hbox{% \BeginAccSupp{ActualText={}}% \verbsoftwrapiconcolorcmd\usefont{U}{MdSymbolC}{m}{n}\char 48 \EndAccSupp{}% }% }% \kern.5ex}% } \AtBeginDocument {\SetSoftWrapIcons }% ok car ttzfamily déjà fait \catcode`_ 8 % everbatim environment % ===================== \def\restoreMacroFont {\def\MacroFont {\ttfamily \ifinlefted\else\color{everbatimfgcolor}\fi }} \restoreMacroFont % Notice that \macrocode uses \macro@font which stores the \MacroFont meaning % in force at \begin{document}. But doc.sty's verbatim uses current \MacroFont % not the meaning at \begin{document}. Comprenne qui pourra... % October 13-14, 2014 % Verbatim with an \everypar hook, mainly to have background color, followed by % execution of the contents (not limited by a group-scope) \catcode`_ 11 \def\everbatim {\s@everbatim\@everbatim} \@namedef{everbatim*}{\s@everbatim\@everbatimx} % Note: one can not use everbatim inside itself or everbatim* inside itself \def\s@everbatim {% % \ineverbtrue \everbatimtop % put there size changes \topsep \z@skip \partopsep \z@skip \itemsep \z@skip \parsep \z@skip \parskip \z@skip \lineskip \z@skip \let\do\@makeother \dospecials \let\do\do@noligs \verbatim@nolig@list \makestarlowast \everbatimhook \trivlist \@topsepadd \z@skip \item\relax \leftskip \@totalleftmargin \rightskip \z@skip \parindent \z@ \parfillskip\@flushglue \parskip \z@skip \@@par \def\par{\leavevmode\null\@@par\pagebreak[1]}% \everypar\expandafter{\the\everypar \unpenalty \everbatimeverypar \everypar \expandafter{\the\everypar\everbatimeverypar}% }% \obeylines \@vobeyspaces } % 27 mai 2022, plus de \small \def\everbatimtop {\MacroFont }% \let\everbatimhook\empty \def\everbatimeverypar{\strut {\color{everbatimbgcolor}\vrule\@width\linewidth }% \kern-\linewidth \kern\everbatimindent } \def\everbatimindent {\z@}% voir plus loin atbegindocument \begingroup \lccode`X 13 \catcode`X \active \lccode`Y `* % this is because of \makestarlowast. % I have to think whether this is useful: obviously if I were to provide % everbatim and everbatim* in a package I wouldn't do that. \catcode`Y \active \catcode`| 0 \catcode`[ 1 \catcode`] 2 \catcode`* 12 \catcode`{ 12 \catcode`} 12 |catcode`\\ 12 |lowercase[|endgroup% both freezes catcodes and converts X to active ^^M |def|@everbatim #1X#2\end{everbatim}% [#2|end[everbatim]|everbatimbottom ] |def|@everbatimx #1X#2\end{everbatimY}]% {#2\end{everbatim*}% % No group here: this allows executed code to make macro % definitions which may reused in later uses of everbatim. % refactored 2022/01/11, rather than passing \newlinechar value % as was done formerly via everbatim* (see above) and fetching it here as #1 % it is thus assumed executed contents do not terminate a scope \edef\everbatimrestorenewlinechar{\newlinechar\the\newlinechar\relax}% \newlinechar 13 % refactored 2022/01/11 to fix a \parskip issue % attention, \parskip thus set to zero for execution of contents % reason: avoid extra space if everbatim* is in an \item of a list % between verbatim and output of execution, if it starts a paragraph % a \vskip-\parskip approach (cf former \everbatimundoparskip) % would be no good in case contents create a display \edef\everbatimrestoreparskip{\parskip\the\parskip\relax}% \parskip\z@skip % execution of the contents (expected to be LaTeX code...) \everbatimxprehook \scantokens {#2}% \everbatimrestorenewlinechar \everbatimrestoreparskip \everbatimxposthook % input after \end{everbatim*} on same line in source is allowed }% % L'espace venant du endofline final mis par \scantokens sera inhibé si #2 se % termine par un % ou un \x, etc... \let\everbatimbottom\empty \def\endeverbatim{\if@newlist \leavevmode\fi\endtrivlist} \@namedef{endeverbatim*}{\endeverbatim} % There is an issue with how to inhibit the \parskip if execution % of contents generate a paragraph. Because the design is aimed at % keeping output close to verbatim input. % Even in a document with zero \parskip overall, the \parskip will possibly % be reset to some annoying high value e.g. if we are in an \item of a list % environment. % In this documentation, many usage of everbatim* are indeed inside such % \item's. The former (2020) approach was to do: % \@namedef{endeverbatim*}{\endeverbatim\aftergroup\everbatimundoparskip} % \def\everbatimundoparskip{\vbox{}\kern-\baselineskip\kern-\parskip\leavevmode} % but it had its problems if executed contents start a display, with % not enough vertical whitespace then % Also if source had two everbatim* environments one after the other, % the first one not producing any ouput, this caused overlap. % The new approach (Feb 2022) is much simpler and avoids these problems. % These definitions are provisory and get overwritten below in order % to avoid color stack overflow problems with latex + dvipdfmx, and xelatex \def\everbatimxprehook {\colorlet{everbsavedcolor}{.}% \color{everbatimxfgcolor}}% \def\everbatimxposthook{\color{everbsavedcolor}} % actual definitions: {\sbox0{\color{everbatimxfgcolor}\xdef\@tempa{\current@color}}} \ifpdf \ifluatex \edef\everbatimxprehook {\pdfextension colorstack\noexpand\@pdfcolorstack push{\@tempa}\relax} \def\everbatimxposthook {\pdfextension colorstack\@pdfcolorstack pop\relax} \else \edef\everbatimxprehook {\pdfcolorstack\noexpand\@pdfcolorstack push{\@tempa}\relax} \def\everbatimxposthook{\pdfcolorstack\@pdfcolorstack pop\relax} \fi \else % Le 24 juin 2021 je vérifie que ceci est encore nécessaire avex xelatex % (sinon color leak de OrangeRed à partir de la page 97 dans la doc) % et aussi pour dvipdfmx (sinon color stack overflow au moment de la page 98 % lors du passage par dvipdfmx) \ifxetex \edef\everbatimxprehook{\special{color push \@tempa}} \def\everbatimxposthook{\special{color pop}} \else \ifnum\Withdvipdfmx=1 \edef\everbatimxprehook{\special{color push \@tempa}} \def\everbatimxposthook{\special{color pop}} \fi \fi \fi % \everb % ====== % % Original was called \dverb and I did it in June 2013. % Then after doing everbatim, I transformed \dverb, now called \everb % for itself being as compatible as standard verbatim with list making % surrounding environments. % Supposed to be used as % \everb|@ this will be ignored % stuff % escape character: " % | not necessarily starting a line. % I chose @ as comment character, mainly for pretty-formatting of the % source, this can be changed by \everbhook. % " comme caractère d'échappement. Par exemple pour colorier des parties. % Le "" redonne à { et } leurs catcodes normaux mais attention c'est % alors à utiliser avec un terminateur ;! pour la partie concernée \def\restoreeverbhook{\def\everbhook{% \def\"{\begingroup\catcode123 1 \catcode 125 2 \everbescape }% \catcode`\" 0 \catcode`\@ 14 }}\restoreeverbhook \def\everbescape #1;!{#1\endgroup } \def\everb {% \bgroup \let\everbatimhook\everbhook \s@everbatim \@everb } \def\@everb #1{\catcode`#1\active \lccode`\~`#1% \lowercase{\def~{\if@newlist \leavevmode\fi \endtrivlist \egroup \@doendpe \everbatimbottom }}% }% \catcode`_8 % \printnumber % ============ \catcode`_ 11 \catcode`& 3 \def\allowsplits_a {\futurelet\printnumber_token\allowsplits_b }% \def\allowsplits_b{\ifx\printnumber_token\@sptoken\space\fi\allowsplits_c } \def\allowsplits_c #1{\ifx \xint_dothis\xint_gobble_i\fi \if ,#1\xint_dothis {\discretionary{\rlap,}{}{,}}\fi \xint_orthat{\discretionary {\copy\SoftWrapIconA}% {\copy\SoftWrapIconB}% {}#1}\allowsplits_a }% \def\printnumber #1{\expandafter\allowsplits_a \romannumeral-`0#1&}% \hyphenpenalty \z@ \catcode`& 4 \catcode`_ 8 % Parameters for lists % ==================== \AtBeginDocument{% \leftmargini \dimexpr4\fontcharwd\font`X\relax \leftmarginii\dimexpr3\fontcharwd\font`X\relax \leftmarginiii \leftmarginii \leftmarginiv \leftmarginii \parindent\dimexpr2\fontcharwd\font`X\relax \leftmargin\leftmargini % pourquoi pas 0? % formerly everbatim indent was set to leftmargingi, reduce it (2017/08/26) % \edef\everbatimindent{\the\dimexpr\leftmargini\relax\space }% % setting it to \parindent does not work with \everb construct % \def\everbatimindent{\parindent}% \edef\everbatimindent{\the\dimexpr2\fontcharwd\font`X\relax\space}% \cftsubsecnumwidth 2\leftmarginii \cftsubsubsecnumwidth 2\leftmargini \cftsubsecindent 0pt \cftsubsubsecindent \cftsubsecnumwidth }% % ========== % Hyperlinks % ========== % \csa, \csbxint, \csh etc... % =========================== % The underscore and caret things are for implementation part \DeclareRobustCommand\csa[1] {{\ttzfamily\char92\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}} % csan: n means no backslash \DeclareRobustCommand\csan[1] {{\ttzfamily\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}} % For some legacy reasons rather than doing: % \pdfstringdefDisableCommands{% % \def\csa#1{\textbackslash\detokenize{#1}}% % \def\csan#1{\detokenize{#1}}% % }% % I defined years ago variants for usage within section titles. These % variants will get redefined in implementation section to automatically % insert \label's and use \csa and \csan. Here in user manual, they simply % use \csa or \csan, but are careful to do \texorpdfstring. \newcommand\csh[1] {\texorpdfstring{\csa{#1}}{\textbackslash\detokenize{#1}}} % This one is actually never used inside the user manual, only encountered % in the implementation part. \newcommand\cshn[1] {\texorpdfstring{\csan{#1}}{\detokenize{#1}}} % Let's preserve these meanings for when I will want to use them in sections % of the implementation part but not insert labels. \let\cshnolabel\csh \let\cshnnolabel\cshn % 2022/06/10 % If producing xint-all.pdf add hyperlinks from user documentation % to source code. Should have I used some superscript? Less trouble % and less work intensive for TeX I guess than the centered align. % \def\myalign@vbox#1{\leavevmode\vbox{\baselineskip\z@skip \lineskip.75ex% % \ialign{\hfil##\hfil\crcr#1\crcr}}} % %%\def\oalign#1{\leavevmode\vtop{\baselineskip\z@skip \lineskip.25ex% % %% \ialign{##\crcr#1\crcr}}} % \myalign@vbox{\hyperref[\xintimplabelprefix\detokenize{#1}]{\usebox\codelinkbox}\cr % \csa{#1}}% % 2026/03/01 % Less vertical separation (0.35ex not 0.75ex) \def\myalign@vbox#1{%\leavevmode \vbox{% \@tempboxa is not used by \smash... and I hope \hyperref too \kern.15ex % added 2026/03/01 \baselineskip\z@skip\lineskip.35ex\relax \sbox\@tempboxa{\csa{#1}}% \hbox to\wd\@tempboxa{\hss \hyperref[\xintimplabelprefix\detokenize{#1}]{\usebox\codelinkbox}% \hss}% \box\@tempboxa }% }% \newsavebox\codelinkbox % \familydefault already configured % trying to add some \vphantom{X} has no impact it seems on the % size of the clickable area (tested with Skim and Preview on mac os) % so using \small not \footnotesize \sbox\codelinkbox{\color{macrocodelinktosectioncolor}% \normalfont\small\itshape code} % For 1.4p I rmove the \smash % \def\cswithsourcelink#1{\smash{\myalign@vbox{#1}}}% \def\cswithsourcelink#1{\myalign@vbox{#1}}% % the references should exist on second LaTeX pass % and we don't want complications in tables of contents \def\csperhapswithlink#1{\ifx\thepage\relax\csa{#1}\else \ifcsname r@\xintimplabelprefix\detokenize{#1}\endcsname \cswithsourcelink{#1}% \else \csa{#1}% \fi\fi } \ifnum\doxintsource=0 \ifnum\NoSourceCode=0 \renewcommand\csh[1] {\texorpdfstring {\csperhapswithlink{#1}} {\textbackslash\detokenize{#1}}% } % \renewcommand\cshn[1] % but it is used nowhere in user manual \fi\fi % The "b" is there originally for "blue" in fact, from the hyperlink. \DeclareRobustCommand\csb [1] {\perhapshyperref[\xintlabelprefix\detokenize{#1}]% {{\char92 \endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} \DeclareRobustCommand\csbn[1] {\perhapshyperref[\xintlabelprefix\detokenize{#1}]% {{\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} \DeclareRobustCommand\csbxint[1] {\perhapshyperref[\xintlabelprefix\detokenize{xint#1}]% {{\char92\mbox{xint}\-\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} \DeclareRobustCommand\csbXINT[1] {\perhapshyperref[\xintlabelprefix\detokenize{XINT#1}]% {{\char92\mbox{XINT}\-\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} % 2022/06/08, I finally add this % although this is is not immediately useful as I have interiorized for years % not to use \csbxint et al. in section titles... \pdfstringdefDisableCommands{% \let\csb\cs % \cs already in DisableCommands, I hope its redefinition is done % first, well yes one has to chase \ltx@GlobalAppendToMacro % all the way to ltxcmds... \let\csbn\detokenize \def\csbxint#1{\textbackslash xint\detokenize{#1}}% \def\csbXINT#1{\textbackslash XINT\detokenize{#1}}% }% % \func, \funcdesc, \keyword, \keyworddesc, \prec, \precdesc, \oper, \operdesc % ============================================================================ \NewDocumentCommand{\func}{m}{\hyperlink{\detokenize{func-#1}}{#1}()} \newcommand\funcdesc[2][x]{\item[#2({#1})]\hypertarget{\detokenize{func-#2}}{}}% \newcommand\keyword[1]{\hyperlink{\detokenize{kwd-#1}}{#1}} \newcommand\keyworddesc[1]{\item[#1]\hypertarget{\detokenize{kwd-#1}}{}}% \let\prec\relax % sinon, c'est \mathchar"321E \newcommand\prec[1]{\hyperlink{\detokenize{prec-#1}}{#1}} \newcommand\precdesc[1]{\item[\texttt{#1}]\hypertarget{\detokenize{prec-#1}}{}\leavevmode}% %\let\var\relax % défini par koma-script-source-doc que scrdoc % utilise avec LaTeX 2022/06/01 % mais finalement je n'utilise plus scrdoc/ltxdoc % mais doc directement. \newcommand\var[1]{\hyperlink{\detokenize{var-#1}}{#1}} \newcommand\vardesc[1]{\item[#1]\hypertarget{\detokenize{var-#1}}{}}% \newcommand\oper[1]{\hyperlink{\detokenize{oper-#1}}{#1}} \newcommand\operdesc[1]{\item[\texttt{#1}]\hypertarget{\detokenize{oper-#1}}{}}% % \xintname, \xintnameimp etc... % ============================== \xintForpair #1#2 in {(kernel,kernel), (tools,tools), (core,core),(,xint),(binhex,binhex),(gcd,gcd),% (frac,frac),(series,series),(cfrac,cfrac),(expr,expr),% (trig, trig), (log, log)} \do {% \expandafter\def\csname xint#1name\endcsname {\texorpdfstring {\perhapshyperref[sec:#2]% {{\color{xintnamecolor}\MakeNameUp {\mbox{xint}\-#1} {xint#1}% }% }% }% {xint#1}% \xspace }% \expandafter\def\csname xint#1nameimp\endcsname {\texorpdfstring {\perhapshyperref[sec:#2imp]% {{\color{xintnameimpcolor}\MakeNameUp {\mbox{xint}\-#1} {xint#1}% }% }% }% {xint#1}% \xspace }% }% \xintForpair #1#2 in {(,), (core,core), (int,int), (fp,fp), (trig,trig), (trigdata, trigdata), (log,log), (logdata, logdata)} \do {% \expandafter\def\csname calx#1name\endcsname {\texorpdfstring {\perhapshyperref[sec:calx#2]% {{\color{xintnamecolor}\MakeNameUp {\mbox{calx}\-#1} {calx#1}% }% }% }% {calx#1}% \xspace }% \expandafter\def\csname calx#1nameimp\endcsname {\texorpdfstring {\perhapshyperref[sec:calx#2imp]% {{\color{xintnameimpcolor}\MakeNameUp {\mbox{calx}\-#1} {calx#1}% }% }% }% {calx#1}% \xspace }% }% \def\xintbundlename {\texorpdfstring {\perhapshyperref[sec:bundle]% {{\color{xintnamecolor}\MakeNameUp {\mbox{xint} bundle} {xintbundle}% }% }% }% {xint bundle}% \xspace }% \def\calxbundlename {\texorpdfstring {\perhapshyperref[sec:bundle]% {{\color{xintnamecolor}\MakeNameUp {\mbox{calx} bundle} {calxbundle}% }% }% }% {calx bundle}% \xspace }% \gdef\DOCxintfrontpage {\perhapshyperref[frontpage]{{\color{xintnamecolor}TOC}}}% \ifnum\doxintsource=1 % xintsource.pdf \gdef\DOCxintfrontpage {\perhapshyperref[frontpage]{{\color{xintnameimpcolor}TOC}}}% \gdef\DOCcalxfrontpage {\perhapshyperref[frontpage]{{\color{xintnameimpcolor}TOC}}}% \else \ifnum\NoSourceCode=0 % xint-all.pdf % Not using \hypersetup with linkcolor because a few pages are with % a TOC à cheval on two pages, and my eTOCs are configured to do % \hypersetup{hidelinks} \protected\def\DOCxintfrontpage {\smash{\vbox{\hbox{\perhapshyperref[partiii]{{\color{xintnameimpcolor}TOC}}}% \kern1ex \hbox{\perhapshyperref[frontpage]{{\color{xintnamecolor}TOC}}}}}}% \fi\fi \protected\def\MakeNameUp#1#2{% \ifcsname #2nameUp\endcsname \expandafter\@firstoftwo\else \expandafter\@secondoftwo \fi % \ifinheader 2020/01/30 {\ifinheader\fbox{\textup{#1}}\else#1\fi}% {#1}% } \newif\ifinheader % doit être protégé \protected\def\inheadertrue{\let\ifinheader\iftrue} % \RaisedLabel % ============ % Samedi 16 juin 2018 à 15:23:22 % trick to see header of target page % there is probably better way to use the already in place % anchor from \section, but no time to go into hyperref source \newcommand\RaisedLabel[2][6]{% \vspace*{-#1\baselineskip}% \begingroup \let\leavevmode\relax\phantomsection \label{#2}% \endgroup \vspace*{#1\baselineskip}% } % It seems I need this for a bookmark in xint-all.pdf % reaching the top of the page where Part III starts % 2022/06/10 \newcommand\RaisedTarget[2][6]{% \vspace*{-#1\baselineskip}% \hypertarget{#2}{}% \vspace*{#1\baselineskip}% } % 31 janvier 2020 % 2022/06/10 no need for \texorpdfstring here \def\DOCxintexprintro {\perhapshyperref[part:1]{{\color{xintnamecolor}% \MakeNameUp{Start here}% {Start here}% }% }% }% \def\DOCxintexprmacros {\perhapshyperref[sec:oldxintexpr]{{\color{xintnamecolor}% \MakeNameUp{xintexpr (old doc)}% {xintexpr (old doc)}% }% }% }% \def\DOCexamples {\perhapshyperref[sec:examples]{{\color{xintnamecolor}% \MakeNameUp{Examples}{Examples}% }% }% }% % Vendredi 15 juin 2018 % Someone makes the comma active (not me! not sure if doc.sty or KOMA) and % this derails xspace.sty, in the headers, as it uses \scantokens on a list of % tokens, so it fails to recognize the commas which of course are of catcode12 % Update Friday, June 25 2021 % I finally take the time to go to the root of this: the culprit is everbatim % when its output crosses pagebreaks, but the same of course happens with % verbatim. % I opened ticket https://github.com/latex3/latex2e/issues/600 \def\xintRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, \DOCxintexprintro, \xintexprname, \DOCxintexprmacros, \calxtrigname, \calxlogname, \xinttoolsname, \DOCexamples, \xintbundlename}} % MEMO: the \markboth must be done after \begin{document}. Else it appears to % work, but actually the hyperlinks are missing. This is due to % \perhapshyperref (see above) needing the .aux file to have been read to % find the label. % \markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} % 18 mai 2019, turned into an environment 27 mai 2022 \newenvironment{TeXnote}{\par\small\medskip\noindent\textbf{\TeX-hackers note: }}{\par\medskip} \DeclareRobustCommand\ctanpackage[1]{\href{https://ctan.org/pkg/#1}{#1}} \etocsetlevel{toctobookmark}{6} \makeatother % begin{document} % =============== % \ttzfamily done at begin document \begin{document}\thispagestyle{empty} \markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} \pdfbookmark[1]{Title page}{TOP} \def\partname{Part} \addto\captionsenglish{\def\partname{Part}} \ifnum\doxintsource=1 \noindent\begin{minipage}[t][8\baselineskip][c]{\linewidth} \normalfont\Huge \centering The \calxnameimp, \xintexprnameimp and allied packages source code\par \else \begingroup \normalfont\Huge \centering The \calxname, \xintexprname and allied packages\par \endgroup \fi \RaisedLabel{frontpage} \normalsize\ttzfamily {\centering \textsc{Jean-Fran\c cois Burnol}\par \footnotesize jfbu (at) free (dot) fr\par Package version: \xintbndlversion\ (\xintbndldate).\par {From source file \texttt{xint-calx.dtx}. \xintdtxtimestamp.}\par } \ifnum\doxintsource=1 \end{minipage} \else \medskip \fi % Skips safely. \ifnum\doxintsource=1 \catcode`+ 0 \catcode0 9 % n'importe quoi sauf 15 (car ^^@) \catcode`\\ 12 +expandafter+iffalse+fi \fi % \makeatletter \etocsetlevel{xinttable}{2}% subsection \let\orig@etoctoclineleaders\etoctoclineleaders \def\etoctoclineleaders {\hbox{\normalfont\normalsize\hbox to 1ex {\hss.\hss}}} \def\etocbelowtocskip{\z@skip} \def\etocinnertopsep{\z@skip} \etocsettocstyle{}{} \etocsettagdepth {part1A}{subsection}% style de subsection défini dans preamble \etocsettagdepth {part1B}{section}% style de section aussi \etocsettagdepth {macros}{none} \etocsettagdepth {implementation}{none} \etocsettocdepth{subsection} %% Legacy etoc style for part, with an improvement to get "Part" %% hyperlinked %% Also some hack to let the TOC of xint-all.pdf fit on one page %% `part': (modified 2026/11/04 pour que ça s'applique aussi à xint-manual.pdf) \etocsetstyle{part} {\ifnum\doxintsource=0 \def\etocabovetocskip{\z@skip}% \def\etocsepminusone{\bigskipamount}% \def\etocsepzero{\medskipamount}% \def\tocstylesectionVSKIP{\vskip\smallskipamount}% \fi \addpenalty\@M\etocskipfirstprefix} {\addpenalty\@secpenalty} {% \begingroup \etocfontminusone \addvspace{\etocsepminusone}% \parindent \z@ \leftskip \etocminusoneleftmargin \rightskip \etocminusonerightmargin \parfillskip \@flushglue % original from etoc : %\vbox{\etocifnumbered{\etocpartname\enspace\etocnumber.\quad}{}...} \vbox{\etocifnumbered{\etoclink{\etocpartname\enspace\etocthenumber.}\quad}{}% \etocname \baselineskip\etocbaselinespreadminusone\baselineskip \par}% \addpenalty\@M \addvspace{\etocsepzero}% \endgroup} {}% % THIS IS THE FIRST HALF OF THE TOC ON PAGE 1 \tableofcontents % May 23 2022, some hack to replace the \etocmulticolstyle and % have same output except that Part line will use full line width % % Formerly I used this but the Part was then folded... % \etocmulticolstyle [2]{\parskip\z@skip%\raggedcolumns % \setlength{\columnsep}{\leftmarginii}% % \setlength{\columnseprule}{0pt}% % }% % \etocsetstyle{part}% @minusone in etoc.sty {\if1\ifnum\doxintsource=1 0\fi\ifnum\NoSourceCode=1 0\fi1% xint-all.pdf \def\etocabovetocskip{\z@skip}% \def\etocsepminusone{\bigskipamount}% \def\etocsepzero{\medskipamount}% \fi \addpenalty\@M\etocskipfirstprefix} % May 23, 2022 % Small hack to configure to our taste the TOC for the pdf combining % the user manual and the source code. We want a Part III in the TOC, % and the sections of Part II with a multicols. We can not open the % multicols in the `part' style and have it closed in the 4th argument % of \etocsettyle, as it needs to be closed when Part III will be % typeset. Thanks to \etocskipfirstprefix we can simply close it % in the "EtocPrefix", this \end{multicols} will be skipped for the % first one. % % However, as this closes a group we will use \etocglobaldefs for this % toc else \etocname, etc... would not have the good meanings. I think % there must be some hack like this in etoc manual. {\end{multicols}% \addpenalty\@secpenalty } {% % \kern and not \vskip to avoid multicolumn balncing columns \def\tocstylesectionVSKIP{\kern\smallskipamount}% \if1\ifnum\doxintsource=1 0\fi\ifnum\NoSourceCode=1 0\fi1% % xint-all.pdf only % quite a challenge to get everything on single page, but not too cramped... \def\tocstylesectionVSKIP{\kern.75\smallskipamount}% \fi \begingroup % adapted from etoc.sty default Part style \etocfontminusone \addvspace{\etocsepminusone}% \parindent \z@ \leftskip \etocminusoneleftmargin \rightskip \etocminusonerightmargin \parfillskip \@flushglue % \etoclink is handy else only the number get hyperlinked \vbox{\etocifnumbered{\etoclink{\etocpartname\enspace\etocthenumber.\quad}}{}\etocname \baselineskip\etocbaselinespreadminusone\baselineskip \par}% \addpenalty\@M\addvspace{\etocsepzero}% \endgroup % now emulate what \etocmulticolstyle would have set-up \let\etocoldpar\par% surely fishy by now but I am copying from % how \etocsettocstyle is used by \etocmulticolstyle \addvspace{\etocabovetocskip}% configured below \multicolpretolerance\etocmulticolpretolerance \multicoltolerance\etocmulticoltolerance \setlength{\columnsep}{\etoccolumnsep}% \setlength{\multicolsep}{\etocmulticolsep}% \begin{multicols}{2}[\parskip\z@skip%\raggedcolumns \setlength{\columnsep}{\leftmarginii}% \setlength{\columnseprule}{0pt}% \etocoldpar %\addvspace{\etocinnertopsep} \addvspace{\etocabovetocskip}]% }% {\end{multicols} }% % this macro is defined by etoc for use in its own display styles % like the one from \etocmulticolstyle. We use it manually above. \renewcommand*\etocabovetocskip{\bigskipamount} \makeatother \etocsettagdepth {part1A}{none} \etocsettagdepth {part1B}{none} \etocsettagdepth {macros} {section} \ifnum\doxintsource=1 % xintsource.pdf \etocsettagdepth {implementation}{section} \else \ifnum\NoSourceCode=1 % xint.pdf \etocsettagdepth {implementation}{part} \else % xint-calx.pdf \etocsettagdepth {implementation}{part} \fi \fi % THIS IS THE SECOND HALF OF THE TOC ON PAGE 1, WITH PARTS II AND III \etocglobaldefs \tableofcontents \etoclocaldefs \etocignoredepthtags % 30 juillet 2025, simplification du contrôle espacement après TOCs \makeatletter \def\etocabovetocskip{\z@skip} \makeatother \def\etocbelowtocskip{\bigskipamount} \etocmulticolstyle [1]{% \phantomsection% \section* {Contents} \etoctoccontentsline*{toctobookmark}{Contents}{2}% } \inmanualmaintocfalse \clearpage % ---- % Fibonacci code % % The first version was done on % December 7, 2013. Expandably computing a big Fibonacci number % with the help of TeX+\numexpr+\xintexpr, © Jean-François Burnol % % The code was redone on September 22 (and 27) 2025, after the % 1.4o release, so for 1.4p release. % Less multiplications. % First convert to binary with the help of \xintDecToBin. % This second version though requires positive argument. % % Transferred from bnumexpr.dtx with \xintiiexpr replacing \bnumexpr, % comments in sync on Sep. 27. % (MEMO: we are already here in the document body but a catcode active % semi-colon from babel-french for example is not here a problem). \makeatletter \newcommand\Fibonacci[1]{% \expandafter\Fibo@start \romannumeral0\xintdectobin{\the\numexpr#1\relax};% } % To chain \xintiiexpr's easily we use the once-expanded form which is % \romannumeral0\xintiiexpro. We could also have used \expanded and \xintiieval % calls, that would have been simpler but old habits die hard. % % Gobble the first digit which is 1 (this is where we could have tested for a % negative or zero input). Prepare encapsulated 1 and 0. Then repeatedly % dispatch according to binary digits (which are strategically located at end % of input stream to optimize), or the semicolon which signals completion. % % We use \csname-governed branching (because it is cool). We could have % used some \if test or even an \ifcase with an {-1} at end, or any other % of the many possibilities opened up by TeX syntax. \def\Fibo@start 1#1{% \csname Fibo@#1\expandafter\endcsname \romannumeral0\xintiiexpro 1\expandafter\relax\expandafter;% \romannumeral0\xintiiexpro 0\relax;% } \@namedef{Fibo@0}#1;#2;#3{% \csname Fibo@#3\expandafter\endcsname \romannumeral0\xintiiexpro (#1+2*#2)*#1\expandafter\relax\expandafter;% \romannumeral0\xintiiexpro #1*#1+#2*#2\relax;% } \@namedef{Fibo@1}#1;#2;#3{% \csname Fibo@#3\expandafter\endcsname \romannumeral0\xintiiexpro 2*(#1+#2)*#1+#2*#2\expandafter\relax\expandafter;% \romannumeral0\xintiiexpro (#1+2*#2)*#1\relax;% } % #1 is F_N (and #2 is F_{N-1}) but in need of unpacking. \@namedef{Fibo@;}#1;#2;{\xintthe#1} \makeatother \def\specialprintone #1% {% \ifx #1\relax \else \makebox[877496sp]{#1}\hskip 0pt plus 2sp\relax \expandafter\specialprintone\fi }% \def\specialprintnumber #1% first ``fully'' expands its argument. {\expandafter\specialprintone \romannumeral-`0#1\relax }% % Updated september 9, 2025, 11 years and 8 months after initial % version, to add a nice legend at bottom right and print F_{1250} % at top left. I don't think many people had understood that the % displayed digits were those of the 1250th Fibonacci number... % \AddToShipoutPicture*{% \put(10.5cm,14.85cm) {\edef\z{\Fibonacci{1250}}% \makebox(0,0) {\resizebox{17cm}{!}{% \vbox{\hsize 8cm\Huge \baselineskip.8\baselineskip \color{black!15}% \makebox[6\dimexpr877496sp\relax][l]{$F_{1250}={}$}% \hskip0pt plus12sp\relax \specialprintnumber{\z}% <-- careful no space token here \parbox[c]{5.5\fontcharwd\font`0 }% 5 cm is a bit too narrow for text {\color{black}\tiny \raggedright The $1250^{th}$ Fibonacci number has \expandafter\xintLength\expandafter{\z} digits.\par}% \kern-0.5\fontcharwd\font`0 \par }% }% arg of \resizebox }% }% } \pdfbookmark[1]{Dependency graph}{DependencyGraph} \tikzstyle{block} = [rectangle, draw, fill=yellow!10, % fill opacity=0.5, draw=black!30, line width=2pt, text width=6em, text centered, rounded corners, minimum height=4em] \tikzstyle{line} = [draw, line width=1pt, color=black!30] %\vspace*{\stretch{0.1666}} \begin{figure}[ht!] \phantomsection\label{dependencygraph} \centeredline{% \begin{tikzpicture} % Main calx column \node [block] (kernel) at (-2.8,0) {\xintkernelname}; \node [block] (calxcore) at (-2.8,-2.2) {\calxcorename}; \node [block] (calxint) at (-2.8,-4.35) {\calxintname}; \node [block] (calxfp) at (-2.8,-6.5) {\calxfpname}; \node [block] (calx) at (-2.8,-8.65) {\calxname}; % Shared dependencies \node [block] (tools) at (3.8,-.5) {\xinttoolsname}; \node [block] (binhex) at (7.3,-.5) {\xintbinhexname}; % Legacy column \node [block] (xcore) at (2.1,-2.55) {\xintcorename}; \node [block] (xint) at (2.1,-4.7) {\xintname}; \node [block] (frac) at (2.1,-6.85) {\xintfracname}; \node [block] (expr) at (2.1,-9) {\xintexprname}; % Auxiliary xint packages \node [block] (bnumexpr) at (7.3,-2.55) {\ctanpackage{bnumexpr}}; \node [block] (gcd) at (7.3,-4.7) {\xintgcdname}; \node [block] (series) at (7.3,-6.85) {\xintseriesname}; \node [block] (cfrac) at (7.3,-8.45) {\xintcfracname}; % External packages \node [block] (zeck) at (7.3,-10.7) {\ctanpackage{zeckendorf}}; \node [block] (session) at (2.1,-13.5) {rlwrap etex \ctanpackage{xintsession}}; \node [block] (polexpr) at (7.3,-13.5) {\ctanpackage{polexpr}}; % Main calx chain \path [line,-{Stealth[length=5mm]}] (kernel) -- (calxcore); \path [line,-{Stealth[length=5mm]}] (calxcore) -- (calxint); \path [line,-{Stealth[length=5mm]}] (calxint) -- (calxfp); \path [line,-{Stealth[length=5mm]}] (calxfp) -- (calx); % Dependencies on xintkernel \path [line,-{Stealth[length=5mm]}] (kernel.east) -- (tools.west); % xintkernel -> xintbinhex: clear xintcore from above \path [line,-{Stealth[length=5mm]}] (kernel.east) to[out=-65,in=180] (-.9,-1.55) -- (5.5,-1.55) to[out=0,in=230] (binhex.south west); % xinttools -> calx: diagonal entry at top-left corner \path [line,rounded corners=4pt,-{Stealth[length=5mm]}] (tools.north) -- (3.8,2.1) -- (-4.5,2.1) -- (-4.5,-7.45) -- (calx.north west); % xintbinhex -> calx: horizontal arrival at west \path [line,rounded corners=9pt,-{Stealth[length=5mm]}] (binhex.north) -- (7.3,2.9) -- (-5.2,2.9) -- (-5.2,-8.65) -- (calx.west); % Bridges from calx to legacy packages \path [line,-{Stealth[length=5mm]}] (calxcore) -- (xcore); \path [line,-{Stealth[length=5mm]}] (calxint) -- (xint); \path [line,-{Stealth[length=5mm]}] (calxfp) -- (frac); \path [line,-{Stealth[length=5mm]}] (calx) -- (expr); % Legacy chain \path [line,-{Stealth[length=5mm]}] (xcore) -- (xint); \path [line,-{Stealth[length=5mm]}] (xint) -- (frac); \path [line,-{Stealth[length=5mm]}] (frac) -- (expr); % bnumexpr dependencies \path [line,-{Stealth[length=5mm]}] (xcore) -- (bnumexpr); \path [line,-{Stealth[length=5mm]}] (binhex.south) -- (bnumexpr.north); % xintgcd, xintseries, xintcfrac \path [line,-{Stealth[length=5mm]}] (xint) -- (gcd); \path [line,-{Stealth[length=5mm]}] (frac) -- (series); \path [line,-{Stealth[length=5mm]}] (frac.south east) to [out=-35,in=180] (cfrac.west); % Additional xinttools dependencies \path [line,-{Stealth[length=5mm]}] (tools.south east) to [out=-65,in=135] (gcd.north west); \path [line,-{Stealth[length=5mm]}] (tools.south) to [out=-90,in=155] (cfrac.north west); % External packages \path [line,-{Stealth[length=5mm]}] (expr) -- (zeck); \path [line,-{Stealth[length=5mm]}] (expr) -- (session); \path [line,-{Stealth[length=5mm]}] (expr) -- (polexpr); \path [line,-{Stealth[length=5mm]}] (polexpr) -- (session); \end{tikzpicture}}\bigskip \end{figure} % \begin{figure}[ht!] % \phantomsection\label{dependencygraph} % \centeredline{% % \begin{tikzpicture}[node distance = 2.5cm] % % Place nodes % \node [block] (kernel) {\xintkernelname}; % % \node [left of=kernel] (A) {}; % % \node [right of=kernel] (B) {}; % \node [block, below of=kernel] (core) {\xintcorename}; % \node [block, right of=core, xshift=1cm] (binhex) {\xintbinhexname}; % \node [block, left of=core, xshift=-2.5cm] (tools) {\xinttoolsname}; % \node [block, below of=core] (xint) {\xintname}; % \node [block, right of=xint, xshift=1cm] (bnumexpr) {\ctanpackage{bnumexpr}}; % \node [block, left of=xint, xshift=-0.5cm] (gcd) {\xintgcdname}; % \node [block, below of=xint] (frac) {\xintfracname}; % \node [block, below of=frac, yshift=-.5cm] (expr) {\xintexprname}; % \node [block, below right of=expr, yshift=-.5cm, xshift=2.25cm] (polexpr) {\ctanpackage{polexpr}}; % \node [block, below of=polexpr] (session) {rlwrap etex \ctanpackage{xintsession}}; % \node [block, right of=expr, xshift=3cm] (zeck) {\ctanpackage{zeckendorf}}; % \node [block, below of=expr, yshift=-.5cm] (trig) {\xinttrigname}; % \node [block, left of=trig] (log) {\xintlogname}; % \node [block, left of=log, xshift=-1cm] (poormanlog) {\ctanpackage{poormanlog}}; % \node [block, below of=gcd, yshift=1cm] (cfrac) {\xintcfracname}; % \node [block, below of=cfrac, yshift=1cm] (series) {\xintseriesname}; % % Draw edges % \path [line,-{Stealth[length=5mm]}] (kernel) -- (core); % \path [line,-{Stealth[length=5mm]}] (kernel) -- (tools); % \path [line,-{Stealth[length=5mm]}] (kernel) -- (binhex); % \path [line,-{Stealth[length=5mm]}] (core) -- (bnumexpr); % \path [line,-{Stealth[length=5mm]}] (binhex) -- (bnumexpr); % \path [line,-{Stealth[length=5mm]}] (core) -- (xint); % \path [line,-{Stealth[length=5mm]}] (xint) -- (frac); % \path [line,-{Stealth[length=5mm]}] (xint) -- (gcd); % \path [line,-{Stealth[length=5mm]}] (frac) -- (expr); % \path [line,-{Stealth[length=5mm]}] (frac) -- (series); % \path [line,-{Stealth[length=5mm]}] (frac) -- (cfrac); % \path [line,-{Stealth[length=5mm]}] (expr) -- (polexpr); % \path [line,{Stealth[length=5mm]}-{Stealth[length=5mm]}] (expr) -- (trig); % \path [line,{Stealth[length=5mm]}-{Stealth[length=5mm]}] (expr) -- (log); % \path [line,-{Stealth[length=5mm]}] (poormanlog) -- (log); % \path [line,-{Stealth[length=5mm]}] (expr) -- (polexpr); % \path [line,-{Stealth[length=5mm]}] (expr) -- (session); % \path [line,-{Stealth[length=5mm]}] (expr) -- (zeck); % \path [line,-{Stealth[length=5mm]}] (polexpr) -- (session); % \path [line,-{Stealth[length=5mm]}] (trig.south) to [out=-90,in=180] (session.west); % \path [line,-{Stealth[length=5mm]}] (log.south) to [out=-90,in=180] (session.west); % % at 1.4n, xintbinhex is automatically loaded by xintexpr, no more "dashed" % \path [line,-{Stealth[length=5mm]}] (binhex.south east) to [out=-45,in=15] (expr); % % at 1.4 xintgcd loads xinttools % \path [line,-{Stealth[length=5mm]}] (tools.south west) to [out=-90,in=180](gcd.west); % % at 1.4n, xintcfrac loads xinttools automatically % \path [line,-{Stealth[length=5mm]}] (tools.south west) to [out=-90,in=180](cfrac.west); % \path [line,-{Stealth[length=5mm]}] (tools.south west) to [out=-90,in=180] (expr.west); % \end{tikzpicture}}\bigskip % \end{figure} %\vspace{\baselineskip} \begin{addmargin}{1.5cm} \normalfont\footnotesize Dependency graph for the \xintbundlename components. % Modules pointed to by arrows \textbf{automatically} import the module from which the arrow originates. \calxcorename, \calxintname and \calxfpname provide no user interface at all. DO NOT USE THEM DIRECTLY. \ctanpackage{bnumexpr} is a \LaTeX{} package by the author which uses (by default) \xintcorename as its mathematical engine. To use it under Plain e\TeX{} issue first |\input miniltx.tex| then |\input bnumexpr.sty|. \ctanpackage{zeckendorf} can be used with Plain \eTeX{} or with \LaTeX{} and also directly on the command line. It enriches the \csbxint{eval} interface with tools related to Fibonacci numbers and the Bergman $\phi$-representation. \ctanpackage{polexpr} handles definitions and algebraic operatione on one-variable polynomials, as well as root localization to arbitrary precision. It works both with Plain \TeX\ and with \LaTeX. \ctanpackage{xintsession} is invoked on the command line as |etex xintsession| (or, much better if available: |rlwrap etex xintsession|). \par \end{addmargin} \vfill \clearpage \etocdepthtag.toc {part1A} \csname Start herenameUp\endcsname \part{The \calxname and \xintexprname packages} \RaisedLabel[12]{part:1} \etocsetnexttocdepth{section} \localtableofcontents \section{The \calxname package} \label{sec:calxcore} \label{sec:calxint} \label{sec:calxfp} \label{sec:calx} \localtableofcontents \begin{framed} \textsc{Jürgen Gilg}'s interest into what he called {|"XINT"|} was instrumental in keeping the author motivated over the years. % We exchanged on many topics extending beyond \TeX{} and often reacted similarly to private and public events. I knew he was a very kind and devoted person, who took care of the needs of others prior to his own, although he never mentioned it. % Jürgen suffered a sudden, unexpected, and deadly stroke in May 2022. I will miss his friendship profoundly. \end{framed} \begin{framed} The advent of \xintexprname 2.0, also known as \calxname, is almost entirely backward compatible. There are a few breaking changes and probably not all of them are properly documented for the \dtt{2.0a1} release. \end{framed} \subsection{Usage} Loading: \begin{everbatim} \usepackage{calx}% with LaTeX \input calx.sty\relax with other e-TeX formats. \end{everbatim} Example: \begin{everbatim*} $2^{200}=\calxinteval{2^200}$% \calxinteval and \xintiieval are the same thing. \noindent % \calxeval and \xintfloateval are the same thing. $(\ln(3), \pi)\approx (\calxeval{ln(3), Pi})$ \xintDigits:= 32\relax % or \xintSetDigits{32} \noindent % with 32 digits (hence, here, 31 decimal places). $(\ln(3), \pi) \approx (\calxeval{ln(3), Pi})$ \xintDigits:= 16\relax % back to default setting \end{everbatim*} You can set the floating point precision up to \dtt{100}. For tips on how to let \TeX{} print such long numeric output without overflowing into the right margin, please search for |\printnumber| in the legacy manual (which is actually the bulk of this PDF). Note: loading \xintexprname automatically loads \calxname. So legacy documents automatically benefit from the speed-up and higher accuracy. \subsection{What is \calxname?} It is the new arithmetic unit (floating point and big integers) of \xintexprname at release 2.0. It is a complete rewrite of thousands of lines of code, and addition of thousands more% % \footnote{Roughly the whole codebase has increased by 50\%. If one loads only \calxname, the "size" is increased only about 25\% compared with what applied with 1.4 series \xintexprname, due to \calxname not providing the support for fractions.}, % which was done in October 2026 (and took the whole month to get completed) by (mainly) Claude Opus 5.5, and ChatGPT 6. This was under the training, guidance and general supervision by an anonymous human assistant to Professor Burnol. NOTA BENE: \emph{the anonymous assistant checked only very little of the produced code and was each time horrified by what he saw.} He tried to fix a few obvious sub-optimalities and to get the AI assistants to learn from him (which he thought they had, but no), with little success. Much remains to be done at time of the \texttt{2.0a1} release for cleaning up the code. But it works. % 2.0a1 % xintkernel 715 (162) % xinttools 1625 (378) % xintbinhex 828 (164) % calxcore 2275 (607) % calxint 2521 (619) % calxfp 2879 (693) % calx 5264 (1556) % calxlog 3233 (555) % calxlogdata 1488 (470) % calxtrig 3644 (656) % calxtrigdata 1228 (536) % TOTAL: % 715 +1625 +828 +2275 +2521 +2879 +5264 +3233 +1488 +3644 +1228 = 25700 % 162 + 378 + 164 + 607 + 619 + 693 + 1556 + 555 + 470 + 656 + 536 = 6396 % ---- % 1.4o % xintkernel 701 (160) % xinttools 1625 (376) % xintcore 2104 (525) % xint 1611 (405) % xintbinhex 783 (157) % xintgcd 366 (63) % xintfrac 3683 (988) % xintseries 384 (66) % xintcfrac 1038 (257) % xintexpr 4788 (1407) % xinttrig 869 (68) % xintlog 1395 (123) % TOTAL: % 701 + 1625 + 2104 + 1611 + 783 + 366 + 3683 + 384 + 1038 + 4788 + 869 + 1395 = 19347 % 160 + 376 + 525 + 405 + 157 + 63 + 988 + 66 + 257 + 1407 + 68 + 123 = 4595 % --- 2.0a1 % xintkernel 715 (162) % xinttools 1625 (378) % xintbinhex 828 (164) % xintcore 443 (153) % xint 772 (249) % xintfrac 2805 (780) % xintexpr 667 (152) % xintgcd 366 (63) % xintseries 384 (66) % xintcfrac 1038 (257) The whole process was much more difficult and lengthy than originally envisioned. It reached the limits of what the anonymous assistant was willing to devote to an open source project with no financial gratification (especially when on a few occasions the human did buy some additional credits on top of the basic monthly subscription). However it was seen as an escape from the Apocalypse of July-August-September 2026 which completely changed the field of interest of the anonymous assistant: mathematics. Its sociology is going to change for the worse very quickly and irremediably now. Contrarily to \xintexprname, \calxname loads \emph{none} of \xintcorename, \xintname, \xintfracname. \textbf{It does not handle fractions}. For this you must load \xintexprname package for its |\xinteval| evaluator. For mathematical functions the target accuracy was set at a maximal error of \texttt{0.005ulp}. This means roughly that correct rounding is achieved in \dtt{99.5\%} of the cases (because at distance \texttt{0.005ulp} from a tie, there is \dtt{50\%} chance to be wrongly rounded). It seems that trigonometry actually achieved ten times better results, which may be modified in next relase to increase speed. For example for \dtt{4872} cases involvoing \func{log}, \func{exp}, \func{log1p}, \func{expm1}, only \dtt{21} were not correctly rounded and the error was then \texttt{1ulp}. Among \dtt{20300} trigonometrical evaluations \dtt{19} were not correctly rounded, and \dtt{18} among them were for \dtt{$P\leq8$}. The \dtt{$P=8$} mode has an about ten times degraded target accuracy, speed being the priority. (The core on arithmetic operations has not yet been optimized for \dtt{$P=8$}, it probably shares some overhead with the general precision case). \subsection{Timing comparisons versus \cs{fpeval} for \func{sin}, \func{ln}, \func{exp}, \dots} \label{sec:calx-speed} % Build-time comparison of \calxname 2.0a1 and LaTeX3 floating point evaluation. % The first run writes \jobname-benchmark.tex; subsequent runs reuse it. % Delete that file to remeasure after changing the code, engine or machine. \def\CalxBenchmarkExprSin{sin(1.2345678)} \def\CalxBenchmarkExprCos{cos(1.2345678)} \def\CalxBenchmarkExprTan{tan(1.2345678)} \def\CalxBenchmarkExprAsin{asin(0.56784321)} \def\CalxBenchmarkExprAcos{acos(0.56784321)} \def\CalxBenchmarkExprAtan{atan(1.2345678)} \def\CalxBenchmarkExprLog{ln(2.3456789)} \def\CalxBenchmarkExprExp{exp(1.2345678)} \def\CalxBenchmarkExprPowI{12.3456^78.9012} \def\CalxBenchmarkExprPowG{1.23456^789.012} \newcommand\CalxBenchmarkLabel[1]{% \texttt{\detokenize\expandafter{#1}}} % Only the l3benchmark interface needs expl3 syntax. \ExplSyntaxOn \fp_gset:Nn \g_benchmark_duration_target_fp { 0.025 } \cs_new_protected:Npn \CalxBenchmarkMeasure #1 { \benchmark_silent:n {#1} \xdef\CalxBenchmarkLastTime{\fp_to_decimal:N \g_benchmark_time_fp} } \ExplSyntaxOff % Benchmark raw timings are ordinary macros named % \calxDocumentBenchmarkRaw@@ (accessed via \csname). % The reference timing has the name calxDocumentBenchmarkRaw@unit. \def\CalxBenchmarkOne#1#2{% \CalxBenchmarkMeasure{\edef\calxDocumentBenchmarkSink{\fpeval{#2}}}% \expandafter\xdef\csname calxDocumentBenchmarkRaw@#1@fp\endcsname {\CalxBenchmarkLastTime}% \xintFor ##1 in {8,16,32}\do{% \begingroup \xintDigits=##1\relax \CalxBenchmarkMeasure{\edef\calxDocumentBenchmarkSink{\calxeval{#2}}}% \expandafter\xdef\csname calxDocumentBenchmarkRaw@#1@p##1\endcsname {\CalxBenchmarkLastTime}% \endgroup }% } \def\DOTIMINGS{% \def\CalxBenchmarkSum{0}% \xintFor ##1 in {1,2,3,4,5}\do{% \CalxBenchmarkMeasure{\edef\calxDocumentBenchmarkSink{\fpeval{sin(1)}}}% \edef\CalxBenchmarkSum {\xintfloateval{\CalxBenchmarkSum+\CalxBenchmarkLastTime}}% }% \expandafter\xdef\csname calxDocumentBenchmarkRaw@unit\endcsname {\xintfloateval{\CalxBenchmarkSum/5}}% \xintForpair ##1##2 in {(sin,Sin),(cos,Cos),(tan,Tan),(asin,Asin),(acos,Acos), (atan,Atan),(log,Log),(exp,Exp),(powi,PowI),(powg,PowG)}\do{% \CalxBenchmarkOne{##1}{\csname CalxBenchmarkExpr##2\endcsname}% }% } % Cache the raw per-evaluation times, not the displayed rounded ratios. \newwrite\CalxBenchmarkStream \def\CalxBenchmarkWriteRaw#1{% \immediate\write\CalxBenchmarkStream{% \string\expandafter\string\gdef \string\csname\space calxDocumentBenchmarkRaw@#1\string\endcsname {\csname calxDocumentBenchmarkRaw@#1\endcsname}}% } \def\CalxBenchmarkSaveResults{% \immediate\openout\CalxBenchmarkStream=\jobname-benchmark.tex\relax \CalxBenchmarkWriteRaw{unit}% \xintFor ##1 in {sin,cos,tan,asin,acos,atan,log,exp,powi,powg}\do{% \xintFor ##2 in {fp,p8,p16,p32}\do{% \CalxBenchmarkWriteRaw{##1@##2}% }% }% \immediate\closeout\CalxBenchmarkStream } % All seven displayed columns are rounded with \xintieval[2]. \def\CalxBenchmarkPrepareTable{% \xintFor ##1 in {sin,cos,tan,asin,acos,atan,log,exp,powi,powg}\do{% \expandafter\xdef\csname calxDocumentBenchmarkRatio@##1@fp\endcsname{% \xintieval[2]{% \csname calxDocumentBenchmarkRaw@##1@fp\endcsname/ \csname calxDocumentBenchmarkRaw@unit\endcsname}}% \xintFor ##2 in {p8,p16,p32}\do{% \expandafter\xdef\csname calxDocumentBenchmarkRatio@##1@##2units\endcsname{% \xintieval[2]{% \csname calxDocumentBenchmarkRaw@##1@##2\endcsname/ \csname calxDocumentBenchmarkRaw@unit\endcsname}}% \expandafter\xdef\csname calxDocumentBenchmarkRatio@##1@##2\endcsname{% \xintieval[2]{% \csname calxDocumentBenchmarkRaw@##1@##2\endcsname/ \csname calxDocumentBenchmarkRaw@##1@fp\endcsname}}% }% }% } \def\CalxBenchmarkCell#1#2{\csname calxDocumentBenchmarkRatio@#1@#2\endcsname} The \autoref{tab:timings} compares |\fpeval| with |\calxeval| used at precision settings P=8, 16 and 32 (P is the value set by \csbxint{SetDigits}). The average evaluation time of |\fpeval{sin(1)}| is used as a time unit for the entries in the |\fpeval| columns. The |\calxeval| columns show the ratios of \calxname timings with those of |\fpeval|. Thus, a value below one indicates that \calxname is faster, and a value above one that it is slower. All measurements include expansion of the expression and assignment of its result to a macro via |\edef|. In particular they include the overhead of the respective parsers gathering the input and printing the output. \IfFileExists{\jobname-benchmark.tex} {\input{\jobname-benchmark.tex}} {\typeout{******** No benchmark file, doing it myself ********}% \DOTIMINGS \CalxBenchmarkSaveResults} \CalxBenchmarkPrepareTable \begin{table}[htbp] \capstart \centering \setlength{\tabcolsep}{2pt}% %\begin{tabular}{|l||c|cc||cc||cc|} \begin{tabular}{|l||c|c||c||c|} \hline % Expression & |\fpeval| % & \multicolumn{2}{c||}{\texttt{\string\calxeval} (P=16)} % & \multicolumn{2}{c||}{\texttt{\string\calxeval} (P=8)} % & \multicolumn{2}{c|}{\texttt{\string\calxeval} (P=32)} & \texttt{\string\calxeval} (P=16) & \texttt{\string\calxeval} (P=8) & \texttt{\string\calxeval} (P=32) \\ & \begin{tabular}{c}sin(1)\\[-.5\jot]units\end{tabular} %& \begin{tabular}{c}sin(1)\\[-.5\jot]units\end{tabular} & \begin{tabular}{c}timing ratio to\\[-.5\jot]\texttt{\string\fpeval}\end{tabular} %& \begin{tabular}{c}sin(1)\\[-.5\jot]units\end{tabular} & \begin{tabular}{c}timing ratio to\\[-.5\jot]\texttt{\string\fpeval}\end{tabular} %& \begin{tabular}{c}sin(1)\\[-.5\jot]units\end{tabular} & \begin{tabular}{c}timing ratio to\\[-.5\jot]\texttt{\string\fpeval}\end{tabular} \\ \hline \CalxBenchmarkLabel{\CalxBenchmarkExprSin} & \CalxBenchmarkCell{sin}{fp} %& \CalxBenchmarkCell{sin}{p16units} & \CalxBenchmarkCell{sin}{p16} %& \CalxBenchmarkCell{sin}{p8units} & \CalxBenchmarkCell{sin}{p8} %& \CalxBenchmarkCell{sin}{p32units} & \CalxBenchmarkCell{sin}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprCos} & \CalxBenchmarkCell{cos}{fp} %& \CalxBenchmarkCell{cos}{p16units} & \CalxBenchmarkCell{cos}{p16} %& \CalxBenchmarkCell{cos}{p8units} & \CalxBenchmarkCell{cos}{p8} %& \CalxBenchmarkCell{cos}{p32units} & \CalxBenchmarkCell{cos}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprTan} & \CalxBenchmarkCell{tan}{fp} %& \CalxBenchmarkCell{tan}{p16units} & \CalxBenchmarkCell{tan}{p16} %& \CalxBenchmarkCell{tan}{p8units} & \CalxBenchmarkCell{tan}{p8} %& \CalxBenchmarkCell{tan}{p32units} & \CalxBenchmarkCell{tan}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprAsin} & \CalxBenchmarkCell{asin}{fp} %& \CalxBenchmarkCell{asin}{p16units} & \CalxBenchmarkCell{asin}{p16} %& \CalxBenchmarkCell{asin}{p8units} & \CalxBenchmarkCell{asin}{p8} %& \CalxBenchmarkCell{asin}{p32units} & \CalxBenchmarkCell{asin}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprAcos} & \CalxBenchmarkCell{acos}{fp} %& \CalxBenchmarkCell{acos}{p16units} & \CalxBenchmarkCell{acos}{p16} %& \CalxBenchmarkCell{acos}{p8units} & \CalxBenchmarkCell{acos}{p8} %& \CalxBenchmarkCell{acos}{p32units} & \CalxBenchmarkCell{acos}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprAtan} & \CalxBenchmarkCell{atan}{fp} %& \CalxBenchmarkCell{atan}{p16units} & \CalxBenchmarkCell{atan}{p16} %& \CalxBenchmarkCell{atan}{p8units} & \CalxBenchmarkCell{atan}{p8} %& \CalxBenchmarkCell{atan}{p32units} & \CalxBenchmarkCell{atan}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprLog} & \CalxBenchmarkCell{log}{fp} %& \CalxBenchmarkCell{log}{p16units} & \CalxBenchmarkCell{log}{p16} %& \CalxBenchmarkCell{log}{p8units} & \CalxBenchmarkCell{log}{p8} %& \CalxBenchmarkCell{log}{p32units} & \CalxBenchmarkCell{log}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprExp} & \CalxBenchmarkCell{exp}{fp} %& \CalxBenchmarkCell{exp}{p16units} & \CalxBenchmarkCell{exp}{p16} %& \CalxBenchmarkCell{exp}{p8units} & \CalxBenchmarkCell{exp}{p8} %& \CalxBenchmarkCell{exp}{p32units} & \CalxBenchmarkCell{exp}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprPowI} & \CalxBenchmarkCell{powi}{fp} %& \CalxBenchmarkCell{powi}{p16units} & \CalxBenchmarkCell{powi}{p16} %& \CalxBenchmarkCell{powi}{p8units} & \CalxBenchmarkCell{powi}{p8} %& \CalxBenchmarkCell{powi}{p32units} & \CalxBenchmarkCell{powi}{p32} \\ \CalxBenchmarkLabel{\CalxBenchmarkExprPowG} & \CalxBenchmarkCell{powg}{fp} %& \CalxBenchmarkCell{powg}{p16units} & \CalxBenchmarkCell{powg}{p16} %& \CalxBenchmarkCell{powg}{p8units} & \CalxBenchmarkCell{powg}{p8} %& \CalxBenchmarkCell{powg}{p32units} & \CalxBenchmarkCell{powg}{p32} \\ \hline \end{tabular} \caption{Timings}\label{tab:timings} \end{table} The given values are indicative, variations of a few percent are typically observed whenever launching again the tests. The \dtt{$P=8$} precision is often enough for plots, perhaps a future release will include some interface to use the \calxname floating point engine in TikZ/pgf or PSTricks, but for now there is only \csbxint{thecoords} and \csbxint{thespaceseparated} (check the legacy xint user manual). \emph{The gap for \texttt{atan()} between P=8 and P=16 may be a sign of some serious sub-optimatlity in the current implementation. This may be addressed, if ever, at a next release.} \subsection{User interface} The user interface is reduced to: \begin{itemize} \item |\calxeval| or its legacy alias \csbxint{floateval}: a parser of floating point expressions at a given arbitrary precision P which can be any integer from 1 to 100 and is set by \csbxint{SetDigits}. For details of the available syntax elements see the legacy \xintexprname manual. Trigonometry and logarithm/exponential/powers are all available (the legacy maximal precision was 62). \item |\calxinteval| or its legacy alias \csbxint{iieval}: handles arbitrarily large integers. Refer to the legacy \xintexprname manual. \item The interface to set the floating point precision via \csbxint{SetDigits}\marg{P} or equivalently \csbxint{Digits}|=|\meta{P}|\relax|. Their starred variants are now aliases to the non-starred ones. Modifying the precision does not trigger a reload of the scientific libraries: they adjust automatically with no reloading needed. The only overhead is the re-assignment of the trigonometrical constants documented in the legacy manual, such as \texttt{Pi}. The legacy scientific libraries |xintlog.sty| and |xinttrig.sty| are gone, replaced by the \calxname ones. \item The legacy \xintexprname interface to define functions and variables: \csbxint{NewFunction}, \csbxint{deffloatfunc}, \csbxint{deffloatvar}, \csbxint{defiifunc}, \csbxint{defiivar}. \item Things such as \csbxint{globaldefstrue}, \csbxint{verbosetrue}, \csbxint{thecoords}, and a few others. \item |\calxsetup| which is described in the next section devoted to the handling of condition signals. \end{itemize} The packages \xintkernelname, \xintbinhexname, and \xinttoolsname are loaded automatically. Loading \xintexprname does not modify anything to \calxname interface and functionalities. It adds to it the \csbxint{eval} parser (together with \csbxint{deffunc}, \csbxint{defvar}) and loads all of \xintcorename, \xintname, and \xintfracname. The macro interface of the latter is unchanged but arithmetic internals are remapped to the \calxname substratum. Some undocumented at user level macros of \xintfracname having to do with floating point numbers are gone. The \texttt{2.0a1} release has a few breaking changes (behavior and availability of \func{qfloat} and \func{qfrac} come to mind) which may not have been documented in time. The code comments are very likely either outdated or barely legible. \subsection{Arithmetic signals, exceptional results and error handling} \label{sec:calx-signals} \etocsetnexttocdepth{subsubsection} \localtableofcontents \textbf{Summary:} \emph{an arithmetic condition is not necessarily a \TeX\ error. In fact, by default \calxname~\texttt{2.0a1} in case of division by zero returns a non-finite result (\textbf{NaN}, \textbf{+Infinity}, or \textbf{-Infinity}) while the compilation continues: \emph{more generally, all arithmetic traps are disabled initially}.} A \emph{trap} raises an error message and causes \TeX{} to consider that a build error has arisen; applications which prefer active traps may enable them individually one-by-one or globally. The codebase was already done by Professor Burnol in 2017 but was left then in a state where all error conditions are trapped, i.e.\@ do trigger \TeX{} errors. \begin{framed} The whole signal-handler system, described next, is available only for arithmetic with |\calxeval| (aka \csbxint{floateval}, i.e.\@ floating point calculations) and |\calxinteval| (aka \csbxint{iieval}, i.e.\@ big integers calculations). The legacy evaluator \csbxint{eval} (which handles fractions but also authorizes the mathematical functions) does not support the special values \texttt{NaN}, \texttt{+Infinity} and \texttt{-Infinity} as arithmetic operands. Note that the fact that \csbxint{eval} authorizes mathematical functions such as \func{sin} and \func{exp} should not be abused: any multiplication of two such creates mantissas twice as big, obviously. \end{framed} \subsubsection{Default: division by zero without a \TeX\ error} The following code does not interrupt the compilation: \begin{everbatim*} \calxresetflags \edef\result{\calxeval{1/0}} % \result expands to +Infinity \calxifflagraised{DivisionByZero} {Division by zero occurred.} {No division by zero occurred.} The result is \result. \end{everbatim*} Similarly |\calxeval{-1/0}| produces \dtt{\calxeval{-1/0}}. The calculation raises the \texttt{DivisionByZero} flag and returns \texttt{+Infinity}. Since \calxname has no signed zero, division of a nonzero numerator by zero uses the numerator's sign to determine the infinity. For |\calxeval{0/0}|, the result is instead \texttt{NaN}; this is the \texttt{DivisionUndefined} condition, which raises the \texttt{InvalidOperation} flag rather than \texttt{DivisionByZero}. A flag is raised when the expression is actually expanded, as in the |\edef| above. Merely storing an unevaluated expression via |\def| or, in \LaTeX, |\newcommand|, does not raise a flag. To make division by zero a \TeX\ error, enable its trap: \begin{everbatim} \calxsetup{DivisionByZero.trap=true} \end{everbatim} A trapped condition emits an expandable \TeX\ error and returns the operation's trap value. To restore the default behavior, use: \begin{everbatim} \calxsetup{DivisionByZero.trap=false} \end{everbatim} \subsubsection{Exceptional values and their printed forms} The expression parsers |\calxeval| and |\calxinteval| recognize \texttt{NaN} and \texttt{Infinity} as reserved constants. A negative infinity can be written \texttt{-Infinity}. Thus, the following expressions all yield a non-finite result, without necessarily raising a new signal: \begin{everbatim*} \calxeval{NaN, Infinity, -Infinity} \end{everbatim*} In particular, using a special constant is not the same as signalling an arithmetic condition. An application which prefers \texttt{NaN} for division by zero such as \texttt{1/0} can replace the default handler. The handler receives the numerator's sign as its argument; it may ignore it and emi the internal marker for \texttt{NaN}, which is \texttt{I?}. \begin{everbatim} \def\calxDivisionByZeroAsNaN#1{I?} \calxsetup{DivisionByZero.handler=\calxDivisionByZeroAsNaN} \edef\result{\calxeval{1/0}} % \result expands to NaN (which is the printed form of I?) \end{everbatim} Overflow independently retains its default results, \texttt{+Infinity} and \texttt{-Infinity}. \emph{Note that the internal markers for the non-finite values differ from the user interface ones \texttt{NaN}, \texttt{+Infinity} and \texttt{-Infinity}: they are respecitevly \texttt{I?}, \texttt{I+}, \texttt{I-}. These internal notations are \emph{only} to be used in defining handlers as above.} \subsubsection{Testing an expression for a non-finite result} The expandable predicate \csbxint{ifNonFinitefloatexpr} takes a floating-point expression followed by two branches: \begin{everbatim} \xintifNonFinitefloatexpr{}{}{} \end{everbatim} It evaluates the expression once and selects the first branch when its \emph{internal result} is \texttt{I?}, \texttt{I+} or \texttt{I-}. The second branch is selected for a finite result. For example: \begin{everbatim*} \xintifNonFinitefloatexpr{1/0}{YES}{NO}% YES \xintifNonFinitefloatexpr{NaN}{YES}{NO}% YES \xintifNonFinitefloatexpr{Infinity}{YES}{NO}% YES \xintifNonFinitefloatexpr{sin(1)}{YES}{NO}% NO \end{everbatim*} This predicate examines the computed value, not the signal flags or its printed spelling. Evaluating an expression inside this test can itself raise signal flags. \subsubsection{Testing signals after a calculation} If the calculation has already been performed, use the expandable predicate shown below to check the flags for invalid operations, division by zero and overflow: \begin{everbatim} \xintifNonFiniteSignalled{}{} \end{everbatim} For example: \begin{everbatim*} \calxresetflags \edef\result{\calxeval{1/0}} \xintifNonFiniteSignalled {A non-finite condition was signalled} {No non-finite condition was signalled} \end{everbatim*} This test does not re-evaluate an expression and does not inspect |\result|. A handler may return a finite value while leaving a signal flag raised; conversely, a literal \texttt{NaN} or \texttt{Infinity} need not raise a flag. Flags persist until cleared within their scope (e.g.\@ \LaTeX{} environments), so use |\calxresetflags| before a calculation when only its newly raised conditions are of interest. \subsubsection{Signals, flags, traps and handlers} There are eight signals: \begin{everbatim} Clamped DivisionByZero Inexact InvalidOperation Overflow Rounded Subnormal Underflow \end{everbatim} Each has a flag and an independently configurable trap. No arithmetic trap is enabled by default. Five additional conditions use the \texttt{InvalidOperation} flag and trap: \begin{everbatim} ConversionSyntax DivisionImpossible DivisionUndefined InvalidContext ControversialOperation \end{everbatim} They each have individually configurable handlers. Flags are inspected and cleared with the following commands: \begin{everbatim} \calxifflagraised{InvalidOperation}{}{} \calxresetflag{InvalidOperation} \calxresetflags \end{everbatim} The flag test is expandable; the reset commands are assignments and are not expandable. Flags are local to \TeX\ groups. Examine flags raised inside a group before leaving it. Reset commands obey the prevailing \csbxint{globaldefs} setting, as do assignments by |\calxsetup|. The default handlers for \texttt{InvalidOperation} and its subordinate conditions return internal \texttt{I?}; the \texttt{DivisionByZero} and \texttt{Overflow} handlers return \texttt{I+} or \texttt{I-}, according to the sign. The default handlers for \texttt{Clamped}, \texttt{Inexact}, \texttt{Rounded}, \texttt{Subnormal} and \texttt{Underflow} leave the computed result unchanged. Traps and handlers are configured with |\calxsetup|: \begin{everbatim} \calxsetup{InvalidOperation.trap=true} \calxsetup{Overflow.trap=false} \calxsetup{ControversialOperation.handler=\myHandler} \end{everbatim} The value of a \texttt{.handler} key is a single control sequence denoting an expandable one-argument handler. An unknown setup key or invalid trap value is a configuration error and is reported by \TeX, regardless of the arithmetic-trap settings. \section {Introduction to the rest of this manual (which is the legacy 1.4 documentation)} \localtableofcontents \subsection{This documentation} Whenever you see \textcolor{macrocodelinktosectioncolor}{\textbf{\textit{code}}} above some control sequence \textbf{\string\foo}, it is an hyperlink to its coding in the second part of this document. You should find there, near your landing point, the control sequence \textcolor{macrocodelinktouserdoccolor}{\textbf{\string\foo}} in orange: this is a hyperlink to go back to its documentation in the user manual part. Within the source code, other colored control sequences should link back to the location of first definition. And throughout the user manual part, blue color such as \csbxint{eval} signals an hyperlink to the documentation of the macro. You can try it now. \subsection{Compatible engines and formats} The components of the \xintbundlename can be used indifferently with Plain \TeX{} (and other formats, as mentioned next) or with \LaTeX{}. The sole difference being that with the latter the loading must be done by \cs{usepackage} whereas with any non-\LaTeX{} format it has to be via \cs{input} (using |.sty| filename extension, not |.tex|). The engine can be PDF\TeX, Xe\TeX, or Lua\TeX. With release |1.4n| you can also use the packages with Con\TeX t (only latest one, with LuaMeta\TeX{} engine), and Op\TeX. You can't use the \xintbundlename with Knuth's original |tex| binary, because its functionalities require \cs{numexpr} and other e-\TeX{} extensions as well as the more recent \cs{expanded} engine primitive (and \cs{pdfstrcomp} or \cs{strcmp}). \xintexprname will be probably the main entry point, and it actually automatically loads most other components. The aim of \xintexprname is to provide expandable parsers of numerical expressions, either floating point numbers or fractions. \subsection{Usage} Here is an example: \begin{everbatim*} \xintfloateval{cos(3Pi/17)*sin(1)^0.123 + log(3.42e5)} \end{everbatim*} You can get the result with more digits: \begingroup \begin{everbatim*} \xintSetDigits*{32} \xintfloateval{cos(3Pi/17)*sin(1)^0.123 + log(3.42e5)} \end{everbatim*} \endgroup \noindent And with still more digits (the |[-2]| rounds away the two least significant ones): \begingroup \begin{everbatim*} \xintSetDigits*{62} \xintfloateval[-2]{cos(3Pi/17)*sin(1)^0.123 + log(3.42e5)} \end{everbatim*} \endgroup Here is now an example with fractions: \begin{everbatim*} \xinteval{reduce(add(1/i^3, i=1..25))} \end{everbatim*} And two examples with large integers: \begin{everbatim*} $2^{1000}=\printnumber{\xinteval{2^1000}}$.\newline $100!^3=\printnumber{\xintiieval{100!^3}}$. \end{everbatim*} The \hyperref[ssec:printnumber]{\string\printnumber} utility to wrap very long output is not part of the package. It is documented in \autoref{ssec:printnumber} next. The table of \hyperref[tab:functions]{built-in functions} and the one of \hyperref[tab:precedences]{built-in operators} will give a quick overview of the available syntax. \subsection{\ctanpackage{xintsession}} The simplest way\footnote{I am assuming here in the displayed example a Unixen system, i.e. Mac OS or Linux, adapt to your environment.} to test the syntax is to work interactively on the command line (this feature is available since April 2021, the version of \ctanpackage{xintsession} used here is |1.3a|). Beware though that ill-formed inputs will trigger \TeX{} famously antiquated error handling, from which it is hard to recover, altough hitting |S| may sometimes miraculously bring you back to the \ctanpackage{xintsession} prompt. \begin{everbatim} rlwrap etex xintsession [...welcome banner...] Magic words: `&pause' (or `;'), `&help', `&bye', `&exact', `&fp', `&int', `&pol'. \jobname is xintsession Transcript will go to log and to xintsession-210609_12h00.tex Starting in exact mode (floating point evaluations use 16 digits) >>> 2^100; @_1 1267650600228229401496703205376 >>> cos(1); @_2 0.5403023058681397 >>> &fp=32 (/usr/local/texlive/2021/texmf-dist/tex/generic/xint/xintlog.sty) (/usr/local/texlive/2021/texmf-dist/tex/generic/xint/xinttrig.sty) fp mode (log and trig reloaded at Digits=32) >>> cos(1); @_3 0.54030230586813971740093660744298 >>> 3^1000; @_4 1.3220708194808066368904552597521e477 >>> &exact exact mode (floating point evaluations use 32 digits) >>> 3^1000; @_5 13220708194808066368904552597521443659654220327521481676649203682268285 9734670489954077831385060806196390977769687258235595095458210061891186534272525 7953674027620225198320803878014774228964841274390400117588618041128947815623094 4380615661730540866744905061781254803444055470543970388958174653682549161362208 3026856377858229022841639830788789691855640408489893760937324217184635993869551 6765018940588109060426089671438864102814350385648747165832010614366132173102768 902855220001 >>> &bye Did I say something wrong? Session transcript written on xintsession-210609_12h00.tex ) No pages of output. Transcript written on xintsession.log. \end{everbatim} \subsection{\ctanpackage{zeckendorf}} This package enriches the \csbxint{eval} interface with tools related to Fibonacci numbers and Bergman $\phi$-representation. In particular, it implements the Knuth Fibonacci multiplication. It can be used either as a \LaTeX{} package, or with Plain \eTeX{}, or also on the command line via \verb+rlwrap etex zeckendorf+. \subsection{\ctanpackage{polexpr}} The package \ctanpackage{polexpr} enriches the \csbxint{eval} syntax (but not the one of \csbxint{floateval}) with a polynomial type with associated constructor |pol([c0,c1,...])|, and polynomial specific functions such as |polgcd(pol1, pol2, ...)|. Full usage of polynomials (and algebraic notations |c_0 + c_1 x + c_2 x^2 + ...| for input and also output) goes through a dedicated |\poldef| parser which is based upon \csbxint{defvar}/\csbxint{deffunc} and is a necessary step to then access via a dedicated macro interface operations such as identifying all rational roots and isolating all real roots to arbitrary precision. The simplest manner to experiment with \ctanpackage{polexpr} is via the |&pol| mode of \ctanpackage{xintsession}. \subsection{\ctanpackage{bnumexpr}} This \LaTeX{} package loads \xintcorename and \xintbinhexname and provides \cs{bnumeval} which is a scaled-down \csbxint{iieval} (omitting support for nested structures, functions, variables, boolean branching, etc...). It can be used with Plain e\TeX, thanks to \ctanpackage{miniltx}. For this, use |\input miniltx.tex| followed by |\input bnumexpr.sty| (remark: \ctanpackage{miniltx} is not needed for \xintexprname). \cs{bnumeval} is thus a boosted \cs{inteval} which addition of support for arbitrarily large integers, powers with |**| and |^|, rounded division with |/|, floored division with |//| and associated modulo |/:|, factorials via |!| postfix operator, comma separated multi-item expressions. It also supports as \csbxint{iieval} does the |'|, |"|, |0b|, |0o| and |0x| input prefixes and the optional arguments |[b]|, |[o]|, or |[h]|. Further, it provides an interface (which does not exist with \xintexprname) to let all operations be done by macros of one's own choosing, as replacement for some or all of the operations by default implemented via the help of \xintcorename and \xintbinhexname. It even makes it possible to add to the syntax extra infix or postfix operators and to modify the precedence levels of those already defined. \subsection{Printing big numbers on the page}\label{ssec:printnumber} When producing very long numbers there is the question of printing them on the page, without going beyond the page limits. In this document, I have most of the time made use of a ``|\printnumber|'' macro, which is not provided by the package. A primitive form would be: \everb|@ \def\allowsplits #1{\ifx #1\relax \else #1\hskip 0pt plus 1pt\relax \allowbreak \expandafter\allowsplits\fi}% \def\printnumber #1{\expandafter\allowsplits \romannumeral-`0#1\relax }% | This macro triggers ``\fexpan sion'' of its argument (and indeed \csbxint{eval} and friends expand completely under such trigger), then it goes through the computation result character by character inserting some stretchable glue in-between them. The |\allowbreak|'s (which is known both to Plain \TeX{} and to \LaTeX{} and perhaps other formats, else use |\penalty0\relax|) are here only for the case of usage in inline math mode (they are ineffective in display math mode). The actual |\printnumber| used for building this documentation is a more sophisticated variant (never used in math mode), which handles comma separated lists without gobbling spaces and prints continuation symbols at line endings. \subsection{Repository} It is at \url{https://github.com/jfbu/xint}. At this stage, it does not serve for real-time development but only proposes all actual successive \href{https://ctan.org}{CTAN} releases since 2013. Use it to report issues. Don't forget to include |@jfbu| in the ticket else I will not be pinged. A front page at \url{https://jfbu.github.io/xint} provides, in addition to the present |xint.pdf| and to |README.md| a file |CHANGES.html|, which contains the complete list of changes relevant to user level since the initial release of the package: % \centeredline{\url{https://jfbu.github.io/xint/CHANGES.html}} Its version |xintchanges.md| in Markdown format is included in the \href{https://ctan.org/pkg/xint}{CTAN} upload, % \centeredline{|texdoc xintchanges.md|} Warning: I don't have the time to maintain perfectly such large documentation. It combines old documentation which never really got updated and may be locally obsolete with more recent stuff mostly written on occasion of the |1.4| release of January 2020 and the |1.4e| one of May 2021, and the intervening changes might also have made some of it not completely accurate, despite my best efforts. \subsection{License and installation instructions} \label{ssec:install} The \xintbundlename components are made available under the \href{http://www.latex-project.org/lppl/lppl-1-3c.txt}{LaTeX Project Public License 1.3c}. They are available at \href{https://ctan.org/pkg/xint}{CTAN}. They are included in all major \TeX\ distributions, thus there is probably no need for a custom install: just use the package manager to update from time to time to latest version. \clearpage \expandafter\let\csname Start herenameUp\endcsname\undefined \csname xintexprnameUp\endcsname \section{Syntax reference and user guide} \RaisedLabel{sec:expr} \localtableofcontents \subsection{Introduction: the three-parsers way} \begin{framed} \textbf{WARNING:} this documentation goes sometimes into too much details, and does need some improvements. But there is no time for that at |1.4n|. Although people do not believe me when I say that, there is ample intellectual reward in actually reading the documentation, and it would be nice if at least, at last someone on Earth did, once (as \textsc{Jürgen Gilg} some years back). \end{framed} \xintexprname provides three numerical expression parsers corresponding to these three respective tasks: \begin{description}[noitemsep] \item[\csa{xintfloateval}:] evaluations with floating point numbers; the default precision is with 16 digits, it can be set via \csbxint{SetDigits*}, \item[\csa{xinteval}:] exact evaluations with fractions, decimal fixed point numbers, numbers in scientific notation, with no size limitation, \item[\csa{xintiieval}:] evaluations allowing only integers with no size limitation. \end{description} % They are designed to be compatible with expansion only context. All % computations ultimately rely on (and reduce to) usage of the |\numexpr| % primitive from \eTeX{}% % % % \footnote{It can handle only integers, and they must be at most % $2^{31}-1={}$\dtt{\the\numexpr"7FFFFFFF\relax}. Thus some work has to be done % to handle arbitrarily big integers or arbitrary float precision.}. % % % These \eTeX{} extensions date % back to 1999 and are by default incorporated into the |pdftex| % etc...\@{} executables from major modern \TeX{} installations for more than % fifteen years now. The interface is: \begin{itemize} \item \csbxint{floateval}\oarg{Q}\marg{expression} does floating point computations with a given precision, which defaults to |16|. The precision |P| can be set using \csbxint{Digits*}|:=P\relax| or \csbxint{SetDigits*}|{P}| syntaxes. Its optional argument |[Q]|, if present, means to do a \emph{final} float rounding to a mantissa of |Q| digits (this thus makes sense only if |Q0|: the nearest fixed point number with |D| digits after the decimal mark, \item if |D=0|: the nearest integer (as for \csbxint{ieval} with no optional argument), \item if |D<0|: the rounded quotient by |10^(-D)|. \end{itemize} The optional argument \oarg{D} can also be located \emph{within} the braces at the start of the expression (this was actually the legacy syntax until |1.4k|). \item \csbxint{iieval}\marg{expression} executes computations \emph{on (big) integers only.} It is (only slightly) faster than \csbxint{eval} for the same expression. Attention: the forward slash \oper{/} does the \emph{rounded} integer division to match behaviour of |\numexpr|. The \oper{//} operator does floored division as in \csbxint{eval}. The \oper{/:} is the associated modulo operator (we could easily let the catcode 12 |%| character be an alias, but using such an unusual percent character would be a bit cumbersome in a \TeX{} workflow, if only for matters of syntax highlighting in \TeX-aware text editors). \begin{everbatim*} % add the i^5 only if i is a multiple of 7 \xintiieval{add((i/:7)?{omit}{i^5}, i=1000..1020)} \end{everbatim*} An\NewWith{1.4n} optional argument |[h]|, |[o]|, or |[b]| says to convert the output to hexadecimal, octal or binary: \begin{everbatim*} \xintiieval[h]{3^100} \end{everbatim*} \end{itemize} % The user can define variables and functions. Definition of functions is either % per parser (\csbxint{deffunc}, \csbxint{deffloatfunc}, ...), but there are % some restrictions, or generic (\csbxint{NewFunction}) but the latter is only % syntactic sugar for function-like disguise of a \TeX{} macro having not done % any pre-parsing. \begin{framed} Please note: \begin{itemize}[noitemsep] \item If you find that \csbxint{floateval} is too much of a mouthful, you can create an alias named, for example, |\fpeval|. Oops, no, that is \LaTeX3 very efficient floating point engine (for 16 decimal digits of precision). It is faster than \csbxint{floateval} due to the excellent coding and algorithms it employs, but also for reasons having to do in part with the fact that \xintname initially was created to handle big integers only, and support for arbitrary precision floating point was added on top of that, via some expedients which have never been refactored, yet. \item Although \csbxint{eval} manipulates arbitrarily long integers or fractions it also accepts scientific notation on input, as well as all the mathematical functions (evaluated using the prevailing digits precision), and (depending on customization) can thus produce also scientific notation on output. But be careful that for example a multiplication will then automatically roughly double the number of digits in general (some operations avoid extending mantissas, so short mantissas may remain short). \item So far, individual operations and the printing routine of \csbxint{eval} do not automatically reduce fractions to their lowest terms. \end{itemize} \end{framed} There is a core syntax: \begin{itemize}[nosep] \item \csbxint{expr}\meta{expression}|\relax|, \item \csbxint{iexpr}\meta{expression}|\relax|, \item \csbxint{iiexpr}\meta{expression}|\relax|, \item \csbxint{floatexpr}\meta{expression}|\relax|, \item \csbxint{boolexpr}\meta{expression}|\relax|. \end{itemize} \csbxint{boolexpr}\meta{expression}|\relax| does all computations like \csbxint{expr} then converts all (non-empty) leaves% % \footnote{Currently, empty leaves are output using \csbxint{exprEmptyItem}, i.e.\@{} default to \dtt{\xintexprEmptyItem}. This may change.} % to |true| or |false| (cf.\@{} \csbxint{boolexprPrintOne}). There is no |\xintbooleval|.\CHANGED{1.4m}\footnote{This was |True| and |False| prior to |1.4m|.} Formerly the \csbxint{expr}|...\relax| legacy syntax had to be prefixed by |\xintthe| if in typesetting context, else an error was raised (deliberately). The |\xintthe| prefix was made optional at |1.4|. In an |\edef| these constructs expand to some braced nested data, all computations having been completely done, which is prefixed with some |\protected| \myenquote{typesetter} macros. In an |\edef|, \csbxint{eval} (in contrast to \csbxint{expr}), or \csbxint{floateval} (in contrast to \csbxint{floatexpr}) expand the \myenquote{typesetting macros} and the final complete expansion consists of explicit digits and other characters such as those of scientific notation or square brackets.% % \footnote{\csbxint{eval} and \csbxint{expr} both expand completely in exactly two steps. And \csbxint{expr} expands fully under \fexpan sion (of the |\romannumeral0| or |-`0| type). As per \csbxint{eval} attention that it may expand to nothing, then naturally \fexpan sion propagates to tokens following up in the input stream.} In \LaTeX\ it is possible to use the core syntax \csbxint{expr}\meta{expression}|\relax| also in so-called moving arguments, because when written out to a file the final expansion outcome uses only standard catcodes and thus will get retokenized and expand as expected if it has been written to an external file which is then reloaded. One needs \csbxint{eval} et al.\@{} only if one really wants the final digits (and other characters), for example in a context where \TeX{} expects a number or a dimension. As alternative to \csbxint{eval}\marg{expression}, an equivalent is \csbxint{the}\csbxint{expr}\meta{expression}|\relax|. Similarly \csbxint{the} can prefix all other core parsers. And one can also use \csbxint{theexpr} as shortcut for \csbxint{the}\csbxint{expr}. Doing exact computations with fractions leads very quickly to very big results (and furthermore one needs to use explicitly the |reduce()| function to convert the fractions into smallest terms). Thus most probably what you want is \csbxint{floateval} and \csbxint{floatexpr}. \subsection{Output customization} \subsubsection{\csh{xintfloatexprPrintOne} et al{.} for numerical values} \label{xintexprEmptyItem} \label{xintexprPrintOne} \label{xintiiexprPrintOne} \label{xintiiexprPrintOneHex} \label{xintiiexprPrintOneOct} \label{xintiiexprPrintOneBin} \label{xintiexprPrintOne} \label{xintfloatexprPrintOne} \label{xintboolexprPrintOne} The package provides only minimal facilities for formatting the output from \csbxint{eval} or \csbxint{floateval} or\dots. And this output may well consist of comma separated values, even nested ones with, by default, square brackets. First we explain how to influence the handling of individual \myenquote{leaves}. Here are the default definitions to this effect: \begin{everbatim} \def\xintexprEmptyItem{[]} % (all parsers) \def\xintexprPrintOne #1{\xintFracToSci{#1}} % \xinteval \def\xintiexprPrintOne #1{\xintDecToString{#1}} % \xintieval \def\xintiiexprPrintOne#1{#1} % \xintiieval \def\xintfloatexprPrintOne [#1]#2{\xintPFloat[#1]{#2}} % \xintfloateval \def\xintboolexprPrintOne#1{\xintiiifNotZero{#1}{true}{false}} \end{everbatim} They can be re-defined to one's wishes. If configured to do anything non expandable they must be |\protected|. \LaTeX\ users will want to use |\RenewDocumentCommand| for this. \begin{TeXnote} \begin{itemize} \item Actually, the defaults are more done in the style \begin{everbatim} \let\xintexprPrintOne\xintFracToSci \end{everbatim} thus sparing grabbing the argument |#1|. And one can do \begin{everbatim} \def\xintexprPrintOne{\xintFracToSci} \end{everbatim} too. \item |\xintexprPrintOne| defaults in truth to some private variant of \csbxint{FracToSci} with exactly the same output but able to understand only certain limited types of inputs as used internally. \item |\xintiiexprPrintOne| is used with \csbxint{iieval}. But it gets replaced with |\xintiiexprPrintOneHex|, |\xintiiexprPrintOneOct|, or |\xintiiexprPrintOneOct| if the optional argument |[h]|, |[o]|, or |[b]| is used.\NewWith{1.4n} These macros default to respectively \csbxint{DecToHex}, \csbxint{DecToOct} and \csbxint{DecToBin}. \item |\xintfloatexprPrintOne| defaults in fact to a private variant of \csbxint{PFloat} which assumes the optional argument |[P]| is present as it will be the case always in this context. This optional argument |[P]| is the optional argument |[Q]| of \csbxint{floateval} (or |Digits+Q| if |Q<0|). \item The typesetter for \csbxint{iiexpr} simply prints ``as is'', but this may change in future, if some internal format is used requiring a conversion step. \end{itemize} \end{TeXnote} Here is a possibly not up-to-date list of macros of interest, whose documentations you might consider reading (the first two require math mode): \begin{itemize}[nosep] \item \csbxint{TeXFromSci}, \item \csbxint{TeXFrac}, \item \csbxint{DecToString}, \item \csbxint{PRaw}, \item \csbxint{FracToSci}, \item \csbxint{FracToDecimal}, \item \csbxint{PFloat}, \item and \csbxint{FloatToDecimal}. \end{itemize} Naming scheme, as one can see, has been pretty much incoherent, apologies. Among packages providing macros formatting numeric values, there are \ctanpackage{numprint} and its macro |\np| (or |\numprint| without the option |np|), and \ctanpackage{siunitx} and its |\num|, and possibly more packages not known to the author.% % \footnote{There does not seems to be yet a \LaTeX\ user level interface to the \liiistrformat\ package, part of |l3experimental|, which provides an implementation of the Python |format| function.} % These macros are suitable in combination with \csbxint{Float} as in the example below to customize the \csbxint{floateval} output. % 27 mai 2022, en effet \num{1/7} ne marche pas et \numprint{1/7} non plus Numerical output from \csbxint{eval} is more challenging as individual values may naturally contain the |/| character for fractions which the above mentioned packages will not know how to handle, as far as I know. Here an example, with \LaTeX{} and |\num| from \ctanpackage{siunitx}: \begin{everbatim} \RenewDocummentCommand\xintfloatexprPrintOne{o m}{\num{\xintFloat[#1]{#2}}} \end{everbatim} We could have used here simply |\def| with delimited parameters |[#1]#2| because: \begin{itemize}[nosep] \item the optional argument will always be present at time of use, \item |\num| is a |\protected| macro. \end{itemize} Note that when using only |\def| for the definition, the argument of |\num| is getting to be expanded first, but |\num| would have done that anyhow. With \ctanpackage{numprint}, one can similarly do: \begin{everbatim} \RenewDocumentCommand\xintfloatexprPrintOne{o m}{\numprint{\xintPFloat[#1]{#2}}} \end{everbatim} This used \csbxint{PFloat} rather than \csbxint{Float} as with |\num|. This is because (in my limited testing) |\numprint| with not silently remove a zero scientific exponent but it will typeset it, for example as $1.5\cdot10^0$. So we use our own \csbxint{PFloat} poor man \myenquote{prettifier}. Maybe you want to use a macro which is unable to have |\xintPFloat[#1]{#2}| as argument because it needs to see only a number in scientific notation and nothing else. If that macro is |\protected|, do the definition with |\def|. It it is not |\protected| and not purely expandable either, one can do this: \begin{everbatim} \protected\def\myfoo{\foo}%<<<--- with options perhaps \def\xintfloatexprPrintOne[#1]#2{\myfoo{\xintPFloat[#1]{#2}}} \end{everbatim} Then when |\myfoo| finally expands, its argument has been expanded already. The current behaviour of \csbxint{floateval} corresponds to this set-up: \begin{everbatim} \def\xintfloatexprPrintOne [#1]#2{\xintPFloat[#1]{#2}} \end{everbatim} and to this default configuration of \csbxint{PFloat}: \begin{everbatim} \def\xintPFloatE{e} \def\xintPFloatZero{0} \def\xintPFloatIntSuffix{} \def\xintPFloatLengthOneSuffix{} \def\xintPFloatNoSciEmax{5} \def\xintPFloatNoSciEmin{-4} \def\xintPFloatMinTrimmed{4} \end{everbatim} With the custom replacement \begin{everbatim} \def\xintfloatexprPrintOne{\xintFloatToDecimal} \end{everbatim} the \csbxint{floateval} output will use decimal fixed point notation, i.e.\@{} no scientific exponents, and as many zeros as are needed (but no more, as trailing zeros will be removed from the significant digits). Here is an example comparing outputs from the default configuration and custom ones: \begingroup % DÉBUT DU GROUPE POUR DES EXEMPLES \begin{everbatim*} \xintfloateval{exp(-32.456)/2000} (default, i.e. PFloat)\newline \def\xintfloatexprPrintOne{\xintFloatToDecimal}% \xintfloateval{exp(-32.456)/2000} (FloatToDecimal)\newline \def\xintfloatexprPrintOne[#1]#2{\xintTeXFromSci{\xintFloat[#1]{#2}}}% $\xintfloateval{exp(-32.456)/2000}$ (TeXFromSci on Float)\par % math mode required \end{everbatim*} Some examples showing now the effect of sensible customizations on \csbxint{eval}: \begin{everbatim*} \xinteval{exp(-32.456)/2000} (default, i.e. FracToSci)\newline \def\xintexprPrintOne{\xintFracToDecimal}% \xinteval{exp(-32.456)/2000} (FracToDecimal)\newline \def\xintexprPrintOne#1{\xintTeXFromSci{\xintFracToSci{#1}}}% $\xinteval{exp(-32.456)/2000}$ (TexFromSci on FracToSci)\par % math mode required \end{everbatim*} Notice that the |/2000| denominator remains ``as is'' in the output, in conformity with the documented behaviour of \csbxint{FracToSci} in the first example and of \csbxint{FracToDecimal} for the second example. This has not changed since |1.4| (the handling of the numerator part has changed at |1.4e| and again slightly at |1.4k|, the zero value being now always printed as \dtt{0} and not \dtt{0} or \dtt{0.0} depending on the input) but is to be considered unstable and undecided so far. A slightly more costly typesetter could be for example: \begin{everbatim} \def\xintexprPrintOne#1{\xintDecToStringREZ{\xintIrr{#1}}} \end{everbatim} Then \begin{itemize}[nosep] \item the fraction (inclusive of its power of ten part) will be reduced to lowest terms (see \csbxint{Irr}), \item next the trailing zeros will be moved as an exponent (positive or negative) to the numerator, \item this numerator with a power of ten part will be printed in decimal fixed point notation, with as few zeros as are needed, \item and finally the denominator |B|, which has been trimmed of trailing zeros, will be printed as |/B| or not at all if |B=1|. \end{itemize} With the use case above: \begin{everbatim*} \def\xintexprPrintOne#1{\xintDecToStringREZ{\xintIrr{#1}}} \xinteval{exp(-32.456)/2000}\par \end{everbatim*} This trailing |/2| is somewhat of a pain, but as documented and mentioned already \csbxint{DecToStringREZ} currently has not been educated to identify its presence and handle it. Slightly faster (see \csbxint{PIrr}) is \begin{everbatim} \def\xintexprPrintOne#1{\xintDecToStringREZ{\xintPIrr{#1}}} \end{everbatim} which with the used example produces the same output. One can also consider this for math mode: \begin{everbatim*} \def\xintexprPrintOne#1{\xintTeXFromSci{\xintDecToStringREZ{\xintIrr{#1}}}} $\xinteval{exp(-32.456)/2000}$\par \end{everbatim*} See our hesitations about what \csbxint{TeXFromSci} should do with denominators. \begin{TeXnote} One can hope that in future \csbxint{DecToString} will identify denominators being products of only two's and five's, but even then of course \csbxint{TeXFromSci} will have to decide how to handle other denominators. \end{TeXnote} \endgroup % FIN DU GROUPE POUR LES EXEMPLES \begin{TeXnote} The macro used as customization of \csbxint{exprPrintOne} (whose default is a private variant of \csbxint{FracToSci} with exactly same output) must understand the internal \xintfracname format |A/B[N]|, but with the |/B| and |[N]| parts being only optional. This is not a problem when using for this task (nested) macros of \xintfracname, as they of course accept such inputs as argument and in fact much more general ones. In particular one can benefit from \csbxint{Raw}, or \csbxint{RawBraced}, to convert the argument into a well defined shape (|A/B[N]| for the former and |{N}{A}{B}| for the latter) and then work from there. The macro used by \csbxint{floatexprPrintOne} has the guarantee that the |[P]| will be always present at expansion time. The customization should be compatible with being exposed to |\expanded| (which is like expansion in an |\edef|), either from being completely expandable or at the opposite from being |\protected|. \LaTeX2e commands defined via |\newcommand| as macros with one optional parameter are not compatible with this requirement. Attention! The interface requirements described above for the macros customizing the behaviours of \csbxint{exprPrintOne} and \csbxint{floatexprPrintOne} may change at any release... as they depend on some internal structures and it is not certain backwards compatiblity will be maintained systematically in case of evolution. \end{TeXnote} \subsubsection{\csh{xintthealign} for output of general oples} \label{xintthealign} With \csbxint{thealign} one can get nested data use a \TeX{} alignment in the output. Here is an example : \begin{everbatim*} \xintthealign\xintexpr ndseq(1/(i+j), i = 1..10; j=1..10)\relax \end{everbatim*} Attention, this \csa{xintthealign} must be a prefix to \csbxint{expr}, or \csbxint{floatexpr} etc..., but there will be low-level \TeX\ errors if it is used to prefix \csbxint{eval} et al. or \csbxint{theexpr} et al. It is possible to customize the behaviour of |\xintthealign|. For example: \begin{everbatim} \protected\def\xintexpralignbegin {\halign\bgroup\tabskip2ex\hfil##&&##\hfil\cr}% \def\xintexpralignend {\crcr\egroup}% removed \protected at 1.4c \protected\def\xintexpralignlinesep {,\cr}% separates "lines" \protected\def\xintexpralignleftsep {&}% at left of first item in a "line" % (after "left bracket") \protected\def\xintexpraligninnersep {,&}% at the left of non-first items \protected\def\xintexpralignrightsep {&}% at right of last item in a "line" % (before "right bracket") \protected\def\xintexpralignleftbracket {[}% \protected\def\xintexpralignrightbracket{]}% \end{everbatim} The above definitions use |\protected| with no strong reason, as the replacement tokens are not expanding anyhow, but the idea is that this allows to execute a computation via an |\edef| and later one can change the meaning of the auxiliary macros depending on what one wants to do with the expansion result. \begin{TeXnote} \csa{xintexpralignend} is expanded once, after the body has been submitted to exhaustive expansion (|\expanded| induced), and prior to the expansion of \csa{xintexpralignbegin}. \end{TeXnote} Although we will try to keep stable the way \myenquote{regular arrays} as in the above example are rendered by default,\UNSTABLE{} the |\xintthealign| macro (and its associated customizability) is to be considered work-in-progress and may experience breaking changes. Use for example this for outputting to a file or a terminal:% % {\catcode`^ 12 \footnote{With the |xetex| engine this will need its |-8bit| option else the |^^J| in |\xintexpralignlinesep| will be printed literally instead of being converted into a line separator in the file or terminal output.}} \begin{everbatim} % Better here without \protected. % We assume here \newlinechar has the LaTeX setting. \def\xintexpralignbegin {}% \def\xintexpralignend {}% \def\xintexpralignlinesep {,^^J}% separates "lines" \def\xintexpralignleftsep { }% at left of first item in a "line" (after brackets) \def\xintexpraligninnersep {, }% at the left of non-first items \def\xintexpralignrightsep { }% at right of last item in a "line" (before brackets) \def\xintexpralignleftbracket {[}% \def\xintexpralignrightbracket{]}% \end{everbatim} In the \LaTeX{} example next using a |pmatrix| environment, |\noexpand| rather than |\protected| is used. This environment will not break across pages, contrarily to the display produced by the default \csbxint{thealign} configuration which uses \TeX{}'s |\halign|. %\kern10\baselineskip %\hbox{Big empty space here} %\kern-11\baselineskip \begin{everbatim*} \[ \def\xintexpralignbegin {\begin{pmatrix}}% \def\xintexpralignend {\end{pmatrix}}% \def\xintexpralignlinesep {\noexpand\\}% needed to counteract an internal \expanded \def\xintexpraligninnersep {&}% \let\xintexpralignleftbracket\empty \let\xintexpralignleftsep\empty \let\xintexpralignrightbracket\empty \let\xintexpralignrightsep\empty % by default amsmath matrices can have 10 columns at most % (cf amsmath documentation for what to do to allow more) l.c.m.=\xintthealign\xintiiexpr ndmap(lcm, 1..12; 1..10)\relax \] \end{everbatim*} \subsection{Built-in operators and their precedences} The parser implements precedence rules based on concepts which are summarized below (only for binary infix operators): \begin{itemize}[noitemsep] \item an infix operator has two associated precedence levels, say |L| for left and |R| for right, \item the parser proceeds from left to right, pausing each time it has found a new number and an operator following it, \item the parser compares the left-precedence |L| of the new found operator to the right-precedence |R_last| of the last delayed operation (which already has one argument and would like to know if it can use the new found one): if |L| is at most equal to it, the delayed operation is now executed, else the new-found operation is kept around to be executed first, once it will have gathered its arguments, of which only one is known at this stage. \end{itemize} This means for example in the case of the multiplication \oper{\lowast} and the division operators \oper{/}, \oper{//}, \oper{/:} that they are parsed in a left-associative way because they all share the same (left and right) precedence level. This is the case with the analogous operators from the Python language, as well. At |1.4g| the power operators were changed to act in a right associative way. Again, this matches the behaviour of e.g.\@{} Python:% \begin{everbatim*} \xinteval{2^-3^4} \end{everbatim*} \makeatletter \def\@floatboxreset{\@setminipage}% faudra contrôler celui-là \makeatother \begin{table}[p] \edef\Ampersand{\string&}% \edef\restorehtdpstrutbox {\ht\strutbox\the\ht\strutbox\dp\strutbox\the\dp\strutbox} \ht\strutbox12pt\dp\strutbox5pt \capstart \centering\begin{tabular}{|c|p{.5\textwidth}|} \hline \multicolumn{2}{|p{.6\textwidth}|}{\prec{$\infty$}: at this top level the syntax elements whose execution is done prior to operators preceding them: \begin{itemize}[nosep] \item \hyperref[ssec:builtinfunctions]{built-in} or \hyperref[ssec:userfunctions]{user-defined} functions, \item \hyperref[ssec:uservariables]{variables}, \item the \oper{\empty\lowast} unpacking operator, \item intrinsic constituents of numbers: decimal mark \oper{\strut.}, \oper{e} and \oper{E} of scientific notation, hexadecimal prefix \oper{"}. \end{itemize}\par}% \\\hline\hline Precedence&``Operators'' at this level\strut\\ \hline \prec{20}& postfix \oper{!} and branching \oper{?}, \oper{??} operators\strut\\\hline % \prec{-}& minus sign as unary operator inherits the right-\hskip0pt precedence of the infix operator it follows, if that precedence is higher than the one of binary \oper{+} and \oper{-}, else it inherits the latter\strut\\\hline % \prec{18} (17)& \oper{\string^} and \oper{\lowast\lowast} are synonymous; they act in a right-associative way (\textcolor[named]{Red}{\bfseries Changed at 1.4g!})\strut\\\hline % \prec{16} (14)& \hyperref[ssec:tacit multiplication]{Tacit multiplication} has an elevated (left) precedence\strut\\\hline % \prec{14}& \oper{\lowast}, \oper{/}, \oper{//} (floored division), and \oper{/:} (associated modulo, alias \oper{'mod'})\strut\\\hline % \prec{12}& \oper{+}, \oper{-}\strut\\\hline % \prec{10}& \oper{<}, \oper{>}, \oper{==}, \oper{<=}, \oper{>=}, \oper{!=} (they can be chained)\strut\\\hline % \prec{8}& Boolean conjunction \oper{\Ampersand\Ampersand} and its alias \oper{'and'}\strut\\\hline % \prec{6}& Boolean disjunction \oper{\string|\string|} and its alias \oper{'or'}. Also \oper{'xor'} and \oper{\strut..}, \oper{..[}, \oper{{]..}}, and \oper{:} have this precedence\strut\\\hline % \prec{4}& the brackets for slicers and extractors \oper{\empty[}, \oper{\empty]}\strut\\\hline % \prec{3}& the comma \oper{,}\strut\\\hline % \prec{2}& the bracketers \oper{[}, \oper{]} construct nestable \myenquote{arrays}\strut\\\hline % \prec{1}& the parentheses \oper{(}, \oper{)}, and the semi-colon \oper{;} in \func{iter}, \func{rseq}, and further structures\strut\\\hline % \hline % \multicolumn{2}{|p{.6\textwidth}|}{% \begin{itemize}[nosep] \item Binary operators have a left and a right precedence, which for most coincide. The right precedence is indicated within parentheses. \item \hyperref[ssec:tacit multiplication]{Tacit multiplication} has an elevated left precedence level: |(1+2)/(3+4)5| is computed as |(1+2)/((3+4)*5)| and |x/2y| is interpreted as |x/(2*y)| when using variables. \end{itemize} }\\\hline \end{tabular} \caption{Precedence levels} \label{tab:precedences} \etoctoccontentsline {xinttable}{\protect\emph{Table of precedence levels of operators}} \restorehtdpstrutbox \end{table} The entries of \autoref{tab:precedences} are hyperlinked to the more detailed discussion at each level. In these entries the number within parentheses indicates the right-\hskip0pt precedence, if it differs from the left. \begin{description} %[parsep=0pt, listparindent=\leftmarginiii] % [parsep=0pt,align=left,itemindent=0pt, % leftmargin=\leftmarginii, labelwidth=\leftmarginii, labelsep=0pt, % labelindent=0pt, listparindent=\leftmarginiii] \edef\Ampersand{\string&}% \precdesc{$\infty$} At this highest level of precedence, one finds: \begin{description} \item[{\hyperref[ssec:builtinfunctions]{functions} and \hyperref[ssec:uservariables]{variables}}] Functions (even the logic functions \func{!} and \func{?} whose names consist of a single non-letter character) must be used with parentheses. These parentheses may arise from expansion after the function name is parsed (there are exceptions which are documented at the relevant locations.) \operdesc{\empty\lowast} Python-like \myenquote{unpacking} prefix operator. Sometimes one needs to use it as function |*()| (but I can't find an example right now) but most of the time parentheses are unneeded. \operdesc{\strut.} is decimal mark; the number scanner treats it as an inherent, optional and unique component of a being formed number. |\xintexpr 0.^2+2^.0\relax| is interpreted as |0^2+2^0| and thus produces \dtt{\xintexpr 0.^2+2^.0\relax}. Since release |1.2| an isolated decimal mark is illegal input in the \xintexprname parsers (it remains legal as argument to the macros of \xintfracname). \operdesc{e} scientific notation. \operdesc{E} scientific notation. For output, see \csbxint{PFloatE}. \operdesc{"} prefix for hexadecimal input. Only uppercase letters, and one optional |.| separating integer and fractional hexadecimal parts. \begin{everbatim*} \xintexpr "FEDCBA9876543210\relax\newline \xintexpr ".FEDCBA9876543210\relax\newline \xintexpr 16^5-("F75DE.0A8B9+"8A21.F5746+16^-5)\relax \end{everbatim*} It is possible that in future the |"| prefix could be dropped in favour of |0x| prefix. This would free |"| to be used for input of \myenquote{string}-like entities. \end{description} \precdesc{20} The postfix operators |!| and the branching conditionals |?|, |??|. \begin{description} \operdesc{!} computes the factorial of an integer. \operdesc{?} is used as |(stuff)?{yes}{no}|. It evaluates |stuff| and chooses the |yes| branch if the result is non-zero, else it executes |no|. After evaluation of |stuff| it acts as a macro with two mandatory arguments within braces, chooses the correct branch \emph{without evaluating the wrong one}. Once the braces are removed, the parser scans and expands the uncovered material. % so for % example % % % \leftedline{|\xinttheiexpr (3>2)?{5+6}{7-1}2^3\relax|} % % % is legal and computes % |5+62^3=|\dtt{\xinttheiexpr(3>2)?{5+(6}{7-(1}2^3)\relax}. It would be % better practice to include here the |2^3| inside the branches. The % contents of the branches may be arbitrary as long as once glued to what is % next the syntax is respected: {|\xintexpr (3>2)?{5+(6}{7-(1}2^3)\relax| % also works.} \operdesc{??} is used as |(stuff)??{<0}{=0}{>0}|, where |stuff| is anything, its sign is evaluated and depending on the sign the correct branch is un-braced, the two others are discarded with no evaluation of their contents. % The un-braced branch will then be parsed as % usual. % % % \leftedline{|\def\x{0.33}\def\y{1/3}|} % % % \leftedline{|\xinttheexpr (\x-\y)??{sqrt}{0}{1/}(\y-\x)\relax|% % \dtt{=\def\x{0.33}\def\y{1/3}% % \xinttheexpr (\x-\y)??{sqrt}{0}{1/}(\y-\x)\relax }} % % \end{description} \precdesc{-} As unary operator, the minus sign inherits as precedence the minimum of |12| (which is the precedence for addition and subtraction) and of the (right-) precedence of the operators preceding it (if any). \begin{everbatim*} \xintexpr -3-4*-5^-7, (-3)-(4*(-(5^(-7))))\relax\newline \xintexpr -3^-4*-5-7, (-((3^(-4))*(-5)))-7\relax\newline |2^-10| gives \xintexpr 2^-10\relax\space \end{everbatim*}and is thus perfectly legal, no need for parentheses. The |+| character as prefix unary operator is simply ignored during input parsing. \precdesc{18} \begin{description} \operdesc{\string^} \operdesc{\lowast\lowast} Both compute powers. They act in a right associative way. \begin{everbatim*} \xintiiexpr 2^3^4\relax \end{everbatim*} \end{description} % et: % *2^-3^-4; % (@_1) 0.991479137495678 % *2**-3**-4; % (@_2) 0.991479137495678 % Python: % >>> 2**-3**-4; % 0.9914791374956781 \precdesc{16} see \hyperref[ssec:tacit multiplication]{Tacit multiplication}. \precdesc{14} \begin{description} \operdesc{\lowast} multiplication \operdesc{/} division: \begin{itemize} \item in \csbxint{eval}: exact division in the field of rational numbers (not automatically reduced to lowest terms), \item in \csbxint{floateval}: correct rounding of the exact division; the two operands are, if necessary, float-rounded before the fraction is evaluated and rounded (to obtain the correcty rounded |A/B| without prior rounding of |A| and |B| see \func{qfloat}), \item in \csbxint{iieval}: for compatibility with the legacy behaviour of |/| in |\numexpr|, it rounds the exact fraction \emph{with half-integers going towards the infinity of the same sign}. \end{itemize} The division is left-associative. Example: \begin{everbatim*} \xintexpr reduce(100/50/2)\relax \end{everbatim*} \operdesc{//} floored division (and thus produces an integer, see \func{divmod} for details) \operdesc{/:} the associated modulo (see \func{divmod} and \func{mod}) Left-associativity applies to the division operators: \begin{everbatim*} \xintexpr 100000/:13, 100000 'mod' 13\relax, \xintexpr 100000/:13/13\relax \end{everbatim*} Nothing special needs to be done in contexts such as \LaTeX3 |\ExplSyntaxOn| where |:| is of catcode letter, but if |:| is an active character one needs to use input such as |/\string :| (or replace it with usage of the function \func{mod}). Bulky workarounds such as |/\string :| are \fbox{\emph{unneeded}} if activation is due to Babel.\NewWith{1.4n} See also \csbxint{exprSafeCatcodes} and a framed note found in \autoref{xintexpr}. \operdesc{'mod'} is same as \oper{/:}. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'mod'| can not follow a variable name. Add parentheses around the variable, or use |/:|. \end{description} \precdesc{12} \begin{description} \operdesc{+} addition \operdesc{-} subtraction. According to the general left-associativity rule in case of equal precedence, it is left associative: \begin{everbatim*} \xintiiexpr 100-50-2\relax \end{everbatim*} \end{description} \precdesc{10} Comparison operators are (as in Python) all at the same level of precedence, use parentheses for disambiguation. \begin{description} \operdesc{<} |a} |a>b| evaluates to \dtt{1} if the strict inequality holds to \dtt{0} if not. \operdesc{==} |a==b| evaluates to \dtt{1} if equality holds to \dtt{0} if not. \operdesc{<=} |a<=b| evaluates to \dtt{1} if left hand side is at most equal to right hand side, to \dtt{0} if not. \operdesc{>=} |a>=b| evaluates to \dtt{1} if left hand side is at least equal to right hand side, to \dtt{0} if not. \operdesc{!=} |a!=b| evaluates to \dtt{1} if they differ, to \dtt{0} if not. \end{description} Comparisons can be chained arbitrarily, e.g., |x < y <= z != t| is equivalent to |x < y 'and' y <= z 'and' z != t| (and also to |all(x1}{true}{\error}, \xintifboolexpr{1<=2>=3<4>1}{\error}{false}, \xintifboolexpr{3 != 3! == 6 != 4! == 24}{true}{\error} \end{everbatim*} \precdesc{8} \begin{description} \operdesc{\Ampersand\Ampersand} logical conjunction. Evaluates to \dtt{1} if both sides are non-zero, to \dtt{0} if not. \operdesc{'and'} same as \verb+&&+. See also the \func{all} multi-arguments function. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'and'| can not follow a variable name. Add then parentheses around the variable name. \begin{snugframed} \noindent\centeredline{\xintReplicate{17}{\cautionsign[20pt]}\IMPORTANTf} The character |&| has a special meaning to \TeX{} inside alignments (this includes \LaTeX's |tabulars| and all similar environments). As soon as \TeX{} considers that the cell typesetting starts, it switches to a mode where as soon as it sees a |&|, even if it was originally nested into some macros, \TeX{} will complain if it is not a cell delimiter (possibly via some mysterious unrelated error such as \emph{Missing number, treated as zero}). This issue used to apply to \LaTeX's floating point engine as well see \url{https://github.com/latex3/latex2e/issues/1958}. \xintexprname users have a number of work-arounds: \begin{itemize}[nosep] \item Use |'and'|, \item or define some token |\edef\myAND{\string&\string&}| and use it, \item or use the \func{any} function. \end{itemize} For package authors creating macros with no control where they can end up being used, it is best to avoid |&&|. Use one of the above work-arounds. Read the above caveat about |'and'| though. For time being (March 4, 2026), upper-management has decided not to apply a similar fix as was done in the \LaTeX{} kernel (see above GitHub issue). If such a fix was applied (up to the prize of some very small overhead), upper-management would not have the pleasure to write this advisory notice and show they care. \end{snugframed} \end{description} \precdesc{6} \begin{description} \operdesc{\string|\string|} logical (inclusive) disjunction. Evaluates to \dtt{1} if one or both sides are non-zero, to \dtt{0} if not. \operdesc{'or'} same as as \verb+||+. See also the \func{any} multi-arguments function. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'or'| can not follow a variable name. Add parentheses around the variable, or use \verb=||=. \operdesc{'xor'} logical (exclusive) disjunction. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'xor'| can not follow a variable name. Add parentheses around the variable, or use the \func{xor} function syntax. \operdesc{\strut..} \operdesc{..[} \operdesc{{]..}} Syntax for arithmetic progressions. See \autoref{ssec:arithseq}. \operdesc{:} This is a separator involved in |[a:b]| Python-like slicing syntax. \end{description} \precdesc{4} \begin{description} \operdesc{\empty[} \operdesc{\empty]} Involved in Python-like slicing |[a:b]| and extracting |[N]| syntax. And its extension à la NumPy |[a:b,N,c:d,...,:]|. Ellipsis |...| is not yet implemented. The \myenquote{step} parameter as in |[a:b:step]| is not yet implemented. \end{description} \precdesc{3} \begin{description} \operdesc{,} The comma separates expressions (or function arguments).% % \footnote{The comma is really like a binary operator, which may be called ``join''. It has lowest precedence of all (apart the parentheses) because when it is encountered all postponed operations are executed in order to finalize its \emph{first} operand; only a new comma or a closing parenthesis or the end of the expression will finalize its \emph{second} operand.} % \begin{everbatim*} \xintiiexpr 2^3,3^4,5^6\relax \end{everbatim*} \end{description} \precdesc{2} \begin{description} \operdesc{[} \operdesc{]} The bracketers construct nestable \myenquote{array-like} structures. Arbitrary (heterogeneous) nesting is allowed. For output related matters see \csbxint{thealign} (its usage is optional, without it rendering is \myenquote{one-dimensional}). Output shape of non-homogeneous arrays is to be considered unstable at this time. \end{description} \precdesc{1} \begin{description} \operdesc{(} \operdesc{)} The parentheses serve as mandatory part of the syntax for functions, and to disambiguate precedences.% % \footnote{It is not apt to describle the opening parenthesis as an operator, but the closing parenthesis is analogous to a postfix unary operator. It has lowest precedence which means that when it is encountered all postponed operations are executed to finalize its operand. The start of this operand was decided by the opening parenthesis.} % They do not construct any nested structure. \operdesc{;} The semi-colon as involved as part of the syntax of \func{iter}, \func{rseq}, \func{ndseq}, \func{ndmap} has the same precedence as a closing parenthesis. \end{description} \item[|\relax|] This is the expression terminator for \csbxint{expr} et al. It may arise from expansion during the parsing itself. As alternative to \csbxint{expr} (et al.) use \csbxint{eval} (et al.) which have the usual macro interface (with one mandatory argument). \end{description} The |;| also serves as syntax terminator for \csbxint{defvar} and \csbxint{deffunc}. It can in this rôle not arise from expansion as the expression body up to it is fetched by a delimited macro. But this is done in a way which does not require any specific hiding for inner semi-colons as involved in the syntax of \func{iter}, etc... \subsection{Built-in functions}\label{ssec:builtinfunctions} See \autoref{tab:functions} whose elements are hyperlinked to the corresponding definitions. Functions are at the same top level of priority. All functions even \func{?} and \func{!} require parentheses around their arguments. % Table of functions \begin{table}[btp] \capstart \centering \xintAssignArray\xintCSVtoList{!, ?, `\lowast`, `+`, Arg, Argd, abs, acos, acosd, acosh, acoth, acsc, acsch, add, all, any, arccos, arccsc, arcsec, arcsin, arctg, argch, argcoth, argcsch, argsech, argsh, argth, asec, asech, asin, asind, asinh, atan, atan2, atan2d, atand, atanh, binomial, bool, ceil, ch, cos, cosd, cosh, cot, cotd, cotg, coth, csc, cscd, csch, divmod, even, exp, expm1, factorial, first, flat, float, float\string_dgt, floor, frac, gcd, if, ifint, ifone, ifsgn, ilog10, inv, iquo, irem, isint, isone, iter, iterr, last, lcm, len, ln, log, log10, log1p, max, min, mod, mul, ndfillraw, ndmap, ndseq, not, num, nuple, odd, pArg, pArgd, pfactorial, pow, pow10, preduce, qfloat, qfrac, qint, qrand, qraw, random, randrange, rbit, reduce, reversed, round, rrseq, rseq, sec, secd, sech, seq, sgn, sh, sin, sinc, sind, sinh, sqr, sqrt, sqrtr, subs, subsm, subsn, tan, tand, tanh, tg, th, togl, trunc, unpack, xor, zip } \to\Functions \cnta\Functions{0} \cntb\xinttheexpr ceil(\cnta/7)\relax\space \newcommand\builtinfunction[1]{\expandafter\expandafter\expandafter\func \expandafter\expandafter\expandafter{\Functions{#1}}}% \centeredline{\begin{tabular}{|*{7}{p{2cm}|}} \hline \xintFor* #1 in {\xintSeq{1}{\cntb}}\do {\builtinfunction{#1}& \builtinfunction{#1+\cntb}&% \builtinfunction{#1+2*\cntb}&% \builtinfunction{#1+3*\cntb}&% \builtinfunction{#1+4*\cntb}&% \builtinfunction{#1+5*\cntb}&% \ifnumgreater{#1+6*\cntb}{\cnta} {} {\builtinfunction{#1+6*\cntb}}% \\\hline}% \end{tabular}} \caption{Functions (click on names)}\label{tab:functions} \etoctoccontentsline {xinttable}{\protect\emph{Table of functions in expressions}} \etocsetnexttocdepth{subsubsection} \localtableofcontents \end{table} Miscellaneous notes: \begin{itemize}[nosep] \item since release |1.3d| \func{gcd} and \func{lcm} are extended to apply to fractions too, and do NOT require the loading of \xintgcdname, \item The randomness related functions \func{random}, \func{qrand} and \func{randrange} require that the \TeX\ engine provides the \csa{uniformdeviate} or \csa{pdfuniformdeviate} primitive. This primitive is abstracted into \csa{xinttexuniformdeviate}, but the functions use a wrapper \csbxint{UniformDeviate} which provides more randomness. \item \func{togl} is provided for the case |etoolbox| package is loaded, \item \func{bool}, \func{togl} use delimited macros to fetch their argument and the closing parenthesis must be explicit, it can not arise from on the spot expansion. The same holds for \func{qint}, \func{qfrac}, \func{qfloat}, \func{qraw}, \func{random} and \func{qrand}. \item Also \hyperlink{ssec:dummies}{functions with dummy variables} use delimited macros for some tasks. See the relevant explanations there. \item Functions may be called with \emph{oples} as arguments as long as the total length is the number of arguments the function expects. \end{itemize} \subsubsection{Functions with no argument} \begin{description} % [parsep=0pt,align=left, % leftmargin=0pt, itemindent=0pt, % labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, % listparindent=\leftmarginiii] \funcdesc[]{random} returns a random float |x| verifying |0 <= x < 1|. It obeys the prevailing precision as set by \csbxint{Digits}: i.e.\@{} with |P| being the precision the random float multiplied by |10^P| is an integer, uniformly distributed in the |0..10^P-1| range. This description implies that if |x| turns out to be |<0.1| then its (normalized) mantissa has |P-1| digits and a trailing zero, if |x<0.01| it has |P-2| digits and two trailing zeros, etc... This is what is observed also with Python's |random()|, of course with |10| replaced there by radix |2|.% \begin{everbatim*} \xintsetrandomseed 12345 \xintDigits:=37\relax \xintthefloatexpr random()\relax\newline \xintthefloatexpr random()\relax\par \end{everbatim*} \funcdesc[]{qrand} returns a random float |0 <= x < 1| using \dtt{16} digits of precision (i.e.\@{} |10^{16}x| is an integer). This is provided when speed is a at premium as it is optimized for precision being precisely \dtt{16}.% \begin{everbatim*} % still with 37 digits as prevailing float precision \xintthefloatexpr qrand(), random()\relax\newline \xintDigits:=16\relax \xintthefloatexpr qrand(), random()\relax\par \end{everbatim*} One can use both |qrand()| and |random()| inside the |\xintexpr| parser too. But inside the integer only |\xintiiexpr| parser they will cause some low-level error as soon as they get involved in any kind of computation as they use an internal format not recognized by the integer-only parser. See further \func{randrange}, which generates random integers. Currently there is no |uniform()| function% % \footnote{Because I am not sure how to handle rounding issues: should the computation proceed exactly and a rounding be done only at very end?} % but it can be created by user: \begin{everbatim*} \xintdeffloatfunc uniform(a, b):= a + (b-a)*random(); \romannumeral\xintreplicate{10}% {% \xintthefloatexpr uniform(123.45678, 123.45679)\relax\newline }% \end{everbatim*} \funcdesc[]{rbit} returns a random |0| or |1|. \end{description} \subsubsection{Functions with one argument} \begin{framed} The trigonometric and exponential functions are not included here. See the \calxtrigname and \calxlogname chapters. \end{framed} \begin{description} % [parsep=0pt,align=left, % leftmargin=0pt, itemindent=0pt, % labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, % listparindent=\leftmarginiii] \funcdesc{num} truncates to the nearest integer (truncation towards zero). It has the same sign as |x|, except of course with |-1\relax %\let<*xinttools>\gardesinactifs %^^A------------------------------------------------- %<*xinttools>^^A-------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xinttoolsnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xinttoolsnameimp implementation} % \RaisedLabel{sec:toolsimp} % % \localtableofcontents % % \subsection{Introduction} % % The package \xinttoolsnameimp loads only \xintkernelnameimp. % There is one feature (\csbxint{rationals} syntax with \csbxint{For}) which % requires the user to explicitly load \xintfracnameimp. % % Note that \xintexprnameimp loads automatically both o\xinttoolsnameimp and % \xintfracnameimp. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xinttools.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xinttools Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xinttools}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xinttools.sty \ifx\w\relax % but xintkernel.sty not yet loaded. \def\z{\endgroup\input xintkernel.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xintkernel.sty not yet loaded. \def\z{\endgroup\RequirePackage{xintkernel}}% \fi \else \def\z{\endgroup\endinput}% xinttools already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xinttools}% [2026/11/01 v2.0a1 Expandable and non-expandable utilities (JFB)]% % \end{macrocode} %\begin{lverb} % \XINT_toks is used in macros such as \xintFor. It is not used % elsewhere in the xint bundle. %\end{lverb} % \begin{macrocode} \newtoks\XINT_toks \xint_firstofone{\let\XINT_sptoken= } %<- space here! % \end{macrocode} % \subsection{\csh{xintgodef}, \csh{xintgoodef}, \csh{xintgfdef}} % \added{1.09i} For use in |\xintAssign|. % \begin{macrocode} \def\xintgodef {\global\xintodef }% \def\xintgoodef {\global\xintoodef }% \def\xintgfdef {\global\xintfdef }% % \end{macrocode} % \subsection{\csh{xintRevWithBraces}} % \added{1.06} Makes the expansion of its argument and then reverses % the resulting tokens or braced tokens, adding a pair of braces to each (thus, % maintaining it when it was already there.) The reason for % |\xint:|, here and in other locations, is in case |#1| expands to nothing, % the |\romannumeral-`0| must be stopped. % \begin{macrocode} \def\xintRevWithBraces {\romannumeral0\xintrevwithbraces }% \def\xintRevWithBracesNoExpand {\romannumeral0\xintrevwithbracesnoexpand }% \long\def\xintrevwithbraces #1% {% \expandafter\XINT_revwbr_loop\expandafter{\expandafter}% \romannumeral`&&@#1\xint:\xint:\xint:\xint:% \xint:\xint:\xint:\xint:\xint_bye }% \long\def\xintrevwithbracesnoexpand #1% {% \XINT_revwbr_loop {}% #1\xint:\xint:\xint:\xint:% \xint:\xint:\xint:\xint:\xint_bye }% \long\def\XINT_revwbr_loop #1#2#3#4#5#6#7#8#9% {% \xint_gob_til_xint: #9\XINT_revwbr_finish_a\xint:% \XINT_revwbr_loop {{#9}{#8}{#7}{#6}{#5}{#4}{#3}{#2}#1}% }% \long\def\XINT_revwbr_finish_a\xint:\XINT_revwbr_loop #1#2\xint_bye {% \XINT_revwbr_finish_b #2\R\R\R\R\R\R\R\Z #1% }% \def\XINT_revwbr_finish_b #1#2#3#4#5#6#7#8\Z {% \xint_gob_til_R #1\XINT_revwbr_finish_c \xint_gobble_viii #2\XINT_revwbr_finish_c \xint_gobble_vii #3\XINT_revwbr_finish_c \xint_gobble_vi #4\XINT_revwbr_finish_c \xint_gobble_v #5\XINT_revwbr_finish_c \xint_gobble_iv #6\XINT_revwbr_finish_c \xint_gobble_iii #7\XINT_revwbr_finish_c \xint_gobble_ii \R\XINT_revwbr_finish_c \xint_gobble_i\Z }% % \end{macrocode} %\begin{lverb} % 1.1c revisited this old code and improved upon the earlier endings. %\end{lverb} % \begin{macrocode} \def\XINT_revwbr_finish_c#1{% \def\XINT_revwbr_finish_c##1##2\Z{\expandafter#1##1}% }\XINT_revwbr_finish_c{ }% % \end{macrocode} % \subsection{\csh{xintZapFirstSpaces}} % \added[2013/11/01]{1.09f} % \changed[2014/10/21]{1.1} To % correct the bug in case of an empty argument, or argument containing only % spaces, which had been forgotten in first version. New version is simpler than % the initial one. This macro does NOT expand its argument. % \begin{macrocode} \def\xintZapFirstSpaces {\romannumeral0\xintzapfirstspaces }% \def\xintzapfirstspaces#1{\long \def\xintzapfirstspaces ##1{\XINT_zapbsp_a #1##1\xint:#1#1\xint:}% }\xintzapfirstspaces{ }% % \end{macrocode} %\begin{lverb} % If the original #1 started with a space, the grabbed #1 is empty. Thus % _again? will see #1=\xint_bye, and hand over control to _again which will loop % back into \XINT_zapbsp_a, with one initial space less. If the original #1 did % not start with a space, or was empty, then the #1 below will be a , % then an extract of the original #1, not empty and not starting with a space, % which contains what was up to the first present in original #1, or, % if none preexisted, and all of #1 (possibly empty) plus an ending % \xint:. The added initial space will stop later the \romannumeral0. No % brace stripping is possible. Control is handed over to \XINT_zapbsp_b which % strips out the ending \xint:\xint: %\end{lverb} % \begin{macrocode} \def\XINT_zapbsp_a#1{\long\def\XINT_zapbsp_a ##1#1#1{% \XINT_zapbsp_again?##1\xint_bye\XINT_zapbsp_b ##1#1#1}% }\XINT_zapbsp_a{ }% \long\def\XINT_zapbsp_again? #1{\xint_bye #1\XINT_zapbsp_again }% \xint_firstofone{\def\XINT_zapbsp_again\XINT_zapbsp_b} {\XINT_zapbsp_a }% \long\def\XINT_zapbsp_b #1\xint:#2\xint:{#1}% % \end{macrocode} % \subsection{\csh{xintZapLastSpaces}} % \added[2013/11/01]{1.09f} % \begin{macrocode} \def\xintZapLastSpaces {\romannumeral0\xintzaplastspaces }% \def\xintzaplastspaces#1{\long \def\xintzaplastspaces ##1{\XINT_zapesp_a {}\empty##1#1#1\xint_bye\xint:}% }\xintzaplastspaces{ }% % \end{macrocode} %\begin{lverb} % The \empty from \xintzaplastspaces is to prevent brace removal in the % #2 below. The \expandafter chain removes it. %\end{lverb} % \begin{macrocode} \xint_firstofone {\long\def\XINT_zapesp_a #1#2 } %<- second space here {\expandafter\XINT_zapesp_b\expandafter{#2}{#1}}% % \end{macrocode} %\begin{lverb} % Notice again an \empty added here. This is in preparation for possibly looping % back to \XINT_zapesp_a. If the initial #1 had no , the stuff however % will not loop, because #3 will already be \xint_bye. Notice % that this macro fetches all way to the ending \xint:. This looks not % very efficient, but how often do we have to strip ending spaces from % something which also has inner stretches of _multiple_ space tokens ?;-). %\end{lverb} % \begin{macrocode} \long\def\XINT_zapesp_b #1#2#3\xint:% {\XINT_zapesp_end? #3\XINT_zapesp_e {#2#1}\empty #3\xint:}% % \end{macrocode} %\begin{lverb} % When we have been over all possible things, we reach the % ending space tokens, and #3 will be a bunch of spaces (possibly none) % followed by \xint_bye. So the #1 in _end? will be \xint_bye. In all other cases % #1 can not be \xint_bye (assuming naturally this token does nor arise in % original input), hence control falls back to \XINT_zapesp_e which will loop back % to \XINT_zapesp_a. %\end{lverb} % \begin{macrocode} \long\def\XINT_zapesp_end? #1{\xint_bye #1\XINT_zapesp_end }% % \end{macrocode} %\begin{lverb} % We are done. The #1 here has accumulated all the previous material, % and is stripped of its ending spaces, if any. %\end{lverb} % \begin{macrocode} \long\def\XINT_zapesp_end\XINT_zapesp_e #1#2\xint:{ #1}% % \end{macrocode} %\begin{lverb} % We haven't yet reached the end, so we need to re-inject two space % tokens after what we have gotten so far. Then we loop. %\end{lverb} % \begin{macrocode} \def\XINT_zapesp_e#1{% \long\def\XINT_zapesp_e ##1{\XINT_zapesp_a {##1#1#1}}% }\XINT_zapesp_e{ }% % \end{macrocode} % \subsection{\csh{xintZapSpaces}} % \added[2013/11/01]{1.09f} % \changed[2014/10/21]{1.1} It had the % same bug as |\xintZapFirstSpaces|. We in effect do first |\xintZapFirstSpaces|, % then |\xintZapLastSpaces|. % \begin{macrocode} \def\xintZapSpaces {\romannumeral0\xintzapspaces }% \def\xintzapspaces#1{% \long\def\xintzapspaces ##1% like \xintZapFirstSpaces. {\XINT_zapsp_a #1##1\xint:#1#1\xint:}% }\xintzapspaces{ }% \def\XINT_zapsp_a#1{% \long\def\XINT_zapsp_a ##1#1#1% {\XINT_zapsp_again?##1\xint_bye\XINT_zapsp_b##1#1#1}% }\XINT_zapsp_a{ }% \long\def\XINT_zapsp_again? #1{\xint_bye #1\XINT_zapsp_again }% \xint_firstofone{\def\XINT_zapsp_again\XINT_zapsp_b} {\XINT_zapsp_a }% \xint_firstofone{\def\XINT_zapsp_b} {\XINT_zapsp_c }% \def\XINT_zapsp_c#1{% \long\def\XINT_zapsp_c ##1\xint:##2\xint:% {\XINT_zapesp_a{}\empty ##1#1#1\xint_bye\xint:}% }\XINT_zapsp_c{ }% % \end{macrocode} % \subsection{\csh{xintZapSpacesB}} % \added[2013/11/01]{1.09f} Strips up to one pair of braces (but then % does not strip spaces inside). % \begin{macrocode} \def\xintZapSpacesB {\romannumeral0\xintzapspacesb }% \long\def\xintzapspacesb #1{\XINT_zapspb_one? #1\xint:\xint:% \xint_bye\xintzapspaces {#1}}% \long\def\XINT_zapspb_one? #1#2% {\xint_gob_til_xint: #1\XINT_zapspb_onlyspaces\xint:% \xint_gob_til_xint: #2\XINT_zapspb_bracedorone\xint:% \xint_bye {#1}}% \def\XINT_zapspb_onlyspaces\xint:% \xint_gob_til_xint:\xint:\XINT_zapspb_bracedorone\xint:% \xint_bye #1\xint_bye\xintzapspaces #2{ }% \long\def\XINT_zapspb_bracedorone\xint:% \xint_bye #1\xint:\xint_bye\xintzapspaces #2{ #1}% % \end{macrocode} % \subsection{\csh{xintCSVtoList}, \csh{xintCSVtoListNonStripped}} % \added{1.06} %\begin{lverb} \xintCSVtoList transforms a,b,..,z into {a}{b}...{z}. The comma % separated list may be a macro which is first f-expanded. Here, use of \Z % (and \R) perfectly safe. %\end{lverb} % \changed[2013/11/02]{1.09f} Automatically filters items with % |\xintZapSpacesB| to strip away all spaces around commas, and spaces at the start % and end of the list. The original is kept as |\xintCSVtoListNonStripped|, and is % faster. But ... it doesn't strip spaces. % % ATTENTION: if the input is empty the output contains one item (empty, of % course). This means an |\xintFor| loop always executes at least once the % iteration, contrarily to |\xintFor*|. % \begin{macrocode} \def\xintCSVtoList {\romannumeral0\xintcsvtolist }% \long\def\xintcsvtolist #1{\expandafter\xintApply \expandafter\xintzapspacesb \expandafter{\romannumeral0\xintcsvtolistnonstripped{#1}}}% \def\xintCSVtoListNoExpand {\romannumeral0\xintcsvtolistnoexpand }% \long\def\xintcsvtolistnoexpand #1{\expandafter\xintApply \expandafter\xintzapspacesb \expandafter{\romannumeral0\xintcsvtolistnonstrippednoexpand{#1}}}% \def\xintCSVtoListNonStripped {\romannumeral0\xintcsvtolistnonstripped }% \def\xintCSVtoListNonStrippedNoExpand {\romannumeral0\xintcsvtolistnonstrippednoexpand }% \long\def\xintcsvtolistnonstripped #1% {% \expandafter\XINT_csvtol_loop_a\expandafter {\expandafter}\romannumeral`&&@#1% ,\xint_bye,\xint_bye,\xint_bye,\xint_bye ,\xint_bye,\xint_bye,\xint_bye,\xint_bye,\Z }% \long\def\xintcsvtolistnonstrippednoexpand #1% {% \XINT_csvtol_loop_a {}#1,\xint_bye,\xint_bye,\xint_bye,\xint_bye ,\xint_bye,\xint_bye,\xint_bye,\xint_bye,\Z }% \long\def\XINT_csvtol_loop_a #1#2,#3,#4,#5,#6,#7,#8,#9,% {% \xint_bye #9\XINT_csvtol_finish_a\xint_bye \XINT_csvtol_loop_b {#1}{{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}% }% \long\def\XINT_csvtol_loop_b #1#2{\XINT_csvtol_loop_a {#1#2}}% \long\def\XINT_csvtol_finish_a\xint_bye\XINT_csvtol_loop_b #1#2#3\Z {% \XINT_csvtol_finish_b #3\R,\R,\R,\R,\R,\R,\R,\Z #2{#1}% }% % \end{macrocode} %\begin{lverb} % 1.1c revisits this old code and improves upon the earlier endings. % But as the _d.. macros have already nine parameters, I needed the % \expandafter and \xint_gob_til_Z in finish_b (compare \XINT_keep_endb, or % also \XINT_RQ_end_b). %\end{lverb} % \begin{macrocode} \def\XINT_csvtol_finish_b #1,#2,#3,#4,#5,#6,#7,#8\Z {% \xint_gob_til_R #1\expandafter\XINT_csvtol_finish_dviii\xint_gob_til_Z #2\expandafter\XINT_csvtol_finish_dvii \xint_gob_til_Z #3\expandafter\XINT_csvtol_finish_dvi \xint_gob_til_Z #4\expandafter\XINT_csvtol_finish_dv \xint_gob_til_Z #5\expandafter\XINT_csvtol_finish_div \xint_gob_til_Z #6\expandafter\XINT_csvtol_finish_diii \xint_gob_til_Z #7\expandafter\XINT_csvtol_finish_dii \xint_gob_til_Z \R\XINT_csvtol_finish_di \Z }% \long\def\XINT_csvtol_finish_dviii #1#2#3#4#5#6#7#8#9{ #9}% \long\def\XINT_csvtol_finish_dvii #1#2#3#4#5#6#7#8#9{ #9{#1}}% \long\def\XINT_csvtol_finish_dvi #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}}% \long\def\XINT_csvtol_finish_dv #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}{#3}}% \long\def\XINT_csvtol_finish_div #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}{#3}{#4}}% \long\def\XINT_csvtol_finish_diii #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}{#3}{#4}{#5}}% \long\def\XINT_csvtol_finish_dii #1#2#3#4#5#6#7#8#9% { #9{#1}{#2}{#3}{#4}{#5}{#6}}% \long\def\XINT_csvtol_finish_di\Z #1#2#3#4#5#6#7#8#9% { #9{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% % \end{macrocode} % \subsection{\csh{xintListWithSep}} % \added{1.04} %\begin{lverb} % \xintListWithSep {\sep}{{a}{b}...{z}} returns a \sep b \sep ....\sep z. It % f-expands its second argument. The 'sep' may be \par's: the macro % \xintlistwithsep etc... are all declared long. 'sep' does not have to be a % single token. It is not expanded. The "list" argument may be empty. % % \xintListWithSepNoExpand does not f-expand its second argument. %\end{lverb} % \changed{1.2p} %\begin{lverb} % This venerable macro from 1.04 remained unchanged for a long time and was % finally refactored at 1.2p for increased speed. Tests done with a list of % identical {\x} items and a sep of \z demonstrated a speed increase of about: %( - 3x for 30 items, %: - 4.5x for 100 items, %: - 7.5x--8x for 1000 items. %) %\end{lverb} % \begin{macrocode} \def\xintListWithSep {\romannumeral0\xintlistwithsep }% \def\xintListWithSepNoExpand {\romannumeral0\xintlistwithsepnoexpand }% \long\def\xintlistwithsep #1#2% {\expandafter\XINT_lws\expandafter {\romannumeral`&&@#2}{#1}}% \long\def\xintlistwithsepnoexpand #1#2% {% \XINT_lws_loop_a {#1}#2{\xint_bye\XINT_lws_e_vi}% {\xint_bye\XINT_lws_e_v}{\xint_bye\XINT_lws_e_iv}% {\xint_bye\XINT_lws_e_iii}{\xint_bye\XINT_lws_e_ii}% {\xint_bye\XINT_lws_e_i}{\xint_bye\XINT_lws_e}% {\xint_bye\expandafter\space}\xint_bye }% \long\def\XINT_lws #1#2% {% \XINT_lws_loop_a {#2}#1{\xint_bye\XINT_lws_e_vi}% {\xint_bye\XINT_lws_e_v}{\xint_bye\XINT_lws_e_iv}% {\xint_bye\XINT_lws_e_iii}{\xint_bye\XINT_lws_e_ii}% {\xint_bye\XINT_lws_e_i}{\xint_bye\XINT_lws_e}% {\xint_bye\expandafter\space}\xint_bye }% \long\def\XINT_lws_loop_a #1#2#3#4#5#6#7#8#9% {% \xint_bye #9\xint_bye \XINT_lws_loop_b {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}% }% \long\def\XINT_lws_loop_b #1#2#3#4#5#6#7#8#9% {% \XINT_lws_loop_a {#1}{#2#1#3#1#4#1#5#1#6#1#7#1#8#1#9}% }% \long\def\XINT_lws_e_vi\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6#7#8#9\xint_bye { #2#1#3#1#4#1#5#1#6#1#7#1#8}% \long\def\XINT_lws_e_v\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6#7#8\xint_bye { #2#1#3#1#4#1#5#1#6#1#7}% \long\def\XINT_lws_e_iv\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6#7\xint_bye { #2#1#3#1#4#1#5#1#6}% \long\def\XINT_lws_e_iii\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6\xint_bye { #2#1#3#1#4#1#5}% \long\def\XINT_lws_e_ii\xint_bye\XINT_lws_loop_b #1#2#3#4#5\xint_bye { #2#1#3#1#4}% \long\def\XINT_lws_e_i\xint_bye\XINT_lws_loop_b #1#2#3#4\xint_bye { #2#1#3}% \long\def\XINT_lws_e\xint_bye\XINT_lws_loop_b #1#2#3\xint_bye { #2}% % \end{macrocode} % \subsection{\csh{xintNthElt}} % \added{1.06} % \changed{1.2j} %\begin{lverb} % Last refactored in 1.2j. % % \xintNthElt {i}{List} returns the i th item from List (one pair of braces % removed). The list is first f-expanded. The \xintNthEltNoExpand does no % expansion of its second argument. Both variants expand i inside \numexpr. % % With i = 0, the number of items is returned using \xintLength but with the % List argument f-expanded first. % % Negative values return the |i|th element from the end. % % When i is out of range, an empty value is returned. %\end{lverb} % \begin{macrocode} \def\xintNthElt {\romannumeral0\xintnthelt }% \def\xintNthEltNoExpand {\romannumeral0\xintntheltnoexpand }% \long\def\xintnthelt #1#2{\expandafter\XINT_nthelt_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xintntheltnoexpand #1{\expandafter\XINT_nthelt_a\the\numexpr #1.}% \def\XINT_nthelt_a #1% {% \xint_UDzerominusfork #1-\XINT_nthelt_zero 0#1\XINT_nthelt_neg 0-{\XINT_nthelt_pos #1}% \krof }% \def\XINT_nthelt_zero #1.{\xintlength }% \long\def\XINT_nthelt_neg #1.#2% {% \expandafter\XINT_nthelt_neg_a\the\numexpr\xint_c_i+\XINT_length_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye -#1.#2\xint_bye }% \def\XINT_nthelt_neg_a #1% {% \xint_UDzerominusfork #1-\xint_stop_afterbye 0#1\xint_stop_afterbye 0-{}% \krof \expandafter\XINT_nthelt_neg_b \romannumeral\expandafter\XINT_gobble\the\numexpr-\xint_c_i+#1% }% \long\def\XINT_nthelt_neg_b #1#2\xint_bye{ #1}% \long\def\XINT_nthelt_pos #1.#2% {% \expandafter\XINT_nthelt_pos_done \romannumeral0\expandafter\XINT_trim_loop\the\numexpr#1-\xint_c_x.% #2\xint:\xint:\xint:\xint:\xint:% \xint:\xint:\xint:\xint:\xint:% \xint_bye }% \def\XINT_nthelt_pos_done #1{% \long\def\XINT_nthelt_pos_done ##1##2\xint_bye{% \xint_gob_til_xint:##1\expandafter#1\xint_gobble_ii\xint:#1##1}% }\XINT_nthelt_pos_done{ }% % \end{macrocode} % \subsection{\csh{xintNthOnePy}} % \added{1.4} % See relevant code comments in \xintexprnameimp. % \begin{macrocode} \def\xintNthOnePy {\romannumeral0\xintnthonepy }% \def\xintNthOnePyNoExpand {\romannumeral0\xintnthonepynoexpand }% \long\def\xintnthonepy #1#2{\expandafter\XINT_nthonepy_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xintnthonepynoexpand #1{\expandafter\XINT_nthonepy_a\the\numexpr #1.}% \def\XINT_nthonepy_a #1% {% \xint_UDsignfork #1\XINT_nthonepy_neg -{\XINT_nthonepy_nonneg #1}% \krof }% \long\def\XINT_nthonepy_neg #1.#2% {% \expandafter\XINT_nthonepy_neg_a\the\numexpr\xint_c_i+\XINT_length_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye -#1.#2\xint_bye }% \def\XINT_nthonepy_neg_a #1% {% \xint_UDzerominusfork #1-\xint_stop_afterbye 0#1\xint_stop_afterbye 0-{}% \krof \expandafter\XINT_nthonepy_neg_b \romannumeral\expandafter\XINT_gobble\the\numexpr-\xint_c_i+#1% }% \long\def\XINT_nthonepy_neg_b #1#2\xint_bye{{#1}}% \long\def\XINT_nthonepy_nonneg #1.#2% {% \expandafter\XINT_nthonepy_nonneg_done \romannumeral0\expandafter\XINT_trim_loop\the\numexpr#1-\xint_c_ix.% #2\xint:\xint:\xint:\xint:\xint:% \xint:\xint:\xint:\xint:\xint:% \xint_bye }% \def\XINT_nthonepy_nonneg_done #1{% \long\def\XINT_nthonepy_nonneg_done ##1##2\xint_bye{% \xint_gob_til_xint:##1\expandafter#1\xint_gobble_ii\xint:{##1}}% }\XINT_nthonepy_nonneg_done{ }% % \end{macrocode} % \subsection{\csh{xintKeep}} % \added{1.09m} %\begin{lverb} % \xintKeep{i}{L} f-expands its second argument L. It then grabs the first i % items from L and discards the rest. % % ATTENTION: **each such kept item is returned inside a brace pair** % Use \xintKeepUnbraced to avoid that. % % For i equal or larger to the number N of items in (expanded) L, the full L % is returned (with braced items). For i=0, the macro returns an empty output. % For i<0, the macro discards the first N-|i| items. No brace pairs added to % the remaining items. For i is less or equal to -N, the full L is returned % (with no braces added.) % % \xintKeepNoExpand does not expand the L argument. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Prior to 1.2i the code proceeded along a loop with no pre-computation of % the length of L, for the i>0 case. The faster 1.2i version takes advantage % of novel \xintLengthUpTo from xintkernel.sty. %\end{lverb} % \begin{macrocode} \def\xintKeep {\romannumeral0\xintkeep }% \def\xintKeepNoExpand {\romannumeral0\xintkeepnoexpand }% \long\def\xintkeep #1#2{\expandafter\XINT_keep_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xintkeepnoexpand #1{\expandafter\XINT_keep_a\the\numexpr #1.}% \def\XINT_keep_a #1% {% \xint_UDzerominusfork #1-\XINT_keep_keepnone 0#1\XINT_keep_neg 0-{\XINT_keep_pos #1}% \krof }% \long\def\XINT_keep_keepnone .#1{ }% \long\def\XINT_keep_neg #1.#2% {% \expandafter\XINT_keep_neg_a\the\numexpr #1-\numexpr\XINT_length_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.#2% }% \def\XINT_keep_neg_a #1% {% \xint_UDsignfork #1{\expandafter\space\romannumeral\XINT_gobble}% -\XINT_keep_keepall \krof }% \def\XINT_keep_keepall #1.{ }% \long\def\XINT_keep_pos #1.#2% {% \expandafter\XINT_keep_loop \the\numexpr#1-\XINT_lengthupto_loop #1.#2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_vii\xint_c_vi\xint_c_v\xint_c_iv \xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.% -\xint_c_viii.{}#2\xint_bye% }% \def\XINT_keep_loop #1#2.% {% \xint_gob_til_minus#1\XINT_keep_loop_end-% \expandafter\XINT_keep_loop \the\numexpr#1#2-\xint_c_viii\expandafter.\XINT_keep_loop_pickeight }% \long\def\XINT_keep_loop_pickeight #1#2#3#4#5#6#7#8#9{{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}}% \def\XINT_keep_loop_end-\expandafter\XINT_keep_loop \the\numexpr-#1-\xint_c_viii\expandafter.\XINT_keep_loop_pickeight {\csname XINT_keep_end#1\endcsname}% \long\expandafter\def\csname XINT_keep_end1\endcsname #1#2#3#4#5#6#7#8#9\xint_bye { #1{#2}{#3}{#4}{#5}{#6}{#7}{#8}}% \long\expandafter\def\csname XINT_keep_end2\endcsname #1#2#3#4#5#6#7#8\xint_bye { #1{#2}{#3}{#4}{#5}{#6}{#7}}% \long\expandafter\def\csname XINT_keep_end3\endcsname #1#2#3#4#5#6#7\xint_bye { #1{#2}{#3}{#4}{#5}{#6}}% \long\expandafter\def\csname XINT_keep_end4\endcsname #1#2#3#4#5#6\xint_bye { #1{#2}{#3}{#4}{#5}}% \long\expandafter\def\csname XINT_keep_end5\endcsname #1#2#3#4#5\xint_bye { #1{#2}{#3}{#4}}% \long\expandafter\def\csname XINT_keep_end6\endcsname #1#2#3#4\xint_bye { #1{#2}{#3}}% \long\expandafter\def\csname XINT_keep_end7\endcsname #1#2#3\xint_bye { #1{#2}}% \long\expandafter\def\csname XINT_keep_end8\endcsname #1#2\xint_bye { #1}% % \end{macrocode} % \subsection{\csh{xintKeepUnbraced}} % \added{1.2a} %\begin{lverb} % Same as \xintKeep but will *not* add (or maintain) brace pairs % around the kept items when length(L)>i>0. % % The name may cause a mis-understanding: for i<0, (i.e. keeping only % trailing items), there is no brace removal at all happening. %\end{lverb} % % \changed{1.2i} As |\xintKeep|. % \begin{macrocode} \def\xintKeepUnbraced {\romannumeral0\xintkeepunbraced }% \def\xintKeepUnbracedNoExpand {\romannumeral0\xintkeepunbracednoexpand }% \long\def\xintkeepunbraced #1#2% {\expandafter\XINT_keepunbr_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xintkeepunbracednoexpand #1% {\expandafter\XINT_keepunbr_a\the\numexpr #1.}% \def\XINT_keepunbr_a #1% {% \xint_UDzerominusfork #1-\XINT_keep_keepnone 0#1\XINT_keep_neg 0-{\XINT_keepunbr_pos #1}% \krof }% \long\def\XINT_keepunbr_pos #1.#2% {% \expandafter\XINT_keepunbr_loop \the\numexpr#1-\XINT_lengthupto_loop #1.#2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_vii\xint_c_vi\xint_c_v\xint_c_iv \xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.% -\xint_c_viii.{}#2\xint_bye% }% \def\XINT_keepunbr_loop #1#2.% {% \xint_gob_til_minus#1\XINT_keepunbr_loop_end-% \expandafter\XINT_keepunbr_loop \the\numexpr#1#2-\xint_c_viii\expandafter.\XINT_keepunbr_loop_pickeight }% \long\def\XINT_keepunbr_loop_pickeight #1#2#3#4#5#6#7#8#9{{#1#2#3#4#5#6#7#8#9}}% \def\XINT_keepunbr_loop_end-\expandafter\XINT_keepunbr_loop \the\numexpr-#1-\xint_c_viii\expandafter.\XINT_keepunbr_loop_pickeight {\csname XINT_keepunbr_end#1\endcsname}% \long\expandafter\def\csname XINT_keepunbr_end1\endcsname #1#2#3#4#5#6#7#8#9\xint_bye { #1#2#3#4#5#6#7#8}% \long\expandafter\def\csname XINT_keepunbr_end2\endcsname #1#2#3#4#5#6#7#8\xint_bye { #1#2#3#4#5#6#7}% \long\expandafter\def\csname XINT_keepunbr_end3\endcsname #1#2#3#4#5#6#7\xint_bye { #1#2#3#4#5#6}% \long\expandafter\def\csname XINT_keepunbr_end4\endcsname #1#2#3#4#5#6\xint_bye { #1#2#3#4#5}% \long\expandafter\def\csname XINT_keepunbr_end5\endcsname #1#2#3#4#5\xint_bye { #1#2#3#4}% \long\expandafter\def\csname XINT_keepunbr_end6\endcsname #1#2#3#4\xint_bye { #1#2#3}% \long\expandafter\def\csname XINT_keepunbr_end7\endcsname #1#2#3\xint_bye { #1#2}% \long\expandafter\def\csname XINT_keepunbr_end8\endcsname #1#2\xint_bye { #1}% % \end{macrocode} % \subsection{\csh{xintTrim}} % \added{1.09m} %\begin{lverb} % \xintTrim{i}{L} f-expands its second argument L. It then removes the first i % items from L and keeps the rest. For i equal or larger to the number N of % items in (expanded) L, the macro returns an empty output. For i=0, the % original (expanded) L is returned. For i<0, the macro proceeds from the % tail. It thus removes the last |i| items, i.e. it keeps the first N-|i| % items. For |i|>= N, the empty list is returned. % % \xintTrimNoExpand does not expand the L argument. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Speed improvements for i<0 branch (which hands over to % \xintKeep). Speed improvements with 1.2j for i>0 branch which gobbles items % nine by nine despite not knowing in advance if it will go too far. %\end{lverb} % \begin{macrocode} \def\xintTrim {\romannumeral0\xinttrim }% \def\xintTrimNoExpand {\romannumeral0\xinttrimnoexpand }% \long\def\xinttrim #1#2{\expandafter\XINT_trim_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xinttrimnoexpand #1{\expandafter\XINT_trim_a\the\numexpr #1.}% \def\XINT_trim_a #1% {% \xint_UDzerominusfork #1-\XINT_trim_trimnone 0#1\XINT_trim_neg 0-{\XINT_trim_pos #1}% \krof }% \long\def\XINT_trim_trimnone .#1{ #1}% \long\def\XINT_trim_neg #1.#2% {% \expandafter\XINT_trim_neg_a\the\numexpr #1-\numexpr\XINT_length_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye .{}#2\xint_bye }% \def\XINT_trim_neg_a #1% {% \xint_UDsignfork #1{\expandafter\XINT_keep_loop\the\numexpr-\xint_c_viii+}% -\XINT_trim_trimall \krof }% \def\XINT_trim_trimall#1{% \def\XINT_trim_trimall {\expandafter#1\xint_bye}% }\XINT_trim_trimall{ }% % \end{macrocode} %\begin{lverb} % This branch doesn't pre-evaluate the length of the list argument. % Redone again for 1.2j, manages to trim nine by nine. Some non optimal % looking aspect of the code is for allowing sharing with \xintNthElt. %\end{lverb} % \begin{macrocode} \long\def\XINT_trim_pos #1.#2% {% \expandafter\XINT_trim_pos_done\expandafter\space \romannumeral0\expandafter\XINT_trim_loop\the\numexpr#1-\xint_c_ix.% #2\xint:\xint:\xint:\xint:\xint:% \xint:\xint:\xint:\xint:\xint:% \xint_bye }% \def\XINT_trim_loop #1#2.% {% \xint_gob_til_minus#1\XINT_trim_finish-% \expandafter\XINT_trim_loop\the\numexpr#1#2\XINT_trim_loop_trimnine }% \long\def\XINT_trim_loop_trimnine #1#2#3#4#5#6#7#8#9% {% \xint_gob_til_xint: #9\XINT_trim_toofew\xint:-\xint_c_ix.% }% \def\XINT_trim_toofew\xint:{*\xint_c_}% \def\XINT_trim_finish#1{% \def\XINT_trim_finish-% \expandafter\XINT_trim_loop\the\numexpr-##1\XINT_trim_loop_trimnine {% \expandafter\expandafter\expandafter#1% \csname xint_gobble_\romannumeral\numexpr\xint_c_ix-##1\endcsname }}\XINT_trim_finish{ }% \long\def\XINT_trim_pos_done #1\xint:#2\xint_bye {#1}% % \end{macrocode} % \subsection{\csh{xintTrimUnbraced}} % \added{1.2a} % \changed{1.2i} As |\xintTrim|. % \begin{macrocode} \def\xintTrimUnbraced {\romannumeral0\xinttrimunbraced }% \def\xintTrimUnbracedNoExpand {\romannumeral0\xinttrimunbracednoexpand }% \long\def\xinttrimunbraced #1#2% {\expandafter\XINT_trimunbr_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xinttrimunbracednoexpand #1% {\expandafter\XINT_trimunbr_a\the\numexpr #1.}% \def\XINT_trimunbr_a #1% {% \xint_UDzerominusfork #1-\XINT_trim_trimnone 0#1\XINT_trimunbr_neg 0-{\XINT_trim_pos #1}% \krof }% \long\def\XINT_trimunbr_neg #1.#2% {% \expandafter\XINT_trimunbr_neg_a\the\numexpr #1-\numexpr\XINT_length_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye .{}#2\xint_bye }% \def\XINT_trimunbr_neg_a #1% {% \xint_UDsignfork #1{\expandafter\XINT_keepunbr_loop\the\numexpr-\xint_c_viii+}% -\XINT_trim_trimall \krof }% % \end{macrocode} % \subsection{\csh{xintApply}} % \added{1.04} %\begin{lverb} % \xintApply {\macro}{{a}{b}...{z}} returns {\macro{a}}...{\macro{b}} % where each instance of \macro is f-expanded. The list itself is first % f-expanded and may thus be a macro. %\end{lverb} % \begin{macrocode} \def\xintApply {\romannumeral0\xintapply }% \def\xintApplyNoExpand {\romannumeral0\xintapplynoexpand }% \long\def\xintapply #1#2% {% \expandafter\XINT_apply\expandafter {\romannumeral`&&@#2}% {#1}% }% \long\def\XINT_apply #1#2{\XINT_apply_loop_a {}{#2}#1\xint_bye }% \long\def\xintapplynoexpand #1#2{\XINT_apply_loop_a {}{#1}#2\xint_bye }% \long\def\XINT_apply_loop_a #1#2#3% {% \xint_bye #3\XINT_apply_end\xint_bye \expandafter \XINT_apply_loop_b \expandafter {\romannumeral`&&@#2{#3}}{#1}{#2}% }% \long\def\XINT_apply_loop_b #1#2{\XINT_apply_loop_a {#2{#1}}}% \long\def\XINT_apply_end\xint_bye\expandafter\XINT_apply_loop_b \expandafter #1#2#3{ #2}% % \end{macrocode} % \subsection{\csh{xintApply:x} (WIP, commented-out)} % \added[2020/01/27]{1.4} %\begin{lverb} % For usage in the NumPy-like slicing % routines. Well, actually, in the end I sticked with old-fashioned (quadratic % cost) \xintApply for 1.4 2020/01/31 release. See comments there. % % (Comments mainly from 2020/01/27, but on 2020/02/24 I comment out % the code and add an alternative) % % To expand in \expanded context, and does not need to % do any expansion of its second argument. % % This uses techniques I had developed for 1.2i/1.2j Keep, Trim, Length, % LastItem like macros, and I should revamp venerable \xintApply probably too. % But the latter f-expandability (if it does not have \expanded at disposal) % complicates significantly matters as it has to store material and release at % very end. % % Here it is simpler and I am doing it quickly as I really want to release % 1.4. The \xint: token should not be located in looped over items. I could % use something more exotic like the null char with catcode 3... % %( \long\def\xintApply:x #1#2$% %: {$% %: \XINT_apply:x_loop {#1}#2$% %: {\xint:\XINT_apply:x_loop_enda}{\xint:\XINT_apply:x_loop_endb}$% %: {\xint:\XINT_apply:x_loop_endc}{\xint:\XINT_apply:x_loop_endd}$% %: {\xint:\XINT_apply:x_loop_ende}{\xint:\XINT_apply:x_loop_endf}$% %: {\xint:\XINT_apply:x_loop_endg}{\xint:\XINT_apply:x_loop_endh}\xint_bye %: }$% %: \long\def\XINT_apply:x_loop #1#2#3#4#5#6#7#8#9$% %: {$% %: \xint_gob_til_xint: #9\xint: %: {#1{#2}}{#1{#3}}{#1{#4}}{#1{#5}}{#1{#6}}{#1{#7}}{#1{#8}}{#1{#9}}$% %: \XINT_apply:x_loop {#1}$% %: }$% %: \long\def\XINT_apply:x_loop_endh\xint: #1\xint_bye{}$% %: \long\def\XINT_apply:x_loop_endg\xint: #1#2\xint_bye{{#1}}$% %: \long\def\XINT_apply:x_loop_endf\xint: #1#2#3\xint_bye{{#1}{#2}}$% %: \long\def\XINT_apply:x_loop_ende\xint: #1#2#3#4\xint_bye{{#1}{#2}{#3}}$% %: \long\def\XINT_apply:x_loop_endd\xint: #1#2#3#4#5\xint_bye{{#1}{#2}{#3}{#4}}$% %: \long\def\XINT_apply:x_loop_endc\xint: #1#2#3#4#5#6\xint_bye{{#1}{#2}{#3}{#4}{#5}}$% %: \long\def\XINT_apply:x_loop_endb\xint: #1#2#3#4#5#6#7\xint_bye{{#1}{#2}{#3}{#4}{#5}{#6}}$% %: \long\def\XINT_apply:x_loop_enda\xint: #1#2#3#4#5#6#7#8\xint_bye{{#1}{#2}{#3}{#4}{#5}{#6}{#7}}$% %) % % For small number of items gain with respect to \xintApply is little if any % (might even be a loss). % % Picking one by one is possibly better for small number of items. Like % this for example, the natural simple minded thing: % %(\long\def\xintApply:x #1#2$% %: {$% %: \XINT_apply:x_loop {#1}#2\xint_bye\xint_bye %: }$% %: \long\def\XINT_apply:x_loop #1#2$% %: {$% %: \xint_bye #2\xint_bye {#1{#2}}$% %: \XINT_apply:x_loop {#1}$% %: }$% %) % % Some variant on 2020/02/24 % %( \long\def\xint_Bbye#1\xint_Bye{}$% %: \long\def\xintApply:x #1#2$% %: {$% %: \XINT_apply:x_loop {#1}#2$% %: {\xint_bye}{\xint_bye}{\xint_bye}{\xint_bye}$% %: {\xint_bye}{\xint_bye}{\xint_bye}{\xint_bye}\xint_bye %: }$% %: \long\def\XINT_apply:x_loop #1#2#3#4#5#6#7#8#9$% %: {$% %: \xint_Bye #2\xint_bye {#1{#2}}$% %: \xint_Bye #3\xint_bye {#1{#3}}$% %: \xint_Bye #4\xint_bye {#1{#4}}$% %: \xint_Bye #5\xint_bye {#1{#5}}$% %: \xint_Bye #6\xint_bye {#1{#6}}$% %: \xint_Bye #7\xint_bye {#1{#7}}$% %: \xint_Bye #8\xint_bye {#1{#8}}$% %: \xint_Bye #9\xint_bye {#1{#9}}$% %: \XINT_apply:x_loop {#1}$% %: }$% %) %\end{lverb} % \subsection{\csh{xintApplyUnbraced}} % \added{1.06b} %\begin{lverb} % \xintApplyUnbraced {\macro}{{a}{b}...{z}} returns \macro{a}...\macro{z} % where each instance of \macro is f-expanded using \romannumeral-`0. The second % argument may be a macro as it is itself also f-expanded. No braces % are added: this allows for example a non-expandable \def in \macro, without % having to do \gdef. %\end{lverb} % \begin{macrocode} \def\xintApplyUnbraced {\romannumeral0\xintapplyunbraced }% \def\xintApplyUnbracedNoExpand {\romannumeral0\xintapplyunbracednoexpand }% \long\def\xintapplyunbraced #1#2% {% \expandafter\XINT_applyunbr\expandafter {\romannumeral`&&@#2}% {#1}% }% \long\def\XINT_applyunbr #1#2{\XINT_applyunbr_loop_a {}{#2}#1\xint_bye }% \long\def\xintapplyunbracednoexpand #1#2% {\XINT_applyunbr_loop_a {}{#1}#2\xint_bye }% \long\def\XINT_applyunbr_loop_a #1#2#3% {% \xint_bye #3\XINT_applyunbr_end\xint_bye \expandafter\XINT_applyunbr_loop_b \expandafter {\romannumeral`&&@#2{#3}}{#1}{#2}% }% \long\def\XINT_applyunbr_loop_b #1#2{\XINT_applyunbr_loop_a {#2#1}}% \long\def\XINT_applyunbr_end\xint_bye\expandafter\XINT_applyunbr_loop_b \expandafter #1#2#3{ #2}% % \end{macrocode} % \subsection{\csh{xintApplyUnbraced:x} (WIP, commented-out)} % \added[2020/01/27]{1.4} %\begin{lverb} % For usage in the NumPy-like slicing % routines. % % The items should not contain \xint: and the applied macro should not contain % \empty. % % Finally, xintexpr.sty 1.4 code did not use this macro but the f-expandable % one \xintApplyUnbraced. %\end{lverb} % \changed{1.4b} %\begin{lverb} % For 1.4b I prefer to keep the \xintApplyUnbraced:x code commented out, % and classify it as WIP. %( \long\def\xintApplyUnbraced:x #1#2$% %: {$% %: \XINT_applyunbraced:x_loop {#1}#2$% %: {\xint:\XINT_applyunbraced:x_loop_enda}{\xint:\XINT_applyunbraced:x_loop_endb}$% %: {\xint:\XINT_applyunbraced:x_loop_endc}{\xint:\XINT_applyunbraced:x_loop_endd}$% %: {\xint:\XINT_applyunbraced:x_loop_ende}{\xint:\XINT_applyunbraced:x_loop_endf}$% %: {\xint:\XINT_applyunbraced:x_loop_endg}{\xint:\XINT_applyunbraced:x_loop_endh}\xint_bye %: }$% %: \long\def\XINT_applyunbraced:x_loop #1#2#3#4#5#6#7#8#9$% %: {$% %: \xint_gob_til_xint: #9\xint: %: #1{#2}$% %: \empty#1{#3}$% %: \empty#1{#4}$% %: \empty#1{#5}$% %: \empty#1{#6}$% %: \empty#1{#7}$% %: \empty#1{#8}$% %: \empty#1{#9}$% %: \XINT_applyunbraced:x_loop {#1}$% %: }$% %: \long\def\XINT_applyunbraced:x_loop_endh\xint: #1\xint_bye{}$% %: \long\def\XINT_applyunbraced:x_loop_endg\xint: #1\empty#2\xint_bye{#1}$% %: \long\def\XINT_applyunbraced:x_loop_endf\xint: #1\empty %: #2\empty#3\xint_bye{#1#2}$% %: \long\def\XINT_applyunbraced:x_loop_ende\xint: #1\empty %: #2\empty %: #3\empty#4\xint_bye{#1#2#3}$% %: \long\def\XINT_applyunbraced:x_loop_endd\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty#5\xint_bye{#1#2#3#4}$% %: \long\def\XINT_applyunbraced:x_loop_endc\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty %: #5\empty#6\xint_bye{#1#2#3#4#5}$% %: \long\def\XINT_applyunbraced:x_loop_endb\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty %: #5\empty %: #6\empty#7\xint_bye{#1#2#3#4#5#6}$% %: \long\def\XINT_applyunbraced:x_loop_enda\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty %: #5\empty %: #6\empty %: #7\empty#8\xint_bye{#1#2#3#4#5#6#7}$% %) %\end{lverb} % \subsection{\csh{xintZip} (WIP, not public)} % \added[2020/02/25]{1.4b} %\begin{lverb} % Support for zip(). Requires \expanded. % % The implementation here thus considers the argument is already completely % expanded and is a sequence of nut-ples. I will come back at later date for % more generic macros. % % Consider even the name of the function zip() as WIP. % % As per what this does, it imitates the zip() function. See xint-manual.pdf. % % I use lame terminators. Will think again later on this. I have to be careful % with the used terminators, in particular with the NE context in mind. % % Generally speaking I will think another day about efficiency else I will % never start this. % % OK, done. More compact than I initially thought. Various things should be % commented upon here. Well, actually not so compact in the end as I basically % had to double the whole thing simply to avoid the overhead of having to grab % the final result delimited by some % \xint_bye\xint_bye\xint_bye\xint_bye\empty terminator. Now actually rather % \xint_bye\xint_bye\xint_bye\xint_bye\xint: %\end{lverb} % \begin{macrocode} \def\xintZip #1{\expanded\XINT_zip_A#1\xint_bye\xint_bye}% \def\XINT_zip_A#1% {% \xint_bye#1{\expandafter}\xint_bye \expanded{\xint_noxpd{\XINT_ziptwo_A #1\xint_bye\xint_bye\xint_bye\xint_bye\xint:}\expandafter}% \expanded\XINT_zip_a }% \def\XINT_zip_a#1% {% \xint_bye#1\XINT_zip_terminator\xint_bye \expanded{\xint_noxpd{\XINT_ziptwo_a #1\xint_bye\xint_bye\xint_bye\xint_bye\xint:}\expandafter}% \expanded\XINT_zip_a }% \def\XINT_zip_terminator\xint_bye#1\xint_bye{{}\empty\empty\empty\empty\xint:}% \def\XINT_ziptwo_a #1#2#3#4#5\xint:#6#7#8#9% {% \bgroup \xint_bye #1\XINT_ziptwo_e \xint_bye \xint_bye #6\XINT_ziptwo_e \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_e \xint_bye \xint_bye #7\XINT_ziptwo_e \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_e \xint_bye \xint_bye #8\XINT_ziptwo_e \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_e \xint_bye \xint_bye #9\XINT_ziptwo_e \xint_bye {{#4}#9}% % \end{macrocode} %\begin{lverb} % Attention here that #6 can very well deliver no tokens at all. But % the \ifx will then do the expected thing. Only mentioning! % % By the way, the \xint_bye method means TeX needs to look into tokens % but skipping braced groups. A conditional based method lets TeX look only % at the start but then it has to find \else or \fi so here also it must looks % at tokens, and actually goes into braced groups. But (written 2020/02/26) I % never did serious testing comparing the two, and in xint I have usually % preferred \xint_bye/\xint_gob_til_foo types of methods (they proved superior % than \ifnum to check for 0000 in numerical core context for example, at the % early days when xint used blocks of 4 digits, not 8), or usage of \if/\ifx % only on single tokens, combined with some \xint_dothis/\xint_orthat syntax. %\end{lverb} % \begin{macrocode} \ifx \empty#6\expandafter\XINT_zipone_a\fi \XINT_ziptwo_b #5\xint: }% \def\XINT_zipone_a\XINT_ziptwo_b{\XINT_zipone_b}% \def\XINT_ziptwo_b #1#2#3#4#5\xint:#6#7#8#9% {% \xint_bye #1\XINT_ziptwo_e \xint_bye \xint_bye #6\XINT_ziptwo_e \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_e \xint_bye \xint_bye #7\XINT_ziptwo_e \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_e \xint_bye \xint_bye #8\XINT_ziptwo_e \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_e \xint_bye \xint_bye #9\XINT_ziptwo_e \xint_bye {{#4}#9}% \XINT_ziptwo_b #5\xint: }% \def\XINT_ziptwo_e #1\XINT_ziptwo_b #2\xint:#3\xint: {\iffalse{\fi}\xint_bye\xint_bye\xint_bye\xint_bye\xint:}% \def\XINT_zipone_b #1#2#3#4% {% \xint_bye #1\XINT_zipone_e \xint_bye {{#1}}% \xint_bye #2\XINT_zipone_e \xint_bye {{#2}}% \xint_bye #3\XINT_zipone_e \xint_bye {{#3}}% \xint_bye #4\XINT_zipone_e \xint_bye {{#4}}% \XINT_zipone_b }% \def\XINT_zipone_e #1\XINT_zipone_b #2\xint: {\iffalse{\fi}\xint_bye\xint_bye\xint_bye\xint_bye\empty}% \def\XINT_ziptwo_A #1#2#3#4#5\xint:#6#7#8#9% {% \bgroup \xint_bye #1\XINT_ziptwo_end \xint_bye \xint_bye #6\XINT_ziptwo_end \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_end \xint_bye \xint_bye #7\XINT_ziptwo_end \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_end \xint_bye \xint_bye #8\XINT_ziptwo_end \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_end \xint_bye \xint_bye #9\XINT_ziptwo_end \xint_bye {{#4}#9}% \ifx \empty#6\expandafter\XINT_zipone_A\fi \XINT_ziptwo_B #5\xint: }% \def\XINT_zipone_A\XINT_ziptwo_B{\XINT_zipone_B}% \def\XINT_ziptwo_B #1#2#3#4#5\xint:#6#7#8#9% {% \xint_bye #1\XINT_ziptwo_end \xint_bye \xint_bye #6\XINT_ziptwo_end \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_end \xint_bye \xint_bye #7\XINT_ziptwo_end \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_end \xint_bye \xint_bye #8\XINT_ziptwo_end \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_end \xint_bye \xint_bye #9\XINT_ziptwo_end \xint_bye {{#4}#9}% \XINT_ziptwo_B #5\xint: }% \def\XINT_ziptwo_end #1\XINT_ziptwo_B #2\xint:#3\xint:{\iffalse{\fi}}% \def\XINT_zipone_B #1#2#3#4% {% \xint_bye #1\XINT_zipone_end \xint_bye {{#1}}% \xint_bye #2\XINT_zipone_end \xint_bye {{#2}}% \xint_bye #3\XINT_zipone_end \xint_bye {{#3}}% \xint_bye #4\XINT_zipone_end \xint_bye {{#4}}% \XINT_zipone_B }% \def\XINT_zipone_end #1\XINT_zipone_B #2\xint:#3\xint:{\iffalse{\fi}}% % \end{macrocode} % \subsection{\csh{xintSeq}} % \added{1.09c} % Without the optional argument puts stress on the input stack, % should not be used to generated thousands of terms then. % % \changed{1.4j} % This venerable macro had a brace removal bug in case it produced a single % number: |\xintSeq{10}{10}| expanded to |10| not |{10}|. When I looked at the % code the bug looked almost deliberate to me, but reading the documentation % (which I have not modified), the behaviour is really unexpected. And the % variant with step parameter |\xintSeq[1]{10}{10}| did produce |{10}|, so % yes, definitely it was a bug! % % I take this occasion to do some style (and perhaps efficiency) refactoring % in the coding. I feel there is room for improvement, no time this time. % And I don't touch the variant with step parameter. % % Memo: \xintexprnameimp has some variants, a priori on ultra quick look % they do not look like having similar bug as this one had. % \begin{macrocode} \def\xintSeq {\romannumeral0\xintseq }% \def\xintseq #1{\XINT_seq_chkopt #1\xint_bye }% \def\XINT_seq_chkopt #1% {% \ifx [#1\expandafter\XINT_seq_opt \else\expandafter\XINT_seq_noopt \fi #1% }% \def\XINT_seq_noopt #1\xint_bye #2% {% \expandafter\XINT_seq \the\numexpr#1\expandafter.\the\numexpr #2.% }% \def\XINT_seq #1.#2.% {% \ifnum #1=#2 \xint_dothis\XINT_seq_e\fi \ifnum #2>#1 \xint_dothis\XINT_seq_pa\fi \xint_orthat\XINT_seq_na #2.{#1}{#2}% }% \def\XINT_seq_e#1.#2{}% \def\XINT_seq_pa {\expandafter\XINT_seq_p\the\numexpr-\xint_c_i+}% \def\XINT_seq_na {\expandafter\XINT_seq_n\the\numexpr\xint_c_i+}% \def\XINT_seq_p #1.#2% {% \ifnum #1>#2 \expandafter\XINT_seq_p\the \else \expandafter\XINT_seq_e \fi \numexpr #1-\xint_c_i.{#2}{#1}% }% \def\XINT_seq_n #1.#2% {% \ifnum #1<#2 \expandafter\XINT_seq_n\the \else \expandafter\XINT_seq_e \fi \numexpr #1+\xint_c_i.{#2}{#1}% }% % \end{macrocode} % Note at time of the |1.4j| bug fix : I definitely should improve this branch % and diminish the number of expandafter's but no time this time. % \begin{macrocode} \def\XINT_seq_opt [\xint_bye #1]#2#3% {% \expandafter\XINT_seqo\expandafter {\the\numexpr #2\expandafter}\expandafter {\the\numexpr #3\expandafter}\expandafter {\the\numexpr #1}% }% \def\XINT_seqo #1#2% {% \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space \expandafter\XINT_seqo_a \or \expandafter\XINT_seqo_pa \else \expandafter\XINT_seqo_na \fi {#1}{#2}% }% \def\XINT_seqo_a #1#2#3{ {#1}}% \def\XINT_seqo_o #1#2#3#4{ #4}% \def\XINT_seqo_pa #1#2#3% {% \ifcase\ifnum #3=\xint_c_ 0\else\ifnum #3>\xint_c_ 1\else -1\fi\fi\space \expandafter\XINT_seqo_o \or \expandafter\XINT_seqo_pb \else \xint_afterfi{\expandafter\space\xint_gobble_iv}% \fi {#1}{#2}{#3}{{#1}}% }% \def\XINT_seqo_pb #1#2#3% {% \expandafter\XINT_seqo_pc\expandafter{\the\numexpr #1+#3}{#2}{#3}% }% \def\XINT_seqo_pc #1#2% {% \ifnum #1>#2 \expandafter\XINT_seqo_o \else \expandafter\XINT_seqo_pd \fi {#1}{#2}% }% \def\XINT_seqo_pd #1#2#3#4{\XINT_seqo_pb {#1}{#2}{#3}{#4{#1}}}% \def\XINT_seqo_na #1#2#3% {% \ifcase\ifnum #3=\xint_c_ 0\else\ifnum #3>\xint_c_ 1\else -1\fi\fi\space \expandafter\XINT_seqo_o \or \xint_afterfi{\expandafter\space\xint_gobble_iv}% \else \expandafter\XINT_seqo_nb \fi {#1}{#2}{#3}{{#1}}% }% \def\XINT_seqo_nb #1#2#3% {% \expandafter\XINT_seqo_nc\expandafter{\the\numexpr #1+#3}{#2}{#3}% }% \def\XINT_seqo_nc #1#2% {% \ifnum #1<#2 \expandafter\XINT_seqo_o \else \expandafter\XINT_seqo_nd \fi {#1}{#2}% }% \def\XINT_seqo_nd #1#2#3#4{\XINT_seqo_nb {#1}{#2}{#3}{#4{#1}}}% % \end{macrocode} % \subsection{\csh{xintloop}, \csh{xintbreakloop}, \csh{xintbreakloopanddo}, % \csh{xintloopskiptonext}} % \added[2013/11/22]{1.09g} % \changed{1.09h} Made |\long|. % \begin{macrocode} \long\def\xintloop #1#2\repeat {#1#2\xintloop_again\fi\xint_gobble_i {#1#2}}% \long\def\xintloop_again\fi\xint_gobble_i #1{\fi #1\xintloop_again\fi\xint_gobble_i {#1}}% \long\def\xintbreakloop #1\xintloop_again\fi\xint_gobble_i #2{}% \long\def\xintbreakloopanddo #1#2\xintloop_again\fi\xint_gobble_i #3{#1}% \long\def\xintloopskiptonext #1\xintloop_again\fi\xint_gobble_i #2{% #2\xintloop_again\fi\xint_gobble_i {#2}}% % \end{macrocode} % \subsection{\csh{xintiloop}, % \csh{xintiloopindex}, % \csh{xintbracediloopindex}, % \csh{xintouteriloopindex}, % \csh{xintbracedouteriloopindex}, % \csh{xintbreakiloop}, % \csh{xintbreakiloopanddo}, % \csh{xintiloopskiptonext}, % \csh{xintiloopskipandredo}} % \added[2013/11/22]{1.09g} % \changed{1.09h} Made |\long|. % \added[2018/04/24]{1.3b} % \myenquote{braced} variants. % \begin{macrocode} \def\xintiloop [#1+#2]{% \expandafter\xintiloop_a\the\numexpr #1\expandafter.\the\numexpr #2.}% \long\def\xintiloop_a #1.#2.#3#4\repeat{% #3#4\xintiloop_again\fi\xint_gobble_iii {#1}{#2}{#3#4}}% \def\xintiloop_again\fi\xint_gobble_iii #1#2{% \fi\expandafter\xintiloop_again_b\the\numexpr#1+#2.#2.}% \long\def\xintiloop_again_b #1.#2.#3{% #3\xintiloop_again\fi\xint_gobble_iii {#1}{#2}{#3}}% \long\def\xintbreakiloop #1\xintiloop_again\fi\xint_gobble_iii #2#3#4{}% \long\def\xintbreakiloopanddo #1.#2\xintiloop_again\fi\xint_gobble_iii #3#4#5{#1}% \long\def\xintiloopindex #1\xintiloop_again\fi\xint_gobble_iii #2% {#2#1\xintiloop_again\fi\xint_gobble_iii {#2}}% \long\def\xintbracediloopindex #1\xintiloop_again\fi\xint_gobble_iii #2% {{#2}#1\xintiloop_again\fi\xint_gobble_iii {#2}}% \long\def\xintouteriloopindex #1\xintiloop_again #2\xintiloop_again\fi\xint_gobble_iii #3% {#3#1\xintiloop_again #2\xintiloop_again\fi\xint_gobble_iii {#3}}% \long\def\xintbracedouteriloopindex #1\xintiloop_again #2\xintiloop_again\fi\xint_gobble_iii #3% {{#3}#1\xintiloop_again #2\xintiloop_again\fi\xint_gobble_iii {#3}}% \long\def\xintiloopskiptonext #1\xintiloop_again\fi\xint_gobble_iii #2#3{% \expandafter\xintiloop_again_b \the\numexpr#2+#3.#3.}% \long\def\xintiloopskipandredo #1\xintiloop_again\fi\xint_gobble_iii #2#3#4{% #4\xintiloop_again\fi\xint_gobble_iii {#2}{#3}{#4}}% % \end{macrocode} % \subsection{\csh{XINT_xflet}} % \added[2013/10/29]{1.09e} % We f-expand unbraced tokens and swallow arising % space tokens until the dust settles. % \begin{macrocode} \def\XINT_xflet #1% {% \def\XINT_xflet_macro {#1}\XINT_xflet_zapsp }% \def\XINT_xflet_zapsp {% \expandafter\futurelet\expandafter\XINT_token \expandafter\XINT_xflet_sp?\romannumeral`&&@% }% \def\XINT_xflet_sp? {% \ifx\XINT_token\XINT_sptoken \expandafter\XINT_xflet_zapsp \else\expandafter\XINT_xflet_zapspB \fi }% \def\XINT_xflet_zapspB {% \expandafter\futurelet\expandafter\XINT_tokenB \expandafter\XINT_xflet_spB?\romannumeral`&&@% }% \def\XINT_xflet_spB? {% \ifx\XINT_tokenB\XINT_sptoken \expandafter\XINT_xflet_zapspB \else\expandafter\XINT_xflet_eq? \fi }% \def\XINT_xflet_eq? {% \ifx\XINT_token\XINT_tokenB \expandafter\XINT_xflet_macro \else\expandafter\XINT_xflet_zapsp \fi }% % \end{macrocode} % \subsection{\csh{xintApplyInline}} % \added{1.09a} %\begin{lverb} % \xintApplyInline\macro{{a}{b}...{z}} has the same effect as % executing \macro{a} and then applying again \xintApplyInline to the shortened % list {{b}...{z}} until nothing is left. This is a non-expandable command % which will result in quicker code than using \xintApplyUnbraced. It f-expands % its second (list) argument first, which may thus be encapsulated in a macro. %\end{lverb} % \changed{1.09c} % Rewritten. Nota bene: uses catcode 3 Z as privated list terminator. % \begin{macrocode} \catcode`Z 3 \long\def\xintApplyInline #1#2% {% \long\expandafter\def\expandafter\XINT_inline_macro \expandafter ##\expandafter 1\expandafter {#1{##1}}% \XINT_xflet\XINT_inline_b #2Z% this Z has catcode 3 }% \def\XINT_inline_b {% \ifx\XINT_token Z\expandafter\xint_gobble_i \else\expandafter\XINT_inline_d\fi }% \long\def\XINT_inline_d #1% {% \long\def\XINT_item{{#1}}\XINT_xflet\XINT_inline_e }% \def\XINT_inline_e {% \ifx\XINT_token Z\expandafter\XINT_inline_w \else\expandafter\XINT_inline_f\fi }% \def\XINT_inline_f {% \expandafter\XINT_inline_g\expandafter{\XINT_inline_macro {##1}}% }% \long\def\XINT_inline_g #1% {% \expandafter\XINT_inline_macro\XINT_item \long\def\XINT_inline_macro ##1{#1}\XINT_inline_d }% \def\XINT_inline_w #1% {% \expandafter\XINT_inline_macro\XINT_item }% % \end{macrocode} % \subsection{\csh{xintFor}, \csh{xintFor*}, \csh{xintBreakFor}, \csh{xintBreakForAndDo}} % \added[2013/10/09]{1.09c} %\begin{lverb} % A new kind of loop which uses macro parameters % #1, #2, #3, #4 rather than macros; while not expandable it survives executing % code closing groups, like what happens in an alignment with the $& character. % When inserted in a macro for later use, the # character must be doubled. % % The non-star variant works on a csv list, which it expands once, the % star variant works on a token list, which it (repeatedly) f-expands. %\end{lverb} % \changed{1.09e} %\begin{lverb} % Adds \XINT_forever with \xintintegers, \xintdimensions, \xintrationals % and \xintBreakFor, \xintBreakForAndDo, \xintifForFirst, \xintifForLast. On % this occasion \xint_firstoftwo and \xint_secondoftwo are made long. %\end{lverb} % \changed[2013/11/03]{1.09f} %\begin{lverb} % Rewrites large parts of \xintFor code in order to filter the comma % separated list via \xintCSVtoList which gets rid of spaces. The #1 in % \XINT_for_forever? has an initial space token which serves two purposes: % preventing brace stripping, and stopping the expansion made by \xintcsvtolist. % If the \XINT_forever branch is taken, the added space will not be a problem % there. % % Now allows all macro parameters % from #1 to #9 in \xintFor, \xintFor*, and \XINT_forever. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Slightly more robust \xintifForFirst/Last in case of nesting. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1#2{\ifnum #2<#1 \xint_afterfi {{#########2}}\fi}% \def\XINT_tmpb #1#2{\ifnum #1<#2 \xint_afterfi {{#########2}}\fi}% \def\XINT_tmpc #1% {% \expandafter\edef \csname XINT_for_left#1\endcsname {\xintApplyUnbraced {\XINT_tmpa #1}{123456789}}% \expandafter\edef \csname XINT_for_right#1\endcsname {\xintApplyUnbraced {\XINT_tmpb #1}{123456789}}% }% \xintApplyInline \XINT_tmpc {123456789}% \long\def\xintBreakFor #1Z{}% \long\def\xintBreakForAndDo #1#2Z{#1}% \def\xintFor {\let\xintifForFirst\xint_firstoftwo \let\xintifForLast\xint_secondoftwo \futurelet\XINT_token\XINT_for_ifstar }% \def\XINT_for_ifstar {\ifx\XINT_token*\expandafter\XINT_forx \else\expandafter\XINT_for \fi }% \catcode`U 3 % with numexpr \catcode`V 3 % with xintfrac.sty (xint.sty not enough) \catcode`D 3 % with dimexpr \def\XINT_flet_zapsp {% \futurelet\XINT_token\XINT_flet_sp? }% \def\XINT_flet_sp? {% \ifx\XINT_token\XINT_sptoken \xint_afterfi{\expandafter\XINT_flet_zapsp\romannumeral0}% \else\expandafter\XINT_flet_macro \fi }% \long\def\XINT_for #1#2in#3#4#5% {% \expandafter\XINT_toks\expandafter {\expandafter\XINT_for_d\the\numexpr #2\relax {#5}}% \def\XINT_flet_macro {\expandafter\XINT_for_forever?\space}% \expandafter\XINT_flet_zapsp #3Z% }% \def\XINT_for_forever? #1Z% {% \ifx\XINT_token U\XINT_to_forever\fi \ifx\XINT_token V\XINT_to_forever\fi \ifx\XINT_token D\XINT_to_forever\fi \expandafter\the\expandafter\XINT_toks\romannumeral0\xintcsvtolist {#1}Z% }% \def\XINT_to_forever\fi #1\xintcsvtolist #2{\fi \XINT_forever #2}% \long\def\XINT_forx *#1#2in#3#4#5% {% \expandafter\XINT_toks\expandafter {\expandafter\XINT_forx_d\the\numexpr #2\relax {#5}}% \XINT_xflet\XINT_forx_forever? #3Z% }% \def\XINT_forx_forever? {% \ifx\XINT_token U\XINT_to_forxever\fi \ifx\XINT_token V\XINT_to_forxever\fi \ifx\XINT_token D\XINT_to_forxever\fi \XINT_forx_empty? }% \def\XINT_to_forxever\fi #1\XINT_forx_empty? {\fi \XINT_forever }% \catcode`U 11 \catcode`D 11 \catcode`V 11 \def\XINT_forx_empty? {% \ifx\XINT_token Z\expandafter\xintBreakFor\fi \the\XINT_toks }% \long\def\XINT_for_d #1#2#3% {% \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% \XINT_toks {{#3}}% \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname \the\XINT_toks \csname XINT_for_right#1\endcsname }% \XINT_toks {\XINT_x\let\xintifForFirst\xint_secondoftwo \let\xintifForLast\xint_secondoftwo\XINT_for_d #1{#2}}% \futurelet\XINT_token\XINT_for_last? }% \long\def\XINT_forx_d #1#2#3% {% \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% \XINT_toks {{#3}}% \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname \the\XINT_toks \csname XINT_for_right#1\endcsname }% \XINT_toks {\XINT_x\let\xintifForFirst\xint_secondoftwo \let\xintifForLast\xint_secondoftwo\XINT_forx_d #1{#2}}% \XINT_xflet\XINT_for_last? }% \def\XINT_for_last? {% \ifx\XINT_token Z\expandafter\XINT_for_last?yes\fi \the\XINT_toks }% \def\XINT_for_last?yes {% \let\xintifForLast\xint_firstoftwo \xintBreakForAndDo{\XINT_x\xint_gobble_i Z}% }% % \end{macrocode} % \subsection{\csh{XINT_forever}, \csh{xintintegers}, \csh{xintdimensions}, \csh{xintrationals}} % \added{1.09e} % \changed{1.09f} %\begin{lverb} % The \xintrationals feature uses % \xintiiadd/\xintiimul to avoid the overhead of the full-blown frac version % \xintAdd and \xintMul. Also 1.09f uses % \xintZapSpacesB in this \xintrationals case to get rid of leading and ending % spaces in the #4 and #5 delimited parameters of \XINT_forever_opt_a. % For \xintintegers and \xintdimensions this is not necessary, due to the use % of \numexpr resp. \dimexpr in \XINT_?expr_Ua, resp.\XINT_?expr_Da. %\end{lverb} % \begin{macrocode} \catcode`U 3 \catcode`D 3 \catcode`V 3 \let\xintegers U% \let\xintintegers U% \let\xintdimensions D% \let\xintrationals V% \def\XINT_forever #1% {% \expandafter\XINT_forever_a \csname XINT_?expr_\ifx#1UU\else\ifx#1DD\else V\fi\fi a\expandafter\endcsname \csname XINT_?expr_\ifx#1UU\else\ifx#1DD\else V\fi\fi i\expandafter\endcsname \csname XINT_?expr_\ifx#1UU\else\ifx#1DD\else V\fi\fi \endcsname }% \catcode`U 11 \catcode`D 11 \catcode`V 11 \def\XINT_?expr_Ua #1#2% {\expandafter{\expandafter\numexpr\the\numexpr #1\expandafter\relax \expandafter\relax\expandafter}% \expandafter{\the\numexpr #2}}% \def\XINT_?expr_Da #1#2% {\expandafter{\expandafter\dimexpr\number\dimexpr #1\expandafter\relax \expandafter s\expandafter p\expandafter\relax\expandafter}% \expandafter{\number\dimexpr #2}}% \catcode`Z 11 \def\XINT_?expr_Va #1#2% {% \expandafter\XINT_?expr_Vb\expandafter {\romannumeral`&&@\xintrawwithzeros{\xintZapSpacesB{#2}}}% {\romannumeral`&&@\xintrawwithzeros{\xintZapSpacesB{#1}}}% }% \catcode`Z 3 \def\XINT_?expr_Vb #1#2{\expandafter\XINT_?expr_Vc #2.#1.}% \def\XINT_?expr_Vc #1/#2.#3/#4.% {% \xintifEq {#2}{#4}% {\XINT_?expr_Vf {#3}{#1}{#2}}% {\expandafter\XINT_?expr_Vd\expandafter {\romannumeral0\xintiimul {#2}{#4}}% {\romannumeral0\xintiimul {#1}{#4}}% {\romannumeral0\xintiimul {#2}{#3}}% }% }% \def\XINT_?expr_Vd #1#2#3{\expandafter\XINT_?expr_Ve\expandafter {#2}{#3}{#1}}% \def\XINT_?expr_Ve #1#2{\expandafter\XINT_?expr_Vf\expandafter {#2}{#1}}% \def\XINT_?expr_Vf #1#2#3{{#2/#3}{{0}{#1}{#2}{#3}}}% \def\XINT_?expr_Ui {{\numexpr 1\relax}{1}}% \def\XINT_?expr_Di {{\dimexpr 0pt\relax}{65536}}% \def\XINT_?expr_Vi {{1/1}{0111}}% \def\XINT_?expr_U #1#2% {\expandafter{\expandafter\numexpr\the\numexpr #1+#2\relax\relax}{#2}}% \def\XINT_?expr_D #1#2% {\expandafter{\expandafter\dimexpr\the\numexpr #1+#2\relax sp\relax}{#2}}% \def\XINT_?expr_V #1#2{\XINT_?expr_Vx #2}% \def\XINT_?expr_Vx #1#2% {% \expandafter\XINT_?expr_Vy\expandafter {\romannumeral0\xintiiadd {#1}{#2}}{#2}% }% \def\XINT_?expr_Vy #1#2#3#4% {% \expandafter{\romannumeral0\xintiiadd {#3}{#1}/#4}{{#1}{#2}{#3}{#4}}% }% \def\XINT_forever_a #1#2#3#4% {% \ifx #4[\expandafter\XINT_forever_opt_a \else\expandafter\XINT_forever_b \fi #1#2#3#4% }% \def\XINT_forever_b #1#2#3Z{\expandafter\XINT_forever_c\the\XINT_toks #2#3}% \long\def\XINT_forever_c #1#2#3#4#5% {\expandafter\XINT_forever_d\expandafter #2#4#5{#3}Z}% \def\XINT_forever_opt_a #1#2#3[#4+#5]#6Z% {% \expandafter\expandafter\expandafter \XINT_forever_opt_c\expandafter\the\expandafter\XINT_toks \romannumeral`&&@#1{#4}{#5}#3% }% \long\def\XINT_forever_opt_c #1#2#3#4#5#6{\XINT_forever_d #2{#4}{#5}#6{#3}Z}% \long\def\XINT_forever_d #1#2#3#4#5% {% \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#5}% \XINT_toks {{#2}}% \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname \the\XINT_toks \csname XINT_for_right#1\endcsname }% \XINT_x \let\xintifForFirst\xint_secondoftwo \let\xintifForLast\xint_secondoftwo \expandafter\XINT_forever_d\expandafter #1\romannumeral`&&@#4{#2}{#3}#4{#5}% }% % \end{macrocode} % \subsection{\csh{xintForpair}, \csh{xintForthree}, \csh{xintForfour}} % \added{1.09c} % \changed[2013/11/02]{1.09f} %\begin{lverb} % \xintForpair delegate to \xintCSVtoList and its % \xintZapSpacesB the handling of spaces. Does not share code with \xintFor % anymore. % % \xintForpair extended to accept #1#2, #2#3 etc... up to % #8#9, \xintForthree, #1#2#3 up to #7#8#9, \xintForfour id. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Slightly more robust \xintifForFirst/\xintifForLast in case of nesting. %\end{lverb} % \changed[2025/06/08]{1.4n} %\begin{lverb} % Allow one final extraneous comma (formerly, such input caused a crash). % This goes via testing an extra token #6, which should be an opening parenthesis. % The potential brace removal changes behavior for illegal inputs. % Successive commas in the input list are still not allowed. %\end{lverb} % \begin{macrocode} \catcode`j 3 \long\def\xintForpair #1#2#3in#4#5#6% {% \let\xintifForFirst\xint_firstoftwo \let\xintifForLast\xint_secondoftwo \XINT_toks {\XINT_forpair_d #2{#6}}% \expandafter\the\expandafter\XINT_toks #4jZ% }% \long\def\XINT_forpair_d #1#2#3(#4)#5#6% {% \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% \XINT_toks \expandafter{\romannumeral0\xintcsvtolist{ #4}}% \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname \the\XINT_toks \csname XINT_for_right\the\numexpr#1+\xint_c_i\endcsname}% \if1\ifx #5j1\else\ifx#6j1\else0\fi\fi\expandafter\XINT_for_last?yes\fi \XINT_x \let\xintifForFirst\xint_secondoftwo \let\xintifForLast\xint_secondoftwo \XINT_forpair_d #1{#2}#6% }% \long\def\xintForthree #1#2#3in#4#5#6% {% \let\xintifForFirst\xint_firstoftwo \let\xintifForLast\xint_secondoftwo \XINT_toks {\XINT_forthree_d #2{#6}}% \expandafter\the\expandafter\XINT_toks #4jZ% }% \long\def\XINT_forthree_d #1#2#3(#4)#5#6% {% \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% \XINT_toks \expandafter{\romannumeral0\xintcsvtolist{ #4}}% \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname \the\XINT_toks \csname XINT_for_right\the\numexpr#1+\xint_c_ii\endcsname}% \if1\ifx #5j1\else\ifx#6j1\else0\fi\fi\expandafter\XINT_for_last?yes\fi \XINT_x \let\xintifForFirst\xint_secondoftwo \let\xintifForLast\xint_secondoftwo \XINT_forthree_d #1{#2}#6% }% \long\def\xintForfour #1#2#3in#4#5#6% {% \let\xintifForFirst\xint_firstoftwo \let\xintifForLast\xint_secondoftwo \XINT_toks {\XINT_forfour_d #2{#6}}% \expandafter\the\expandafter\XINT_toks #4jZ% }% \long\def\XINT_forfour_d #1#2#3(#4)#5#6% {% \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% \XINT_toks \expandafter{\romannumeral0\xintcsvtolist{ #4}}% \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname \the\XINT_toks \csname XINT_for_right\the\numexpr#1+\xint_c_iii\endcsname}% \if1\ifx #5j1\else\ifx#6j1\else0\fi\fi\expandafter\XINT_for_last?yes\fi \XINT_x \let\xintifForFirst\xint_secondoftwo \let\xintifForLast\xint_secondoftwo \XINT_forfour_d #1{#2}#6% }% \catcode`Z 11 \catcode`j 11 % \end{macrocode} % \subsection{\csh{xintAssign}} %\begin{lverb} % \xintAssign {a}{b}..{z}\to\A\B...\Z %\end{lverb} % \changed[2015/09/12]{1.1c} %\begin{lverb} % Belatedly corrects some "features" of % \xintAssign which didn't like the case of a space right before the "\to", or % the case with the first token not an opening brace and the subsequent % material containing brace groups. The new code handles gracefully these % situations. %\end{lverb} % \begin{macrocode} \def\xintAssign{\def\XINT_flet_macro {\XINT_assign_fork}\XINT_flet_zapsp }% \def\XINT_assign_fork {% \let\XINT_assign_def\def \ifx\XINT_token[\expandafter\XINT_assign_opt \else\expandafter\XINT_assign_a \fi }% \def\XINT_assign_opt [#1]% {% \ifcsname #1def\endcsname \expandafter\let\expandafter\XINT_assign_def \csname #1def\endcsname \else \expandafter\let\expandafter\XINT_assign_def \csname xint#1def\endcsname \fi \XINT_assign_a }% \long\def\XINT_assign_a #1\to {% \def\XINT_flet_macro{\XINT_assign_b}% \expandafter\XINT_flet_zapsp\romannumeral`&&@#1\xint:\to }% \long\def\XINT_assign_b {% \ifx\XINT_token\bgroup \expandafter\XINT_assign_c \else\expandafter\XINT_assign_f \fi }% \long\def\XINT_assign_f #1\xint:\to #2% {% \XINT_assign_def #2{#1}% }% \long\def\XINT_assign_c #1% {% \def\XINT_assign_tmp {#1}% \ifx\XINT_assign_tmp\xint_bracedstopper \expandafter\XINT_assign_e \else \expandafter\XINT_assign_d \fi }% \long\def\XINT_assign_d #1\to #2% {% \expandafter\XINT_assign_def\expandafter #2\expandafter{\XINT_assign_tmp}% \XINT_assign_c #1\to }% \def\XINT_assign_e #1\to {}% \def\xintRelaxArray #1% {% \edef\XINT_restoreescapechar {\escapechar\the\escapechar\relax}% \escapechar -1 \expandafter\def\expandafter\xint_arrayname\expandafter {\string #1}% \XINT_restoreescapechar \xintiloop [\csname\xint_arrayname 0\endcsname+-1] \global \expandafter\let\csname\xint_arrayname\xintiloopindex\endcsname\relax \ifnum \xintiloopindex > \xint_c_ \repeat \global\expandafter\let\csname\xint_arrayname 00\endcsname\relax \global\let #1\relax }% % \end{macrocode} % \subsection{\csh{xintAssignArray}, \csh{xintDigitsOf}} %\begin{lverb} % \xintAssignArray {a}{b}..{z}\to\U. % % \xintDigitsOf=\xintAssignArray. %\end{lverb} % \changed{1.4p} % Allow usage of the array macro with a negative index. % \begin{macrocode} \def\xintAssignArray{\def\XINT_flet_macro {\XINT_assignarray_fork}% \XINT_flet_zapsp }% \def\XINT_assignarray_fork {% \let\XINT_assignarray_def\def \ifx\XINT_token[\expandafter\XINT_assignarray_opt \else\expandafter\XINT_assignarray \fi }% \def\XINT_assignarray_opt [#1]% {% \ifcsname #1def\endcsname \expandafter\let\expandafter\XINT_assignarray_def \csname #1def\endcsname \else \expandafter\let\expandafter\XINT_assignarray_def \csname xint#1def\endcsname \fi \XINT_assignarray }% % \end{macrocode} % Very old code got refactored at |1.4p|. Hesitation about using |\XINT_tmpa| % or like here potential ganer is used by caller. % \begin{macrocode} \long\def\XINT_assignarray #1\to #2% {% \edef\XINT_restoreescapechar {\escapechar\the\escapechar\relax }% \escapechar -1 \expandafter\def\expandafter\XINT_arrayname\expandafter {\string #2}% \XINT_restoreescapechar \def\XINT_itemcount {0}% \expandafter\XINT_assignarray_loop \romannumeral`&&@#1\xint:#2% }% \long\def\XINT_assignarray_loop #1% {% \def\XINT_assign_tmp {#1}% \ifx\XINT_assign_tmp\xint_bracedstopper \expandafter\let\csname\XINT_arrayname0\endcsname\XINT_itemcount \expandafter\XINT_assignarray_end \else \edef\XINT_itemcount{\the\numexpr\XINT_itemcount+\xint_c_i}% \expandafter\XINT_assignarray_def \csname\XINT_arrayname\XINT_itemcount\expandafter\endcsname \expandafter{\XINT_assign_tmp }% \expandafter\XINT_assignarray_loop \fi }% % \end{macrocode} % \changed{1.4p} Allow negative index, handled as in Python % (positive index retains former meaning, i.e.\@ starts at 1). % % This very old code from 2013 got refactored on this occasion. Code style % hackier. A bit annoying though that |\expandafter\expandafter\expandafter|, % because of |\csname|. Would have been easier to incorporate the terminator % in the |\foo| macro itself but I feared this would be too unexpected in % case of needs of some direct hacking. % % On this occasion the number of items, which is used by |\foo| to test % if the index is out of range is now present via its explicit tokens % rather than via encapsulation |\foo0|. % %\begin{lverb} % #4 is \foo, #3 is foo, #2 is the number of items, and #1 is \foo00. % The Nth item is in \foo. %\end{lverb} % \begin{macrocode} \def\XINT_assignarray_end {% \expandafter\XINT_assignarray_endend \csname\XINT_arrayname00\expandafter\endcsname \expanded{{\XINT_itemcount}{\XINT_arrayname}}% }% \def\XINT_assignarray_endend #1#2#3#4% {% \def #4##1% {% \romannumeral\expandafter\expandafter\expandafter \xint_c_\csname\expandafter#1\the\numexpr ##1.% }% \def #1##1##2.% {% \ifnum\if-##1\else##1\fi##2>#2 \expanded{\noexpand\XINT_expandableerror {Illegal index ##1##2 (\if-##1< -\else> \fi #2) for \string#4}}% empty% \else #3\if-##1\the\numexpr\xint_c_i+#2\fi ##1##2% \fi \endcsname }% }% \let\xintDigitsOf\xintAssignArray % \end{macrocode} % \subsection{CSV (non user documented) variants of Length, Keep, Trim, NthElt, Reverse} % \changed{1.2j} % These routines are for use by |\xintListSel:x:csv| and |\xintListSel:f:csv| % from \xintexprnameimp, and also for the |reversed| and |len| functions. % Refactored for |1.2j| release, following |1.2i| updates to |\xintKeep|, % |\xintTrim|, ... % % These macros will remain undocumented in the user manual: % % -- they exist primarily for internal use by the \xintexprnameimp parsers, % hence don't have to be general purpose; for example, they a priori need to % handle only catcode 12 tokens (not true in |\xintNewExpr|, though) % hence they are not really worried about % controlling brace stripping (nevertheless |1.2j| has paid some secondary % attention to it, see below.) They are not worried about normalizing leading % spaces either, because none will be encountered when the macros are used as % auxiliaries to the expression parsers. % % -- crucial design elements may change in future: % % 1. whether the handled lists must have or not have a final comma. Currently, % the model is the one of comma separated lists with **no** final comma. But % this means that there can not be a distinction of principle between a truly % empty list and a list which contains one item which turns out to be empty. % More importantly it makes the coding more complicated as it is needed to % distinguish the empty list from the single-item list, both lacking commas. % % For the internal use of \xintexprnameimp, it would be ok to require all list % items to be terminated by a comma, and this would bring quite some % simplications here, but as initially I started with non-terminated lists, I % have left it this way in the |1.2j| refactoring. % % 2. the way to represent the empty list. I was tempted for matter of % optimization and synchronization with \xintexprnameimp context to require % the empty list to be always represented by a space token and to not let the % macros admit a completely empty input. But there were complications so for % the time being |1.2j| does accept truly empty output (it is not % distinguished from an input equal to a space token) and produces empty % output for empty list. This means that the status of the «nil» object for % the \xintexprnameimp parsers is not completely clarified (currently it is % represented by a space token). % % The original Python slicing code in \xintexprnameimp |1.1| used % |\xintCSVtoList| and |\xintListWithSep{,}| to convert back and forth to % token lists and apply |\xintKeep/\xintTrim|. Release |1.2g| switched to % devoted f-expandable macros added to \xinttoolsnameimp. Release |1.2j| % refactored all these macros as a follow-up to |1.2i| improvements to % |\xintKeep/\xintTrim|. They were made |\long| on this occasion and % auxiliary |\xintLengthUpTo:f:csv| was added. % % Leading spaces in items are currently maintained as is by the |1.2j| % macros, even by |\xintNthEltPy:f:csv|, with the exception of the first item, % as the list is f-expanded. Perhaps |\xintNthEltPy:f:csv| should remove a % leading space if present in the picked item; anyway, there are no spaces % for the lists handled internally by the Python slicer of \xintexprnameimp, % except the «nil» object currently represented by exactly one space. % % Kept items (with no leading spaces; but first item special as it will have % lost a leading space due to f-expansion) will lose a brace pair under % |\xintKeep:f:csv| if the first argument was positive and strictly less than % the length of the list. This differs of course from |\xintKeep| (which % always braces items it outputs when used with positive first argument) and % also from |\xintKeepUnbraced| in the case when the whole list is kept. % Actually the case of singleton list is special, and brace removal will % happen then. % % This behaviour was otherwise for releases earlier than |1.2j| and may % change again. % % Directly usable names are provided, but these macros (and the behaviour as % described above) are to be considered \emph{unstable} for the time being. % % \subsubsection{\csh{xintLength:f:csv}} % \added{1.2g} % \changed{1.2j} % Contrarily to |\xintLength| from \xintkernelnameimp % this one expands its argument. % \begin{macrocode} \def\xintLength:f:csv {\romannumeral0\xintlength:f:csv}% \def\xintlength:f:csv #1% {\long\def\xintlength:f:csv ##1{% \expandafter#1\the\numexpr\expandafter\XINT_length:f:csv_a \romannumeral`&&@##1\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,\xint:,% \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye \relax }}\xintlength:f:csv { }% % \end{macrocode} %\begin{lverb} % Must first check if empty list. %\end{lverb} % \begin{macrocode} \long\def\XINT_length:f:csv_a #1% {% \xint_gob_til_xint: #1\xint_c_\xint_bye\xint:% \XINT_length:f:csv_loop #1% }% \long\def\XINT_length:f:csv_loop #1,#2,#3,#4,#5,#6,#7,#8,#9,% {% \xint_gob_til_xint: #9\XINT_length:f:csv_finish\xint:% \xint_c_ix+\XINT_length:f:csv_loop }% \def\XINT_length:f:csv_finish\xint:\xint_c_ix+\XINT_length:f:csv_loop #1,#2,#3,#4,#5,#6,#7,#8,#9,{#9\xint_bye}% % \end{macrocode} % \subsubsection{\csh{xintLengthUpTo:f:csv}} % \added{1.2j} %\begin{lverb} % \added{1.2j}\xintLengthUpTo:f:csv{N}{comma-list}. No ending comma. Returns % -0 if length>N, else returns difference N-length. **N must be non-negative!!** % % Attention to the dot after \xint_bye for the loop interface. %\end{lverb} % \begin{macrocode} \def\xintLengthUpTo:f:csv {\romannumeral0\xintlengthupto:f:csv}% \long\def\xintlengthupto:f:csv #1#2% {% \expandafter\XINT_lengthupto:f:csv_a \the\numexpr#1\expandafter.% \romannumeral`&&@#2\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,% \xint_c_viii,\xint_c_vii,\xint_c_vi,\xint_c_v,% \xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye.% }% % \end{macrocode} %\begin{lverb} % Must first recognize if empty list. If this is the case, return N. %\end{lverb} % \begin{macrocode} \long\def\XINT_lengthupto:f:csv_a #1.#2% {% \xint_gob_til_xint: #2\XINT_lengthupto:f:csv_empty\xint:% \XINT_lengthupto:f:csv_loop_b #1.#2% }% \def\XINT_lengthupto:f:csv_empty\xint:% \XINT_lengthupto:f:csv_loop_b #1.#2\xint_bye.{ #1}% \def\XINT_lengthupto:f:csv_loop_a #1% {% \xint_UDsignfork #1\XINT_lengthupto:f:csv_gt -\XINT_lengthupto:f:csv_loop_b \krof #1% }% \long\def\XINT_lengthupto:f:csv_gt #1\xint_bye.{-0}% \long\def\XINT_lengthupto:f:csv_loop_b #1.#2,#3,#4,#5,#6,#7,#8,#9,% {% \xint_gob_til_xint: #9\XINT_lengthupto:f:csv_finish_a\xint:% \expandafter\XINT_lengthupto:f:csv_loop_a\the\numexpr #1-\xint_c_viii.% }% \def\XINT_lengthupto:f:csv_finish_a\xint: \expandafter\XINT_lengthupto:f:csv_loop_a \the\numexpr #1-\xint_c_viii.#2,#3,#4,#5,#6,#7,#8,#9,% {% \expandafter\XINT_lengthupto:f:csv_finish_b\the\numexpr #1-#9\xint_bye }% \def\XINT_lengthupto:f:csv_finish_b #1#2.% {% \xint_UDsignfork #1{-0}% -{ #1#2}% \krof }% % \end{macrocode} % \subsubsection{\csh{xintKeep:f:csv}} % \added[2016/03/17]{1.2g} % \changed{1.2j} %\begin{lverb} % Redone with use of \xintLengthUpTo:f:csv. % Same code skeleton as \xintKeep but handling comma separated but non % terminated lists has complications. The \xintKeep in case of a negative #1 % uses \xintgobble, we don't have that for comma delimited items, hence we do % a special loop here (this style of loop is surely competitive with % xintgobble for a few dozens items and even more). The loop knows before % starting that it will not go too far. % %\end{lverb} % \begin{macrocode} \def\xintKeep:f:csv {\romannumeral0\xintkeep:f:csv }% \long\def\xintkeep:f:csv #1#2% {% \expandafter\xint_stop_aftergobble \romannumeral0\expandafter\XINT_keep:f:csv_a \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% }% \def\XINT_keep:f:csv_a #1% {% \xint_UDzerominusfork #1-\XINT_keep:f:csv_keepnone 0#1\XINT_keep:f:csv_neg 0-{\XINT_keep:f:csv_pos #1}% \krof }% \long\def\XINT_keep:f:csv_keepnone .#1{,}% \long\def\XINT_keep:f:csv_neg #1.#2% {% \expandafter\XINT_keep:f:csv_neg_done\expandafter,% \romannumeral0% \expandafter\XINT_keep:f:csv_neg_a\the\numexpr #1-\numexpr\XINT_length:f:csv_a #2\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,\xint:,% \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye .#2\xint_bye }% \def\XINT_keep:f:csv_neg_a #1% {% \xint_UDsignfork #1{\expandafter\XINT_keep:f:csv_trimloop\the\numexpr-\xint_c_ix+}% -\XINT_keep:f:csv_keepall \krof }% \def\XINT_keep:f:csv_keepall #1.{ }% \long\def\XINT_keep:f:csv_neg_done #1\xint_bye{#1}% \def\XINT_keep:f:csv_trimloop #1#2.% {% \xint_gob_til_minus#1\XINT_keep:f:csv_trimloop_finish-% \expandafter\XINT_keep:f:csv_trimloop \the\numexpr#1#2-\xint_c_ix\expandafter.\XINT_keep:f:csv_trimloop_trimnine }% \long\def\XINT_keep:f:csv_trimloop_trimnine #1,#2,#3,#4,#5,#6,#7,#8,#9,{}% \def\XINT_keep:f:csv_trimloop_finish-% \expandafter\XINT_keep:f:csv_trimloop \the\numexpr-#1-\xint_c_ix\expandafter.\XINT_keep:f:csv_trimloop_trimnine {\csname XINT_trim:f:csv_finish#1\endcsname}% \long\def\XINT_keep:f:csv_pos #1.#2% {% \expandafter\XINT_keep:f:csv_pos_fork \romannumeral0\XINT_lengthupto:f:csv_a #1.#2\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,% \xint_c_viii,\xint_c_vii,\xint_c_vi,\xint_c_v,% \xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye.% .#1.{}#2\xint_bye% }% \def\XINT_keep:f:csv_pos_fork #1#2.% {% \xint_UDsignfork #1{\expandafter\XINT_keep:f:csv_loop\the\numexpr-\xint_c_viii+}% -\XINT_keep:f:csv_pos_keepall \krof }% \long\def\XINT_keep:f:csv_pos_keepall #1.#2#3\xint_bye{,#3}% \def\XINT_keep:f:csv_loop #1#2.% {% \xint_gob_til_minus#1\XINT_keep:f:csv_loop_end-% \expandafter\XINT_keep:f:csv_loop \the\numexpr#1#2-\xint_c_viii\expandafter.\XINT_keep:f:csv_loop_pickeight }% \long\def\XINT_keep:f:csv_loop_pickeight #1#2,#3,#4,#5,#6,#7,#8,#9,{{#1,#2,#3,#4,#5,#6,#7,#8,#9}}% \def\XINT_keep:f:csv_loop_end-\expandafter\XINT_keep:f:csv_loop \the\numexpr-#1-\xint_c_viii\expandafter.\XINT_keep:f:csv_loop_pickeight {\csname XINT_keep:f:csv_end#1\endcsname}% \long\expandafter\def\csname XINT_keep:f:csv_end1\endcsname #1#2,#3,#4,#5,#6,#7,#8,#9\xint_bye {#1,#2,#3,#4,#5,#6,#7,#8}% \long\expandafter\def\csname XINT_keep:f:csv_end2\endcsname #1#2,#3,#4,#5,#6,#7,#8\xint_bye {#1,#2,#3,#4,#5,#6,#7}% \long\expandafter\def\csname XINT_keep:f:csv_end3\endcsname #1#2,#3,#4,#5,#6,#7\xint_bye {#1,#2,#3,#4,#5,#6}% \long\expandafter\def\csname XINT_keep:f:csv_end4\endcsname #1#2,#3,#4,#5,#6\xint_bye {#1,#2,#3,#4,#5}% \long\expandafter\def\csname XINT_keep:f:csv_end5\endcsname #1#2,#3,#4,#5\xint_bye {#1,#2,#3,#4}% \long\expandafter\def\csname XINT_keep:f:csv_end6\endcsname #1#2,#3,#4\xint_bye {#1,#2,#3}% \long\expandafter\def\csname XINT_keep:f:csv_end7\endcsname #1#2,#3\xint_bye {#1,#2}% \long\expandafter\def\csname XINT_keep:f:csv_end8\endcsname #1#2\xint_bye {#1}% % \end{macrocode} % \subsubsection{\csh{xintTrim:f:csv}} % \added[2016/03/17]{1.2g} % \changed[2016/12/20]{1.2j} % Redone on the basis of new |\xintTrim|. % \begin{macrocode} \def\xintTrim:f:csv {\romannumeral0\xinttrim:f:csv }% \long\def\xinttrim:f:csv #1#2% {% \expandafter\xint_stop_aftergobble \romannumeral0\expandafter\XINT_trim:f:csv_a \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% }% \def\XINT_trim:f:csv_a #1% {% \xint_UDzerominusfork #1-\XINT_trim:f:csv_trimnone 0#1\XINT_trim:f:csv_neg 0-{\XINT_trim:f:csv_pos #1}% \krof }% \long\def\XINT_trim:f:csv_trimnone .#1{,#1}% \long\def\XINT_trim:f:csv_neg #1.#2% {% \expandafter\XINT_trim:f:csv_neg_a\the\numexpr #1-\numexpr\XINT_length:f:csv_a #2\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,\xint:,% \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye .{}#2\xint_bye }% \def\XINT_trim:f:csv_neg_a #1% {% \xint_UDsignfork #1{\expandafter\XINT_keep:f:csv_loop\the\numexpr-\xint_c_viii+}% -\XINT_trim:f:csv_trimall \krof }% \def\XINT_trim:f:csv_trimall {\expandafter,\xint_bye}% \long\def\XINT_trim:f:csv_pos #1.#2% {% \expandafter\XINT_trim:f:csv_pos_done\expandafter,% \romannumeral0% \expandafter\XINT_trim:f:csv_loop\the\numexpr#1-\xint_c_ix.% #2\xint:,\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,\xint:\xint_bye }% \def\XINT_trim:f:csv_loop #1#2.% {% \xint_gob_til_minus#1\XINT_trim:f:csv_finish-% \expandafter\XINT_trim:f:csv_loop\the\numexpr#1#2\XINT_trim:f:csv_loop_trimnine }% \long\def\XINT_trim:f:csv_loop_trimnine #1,#2,#3,#4,#5,#6,#7,#8,#9,% {% \xint_gob_til_xint: #9\XINT_trim:f:csv_toofew\xint:-\xint_c_ix.% }% \def\XINT_trim:f:csv_toofew\xint:{*\xint_c_}% \def\XINT_trim:f:csv_finish-% \expandafter\XINT_trim:f:csv_loop\the\numexpr-#1\XINT_trim:f:csv_loop_trimnine {% \csname XINT_trim:f:csv_finish#1\endcsname }% \long\expandafter\def\csname XINT_trim:f:csv_finish1\endcsname #1,#2,#3,#4,#5,#6,#7,#8,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish2\endcsname #1,#2,#3,#4,#5,#6,#7,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish3\endcsname #1,#2,#3,#4,#5,#6,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish4\endcsname #1,#2,#3,#4,#5,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish5\endcsname #1,#2,#3,#4,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish6\endcsname #1,#2,#3,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish7\endcsname #1,#2,{ }% \long\expandafter\def\csname XINT_trim:f:csv_finish8\endcsname #1,{ }% \expandafter\let\csname XINT_trim:f:csv_finish9\endcsname\space \long\def\XINT_trim:f:csv_pos_done #1\xint:#2\xint_bye{#1}% % \end{macrocode} % \subsubsection{\csh{xintNthEltPy:f:csv}} %\begin{lverb} % Counts like Python starting at zero. Last refactored with 1.2j. % Attention, makes currently no effort at removing leading spaces in the % picked item. %\end{lverb} % \begin{macrocode} \def\xintNthEltPy:f:csv {\romannumeral0\xintntheltpy:f:csv }% \long\def\xintntheltpy:f:csv #1#2% {% \expandafter\XINT_nthelt:f:csv_a \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% }% \def\XINT_nthelt:f:csv_a #1% {% \xint_UDsignfork #1\XINT_nthelt:f:csv_neg -\XINT_nthelt:f:csv_pos \krof #1% }% \long\def\XINT_nthelt:f:csv_neg -#1.#2% {% \expandafter\XINT_nthelt:f:csv_neg_fork \the\numexpr\XINT_length:f:csv_a #2\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,\xint:,% \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye -#1.#2,\xint_bye }% \def\XINT_nthelt:f:csv_neg_fork #1% {% \if#1-\expandafter\xint_stop_afterbye\fi \expandafter\XINT_nthelt:f:csv_neg_done \romannumeral0% \expandafter\XINT_keep:f:csv_trimloop\the\numexpr-\xint_c_ix+#1% }% \long\def\XINT_nthelt:f:csv_neg_done#1,#2\xint_bye{ #1}% \long\def\XINT_nthelt:f:csv_pos #1.#2% {% \expandafter\XINT_nthelt:f:csv_pos_done \romannumeral0% \expandafter\XINT_trim:f:csv_loop\the\numexpr#1-\xint_c_ix.% #2\xint:,\xint:,\xint:,\xint:,\xint:,% \xint:,\xint:,\xint:,\xint:,\xint:,\xint_bye }% \def\XINT_nthelt:f:csv_pos_done #1{% \long\def\XINT_nthelt:f:csv_pos_done ##1,##2\xint_bye{% \xint_gob_til_xint:##1\XINT_nthelt:f:csv_pos_cleanup\xint:#1##1}% }\XINT_nthelt:f:csv_pos_done{ }% % \end{macrocode} %\begin{lverb} % This strange thing is in case the picked item was the last one, hence % there was an ending \xint: (we could not put a comma earlier for % matters of not confusing empty list with a singleton list), and we do this % here to activate brace-stripping of item as all other items may be % brace-stripped if picked. This is done for coherence. Of course, in the % context of the xintexpr.sty parsers, there are no braces in list items... %\end{lverb} % \begin{macrocode} \xint_firstofone{\long\def\XINT_nthelt:f:csv_pos_cleanup\xint:} % #1\xint:{ #1}% % \end{macrocode} % \subsubsection{\csh{xintReverse:f:csv}} % \added[2016/03/17]{1.2g} %\begin{lverb} % Contrarily to \xintReverseOrder from xintkernel.sty, this % one expands its argument. Handles empty list too. . %\end{lverb} % \changed{1.2j} Made |\long|. % \begin{macrocode} \def\xintReverse:f:csv {\romannumeral0\xintreverse:f:csv }% \long\def\xintreverse:f:csv #1% {% \expandafter\XINT_reverse:f:csv_loop \expandafter{\expandafter}\romannumeral`&&@#1,% \xint:,% \xint_bye,\xint_bye,\xint_bye,\xint_bye,% \xint_bye,\xint_bye,\xint_bye,\xint_bye,% \xint: }% \long\def\XINT_reverse:f:csv_loop #1#2,#3,#4,#5,#6,#7,#8,#9,% {% \xint_bye #9\XINT_reverse:f:csv_cleanup\xint_bye \XINT_reverse:f:csv_loop {,#9,#8,#7,#6,#5,#4,#3,#2#1}% }% \long\def\XINT_reverse:f:csv_cleanup\xint_bye\XINT_reverse:f:csv_loop #1#2\xint: {% \XINT_reverse:f:csv_finish #1% }% \long\def\XINT_reverse:f:csv_finish #1\xint:,{ }% % \end{macrocode} % \subsubsection{\csh{xintFirstItem:f:csv}} % \added{1.2k} %\begin{lverb} % For use by first() in % \xintexpr-essions, and some amount of compatibility with \xintNewExpr. %\end{lverb} % \begin{macrocode} \def\xintFirstItem:f:csv {\romannumeral0\xintfirstitem:f:csv}% \long\def\xintfirstitem:f:csv #1% {% \expandafter\XINT_first:f:csv_a\romannumeral`&&@#1,\xint_bye }% \long\def\XINT_first:f:csv_a #1,#2\xint_bye{ #1}% % \end{macrocode} % \subsubsection{\csh{xintLastItem:f:csv}} % \added{1.2k} %\begin{lverb} % Based on and sharing code with xintkernel's % \xintLastItem from 1.2i. Output empty if input empty. f-expands its argument % (hence first item, if not protected.) For use by last() in % \xintexpr-essions with to some extent \xintNewExpr compatibility. %\end{lverb} % \begin{macrocode} \def\xintLastItem:f:csv {\romannumeral0\xintlastitem:f:csv}% \long\def\xintlastitem:f:csv #1% {% \expandafter\XINT_last:f:csv_loop\expandafter{\expandafter}\expandafter.% \romannumeral`&&@#1,% \xint:\XINT_last_loop_enda,\xint:\XINT_last_loop_endb,% \xint:\XINT_last_loop_endc,\xint:\XINT_last_loop_endd,% \xint:\XINT_last_loop_ende,\xint:\XINT_last_loop_endf,% \xint:\XINT_last_loop_endg,\xint:\XINT_last_loop_endh,\xint_bye }% \long\def\XINT_last:f:csv_loop #1.#2,#3,#4,#5,#6,#7,#8,#9,% {% \xint_gob_til_xint: #9% {#8}{#7}{#6}{#5}{#4}{#3}{#2}{#1}\xint: \XINT_last:f:csv_loop {#9}.% }% % \end{macrocode} % \subsubsection{\csh{xintKeep:x:csv}} % \added{1.2j} To \xintexprnameimp. Moved here at |1.4|. % Not part of % publicly supported macros, may be removed at any time. % \begin{macrocode} \def\xintKeep:x:csv #1#2% {% \expandafter\xint_gobble_i \romannumeral0\expandafter\XINT_keep:x:csv_pos \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% }% \def\XINT_keep:x:csv_pos #1.#2% {% \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% #2\xint_Bye,\xint_Bye,\xint_Bye,\xint_Bye,% \xint_Bye,\xint_Bye,\xint_Bye,\xint_Bye,\xint_bye }% \def\XINT_keep:x:csv_loop #1% {% \xint_gob_til_minus#1\XINT_keep:x:csv_finish-% \XINT_keep:x:csv_loop_pickeight #1% }% \def\XINT_keep:x:csv_loop_pickeight #1.#2,#3,#4,#5,#6,#7,#8,#9,% {% ,#2,#3,#4,#5,#6,#7,#8,#9% \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% }% \def\XINT_keep:x:csv_finish-\XINT_keep:x:csv_loop_pickeight -#1.% {% \csname XINT_keep:x:csv_finish#1\endcsname }% \expandafter\def\csname XINT_keep:x:csv_finish1\endcsname #1,#2,#3,#4,#5,#6,#7,{,#1,#2,#3,#4,#5,#6,#7\xint_Bye}% \expandafter\def\csname XINT_keep:x:csv_finish2\endcsname #1,#2,#3,#4,#5,#6,{,#1,#2,#3,#4,#5,#6\xint_Bye}% \expandafter\def\csname XINT_keep:x:csv_finish3\endcsname #1,#2,#3,#4,#5,{,#1,#2,#3,#4,#5\xint_Bye}% \expandafter\def\csname XINT_keep:x:csv_finish4\endcsname #1,#2,#3,#4,{,#1,#2,#3,#4\xint_Bye}% \expandafter\def\csname XINT_keep:x:csv_finish5\endcsname #1,#2,#3,{,#1,#2,#3\xint_Bye}% \expandafter\def\csname XINT_keep:x:csv_finish6\endcsname #1,#2,{,#1,#2\xint_Bye}% \expandafter\def\csname XINT_keep:x:csv_finish7\endcsname #1,{,#1\xint_Bye}% \expandafter\let\csname XINT_keep:x:csv_finish8\endcsname\xint_Bye % \end{macrocode} % \subsubsection{Public names for the undocumented csv macros: % \csh{xintCSVLength}, \csh{xintCSVKeep}, \csh{xintCSVKeepx}, \csh{xintCSVTrim}, % \csh{xintCSVNthEltPy}, \csh{xintCSVReverse}, % \csh{xintCSVFirstItem}, \csh{xintCSVLastItem}} % %\begin{lverb} % Completely unstable macros: currently they expand the list argument % and want no final comma. But for matters of xintexpr.sty I could as well % decide to require a final comma, and then I could simplify implementation % but of course this would break the macros if used with current % functionalities. %\end{lverb} % \begin{macrocode} \let\xintCSVLength \xintLength:f:csv \let\xintCSVKeep \xintKeep:f:csv \let\xintCSVKeepx \xintKeep:x:csv \let\xintCSVTrim \xintTrim:f:csv \let\xintCSVNthEltPy \xintNthEltPy:f:csv \let\xintCSVReverse \xintReverse:f:csv \let\xintCSVFirstItem\xintFirstItem:f:csv \let\xintCSVLastItem \xintLastItem:f:csv \let\XINT_tmpa\relax \let\XINT_tmpb\relax \let\XINT_tmpc\relax \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xinttools} % \cleardoublepage\let\xinttoolsnameUp\undefined %\gardesactifs %\let\relax %\let<*xintcore>\gardesinactifs %^^A-------------------------------------------------- %<*xintcore>^^A--------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintcorenameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintcorenameimp implementation} % \RaisedLabel{sec:coreimp} % % \localtableofcontents % % \subsection{Introduction} % % Got split off from \xintnameimp with release |1.1|. % % The core arithmetic routines have been entirely rewritten for release % |1.2|. The |1.2i| and |1.2l| brought again some improvements. % % The commenting continues (\xintbndldate) to be very sparse: actually it got % worse than ever with release |1.2|. I will possibly add comments at a % later date, but for the time being the new routines are not commented at % all. % % |1.3| removes all macros which were deprecated at |1.2o|. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintcore.sty\endcsname \expandafter\let\expandafter\c\csname ver@calxcore.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintcore Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintcore}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xintcore.sty \ifx\c\relax % but calxcore.sty not yet loaded. \def\z{\endgroup\input calxcore.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\c\relax % calxcore.sty not yet loaded. \def\z{\endgroup\RequirePackage{calxcore}}% \fi \else \def\z{\endgroup\endinput}% xintkernel already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintcore}% [2026/11/01 v2.0a1 Expandable arithmetic on big integers (JFB)]% % \end{macrocode} % \subsection{Legacy error reporting} %\begin{lverb} % Legacy integer and rational routines cannot represent NaN or infinity. % Their error path always raises the condition's signal flag, emits an % expandable error, and returns the caller's fallback value. There are no % configurable traps or handlers. % % Syntax (f-expandable): %( % \XINT_legacysignalcondition{C}{M}{H}{V} -> V %) % H is ignored, as in the original trapped-signal path. %\end{lverb} % \begin{macrocode} \catcode`- 11 \def\XINT_ConversionSyntax-signal {{InvalidOperation}}% \let\XINT_DivisionImpossible-signal\XINT_ConversionSyntax-signal \let\XINT_DivisionUndefined-signal \XINT_ConversionSyntax-signal \let\XINT_InvalidContext-signal \XINT_ConversionSyntax-signal \catcode`- 12 \def\XINT_legacysignalcondition #1{\expandafter\XINT_legacysignalcondition_a \romannumeral0\ifcsname XINT_#1-signal\endcsname \xint_dothis{\csname XINT_#1-signal\endcsname}% \fi\xint_orthat{{#1}}{#1}}% \def\XINT_legacysignalcondition_a #1#2#3#4#5{% \expandafter\xint_gobble_i\csname XINT_#1Flag_ON\endcsname \XINT_expandableerror{#3}% \xint_firstofone{#5}% }% \def\XINT_ifFlagRaised #1{% \ifcsname XINT_#1Flag_ON\endcsname \expandafter\xint_firstoftwo \else \expandafter\xint_secondoftwo \fi}% \def\XINT_resetFlag #1% {\expandafter\let\csname XINT_#1Flag_ON\endcsname\XINT_undefined}% \def\XINT_resetFlags {% \XINT_resetFlag{InvalidOperation}% \XINT_resetFlag{DivisionByZero}% \XINT_resetFlag{Underflow}% \XINT_resetFlag{Overflow}% }% \def\XINT_RaiseFlag #1{\expandafter\xint_gobble_i\csname XINT_#1Flag_ON\endcsname}% % \end{macrocode} % \subsection*{Routines handling integers as lists of token digits} % \addcontentsline{toc}{subsection}{Routines handling integers as lists of token digits} %\begin{lverb} % Routines handling big integers which are lists of digit tokens with no % special additional structure. % % Some % routines do not accept non properly terminated inputs like "\the\numexpr1", % or "\the\mathcode`\-", others do. % % These routines or their sub-routines are mainly for internal usage. %\end{lverb} % \subsection{\cshnolabel{xintiiSgn}} % Moved to \calxcorenameimp for STUPID reasons. % % \subsection{\cshnolabel{xintiiOpp}} % Moved to \calxcorenameimp for STUPID reasons. % % \subsection{\csh{xintiiAbs}} %\begin{lverb} % Attention \xintiiAbs non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintiiAbs {\romannumeral0\xintiiabs }% \def\xintiiabs #1% {% \expandafter\XINT_abs \romannumeral`&&@#1% }% \def\XINT_abs #1% {% \xint_UDsignfork #1{ }% -{ #1}% \krof }% \def\XINT_Abs #1% {% \xint_UDsignfork #1{}% -{#1}% \krof }% % \end{macrocode} % \subsection{\csh{xintFDg}} %\begin{lverb} % FIRST DIGIT. % % 1.2l: \xintiiFDg made robust against non terminated input. % % 1.2o deprecates \xintiiFDg, gives to \xintFDg former meaning of \xintiiFDg. %\end{lverb} % \begin{macrocode} \def\xintFDg {\romannumeral0\xintfdg }% \def\xintfdg #1{\expandafter\XINT_fdg \romannumeral`&&@#1\xint:\Z}% \def\XINT_FDg #1% {\romannumeral0\expandafter\XINT_fdg\romannumeral`&&@\xintnum{#1}\xint:\Z }% \def\XINT_fdg #1#2#3\Z {% \xint_UDzerominusfork #1-{ 0}% zero 0#1{ #2}% negative 0-{ #1}% positive \krof }% % \end{macrocode} % \subsection{\csh{xintLDg}} %\begin{lverb} % LAST DIGIT. % % Rewritten for 1.2i (2016/12/10). Surprisingly perhaps, it is faster than % \xintLastItem from xintkernel.sty despite the \numexpr operations. % % 1.2o deprecates \xintiiLDg, gives to \xintLDg former meaning of \xintiiLDg. % % Attention \xintLDg non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintLDg {\romannumeral0\xintldg }% \def\xintldg #1{\expandafter\XINT_ldg_fork\romannumeral`&&@#1% \XINT_ldg_c{}{}{}{}{}{}{}{}\xint_bye\relax}% \def\XINT_ldg_fork #1% {% \xint_UDsignfork #1\XINT_ldg -{\XINT_ldg#1}% \krof }% \def\XINT_ldg #1{% \def\XINT_ldg ##1##2##3##4##5##6##7##8##9% {\expandafter#1% \the\numexpr##9##8##7##6##5##4##3##2##1*\xint_c_+\XINT_ldg_a##9}% }\XINT_ldg{ }% \def\XINT_ldg_a#1#2{\XINT_ldg_cbye#2\XINT_ldg_d#1\XINT_ldg_c\XINT_ldg_b#2}% \def\XINT_ldg_b#1#2#3#4#5#6#7#8#9{#9#8#7#6#5#4#3#2#1*\xint_c_+\XINT_ldg_a#9}% \def\XINT_ldg_c #1#2\xint_bye{#1}% \def\XINT_ldg_cbye #1\XINT_ldg_c{}% \def\XINT_ldg_d#1#2\xint_bye{#1}% % \end{macrocode} % % \subsection{\csh{xintDouble}} %\begin{lverb} % Attention \xintDouble non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintDouble {\romannumeral0\xintdouble}% \def\xintdouble #1{\expandafter\XINT_dbl_fork\romannumeral`&&@#1% \xint_bye2345678\xint_bye*\xint_c_ii\relax}% \def\XINT_dbl_fork #1% {% \xint_UDsignfork #1\XINT_dbl_neg -\XINT_dbl \krof #1% }% \def\XINT_dbl_neg-{\expandafter-\romannumeral0\XINT_dbl}% \def\XINT_dbl #1{% \def\XINT_dbl ##1##2##3##4##5##6##7##8% {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8\XINT_dbl_a}% }\XINT_dbl{ }% \def\XINT_dbl_a #1#2#3#4#5#6#7#8% {\expandafter\XINT_dbl_e\the\numexpr 1#1#2#3#4#5#6#7#8\XINT_dbl_a}% \def\XINT_dbl_e#1{*\xint_c_ii\if#13+\xint_c_i\fi\relax}% % \end{macrocode} % \subsection{\csh{xintHalf}} %\begin{lverb} % Attention \xintHalf non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintHalf {\romannumeral0\xinthalf}% \def\xinthalf #1{\expandafter\XINT_half_fork\romannumeral`&&@#1% \xint_bye\xint_Bye345678\xint_bye *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax}% \def\XINT_half_fork #1% {% \xint_UDsignfork #1\XINT_half_neg -\XINT_half \krof #1% }% \def\XINT_half_neg-{\xintiiopp\XINT_half}% \def\XINT_half #1{% \def\XINT_half ##1##2##3##4##5##6##7##8% {\expandafter#1\the\numexpr(##1##2##3##4##5##6##7##8\XINT_half_a}% }\XINT_half{ }% \def\XINT_half_a#1{\xint_Bye#1\xint_bye\XINT_half_b#1}% \def\XINT_half_b #1#2#3#4#5#6#7#8% {\expandafter\XINT_half_e\the\numexpr(1#1#2#3#4#5#6#7#8\XINT_half_a}% \def\XINT_half_e#1{*\xint_c_v+#1-\xint_c_v)\relax}% % \end{macrocode} % \subsection{\csh{xintInc}} %\begin{lverb} % 1.2i much delayed complete rewrite in 1.2 style. % % As we take 9 by 9 with the input save stack at 5000 this allows a bit less % than 9 times 2500 = 22500 digits on input. % % Attention \xintInc non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintInc {\romannumeral0\xintinc}% \def\xintinc #1{\expandafter\XINT_inc_fork\romannumeral`&&@#1% \xint_bye23456789\xint_bye+\xint_c_i\relax}% \def\XINT_inc_fork #1% {% \xint_UDsignfork #1\XINT_inc_neg -\XINT_inc \krof #1% }% \def\XINT_inc_neg-#1\xint_bye#2\relax {\xintiiopp\XINT_dec #1\XINT_dec_bye234567890\xint_bye}% \def\XINT_inc #1{% \def\XINT_inc ##1##2##3##4##5##6##7##8##9% {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8##9\XINT_inc_a}% }\XINT_inc{ }% \def\XINT_inc_a #1#2#3#4#5#6#7#8#9% {\expandafter\XINT_inc_e\the\numexpr 1#1#2#3#4#5#6#7#8#9\XINT_inc_a}% \def\XINT_inc_e#1{\if#12+\xint_c_i\fi\relax}% % \end{macrocode} % \subsection{\csh{xintDec}} %\begin{lverb} % 1.2i much delayed complete rewrite in the 1.2 style. Things are a % bit more complicated than \xintInc because 2999999999 is too big for TeX. % % Attention \xintDec non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintDec {\romannumeral0\xintdec}% \def\xintdec #1{\expandafter\XINT_dec_fork\romannumeral`&&@#1% \XINT_dec_bye234567890\xint_bye}% \def\XINT_dec_fork #1% {% \xint_UDsignfork #1\XINT_dec_neg -\XINT_dec \krof #1% }% \def\XINT_dec_neg-#1\XINT_dec_bye#2\xint_bye {\expandafter-% \romannumeral0\XINT_inc #1\xint_bye23456789\xint_bye+\xint_c_i\relax}% \def\XINT_dec #1{% \def\XINT_dec ##1##2##3##4##5##6##7##8##9% {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8##9\XINT_dec_a}% }\XINT_dec{ }% \def\XINT_dec_a #1#2#3#4#5#6#7#8#9% {\expandafter\XINT_dec_e\the\numexpr 1#1#2#3#4#5#6#7#8#9\XINT_dec_a}% \def\XINT_dec_bye #1\XINT_dec_a#2#3\xint_bye {\if#20-\xint_c_ii\relax+\else-\fi\xint_c_i\relax}% \def\XINT_dec_e#1{\unless\if#11\xint_dothis{-\xint_c_i#1}\fi\xint_orthat\relax}% % \end{macrocode} % \subsection{\csh{xintDSL}} %\begin{lverb} % DECIMAL SHIFT LEFT (=MULTIPLICATION PAR 10). Rewritten for 1.2i. % This was very old code... I never came back to it, but I should have % rewritten it long time ago. % % Attention \xintDSL non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintDSL {\romannumeral0\xintdsl }% \def\xintdsl #1{\expandafter\XINT_dsl\romannumeral`&&@#10}% \def\XINT_dsl#1{% \def\XINT_dsl ##1{\xint_gob_til_zero ##1\xint_dsl_zero 0#1##1}% }\XINT_dsl{ }% \def\xint_dsl_zero 0 0{ }% % \end{macrocode} % \subsection{\csh{xintDSR}} %\begin{lverb} % Decimal shift right, truncates towards zero. Rewritten for 1.2i. % Limited to 22483 digits on input. % % Attention \xintDSR non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintDSR{\romannumeral0\xintdsr}% \def\xintdsr #1{\expandafter\XINT_dsr_fork\romannumeral`&&@#1% \xint_bye\xint_Bye3456789\xint_bye+\xint_c_v)/\xint_c_x-\xint_c_i\relax}% \def\XINT_dsr_fork #1% {% \xint_UDsignfork #1\XINT_dsr_neg -\XINT_dsr \krof #1% }% \def\XINT_dsr_neg-{\xintiiopp\XINT_dsr}% \def\XINT_dsr #1{% \def\XINT_dsr ##1##2##3##4##5##6##7##8##9% {\expandafter#1\the\numexpr(##1##2##3##4##5##6##7##8##9\XINT_dsr_a}% }\XINT_dsr{ }% \def\XINT_dsr_a#1{\xint_Bye#1\xint_bye\XINT_dsr_b#1}% \def\XINT_dsr_b #1#2#3#4#5#6#7#8#9% {\expandafter\XINT_dsr_e\the\numexpr(1#1#2#3#4#5#6#7#8#9\XINT_dsr_a}% \def\XINT_dsr_e #1{)\relax}% % \end{macrocode} % \subsection{\csh{xintDSRr}} %\begin{lverb} % New with 1.2i. Decimal shift right, rounds away from zero; done in % the 1.2 spirit (with much delay, sorry). Used by \xintRound, \xintDivRound. % % This is about the first time I am happy that the division in \numexpr % rounds! % % Attention \xintDSRr non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintDSRr{\romannumeral0\xintdsrr}% \def\xintdsrr #1{\expandafter\XINT_dsrr_fork\romannumeral`&&@#1% \xint_bye\xint_Bye3456789\xint_bye/\xint_c_x\relax}% \def\XINT_dsrr_fork #1% {% \xint_UDsignfork #1\XINT_dsrr_neg -\XINT_dsrr \krof #1% }% \def\XINT_dsrr_neg-{\xintiiopp\XINT_dsrr}% \def\XINT_dsrr #1{% \def\XINT_dsrr ##1##2##3##4##5##6##7##8##9% {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8##9\XINT_dsrr_a}% }\XINT_dsrr{ }% \def\XINT_dsrr_a#1{\xint_Bye#1\xint_bye\XINT_dsrr_b#1}% \def\XINT_dsrr_b #1#2#3#4#5#6#7#8#9% {\expandafter\XINT_dsrr_e\the\numexpr1#1#2#3#4#5#6#7#8#9\XINT_dsrr_a}% \let\XINT_dsrr_e\XINT_inc_e % \end{macrocode} % \subsection*{Blocks of eight digits} % \addcontentsline{toc}{subsection}{Blocks of eight digits} % % The lingua of release 1.2. Six of them have been moved to \calxcorenameimp % at |2.0a1|. An |\XINT_smallunrevbyviii| was deleted then as it served only % in the legacy addition macros, now replaced by those of \calxcorenameimp. % % % \subsection{\csh{XINT_cuz}} %\begin{lverb} % This (launched by \romannumeral0) iterately removes all leading % zeroes from a sequence of 8N digits ended by \R. % % Rewritten for 1.2l, now uses \numexpr governed expansion and \ifnum test % rather than delimited gobbling macros. % % Note 2015/11/28: with only four digits the gob_til_fourzeroes had proved % in some old testing faster than \ifnum test. But with eight digits, the % execution times are much closer, as I tested back then. %\end{lverb} % \begin{macrocode} \def\XINT_cuz #1{% \def\XINT_cuz {\expandafter#1\the\numexpr\XINT_cuz_loop}% }\XINT_cuz{ }% \def\XINT_cuz_loop #1#2#3#4#5#6#7#8#9% {% #1#2#3#4#5#6#7#8% \xint_gob_til_R #9\XINT_cuz_hitend\R \ifnum #1#2#3#4#5#6#7#8>\xint_c_ \expandafter\XINT_cuz_cleantoend \else\expandafter\XINT_cuz_loop \fi #9% }% \def\XINT_cuz_hitend\R #1\R{\relax}% \def\XINT_cuz_cleantoend #1\R{\relax #1}% % \end{macrocode} % \subsection{\csh{XINT_cuz_byviii}} %\begin{lverb} % This removes eight by eight leading zeroes from a sequence of 8N digits % ended by \R. Thus, we still have 8N digits on output. Expansion started by % \romannumeral0 %\end{lverb} % \begin{macrocode} \def\XINT_cuz_byviii #1#2#3#4#5#6#7#8#9% {% \xint_gob_til_R #9\XINT_cuz_byviii_e \R \xint_gob_til_eightzeroes #1#2#3#4#5#6#7#8\XINT_cuz_byviii_z 00000000% \XINT_cuz_byviii_done #1#2#3#4#5#6#7#8#9% }% \def\XINT_cuz_byviii_z 00000000\XINT_cuz_byviii_done 00000000{\XINT_cuz_byviii}% \def\XINT_cuz_byviii_done #1\R { #1}% \def\XINT_cuz_byviii_e\R #1\XINT_cuz_byviii_done #2\R{ #2}% % \end{macrocode} % \subsection{\csh{XINT_sepbyviii_Z}} % %\begin{lverb} % This is used as %( \the\numexpr\XINT_sepbyviii_Z <8Ndigits>\XINT_sepbyviii_Z_end 2345678\relax %) % It produces 1<8d>!...1<8d>!1;! % % Prior to 1.2l it used \Z as terminator (hence the name). At 1.2l a switch % to ; was done. This was at a time I thought perhaps I would use an internal % format maintaining such 8 digits blocks, and this had to be compatible with % the \csname...\endcsname encapsulation in \xintexpr parsers. That rationale % is obsolete since 1.4 usage of \expanded in $xintexprnameimp, but if an % internal format is one day used it would be nice to be able to externalize % it easily, so catcode 12 tokens are the most convenient. % % As the expansion is done via successive \numexpr, it is convenient to use % something such as ; which terminates it and stays there. The ! itself would % do. But it proved convenient to have unique ending pattern. I could use % two ! perhaps. %\end{lverb} % \changed{1.4n} %\begin{lverb} % Unfortunately LuaMetaTeX has given to ; and : a meaning as operators inside % its \numexpr. Let's hope ! does not acquire meaning too there. Anyway here % I only need to use \relax;! in \XINT_sepbyviii_Z_end. First step in a tedious % check of the entire codebase... %\end{lverb} % \begin{macrocode} \def\XINT_sepbyviii_Z #1#2#3#4#5#6#7#8% {% 1#1#2#3#4#5#6#7#8\expandafter!\the\numexpr\XINT_sepbyviii_Z }% \def\XINT_sepbyviii_Z_end #1\relax {\relax;!}% % \end{macrocode} % \subsection{\csh{XINT_sepbyviii_andcount}} % %\begin{lverb} % This is used as %( \the\numexpr\XINT_sepbyviii_andcount <8Ndigits>$% %: \XINT_sepbyviii_end 2345678\relax %: \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!$% %: \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W %) % It will produce %( 1<8d>!1<8d>!....1<8d>!1\xint:\xint: %) % Used by % \XINT_div_prepare_g for \XINT_div_prepare_h, and also by \xintiiCmp. %\end{lverb} % \begin{macrocode} \def\XINT_sepbyviii_andcount {% \expandafter\XINT_sepbyviii_andcount_a\the\numexpr\XINT_sepbyviii }% \def\XINT_sepbyviii #1#2#3#4#5#6#7#8% {% 1#1#2#3#4#5#6#7#8\expandafter!\the\numexpr\XINT_sepbyviii }% \def\XINT_sepbyviii_end #1\relax {\relax\XINT_sepbyviii_andcount_end!}% \def\XINT_sepbyviii_andcount_a {\XINT_sepbyviii_andcount_b \xint_c_\xint:}% \def\XINT_sepbyviii_andcount_b #1\xint:#2!#3!#4!#5!#6!#7!#8!#9!% {% #2\expandafter!\the\numexpr#3\expandafter!\the\numexpr#4\expandafter !\the\numexpr#5\expandafter!\the\numexpr#6\expandafter!\the\numexpr #7\expandafter!\the\numexpr#8\expandafter!\the\numexpr#9\expandafter!\the\numexpr \expandafter\XINT_sepbyviii_andcount_b\the\numexpr #1+\xint_c_viii\xint:% }% \def\XINT_sepbyviii_andcount_end #1\XINT_sepbyviii_andcount_b\the\numexpr #2+\xint_c_viii\xint:#3#4\W {\expandafter\xint:\the\numexpr #2+#3\xint:}% % \end{macrocode} % \subsection{\csh{XINT_sepandrev}} %\begin{lverb} % This is used typically as %( \romannumeral0\XINT_sepandrev <8Ndigits>$% %: \XINT_rsepbyviii_end_A 2345678$% %: \XINT_rsepbyviii_end_B 2345678\relax UV$% %: \R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\W %) % and will produce %( 1<8digits>!1<8digits>!1<8digits>!... %) % where the blocks have % been globally reversed. The UV here are only place holders (must be \numexpr1 % stoppers) to share same % syntax as \XINT_sepandrev_andcount, they are gobbled (#2 in \XINT_sepandrev_done). %\end{lverb} % \begin{macrocode} \def\XINT_sepandrev {% \expandafter\XINT_sepandrev_a\the\numexpr 1\XINT_rsepbyviii }% \def\XINT_sepandrev_a {\XINT_sepandrev_b {}}% \def\XINT_sepandrev_b #1#2\xint:#3\xint:#4\xint:#5\xint:#6\xint:#7\xint:#8\xint:#9\xint:% {% \xint_gob_til_R #9\XINT_sepandrev_end\R \XINT_sepandrev_b {#9!#8!#7!#6!#5!#4!#3!#2!#1}% }% \def\XINT_sepandrev_end\R\XINT_sepandrev_b #1#2\W {\XINT_sepandrev_done #1}% \def\XINT_sepandrev_done #11#2!{ }% % \end{macrocode} % \subsection*{Core arithmetic} % \addcontentsline{toc}{subsection}{Core arithmetic} %\begin{lverb} % All three raw ii operations use the native calxcore implementations. % Their callers continue to supply and receive raw decimal integers; % representation conversion is confined to these interface macros. %\end{lverb} % % \subsection{\csh{xintiiAdd}} %\begin{lverb} % Input: \xintiiAdd{raw}{raw}; output: raw integer. % Convert both operands to native, apply native addition, convert back. %\end{lverb} % \begin{macrocode} \def\xintiiAdd {\romannumeral0\xintiiadd }% \def\xintiiadd #1#2{\CALX_ntoraw{\CALX_nadd{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{\cshnolabel{xintiiCmp}} % Moved to \calxcorenameimp at |2.0a1| for STUPID reasons. % % Prior to |1.4m| the «strcmp» primitive was not used by \xintcorenameimp. % Here is the old implementation: %\begin{lverb} %( \def\XINT_cmp_plusplus #1#2#3\xint: %: {$% %: \expandafter\XINT_cmp_pp %: \the\numexpr\expandafter\XINT_sepbyviii_andcount %: \romannumeral0\XINT_zeroes_forviii #2#3\R\R\R\R\R\R\R\R{10}0000001\W %: #2#3\XINT_sepbyviii_end 2345678\relax %: \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!$% %: \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W %: #1$% %: }$% %: \def\XINT_cmp_pp #1\xint:#2\xint:#3\xint: %: {$% %: \expandafter\XINT_cmp_checklengths %: \the\numexpr #2\expandafter\xint:$% %: \the\numexpr\expandafter\XINT_sepbyviii_andcount %: \romannumeral0\XINT_zeroes_forviii #3\R\R\R\R\R\R\R\R{10}0000001\W %: #3\XINT_sepbyviii_end 2345678\relax %: \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!$% %: \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W %: #1;!1;!1;!1;!\W %: }$% %: \def\XINT_cmp_checklengths #1\xint:#2\xint:#3\xint: %: {$% %: \ifnum #1=#3 %: \expandafter\xint_firstoftwo %: \else %: \expandafter\xint_secondoftwo %: \fi %: \XINT_cmp_a {\XINT_cmp_distinctlengths {#1}{#3}}#2;!1;!1;!1;!\W %: }$% %: \def\XINT_cmp_distinctlengths #1#2#3\W #4\W %: {$% %: \ifnum #1>#2 %: \expandafter\xint_firstoftwo %: \else %: \expandafter\xint_secondoftwo %: \fi %: { -1}{ 1}$% %: }$% %: \def\XINT_cmp_a 1#1!1#2!1#3!1#4!#5\W 1#6!1#7!1#8!1#9!$% %: {$% %: \xint_gob_til_sc #1\XINT_cmp_equal ;$% %: \ifnum #1>#6 \XINT_cmp_gt\fi %: \ifnum #1<#6 \XINT_cmp_lt\fi %: \xint_gob_til_sc #2\XINT_cmp_equal ;$% %: \ifnum #2>#7 \XINT_cmp_gt\fi %: \ifnum #2<#7 \XINT_cmp_lt\fi %: \xint_gob_til_sc #3\XINT_cmp_equal ;$% %: \ifnum #3>#8 \XINT_cmp_gt\fi %: \ifnum #3<#8 \XINT_cmp_lt\fi %: \xint_gob_til_sc #4\XINT_cmp_equal ;$% %: \ifnum #4>#9 \XINT_cmp_gt\fi %: \ifnum #4<#9 \XINT_cmp_lt\fi %: \XINT_cmp_a #5\W %: }$% %: \def\XINT_cmp_lt#1{\def\XINT_cmp_lt\fi ##1\W ##2\W {\fi#1-1}}\XINT_cmp_lt{ }$% %: \def\XINT_cmp_gt#1{\def\XINT_cmp_gt\fi ##1\W ##2\W {\fi#11}}\XINT_cmp_gt{ }$% %: \def\XINT_cmp_equal #1\W #2\W { 0}$% %) %\end{lverb} % \subsection{\csh{xintiiSub}} %\begin{lverb} % Input: \xintiiSub{raw}{raw}; output: raw integer. % Convert both operands to native, apply native subtraction, convert back. %\end{lverb} % \begin{macrocode} \def\xintiiSub {\romannumeral0\xintiisub }% \def\xintiisub #1#2{\CALX_ntoraw{\CALX_nsub{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{\csh{xintiiMul}} %\begin{lverb} % Input: \xintiiMul{raw}{raw}; output: raw integer. % Convert both operands to native, apply native multiplication, convert back. %\end{lverb} % \begin{macrocode} \def\xintiiMul {\romannumeral0\xintiimul }% \def\xintiimul #1#2{\CALX_ntoraw{\CALX_nmul{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{Reversed eight-digit block output} %\begin{lverb} % Converts a block list, least significant first, terminated by 1;! as % produced by the small multiplication kernels, to an untagged decimal % integer (used by xintfrac). %\end{lverb} % \begin{macrocode} \def\XINT_mul_out {\expandafter\XINT_cuz_small\romannumeral0\XINT_unrevbyviii {}}% % \end{macrocode} % \subsection{\csh{xintiiDivision}} %\begin{lverb} % The public ii entry points accept unexpanded, f-expandable material % yielding raw ii integers, and return raw integers. Each operation delegates % to the corresponding native calxcore % division operation. Internal division callers use \XINT_ndivrawpair with % divisor first and dividend second; it returns raw {quotient}{remainder}. %\end{lverb} % \begin{macrocode} \def\XINT_ndivrawpair #1#2{% \expandafter\XINT_ndivrawpair_a\romannumeral0\CALX_ndivision {\CALX_nfromraw{#2}}{\CALX_nfromraw{#1}}}% \def\XINT_ndivrawpair_a #1#2{% \expandafter\XINT_ndivrawpair_b \romannumeral0\CALX_ntoraw{#2}\xint:{#1}}% \def\XINT_ndivrawpair_b #1\xint:#2{% \expandafter\XINT_ndivrawpair_c \romannumeral0\CALX_ntoraw{#2}\xint:{#1}}% \def\XINT_ndivrawpair_c #1\xint:#2{{#1}{#2}}% \def\xintiiDivision {\romannumeral0\xintiidivision }% \def\xintiidivision #1#2{\XINT_ndivrawpair{#2}{#1}}% \def\xintiiQuo {\romannumeral0\xintiiquo }% \def\xintiiquo #1#2{\CALX_ntoraw{\CALX_nquo{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% \def\xintiiRem {\romannumeral0\xintiirem }% \def\xintiirem #1#2{\CALX_ntoraw{\CALX_nrem{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% \def\xintiiDivRound {\romannumeral0\xintiidivround }% \def\xintiidivround #1#2{\CALX_ntoraw{\CALX_ndivround{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% \def\xintiiDivTrunc {\romannumeral0\xintiidivtrunc }% \def\xintiidivtrunc #1#2{\CALX_ntoraw{\CALX_ndivtrunc{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% \def\xintiiModTrunc {\romannumeral0\xintiimodtrunc }% \def\xintiimodtrunc #1#2{\CALX_ntoraw{\CALX_nmodtrunc{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% \def\xintiiDivMod {\romannumeral0\xintiidivmod }% \def\xintiidivmod #1#2{% \expandafter\XINT_ndivrawmod_a\romannumeral0\CALX_ndivmod {\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}% \def\XINT_ndivrawmod_a #1#2{% \expandafter\XINT_ndivrawpair_b \romannumeral0\CALX_ntoraw{#2}\xint:{#1}}% \def\xintiiDivFloor {\romannumeral0\xintiidivfloor}% \def\xintiidivfloor #1#2{\CALX_ntoraw{\CALX_ndivfloor{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% \def\xintiiMod {\romannumeral0\xintiimod}% \def\xintiimod #1#2{\CALX_ntoraw{\CALX_nmod{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{\csh{xintiiSqr}} %\begin{lverb} % 1.2l: \xintiiSqr made robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintiiSqr {\romannumeral0\xintiisqr }% \def\xintiisqr #1{\CALX_ntoraw{\XINT_nsquare{\CALX_nfromraw{#1}}}}% \def\XINT_nsquare #1{\expandafter\XINT_nsquare_a\romannumeral`&&@#1\xint:}% \def\XINT_nsquare_a #1\xint:{\CALX_nmul{#1}{#1}}% % \end{macrocode} % \subsection{\csh{xintiiPow}} %\begin{lverb} % 1.2f Modifies the initial steps: 1) in order to be able to let more easily % \xintiPow use \xintNum on the exponent once xintfrac.sty is loaded; 2) also % because I noticed it was not very well coded. And it did only a \numexpr on % the exponent, contradicting the documentation related to the "i" convention % in names. % % 1.2l: \xintiiPow made robust against non terminated input. % % The macro makes no a priori test on whether computation has a chance to % complete succesfully, as this depends on TeX memory parameters. But roughly, % the size of the output should be less than the maximal size for addition, % i.e. with TeXLive 2025 settings, have less than about 26600 decimal digits. %\end{lverb} % \begin{macrocode} \def\xintiiPow {\romannumeral0\xintiipow }% \def\xintiipow #1#2% {% \expandafter\xint_pow\the\numexpr #2\expandafter .\romannumeral`&&@#1\xint: }% \def\xint_pow #1.#2%#3\xint: {% \xint_UDzerominusfork #2-\XINT_pow_AisZero 0#2\XINT_pow_Aneg 0-{\XINT_pow_Apos #2}% \krof {#1}% }% \def\XINT_pow_AisZero #1#2\xint: {% \ifcase\XINT_cntSgn #1\xint: \xint_afterfi { 1}% \or \xint_afterfi { 0}% \else \xint_afterfi {\XINT_legacysignalcondition{DivisionByZero}{0 raised to power #1.}{}{ 0}}% \fi }% \def\XINT_pow_Aneg #1% {% \ifodd #1 \expandafter\XINT_opp\romannumeral0% \fi \XINT_pow_Apos {}{#1}% }% \def\XINT_pow_Apos #1#2{\XINT_pow_Apos_a {#2}#1}% \def\XINT_pow_Apos_a #1#2#3% {% \xint_gob_til_xint: #3\XINT_pow_Apos_short\xint: \XINT_pow_AatleastTwo {#1}#2#3% }% \def\XINT_pow_Apos_short\xint:\XINT_pow_AatleastTwo #1#2\xint: {% \ifcase #2 \xintError:thiscannothappen \or \expandafter\XINT_pow_AisOne \else\expandafter\XINT_pow_AatleastTwo \fi {#1}#2\xint: }% \def\XINT_pow_AisOne #1\xint:{ 1}% \def\XINT_pow_AatleastTwo #1% {% \ifcase\XINT_cntSgn #1\xint: \expandafter\XINT_pow_BisZero \or \expandafter\XINT_pow_I_in \else \expandafter\XINT_pow_BisNegative \fi {#1}% }% \def\XINT_pow_BisNegative #1\xint:{\XINT_legacysignalcondition{Underflow}% {Inverse power is not an integer.}{}{ 0}}% \def\XINT_pow_BisZero #1\xint:{ 1}% % \end{macrocode} %\begin{lverb} % B = #1 > 0, A = #2 > 1. Earlier code checked if size of B did not % exceed a given limit (for example 131000). %\end{lverb} % \begin{macrocode} \def\XINT_pow_I_in #1#2\xint:% {\CALX_ntoraw{\CALX_npow{#1}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{\csh{xintiiFac}} %\begin{lverb} % \xintiiFac{k}: k a \numexpr expression; k! as a raw integer, computed by % calxcore's \CALX_nfac. Negative k or k > 10^4: InvalidOperation, 0. %\end{lverb} % \begin{macrocode} \def\xintiiFac {\romannumeral0\xintiifac }% \def\xintiifac #1{\expandafter\XINT_fac_fork\the\numexpr#1.}% \def\XINT_fac_fork #1#2.% {% \xint_UDzerominusfork #1-\XINT_fac_zero 0#1\XINT_fac_neg 0-\XINT_fac_checksize \krof #1#2.% }% \def\XINT_fac_zero #1.{ 1}% \def\XINT_fac_neg #1.{\XINT_legacysignalcondition{InvalidOperation}{Factorial of negative argument: #1.}{}{ 0}}% \def\XINT_fac_checksize #1.% {% \ifnum #1>\xint_c_e_iv \xint_dothis{\XINT_legacysignalcondition {InvalidOperation}{Factorial argument is too large: #1 > 10^4.}% {}{ 0}}\fi \xint_orthat{\CALX_ntoraw{\CALX_nfac{#1}}}% }% % \end{macrocode} % \subsection{\csh{XINT_useiimessage}} %\begin{lverb} % 1.2o %\end{lverb} % \begin{macrocode} \def\XINT_useiimessage #1% used in LaTeX only {% \XINT_ifFlagRaised {#1}% {\@backslashchar#1 (load xintfrac or use \@backslashchar xintii\xint_gobble_iv#1!)\MessageBreak}% {}% }% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintcore} % \cleardoublepage\let\xintcorenameUp\undefined %\gardesactifs %\let\relax %\let<*xint>\gardesinactifs %^^A--------------------------------------------------- %<*xint>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintnameimp implementation} % \RaisedLabel{sec:xintimp} % % \localtableofcontents % % \subsection{Introduction} % % With release |1.1| the core arithmetic routines |\xintiiAdd|, % |\xintiiSub|, |\xintiiMul|, |\xintiiQuo|, |\xintiiPow| were separated to be % the main component of the then new % \xintcorenameimp. % % |1.3b| adds randomness related macros. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \catcode35=6 % # \def\odef#1{\expandafter\def\expandafter#1\expandafter}% \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \def\odef#1{\expandafter\def\expandafter#1\expandafter}% \expandafter\let\expandafter\x\csname ver@xint.sty\endcsname \expandafter\let\expandafter\c\csname ver@calxint.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintcore.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xint Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xint}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xint.sty \ifx\w\relax % but xintcore.sty not yet loaded. \odef\z{\z\input xintcore.sty\relax}% \fi \ifx\c\relax % but calxint.sty not yet loaded. \odef\z{\z\input calxint.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xintcore.sty not yet loaded. \odef\z{\z\RequirePackage{xintcore}}% \fi \ifx\c\relax % calxint.sty not yet loaded. \odef\z{\z\RequirePackage{calxint}}% \fi \else \def\z{\endgroup\endinput}% xint already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty (loaded by xintcore.sty) % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xint}% [2026/11/01 v2.0a1 Expandable operations on big integers (JFB)]% % \end{macrocode} % \subsection{\csh{xintLen}, \csh{xintiLen}} %\begin{lverb} % \xintLen gets extended to fractions by xintfrac.sty: A/B is given % length len(A)+len(B)-1 (somewhat arbitrary). It applies \xintNum to its % argument. A minus sign is accepted and ignored. % % % For parallelism with \xintiNum/\xintNum, 1.2o defines \xintiLen. % % \xintLen gets redefined by $xintfracnameimp. %\end{lverb} % \begin{macrocode} \def\xintiLen {\romannumeral0\xintilen }% \def\xintilen #1{\def\xintilen ##1% {% \expandafter#1\the\numexpr \expandafter\XINT_len_fork\romannumeral0\xintinum{##1}% \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye\relax }}\xintilen{ }% \def\xintLen {\romannumeral0\xintlen }% \let\xintlen\xintilen \def\XINT_len_fork #1% {% \expandafter\XINT_length_loop\xint_UDsignfork#1{}-#1\krof }% % \end{macrocode} % \subsection{\csh{xintiiLogTen}} %\begin{lverb} % 1.3e. Support for ilog10() function in \xintiiexpr. See \XINTiLogTen % in xintfrac.sty which also currently uses -"7FFF8000 as value if input is % zero. %\end{lverb} % \begin{macrocode} \def\xintiiLogTen {\the\numexpr\xintiilogten }% \def\xintiilogten #1% {% \expandafter\XINT_iilogten\romannumeral`&&@#1% \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye \relax }% \def\XINT_iilogten #1{\if#10-"7FFF8000\fi -1+% \expandafter\XINT_length_loop\xint_UDsignfork#1{}-#1\krof}% % \end{macrocode} % \subsection{\csh{xintReverseDigits}} %\begin{lverb} % 1.2. % % This puts digits in reverse order, not suppressing leading zeros % after reverse. Despite lacking the "ii" in its name, it does not apply % \xintNum to its argument (contrarily to \xintLen, this is not very coherent). % % 1.2l variant is robust against non terminated \the\numexpr input. % % This macro is currently not used elsewhere in xint code. %\end{lverb} % \begin{macrocode} \def\xintReverseDigits {\romannumeral0\xintreversedigits }% \def\xintreversedigits #1% {% \expandafter\XINT_revdigits\romannumeral`&&@#1% {\XINT_microrevsep_end\W}\XINT_microrevsep_end \XINT_microrevsep_end\XINT_microrevsep_end \XINT_microrevsep_end\XINT_microrevsep_end \XINT_microrevsep_end\XINT_microrevsep_end\XINT_microrevsep_end\Z 1\Z!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W }% \def\XINT_revdigits #1% {% \xint_UDsignfork #1{\expandafter-\romannumeral0\XINT_revdigits_a}% -{\XINT_revdigits_a #1}% \krof }% \def\XINT_revdigits_a {% \expandafter\XINT_revdigits_b\expandafter{\expandafter}% \the\numexpr\XINT_microrevsep }% \def\XINT_microrevsep #1#2#3#4#5#6#7#8#9% {% 1#9#8#7#6#5#4#3#2#1\expandafter!\the\numexpr\XINT_microrevsep }% \def\XINT_microrevsep_end #1\W #2\expandafter #3\Z{\relax#2!}% \def\XINT_revdigits_b #11#2!1#3!1#4!1#5!1#6!1#7!1#8!1#9!% {% \xint_gob_til_R #9\XINT_revdigits_end\R \XINT_revdigits_b {#9#8#7#6#5#4#3#2#1}% }% \def\XINT_revdigits_end#1{% \def\XINT_revdigits_end\R\XINT_revdigits_b ##1##2\W {\expandafter#1\xint_gob_til_Z ##1}% }\XINT_revdigits_end{ }% \let\xintRev\xintReverseDigits % \end{macrocode} % \subsection{\csh{xintiiE}} %\begin{lverb} % Originally was used in \xintiiexpr. Transferred from xintfrac for % 1.1. % Code rewritten for 1.2i. % \xintiiE{x}{e} extends x with e zeroes if e is positive and simply outputs % x if e is zero or negative. Attention, le comportement pour e < 0 ne doit % pas être modifié car \xintMod et autres macros en dépendent. %\end{lverb} % \begin{macrocode} \def\xintiiE {\romannumeral0\xintiie }% \def\xintiie #1#2% {\expandafter\XINT_iie_fork\the\numexpr #2\expandafter.\romannumeral`&&@#1;}% \def\XINT_iie_fork #1% {% \xint_UDsignfork #1\XINT_iie_neg -\XINT_iie_a \krof #1% }% % \end{macrocode} %\begin{lverb} % le #2 a le bon pattern terminé par ; #1=0 est OK pour \XINT_rep. %\end{lverb} % \begin{macrocode} \def\XINT_iie_a #1.% {\expandafter\XINT_dsx_append\romannumeral\XINT_rep #1\endcsname 0.}% \def\XINT_iie_neg #1.#2;{ #2}% % \end{macrocode} % \subsection{\csh{xintDecSplit}} %\begin{lverb} % DECIMAL SPLIT % % The macro \xintDecSplit {x}{A} cuts A which is composed of digits (leading % zeroes ok, but no sign) (*) into two (each possibly empty) pieces L and R. % The concatenation LR always reproduces A. % % The position of the cut is specified by the first argument x. If x is zero % or positive the cut location is x slots to the left of the right end of the % number. If x becomes equal to or larger than the length of the number then L % becomes empty. If x is negative the location of the cut is |x| slots to the % right of the left end of the number. % % (*) versions earlier than 1.2i first replaced A with its absolute value. % This is not the case anymore. This macro should NOT be used for A with a % leading sign (+ or -). % % Entirely rewritten for 1.2i (2016/12/11). % % Attention: \xintDecSplit not robust against non terminated second argument. %\end{lverb} % \begin{macrocode} \def\xintDecSplit {\romannumeral0\xintdecsplit }% \def\xintdecsplit #1#2% {% \expandafter\XINT_split_finish \romannumeral0\expandafter\XINT_split_xfork \the\numexpr #1\expandafter.\romannumeral`&&@#2% \xint_bye2345678\xint_bye..% }% \def\XINT_split_finish #1.#2.{{#1}{#2}}% \def\XINT_split_xfork #1% {% \xint_UDzerominusfork #1-\XINT_split_zerosplit 0#1\XINT_split_fromleft 0-{\XINT_split_fromright #1}% \krof }% \def\XINT_split_zerosplit .#1\xint_bye#2\xint_bye..{ #1..}% % \end{macrocode} %\begin{lverb} % \XINT_split_fromleft and its subordinates (\XINT_split_fromleft_a, _b, % _end_a, _clean, _end0 to _end7, _end_b) moved verbatim to calxcore.sty % at 2.0a1: the float printer core in calxfp.sty uses them. %\end{lverb} % \begin{macrocode} \def\XINT_split_fromright #1.#2\xint_bye {% \expandafter\XINT_split_fromright_a \the\numexpr#1-\numexpr\XINT_length_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye .#2\xint_bye }% \def\XINT_split_fromright_a #1% {% \xint_UDsignfork #1\XINT_split_fromleft -\XINT_split_fromright_Lempty \krof }% \def\XINT_split_fromright_Lempty #1.#2\xint_bye#3..{.#2.}% % \end{macrocode} % \subsection{\csh{xintDecSplitL}} % \begin{macrocode} \def\xintDecSplitL {\romannumeral0\xintdecsplitl }% \def\xintdecsplitl #1#2% {% \expandafter\XINT_splitl_finish \romannumeral0\expandafter\XINT_split_xfork \the\numexpr #1\expandafter.\romannumeral`&&@#2% \xint_bye2345678\xint_bye..% }% \def\XINT_splitl_finish #1.#2.{ #1}% % \end{macrocode} % \subsection{\csh{xintDecSplitR}} % \begin{macrocode} \def\xintDecSplitR {\romannumeral0\xintdecsplitr }% \def\xintdecsplitr #1#2% {% \expandafter\XINT_splitr_finish \romannumeral0\expandafter\XINT_split_xfork \the\numexpr #1\expandafter.\romannumeral`&&@#2% \xint_bye2345678\xint_bye..% }% \def\XINT_splitr_finish #1.#2.{ #2}% % \end{macrocode} % \subsection{\csh{xintDSHr}} %\begin{lverb} % DECIMAL SHIFTS \xintDSH {x}{A}$\ % si x <= 0, fait A -> A.10^(|x|). % si x > 0, et A >=0, fait A -> quo(A,10^(x))$\ % si x > 0, et A < 0, fait A -> -quo(-A,10^(x))$\ % (donc pour x > 0 c'est comme DSR itéré x fois)$\ % \xintDSHr donne le `reste' (si x<=0 donne zéro). % % Badly named macros. % % Rewritten for 1.2i, this was old code and \xintDSx has changed interface. %\end{lverb} % \begin{macrocode} \def\xintDSHr {\romannumeral0\xintdshr }% \def\xintdshr #1#2% {% \expandafter\XINT_dshr_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% }% \def\XINT_dshr_fork #1% {% \xint_UDzerominusfork 0#1\XINT_dshr_xzeroorneg #1-\XINT_dshr_xzeroorneg 0-\XINT_dshr_xpositive \krof #1% }% \def\XINT_dshr_xzeroorneg #1;{ 0}% \def\XINT_dshr_xpositive {% \expandafter\xint_stop_atsecondoftwo\romannumeral0\XINT_dsx_xisPos }% % \end{macrocode} % \subsection{\csh{xintDSH}} % \begin{macrocode} \def\xintDSH {\romannumeral0\xintdsh }% \def\xintdsh #1#2% {% \expandafter\XINT_dsh_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% }% \def\XINT_dsh_fork #1% {% \xint_UDzerominusfork #1-\XINT_dsh_xiszero 0#1\XINT_dsx_xisNeg_checkA 0-{\XINT_dsh_xisPos #1}% \krof }% \def\XINT_dsh_xiszero #1.#2;{ #2}% \def\XINT_dsh_xisPos {% \expandafter\xint_stop_atfirstoftwo\romannumeral0\XINT_dsx_xisPos }% % \end{macrocode} % \subsection{\csh{xintDSx}} %\begin{lverb} % --> Attention le cas x=0 est traité dans la même catégorie que x > 0 <-- % %( si x < 0, fait A -> A.10^(|x|) %: si x >= 0, et A >=0, fait A -> {quo(A,10^(x))}{rem(A,10^(x))} %: si x >= 0, et A < 0, d'abord on calcule {quo(-A,10^(x))}{rem(-A,10^(x))} %: puis, si le premier n'est pas nul on lui donne le signe - %: si le premier est nul on donne le signe - au second. %) % On peut donc toujours reconstituer l'original A par 10^x Q \pm R % où il faut prendre le signe plus si Q est positif ou nul et le signe moins si % Q est strictement négatif. % % Rewritten for 1.2i, this was old code. % %\end{lverb} % \begin{macrocode} \def\xintDSx {\romannumeral0\xintdsx }% \def\xintdsx #1#2% {% \expandafter\XINT_dsx_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% }% \def\XINT_dsx_fork #1% {% \xint_UDzerominusfork #1-\XINT_dsx_xisZero 0#1\XINT_dsx_xisNeg_checkA 0-{\XINT_dsx_xisPos #1}% \krof }% \def\XINT_dsx_xisZero #1.#2;{{#2}{0}}% \def\XINT_dsx_xisNeg_checkA #1.#2% {% \xint_gob_til_zero #2\XINT_dsx_xisNeg_Azero 0% \expandafter\XINT_dsx_append\romannumeral\XINT_rep #1\endcsname 0.#2% }% \def\XINT_dsx_xisNeg_Azero #1;{ 0}% \def\XINT_dsx_addzeros #1% {\expandafter\XINT_dsx_append\romannumeral\XINT_rep#1\endcsname0.}% \def\XINT_dsx_addzerosnofuss #1% {\expandafter\XINT_dsx_append\romannumeral\xintreplicate{#1}0.}% \def\XINT_dsx_append #1.#2;{ #2#1}% \def\XINT_dsx_xisPos #1.#2% {% \xint_UDzerominusfork #2-\XINT_dsx_AisZero 0#2\XINT_dsx_AisNeg 0-\XINT_dsx_AisPos \krof #1.#2% }% \def\XINT_dsx_AisZero #1;{{0}{0}}% \def\XINT_dsx_AisNeg #1.-#2;% {% \expandafter\XINT_dsx_AisNeg_checkiffirstempty \romannumeral0\XINT_split_xfork #1.#2\xint_bye2345678\xint_bye..% }% \def\XINT_dsx_AisNeg_checkiffirstempty #1% {% \xint_gob_til_dot #1\XINT_dsx_AisNeg_finish_zero.% \XINT_dsx_AisNeg_finish_notzero #1% }% \def\XINT_dsx_AisNeg_finish_zero.\XINT_dsx_AisNeg_finish_notzero.#1.% {% \expandafter\XINT_dsx_end \expandafter {\romannumeral0\XINT_num {-#1}}{0}% }% \def\XINT_dsx_AisNeg_finish_notzero #1.#2.% {% \expandafter\XINT_dsx_end \expandafter {\romannumeral0\XINT_num {#2}}{-#1}% }% \def\XINT_dsx_AisPos #1.#2;% {% \expandafter\XINT_dsx_AisPos_finish \romannumeral0\XINT_split_xfork #1.#2\xint_bye2345678\xint_bye..% }% \def\XINT_dsx_AisPos_finish #1.#2.% {% \expandafter\XINT_dsx_end \expandafter {\romannumeral0\XINT_num {#2}}% {\romannumeral0\XINT_num {#1}}% }% \def\XINT_dsx_end #1#2{\expandafter{#2}{#1}}% % \end{macrocode} % \subsection{\csh{xintiiEq}} %\begin{lverb} % no \xintiieq. %\end{lverb} % \begin{macrocode} \def\xintiiEq #1#2{\romannumeral0\xintiiifeq{#1}{#2}{1}{0}}% % \end{macrocode} % \subsection{\csh{xintiiNotEq}} %\begin{lverb} % Pour xintexpr. Pas de version en lowercase. %\end{lverb} % \begin{macrocode} \def\xintiiNotEq #1#2{\romannumeral0\xintiiifeq {#1}{#2}{0}{1}}% % \end{macrocode} % \subsection{\csh{xintiiGeq}} %\begin{lverb} % PLUS GRAND OU ÉGAL % attention compare les **valeurs absolues** % % 1.2l made \xintiiGeq robust against non terminated items. % % 1.2l rewrote \xintiiCmp, but forgot to handle \xintiiGeq too. Done at 1.2m. % % This macro should have been called \xintGEq for example. %\end{lverb} % \begin{macrocode} \def\xintiiGeq {\romannumeral0\xintiigeq }% \def\xintiigeq #1{\expandafter\XINT_iigeq\romannumeral`&&@#1\xint:}% \def\XINT_iigeq #1#2\xint:#3% {% \expandafter\XINT_geq_fork\expandafter #1\romannumeral`&&@#3\xint:#2\xint: }% \def\XINT_geq #1#2\xint:#3% {% \expandafter\XINT_geq_fork\expandafter #1\romannumeral0\xintnum{#3}\xint:#2\xint: }% \def\XINT_geq_fork #1#2% {% \xint_UDzerofork #1\XINT_geq_firstiszero #2\XINT_geq_secondiszero 0{}% \krof \xint_UDsignsfork #1#2\XINT_geq_minusminus #1-\XINT_geq_minusplus #2-\XINT_geq_plusminus --\XINT_geq_plusplus \krof #1#2% }% \def\XINT_geq_firstiszero #1\krof 0#2#3\xint:#4\xint: {\xint_UDzerofork #2{ 1}0{ 0}\krof }% \def\XINT_geq_secondiszero #1\krof #20#3\xint:#4\xint:{ 1}% \def\XINT_geq_plusminus #1-{\XINT_geq_plusplus #1{}}% \def\XINT_geq_minusplus -#1{\XINT_geq_plusplus {}#1}% \def\XINT_geq_minusminus --{\XINT_geq_plusplus {}{}}% \def\XINT_geq_plusplus {\expandafter\XINT_geq_finish\romannumeral0\XINT_cmp_plusplus}% \def\XINT_geq_finish #1{\if-#1\expandafter\XINT_geq_no \else\expandafter\XINT_geq_yes\fi}% \def\XINT_geq_no 1{ 0}% \def\XINT_geq_yes { 1}% % \end{macrocode} % \subsection{\csh{xintiiGt}} % \begin{macrocode} \def\xintiiGt #1#2{\romannumeral0\xintiiifgt{#1}{#2}{1}{0}}% % \end{macrocode} % \subsection{\csh{xintiiLt}} % \begin{macrocode} \def\xintiiLt #1#2{\romannumeral0\xintiiiflt{#1}{#2}{1}{0}}% % \end{macrocode} % \subsection{\csh{xintiiGtorEq}} % \begin{macrocode} \def\xintiiGtorEq #1#2{\romannumeral0\xintiiiflt {#1}{#2}{0}{1}}% % \end{macrocode} % \subsection{\csh{xintiiLtorEq}} % \begin{macrocode} \def\xintiiLtorEq #1#2{\romannumeral0\xintiiifgt {#1}{#2}{0}{1}}% % \end{macrocode} % \subsection{\csh{xintiiIsZero}} %\begin{lverb} % 1.09a. restyled in 1.09i. 1.1 adds \xintiiIsZero, etc... for % optimization in \xintexpr %\end{lverb} % \begin{macrocode} \def\xintiiIsZero {\romannumeral0\xintiiiszero }% \def\xintiiiszero #1{\if0\xintiiSgn{#1}\xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% % \end{macrocode} % \subsection{\csh{xintiiIsNotZero}} %\begin{lverb} % 1.09a. restyled in 1.09i. 1.1 adds \xintiiIsZero, etc... for % optimization in \xintexpr %\end{lverb} % \begin{macrocode} \def\xintiiIsNotZero {\romannumeral0\xintiiisnotzero }% \def\xintiiisnotzero #1{\if0\xintiiSgn{#1}\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% % \end{macrocode} % \subsection{\csh{xintiiIsOne}} %\begin{lverb} % Added in 1.03. 1.09a defines \xintIsOne. 1.1a adds \xintiiIsOne. % % \XINT_isOne rewritten for 1.2g. Works with expanded strict integers, % positive or negative. % % % %\end{lverb} % \begin{macrocode} \def\xintiiIsOne {\romannumeral0\xintiiisone }% \def\xintiiisone #1{\expandafter\XINT_isone\romannumeral`&&@#1XY}% \def\XINT_isone #1#2#3Y% {% \unless\if#2X\xint_dothis{ 0}\fi \unless\if#11\xint_dothis{ 0}\fi \xint_orthat{ 1}% }% \def\XINT_isOne #1{\XINT_is_One#1XY}% \def\XINT_is_One #1#2#3Y% {% \unless\if#2X\xint_dothis0\fi \unless\if#11\xint_dothis0\fi \xint_orthat1% }% % \end{macrocode} % \subsection{\csh{xintiiOdd}} %\begin{lverb} % \xintOdd is needed for the xintexpr-essions even() and odd() % functions (and also by \xintNewExpr). %\end{lverb} % \begin{macrocode} \def\xintiiOdd {\romannumeral0\xintiiodd }% \def\xintiiodd #1% {% \ifodd\xintLDg{#1} %<- intentional space \xint_afterfi{ 1}% \else \xint_afterfi{ 0}% \fi }% % \end{macrocode} % \subsection{\csh{xintiiEven}} % \begin{macrocode} \def\xintiiEven {\romannumeral0\xintiieven }% \def\xintiieven #1% {% \ifodd\xintLDg{#1} %<- intentional space \xint_afterfi{ 0}% \else \xint_afterfi{ 1}% \fi }% % \end{macrocode} % \subsection{\csh{xintiiMON}} %\begin{lverb} % MINUS ONE TO THE POWER N %\end{lverb} % \begin{macrocode} \def\xintiiMON {\romannumeral0\xintiimon }% \def\xintiimon #1% {% \ifodd\xintLDg {#1} %<- intentional space \xint_afterfi{ -1}% \else \xint_afterfi{ 1}% \fi }% % \end{macrocode} % \subsection{\csh{xintiiMMON}} %\begin{lverb} % MINUS ONE TO THE POWER N-1 %\end{lverb} % \begin{macrocode} \def\xintiiMMON {\romannumeral0\xintiimmon }% \def\xintiimmon #1% {% \ifodd\xintLDg {#1} %<- intentional space \xint_afterfi{ 1}% \else \xint_afterfi{ -1}% \fi }% % \end{macrocode} % \subsection{\csh{xintSgnFork}} %\begin{lverb} % Expandable three-way fork added in 1.07. The argument #1 must expand % to non-self-ending -1,0 or 1. 1.09i with _thenstop (now _stop_at...). %\end{lverb} % \begin{macrocode} \def\xintSgnFork {\romannumeral0\xintsgnfork }% \def\xintsgnfork #1% {% \ifcase #1 \expandafter\xint_stop_atsecondofthree \or\expandafter\xint_stop_atthirdofthree \else\expandafter\xint_stop_atfirstofthree \fi }% % \end{macrocode} % \subsection{\csh{xintiiifSgn}} %\begin{lverb} % Expandable three-way fork added in 1.09a. Branches expandably % depending on whether <0, =0, >0. Choice of branch guaranteed in two steps. % % 1.09i has \xint_firstofthreeafterstop (now \xint_stop_atfirstofthree) etc % for faster expansion. % % 1.1 adds \xintiiifSgn for optimization in xintexpr-essions. Should I move % them to xintcore? (for bnumexpr) %\end{lverb} % \begin{macrocode} \def\xintiiifSgn {\romannumeral0\xintiiifsgn }% \def\xintiiifsgn #1% {% \ifcase \xintiiSgn{#1} \expandafter\xint_stop_atsecondofthree \or\expandafter\xint_stop_atthirdofthree \else\expandafter\xint_stop_atfirstofthree \fi }% % \end{macrocode} % \subsection{\csh{xintiiifCmp}} %\begin{lverb} % 1.09e % \xintifCmp {n}{m}{if nm}. 1.1a adds ii variant %\end{lverb} % \begin{macrocode} \def\xintiiifCmp {\romannumeral0\xintiiifcmp }% \def\xintiiifcmp #1#2% {% \ifcase\xintiiCmp {#1}{#2} \expandafter\xint_stop_atsecondofthree \or\expandafter\xint_stop_atthirdofthree \else\expandafter\xint_stop_atfirstofthree \fi }% % \end{macrocode} % \subsection{\csh{xintiiifEq}} %\begin{lverb} % 1.09a \xintifEq {n}{m}{YES if n=m}{NO if n<>m}. 1.1a adds ii variant %\end{lverb} % \begin{macrocode} \def\xintiiifEq {\romannumeral0\xintiiifeq }% \def\xintiiifeq #1#2% {% \if0\xintiiCmp{#1}{#2}% \expandafter\xint_stop_atfirstoftwo \else\expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintiiifGt}} %\begin{lverb} % 1.09a \xintifGt {n}{m}{YES if n>m}{NO if n<=m}. 1.1a adds ii variant %\end{lverb} % \begin{macrocode} \def\xintiiifGt {\romannumeral0\xintiiifgt }% \def\xintiiifgt #1#2% {% \if1\xintiiCmp{#1}{#2}% \expandafter\xint_stop_atfirstoftwo \else\expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\cshnolabel{xintiiifLt}} % % Moved to \calxintnameimp for stupid reasons. % % \subsection{\csh{xintiiifZero}} %\begin{lverb} % Expandable two-way fork added in 1.09a. Branches expandably depending on % whether the argument is zero (branch A) or not (branch B). 1.09i restyling. By % the way it appears (not thoroughly tested, though) that \if tests are faster % than \ifnum tests. 1.1 adds ii versions. %\end{lverb} % \begin{macrocode} \def\xintiiifZero {\romannumeral0\xintiiifzero }% \def\xintiiifzero #1% {% \if0\xintiiSgn{#1}% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintiiifNotZero}} % \begin{macrocode} \def\xintiiifNotZero {\romannumeral0\xintiiifnotzero }% \def\xintiiifnotzero #1% {% \if0\xintiiSgn{#1}% \expandafter\xint_stop_atsecondoftwo \else \expandafter\xint_stop_atfirstoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintiiifOne}} %\begin{lverb} % added in 1.09i. 1.1a adds \xintiiifOne. %\end{lverb} % \begin{macrocode} \def\xintiiifOne {\romannumeral0\xintiiifone }% \def\xintiiifone #1% {% \if1\xintiiIsOne{#1}% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintiiifOdd}} %\begin{lverb} % 1.09e. Restyled in 1.09i. 1.1a adds \xintiiifOdd. %\end{lverb} % \begin{macrocode} \def\xintiiifOdd {\romannumeral0\xintiiifodd }% \def\xintiiifodd #1% {% \if\xintiiOdd{#1}1% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintifTrueAelseB}, \csh{xintifFalseAelseB}} %\begin{lverb} % 1.09i, with name changes at 1.2i. % % 1.2o uses \xintiiifNotZero, see comments to \xintAND etc... This will work % fine with arguments being nested xintfrac.sty macros, without the overhead % of \xintNum or \xintRaw parsing. %\end{lverb} % \begin{macrocode} \def\xintifTrueAelseB {\romannumeral0\xintiiifnotzero}% \def\xintifFalseAelseB{\romannumeral0\xintiiifzero}% % \end{macrocode} % \subsection{\csh{xintIsTrue}, \csh{xintIsFalse}} %\begin{lverb} % 1.09c. Suppressed at 1.2o. They seem not to have been documented, fortunately. %\end{lverb} % \begin{macrocode} %\let\xintIsTrue \xintIsNotZero %\let\xintIsFalse\xintIsZero % \end{macrocode} % \subsection{\csh{xintNOT}} %\begin{lverb} % 1.09c with name change at 1.2o. Besides, the macro is now defined as ii-type. %\end{lverb} % \begin{macrocode} \def\xintNOT{\romannumeral0\xintiiiszero}% % \end{macrocode} % \subsection{\csh{xintAND}, \csh{xintOR}, \csh{xintXOR}} %\begin{lverb} % Added with 1.09a. But they used \xintSgn, etc... rather than % \xintiiSgn. This brings \xintNum overhead which is not really desired, and % which is not needed for use by xintexpr.sty. At 1.2o I modify them to use % only ii macros. This is enough for sign or zeroness even for xintfrac % format, as manipulated inside the \xintexpr. Big hesitation whether there % should be however \xintiiAND outputting 1 or 0 versus an \xintAND outputting % 1[0] versus 0[0] for example. %\end{lverb} % \begin{macrocode} \def\xintAND {\romannumeral0\xintand }% \def\xintand #1#2{\if0\xintiiSgn{#1}\expandafter\xint_firstoftwo \else\expandafter\xint_secondoftwo\fi { 0}{\xintiiisnotzero{#2}}}% \def\xintOR {\romannumeral0\xintor }% \def\xintor #1#2{\if0\xintiiSgn{#1}\expandafter\xint_firstoftwo \else\expandafter\xint_secondoftwo\fi {\xintiiisnotzero{#2}}{ 1}}% \def\xintXOR {\romannumeral0\xintxor }% \def\xintxor #1#2{\if\xintiiIsZero{#1}\xintiiIsZero{#2}% \xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi }% % \end{macrocode} % \subsection{\csh{xintANDof}} %\begin{lverb} % New with 1.09a. \xintANDof works also with an empty list. Empty items % however are not accepted. % % 1.2l made \xintANDof robust against non terminated items. % % 1.2o's \xintifTrueAelseB is now an ii macro, actually. % % 1.4. This macro as well as ORof and XORof were formally not used by % xintexpr, which uses comma separated items, but at 1.4 xintexpr uses braced % items. And the macros here got slightly refactored and \XINT_ANDof added for % usage by xintexpr and the NewExpr hook. For some random reason I decided to % use ^ as delimiter this has to do that other macros in xintfrac in same % family (such as \xintGCDof, \xintSum) also use \xint: internally and % although not strictly needed having two separate ones clarifies. % %\end{lverb} % \begin{macrocode} \def\xintANDof {\romannumeral0\xintandof }% \def\xintandof #1{\expandafter\XINT_andof\romannumeral`&&@#1^}% \def\XINT_ANDof {\romannumeral0\XINT_andof}% \def\XINT_andof #1% {% \xint_gob_til_^ #1\XINT_andof_yes ^% \xintiiifNotZero{#1}\XINT_andof\XINT_andof_no }% \def\XINT_andof_no #1^{ 0}% \def\XINT_andof_yes ^#1\XINT_andof_no{ 1}% % \end{macrocode} % \subsection{\csh{xintORof}} %\begin{lverb} % New with 1.09a. Works also with an empty list. Empty items % however are not accepted. % % 1.2l made \xintORof robust against non terminated items. % % Refactored at 1.4. %\end{lverb} % \begin{macrocode} \def\xintORof {\romannumeral0\xintorof }% \def\xintorof #1{\expandafter\XINT_orof\romannumeral`&&@#1^}% \def\XINT_ORof {\romannumeral0\XINT_orof}% \def\XINT_orof #1% {% \xint_gob_til_^ #1\XINT_orof_no ^% \xintiiifNotZero{#1}\XINT_orof_yes\XINT_orof }% \def\XINT_orof_yes#1^{ 1}% \def\XINT_orof_no ^#1\XINT_orof{ 0}% % \end{macrocode} % \subsection{\csh{xintXORof}} %\begin{lverb} % New with 1.09a. Works with an empty list, too. Empty items % however are not accepted. \XINT_xorof_c more % efficient in 1.09i. % % 1.2l made \xintXORof robust against non terminated items. % % Refactored at 1.4 to use \numexpr (or an \ifnum). I have not tested if % more efficient or not or if one can do better without \the. % \XINT_XORof for xintexpr matters. %\end{lverb} % \begin{macrocode} \def\xintXORof {\romannumeral0\xintxorof }% \def\xintxorof #1{\expandafter\XINT_xorof\romannumeral`&&@#1^}% \def\XINT_XORof {\romannumeral0\XINT_xorof}% \def\XINT_xorof {\if1\the\numexpr\XINT_xorof_a}% \def\XINT_xorof_a #1% {% \xint_gob_til_^ #1\XINT_xorof_e ^% \xintiiifNotZero{#1}{-}{}\XINT_xorof_a }% \def\XINT_xorof_e ^#1\XINT_xorof_a {1\relax\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% % \end{macrocode} % \subsection{\csh{xintiiMax}} %\begin{lverb} % At 1.2m, a long-standing bug was fixed: \xintiiMax had the overhead of % applying \xintNum to its arguments due to use of a sub-macro of \xintGeq % code to which this overhead was added at some point. % % And on this occasion I reduced even more number of times input is grabbed. %\end{lverb} % \begin{macrocode} \def\xintiiMax {\romannumeral0\xintiimax }% \def\xintiimax #1% {% \expandafter\xint_iimax \romannumeral`&&@#1\xint: }% \def\xint_iimax #1\xint:#2% {% \expandafter\XINT_max_fork\romannumeral`&&@#2\xint:#1\xint: }% % \end{macrocode} %\begin{lverb} % #3#4 vient du *premier*, % #1#2 vient du *second*. I have renamed the sub-macros at 1.2m because the % terminology was quite counter-intuitive; there was no bug, but still. %\end{lverb} % \begin{macrocode} \def\XINT_max_fork #1#2\xint:#3#4\xint: {% \xint_UDsignsfork #1#3\XINT_max_minusminus % A < 0, B < 0 #1-\XINT_max_plusminus % B < 0, A >= 0 #3-\XINT_max_minusplus % A < 0, B >= 0 --{\xint_UDzerosfork #1#3\XINT_max_zerozero % A = B = 0 #10\XINT_max_pluszero % B = 0, A > 0 #30\XINT_max_zeroplus % A = 0, B > 0 00\XINT_max_plusplus % A, B > 0 \krof }% \krof #3#1#2\xint:#4\xint: \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi {#3#4}{#1#2}% }% % \end{macrocode} %\begin{lverb} % Refactored at 1.2m for avoiding grabbing arguments. Position of inputs % shared with iiCmp and iiGeq code. %\end{lverb} % \begin{macrocode} \def\XINT_max_zerozero #1\fi{\xint_stop_atfirstoftwo }% \def\XINT_max_zeroplus #1\fi{\xint_stop_atsecondoftwo }% \def\XINT_max_pluszero #1\fi{\xint_stop_atfirstoftwo }% \def\XINT_max_minusplus #1\fi{\xint_stop_atsecondoftwo }% \def\XINT_max_plusminus #1\fi{\xint_stop_atfirstoftwo }% \def\XINT_max_plusplus {% \if1\romannumeral0\XINT_geq_plusplus }% % \end{macrocode} %\begin{lverb} % Premier des testés |A|=-A, second est |B|=-B. On veut le max(A,B), % c'est donc A si |A|<|B| (ou |A|=|B|, mais peu importe alors). Donc on peut % faire cela avec \unless. Simple. %\end{lverb} % \begin{macrocode} \def\XINT_max_minusminus --% {% \unless\if1\romannumeral0\XINT_geq_plusplus{}{}% }% % \end{macrocode} % \subsection{\csh{xintiiMin}} %\begin{lverb} % New with 1.09a. I add \xintiiMin in 1.1 and \xintMin is % an $xintfracnameimp macro. % % At 1.2m, a long-standing bug was fixed: \xintiiMin had the overhead of % applying \xintNum to its arguments due to use of a sub-macro of \xintGeq % code to which this overhead was added at some point. % % And on this occasion I reduced even more number of times input is grabbed. %\end{lverb} % \begin{macrocode} \def\xintiiMin {\romannumeral0\xintiimin }% \def\xintiimin #1% {% \expandafter\xint_iimin \romannumeral`&&@#1\xint: }% \def\xint_iimin #1\xint:#2% {% \expandafter\XINT_min_fork\romannumeral`&&@#2\xint:#1\xint: }% \def\XINT_min_fork #1#2\xint:#3#4\xint: {% \xint_UDsignsfork #1#3\XINT_min_minusminus % A < 0, B < 0 #1-\XINT_min_plusminus % B < 0, A >= 0 #3-\XINT_min_minusplus % A < 0, B >= 0 --{\xint_UDzerosfork #1#3\XINT_min_zerozero % A = B = 0 #10\XINT_min_pluszero % B = 0, A > 0 #30\XINT_min_zeroplus % A = 0, B > 0 00\XINT_min_plusplus % A, B > 0 \krof }% \krof #3#1#2\xint:#4\xint: \expandafter\xint_stop_atsecondoftwo \else \expandafter\xint_stop_atfirstoftwo \fi {#3#4}{#1#2}% }% \def\XINT_min_zerozero #1\fi{\xint_stop_atfirstoftwo }% \def\XINT_min_zeroplus #1\fi{\xint_stop_atfirstoftwo }% \def\XINT_min_pluszero #1\fi{\xint_stop_atsecondoftwo }% \def\XINT_min_minusplus #1\fi{\xint_stop_atfirstoftwo }% \def\XINT_min_plusminus #1\fi{\xint_stop_atsecondoftwo }% \def\XINT_min_plusplus {% \if1\romannumeral0\XINT_geq_plusplus }% \def\XINT_min_minusminus --% {% \unless\if1\romannumeral0\XINT_geq_plusplus{}{}% }% % \end{macrocode} % \subsection{\csh{xintiiMaxof}} %\begin{lverb} % New with 1.09a. 1.2 has NO MORE \xintMaxof, requires \xintfracname. % 1.2a adds \xintiiMaxof, as \xintiiMaxof:csv is not public. % % NOT compatible with empty list. % % 1.2l made \xintiiMaxof robust against non terminated items. % % 1.4 refactors code to allow empty argument. For usage by \xintiiexpr. % Slight deterioration, will come back. % %\end{lverb} % \begin{macrocode} \def\xintiiMaxof {\romannumeral0\xintiimaxof }% \def\xintiimaxof #1{\expandafter\XINT_iimaxof\romannumeral`&&@#1^}% \def\XINT_iiMaxof{\romannumeral0\XINT_iimaxof}% \def\XINT_iimaxof#1% {% \xint_gob_til_^ #1\XINT_iimaxof_empty ^% \expandafter\XINT_iimaxof_loop\romannumeral`&&@#1\xint: }% \def\XINT_iimaxof_empty ^#1\xint:{ 0}% \def\XINT_iimaxof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_iimaxof_e ^% \expandafter\XINT_iimaxof_loop\romannumeral0\xintiimax{#1}{#2}\xint: }% \def\XINT_iimaxof_e ^#1\xintiimax #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintiiMinof}} %\begin{lverb} % 1.09a. 1.2a adds \xintiiMinof which was lacking. % % 1.4 refactoring for \xintiiexpr matters. %\end{lverb} % \begin{macrocode} \def\xintiiMinof {\romannumeral0\xintiiminof }% \def\xintiiminof #1{\expandafter\XINT_iiminof\romannumeral`&&@#1^}% \def\XINT_iiMinof{\romannumeral0\XINT_iiminof}% \def\XINT_iiminof#1% {% \xint_gob_til_^ #1\XINT_iiminof_empty ^% \expandafter\XINT_iiminof_loop\romannumeral`&&@#1\xint: }% \def\XINT_iiminof_empty ^#1\xint:{ 0}% \def\XINT_iiminof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_iiminof_e ^% \expandafter\XINT_iiminof_loop\romannumeral0\xintiimin{#1}{#2}\xint: }% \def\XINT_iiminof_e ^#1\xintiimin #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintiiSum}} %\begin{lverb} % \xintiiSum {{a}{b}...{z}} % Refactored at 1.4 for matters initially related to xintexpr delimiter % choice. % % %\end{lverb} % \begin{macrocode} \def\xintiiSum {\romannumeral0\xintiisum }% \def\xintiisum #1{\expandafter\XINT_iisum\romannumeral`&&@#1^}% \def\XINT_iiSum{\romannumeral0\XINT_iisum}% \def\XINT_iisum #1{\expandafter\XINT_iisum_loop\expandafter{\romannumeral0\CALX_nfromraw{0}}{#1}}% \def\XINT_iisum_loop #1#2{% \xint_gob_til_^ #2\XINT_iisum_end ^% \XINT_iisum_next{#1}{#2}% }% \def\XINT_iisum_next #1#2{% \expandafter\XINT_iisum_next_a\romannumeral0\CALX_nfromraw{#2}\xint:{#1}% }% \def\XINT_iisum_next_a #1\xint:#2{% \expandafter\XINT_iisum_loop\expandafter {\romannumeral0\CALX_naddready{#2}{#1}}% }% \def\XINT_iisum_end ^\XINT_iisum_next #1#2{\CALX_ntoraw{#1}}% % \end{macrocode} % \subsection{\csh{xintiiPrd}} %\begin{lverb} % \xintiiPrd {{a}...{z}} % % % Macros renamed and refactored (slightly more macros here to supposedly bring % micro-gain) at 1.4 to match changes in xintfrac of delimiter, in sync with % some usage in xintexpr. % % Contrarily to the xintfrac version \xintPrd, this one aborts as soon as it % hits a zero value. % % %\end{lverb} % \begin{macrocode} \def\xintiiPrd {\romannumeral0\xintiiprd }% \def\xintiiprd #1{\expandafter\XINT_iiprd\romannumeral`&&@#1^}% \def\XINT_iiPrd{\romannumeral0\XINT_iiprd}% % \end{macrocode} %\begin{lverb} % The above romannumeral caused f-expansion of the list argument. % We f-expand below the first item and each successive items because % The product is accumulated in native format; each factor is converted % once, and the accumulator is converted back to raw at the end. % %\end{lverb} % \begin{macrocode} \def\XINT_iiprd #1{\expandafter\XINT_iiprd_loop\expandafter{\romannumeral0\CALX_nfromraw{1}}{#1}}% \def\XINT_iiprd_loop #1#2{% \xint_gob_til_^ #2\XINT_iiprd_end ^% \XINT_iiprd_next{#1}{#2}% }% \def\XINT_iiprd_next #1#2{% \expandafter\XINT_iiprd_next_a\romannumeral0\CALX_nfromraw{#2}\xint:{#1}% }% \def\XINT_iiprd_next_a #1\xint:#2{% \expandafter\XINT_iiprd_loop\expandafter {\romannumeral0\CALX_nmulready{#2}{#1}}% }% \def\XINT_iiprd_end ^\XINT_iiprd_next #1#2{\CALX_ntoraw{#1}}% % \end{macrocode} % \subsection{\csh{xintiiSquareRoot}} %\begin{lverb} % First done with 1.08. % % 1.1 added \xintiiSquareRoot. % % 1.1a added \xintiiSqrtR. % % 1.2f (2016/03/01-02-03) has rewritten the implementation, the underlying % mathematics remaining about the same. The routine is much faster for inputs % having up to 16 digits (because it does it all with \numexpr directly now), % and also much faster for very long inputs (because it now fetches only the % needed new digits after the first 16 (or 17) ones, via the geometric % sequence 16, then 32, then 64, etc...; earlier version did the computations % with all remaining digits after a suitable starting point with correct 4 or % 5 leading digits). Note however that the fetching of tokens is via % intrinsically O(N^2) macros, hence inevitably inputs with thousands of % digits start being treated less well. % % Actually there is some room for improvements, one could prepare better % input X for the upcoming treatment of fetching its digits by 16, then 32, % then 64, etc... % % Incidently, as \xintiiSqrt uses subtraction and subtraction was broken from % 1.2 to 1.2c, then for another reason from 1.2c to 1.2f, it could % get wrong in certain (relatively rare) cases. There was also a bug that % made it unneedlessly slow for odd number of digits on input. % % 1.2f also modifies \xintFloatSqrt in xintfrac.sty which now has more % code in common with here and benefits from the same speed improvements. % % 1.2k belatedly corrects the output to {1}{1} and not 11 when input is zero. % As braces are used in all other cases they should have been used here too. % % Also, 1.2k adds an \xintiSqrtR macro, for coherence as \xintiSqrt is % defined (and mentioned in user manual.) % % % calx (s58): at most 16 digits, calxint's \CALX_sqrt_start (Burnol's % start, small and medium paths) as before; more than 16 digits, calxint's % native \CALX_nsqrtrem: {S}{R} with S = isqrt(X), R = X - S^2, and the % output {S+1}{2S+1-R} (\XINT_sqrt_nb, \XINT_sqrt_nc). xint's big path % (\XINT_sqrt_big_*) is deleted. The digit count is that of \xintlength, % so a count register (one token) still takes the \numexpr small path. %\end{lverb} % % \begin{macrocode} \def\xintiiSquareRoot {\romannumeral0\xintiisquareroot }% \def\xintiisquareroot #1{\expandafter\XINT_sqrt_checkin\romannumeral`&&@#1\xint:}% \def\XINT_sqrt_checkin #1% {% \xint_UDzerominusfork #1-\XINT_sqrt_iszero 0#1\XINT_sqrt_isneg 0-\XINT_sqrt \krof #1% }% \def\XINT_sqrt_iszero #1\xint:{{1}{1}}% \def\XINT_sqrt_isneg #1\xint: {\XINT_legacysignalcondition{InvalidOperation}% {Square root of negative: #1.}{}{{0}{0}}}% \def\XINT_sqrt #1\xint: {% \expandafter\XINT_sqrt_a\romannumeral0\xintlength {#1}.#1.% }% \def\XINT_sqrt_a #1.% {% \ifnum #1>\xint_c_xvi \expandafter\XINT_sqrt_n\fi \CALX_sqrt_start #1.% }% \def\XINT_sqrt_n\CALX_sqrt_start #1.#2.% {% \expandafter\XINT_sqrt_nb\romannumeral0\CALX_nsqrtrem{\CALX_nfromraw{#2}}% }% \def\XINT_sqrt_nb #1#2% {% \expandafter\XINT_sqrt_nc \romannumeral0\CALX_nadd{#1}{\XINT_sqrt_one}\xint:{#1}{#2}% }% \def\XINT_sqrt_nc #1\xint:#2#3% {% \expanded{{\romannumeral0\CALX_ntoraw{#1}}% {\romannumeral0\CALX_ntoraw{\CALX_nsub{\CALX_nadd{#1}{#2}}{#3}}}}% }% \expandafter\def\expandafter\XINT_sqrt_one\expandafter{\string N+1.100000001!}% % \end{macrocode} % \subsection{\csh{xintiiSqrt}, \csh{xintiiSqrtR}} % \begin{macrocode} \def\xintiiSqrt {\romannumeral0\xintiisqrt }% \def\xintiisqrt {\expandafter\XINT_sqrt_post\romannumeral0\xintiisquareroot }% \def\XINT_sqrt_post #1#2{\XINT_dec #1\XINT_dec_bye234567890\xint_bye}% \def\xintiiSqrtR {\romannumeral0\xintiisqrtr }% \def\xintiisqrtr {\expandafter\XINT_sqrtr_post\romannumeral0\xintiisquareroot }% % \end{macrocode} %\begin{lverb} % N = (#1)^2 - #2 avec #1 le plus petit possible et #2>0 (hence #2<2*#1). % (#1-.5)^2=#1^2-#1+.25=N+#2-#1+.25. Si 0<#2<#1, <= N-0.75#1 % si #2>=#1, (#1-.5)^2>=N+.25>N, donc rounded->#1-1. %\end{lverb} % \begin{macrocode} \def\XINT_sqrtr_post #1#2% {\xintiiifLt {#2}{#1}{ #1}{\XINT_dec #1\XINT_dec_bye234567890\xint_bye}}% % \end{macrocode} % \subsection{\csh{xintiiBinomial}} %\begin{lverb} % 2015/11/28-29 for 1.2f. % % 2016/11/19 for 1.2h: I truly can't understand why I hard-coded last % year an error-message for arguments outside of the range for binomial % formula. Naturally there should be no error but a rather a 0 return % value for binomial(x,y), if y<0 or x=2^31 an arithmetic overflow error will % have happened already. %\end{lverb} % \begin{macrocode} \def\XINT_binom_fork #1#2.#3#4.#5#6.% {% \if-#5\xint_dothis{\XINT_legacysignalcondition{InvalidOperation}% {Binomial with negative first argument: #5#6.}{}{ 0}}\fi \if-#1\xint_dothis{ 0}\fi \if-#3\xint_dothis{ 0}\fi \if0#1\xint_dothis{ 1}\fi \if0#3\xint_dothis{ 1}\fi \ifnum #5#6>\xint_c_e_viii_mone\xint_dothis {\XINT_legacysignalcondition{InvalidOperation}% {Binomial with too large argument: #5#6 >= 10^8.}{}{ 0}}\fi \ifnum #1#2>#3#4 \xint_dothis{\CALX_ntoraw{\CALX_binom_a #1#2.#3#4.}}\fi \xint_orthat{\CALX_ntoraw{\CALX_binom_a #3#4.#1#2.}}% }% % \end{macrocode} %\begin{lverb} % x-k.k. avec 0=b, return 1 % because of an empty product. If a=0 and % (-1)^(b-a) times |b|...(|a|-1) for b<0. But only for the range 0<= % a <= b < 10^8 is the macro result to be considered as stable. %\end{lverb} % \begin{macrocode} \def\xintiiPFactorial {\romannumeral0\xintiipfactorial }% \def\xintiipfactorial #1#2% {% \expandafter\XINT_pfac_fork\the\numexpr#1\expandafter.\the\numexpr #2.% }% \def\xintPFactorial{\romannumeral0\xintpfactorial}% \let\xintpfactorial\xintiipfactorial % \end{macrocode} %\begin{lverb} % The product is computed by calxcore's \CALX_npfac. %\end{lverb} % \begin{macrocode} \def\XINT_pfac_fork #1#2.#3#4.% {% \unless\ifnum #1#2<#3#4 \xint_dothis\XINT_pfac_one\fi \if-#3\xint_dothis\XINT_pfac_neg\fi \if-#1\xint_dothis\XINT_pfac_zero\fi \ifnum #3#4>\xint_c_e_viii_mone\xint_dothis\XINT_pfac_outofrange\fi \xint_orthat \XINT_pfac_a #1#2.#3#4.% }% \def\XINT_pfac_outofrange #1.#2.% {\XINT_legacysignalcondition{InvalidOperation}% {pFactorial with too large argument: #2 >= 10^8.}{}{ 0}}% \def\XINT_pfac_one #1.#2.{ 1}% \def\XINT_pfac_zero #1.#2.{ 0}% \def\XINT_pfac_neg -#1.-#2.% {% \ifnum #1>\xint_c_e_viii\xint_dothis\XINT_pfac_outofrange\fi \xint_orthat {\ifodd\numexpr#2-#1\relax\xint_afterfi{\expandafter-\romannumeral`&&@}\fi \expandafter\XINT_pfac_a }% \the\numexpr #2-\xint_c_i\expandafter.\the\numexpr#1-\xint_c_i.% }% \def\XINT_pfac_a #1.#2.{\CALX_ntoraw{\CALX_npfac{#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintiiGCD}} %\begin{lverb} % Computed by calxint's \CALX_ngcd (Euclid's algorithm on native integers). %\end{lverb} % \begin{macrocode} \def\xintiiGCD {\romannumeral0\xintiigcd }% \def\xintiigcd #1#2% {\CALX_ntoraw{\CALX_ngcd{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{\csh{xintiiGCDof}} %\begin{lverb} % New with 1.09a (was located in xintgcd.sty). % % 1.2l adds protection against items being non-terminated \the\numexpr. % % 1.4 renames the macro into \xintiiGCDof and moves it here. % Terminator modified to ^ for direct call by \xintiiexpr function. % % 1.4d fixes breakage inherited since 1.3d rom \xintiiGCD, in case % any argument vanished. % % Currently does not support empty list of arguments. %\end{lverb} % \begin{macrocode} \def\xintiiGCDof {\romannumeral0\xintiigcdof }% \def\xintiigcdof #1{\expandafter\XINT_iigcdof_a\romannumeral`&&@#1^}% \def\XINT_iigcdof_a #1{\expandafter\XINT_iigcdof_b\romannumeral`&&@#1!}% \def\XINT_iigcdof_b #1!#2{\expandafter\XINT_iigcdof_c\romannumeral`&&@#2!{#1}!}% \def\XINT_iigcdof_c #1{\xint_gob_til_^ #1\XINT_iigcdof_e ^\XINT_iigcdof_d #1}% \def\XINT_iigcdof_d #1!{\expandafter\XINT_iigcdof_b\romannumeral0\xintiigcd {#1}}% \def\XINT_iigcdof_e #1!#2!{ #2}% % \end{macrocode} % \subsection{\csh{xintiiLCM}} %\begin{lverb} % Computed by calxint's \CALX_nlcm. %\end{lverb} % \begin{macrocode} \def\xintiiLCM {\romannumeral0\xintiilcm}% \def\xintiilcm #1#2% {\CALX_ntoraw{\CALX_nlcm{\CALX_nfromraw{#1}}{\CALX_nfromraw{#2}}}}% % \end{macrocode} % \subsection{\csh{xintiiLCMof}} %\begin{lverb} % See comments of \xintiiGCDof. %\end{lverb} % \begin{macrocode} \def\xintiiLCMof {\romannumeral0\xintiilcmof }% \def\xintiilcmof #1{\expandafter\XINT_iilcmof_a\romannumeral`&&@#1^}% \def\XINT_iilcmof_a #1{\expandafter\XINT_iilcmof_b\romannumeral`&&@#1!}% \def\XINT_iilcmof_b #1!#2{\expandafter\XINT_iilcmof_c\romannumeral`&&@#2!{#1}!}% \def\XINT_iilcmof_c #1{\xint_gob_til_^ #1\XINT_iilcmof_e ^\XINT_iilcmof_d #1}% \def\XINT_iilcmof_d #1!{\expandafter\XINT_iilcmof_b\romannumeral0\xintiilcm {#1}}% \def\XINT_iilcmof_e #1!#2!{ #2}% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xint} % \cleardoublepage\let\xintnameUp\undefined %\gardesactifs %\let\relax %\let<*xintbinhex>\gardesinactifs %^^A------------------------------------------------------- %<*xintbinhex>^^A------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintbinhexnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintbinhexnameimp implementation} % \RaisedLabel{sec:binheximp} % % \localtableofcontents % % \subsection{Introduction} % % The commenting is currently (\xintbndldate) still very sparse. % % |1.2m| (|2017/07/31|) rewrote entirely the original macros coming with % |1.08| (|2013/06/07|). % % At |1.2n| the dependencies on \xintcorenameimp were removed, so now the % package loads only \xintkernelnameimp. % % Also at |1.2n| (|2017/08/06|), \cs{csname} governed expansion was used at some places % rather than \cs{numexpr}. This increased the maximal input sizes for % \csbxint{DecToHex}, \csbxint{DecToBin}, and \csbxint{BinToHex}. % % |1.4n| (|2025/09/05|) adds: % \begin{itemize}[nosep] % \item Conversion to and from octal base. % \item Usage of \cs{expanded} in place of the \cs{csname}-based expansion % from |1.2n|. This has increased the maximal input sizes. The increase is % spectacular for the conversions between binary, octal and hexadecimal, the % limit on size being solely dependent on \TeX{} main memory size. This % change however caused seemingly (but barely tested) a slight (1\%) % decrease in speed for \csbxint{DecToHex} and \csbxint{HexToDec}. % \end{itemize} % % Note that the whole architecture was last re-thought in 2017 at a time % \cs{expanded} did not exist. The most subtle coding, which is the one % regarding conversion to and from decimal radix is of such a nature that I am % not motivated at this stage to modify it other than minimally (see initial % code comments for \csbxint{DecToHex}). So the \cs{expanded} was used % therein but only for some subroutines. For the conversions between binary, % octal, and hexadecimal, the whole expansion basically is governed by a % single \cs{expanded}. But for legacy reasons and stylistic coherence across % the codebase, the code keeps using |\romannumeral0| trigger at the start of % the macros with a systematic naming scheme. I am not much motivated to % engage into systematic changes across about \dtt{20000} code lines in the % \xintnameimp bundle! % % \xintexprnameimp loads \xintbinhexnameimp automatically as of |1.4n|. % Formerly it supported only |"| prefix for hexadecimal, now it supports also % |'| for octal, as well as |0x|, |0o| and |0b|. % % |1.4p| adds \csbxint{LowerHex} and \csbxint{UpperHex}. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintbinhex.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintbinhex Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintbinhex}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xintbinhex.sty \ifx\w\relax % but xintkernel.sty not yet loaded. \def\z{\endgroup\input xintkernel.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xintkernel.sty not yet loaded. \def\z{\endgroup\RequirePackage{xintkernel}}% \fi \else \def\z{\endgroup\endinput}% xintbinhex already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintbinhex}% [2026/11/01 v2.0a1 Expandable radix conversions (2, 8, 10, and 16) (JFB)]% % \end{macrocode} % \subsection{Storage macros} % \changed{1.2n} Switch to \cs{csname}-governed expansion at various places. % % \changed{1.4n} Move two \cs{newcount}'s to \xintkernelnameimp. % % \changed{1.4n} This release uses \cs{expanded} in place of \cs{csname} % governed expansion. This means that the mysterious \cs{endcsname}'s have % vanished from the storage macros. And support for octal was added, hence % a few more storage macros were added. % % \added[2025/09/15]{1.4p} New storage macros for expandable uppercasing and % lowercasing utilities. I hesitate having the same but for all of |a..z| and % |A..Z| but then should I allow more ascii chars beyond decimal digits? % \begin{macrocode} \def\XINT_tmpa #1{\ifx\relax#1\else \expandafter\edef\csname XINT_csdth_#1\endcsname {\ifcase #1 0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or 8\or 9\or A\or B\or C\or D\or E\or F\fi}% \expandafter\XINT_tmpa\fi }% \XINT_tmpa {0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}\relax \def\XINT_tmpa #1{\ifx\relax#1\else \expandafter\edef\csname XINT_csdtb_#1\endcsname {\ifcase #1 0000\or 0001\or 0010\or 0011\or 0100\or 0101\or 0110\or 0111\or 1000\or 1001\or 1010\or 1011\or 1100\or 1101\or 1110\or 1111\fi}% \expandafter\XINT_tmpa\fi }% \XINT_tmpa {0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}\relax \let\XINT_tmpa\relax \expandafter\def\csname XINT_csbth_0000\endcsname {0}% \expandafter\def\csname XINT_csbth_0001\endcsname {1}% \expandafter\def\csname XINT_csbth_0010\endcsname {2}% \expandafter\def\csname XINT_csbth_0011\endcsname {3}% \expandafter\def\csname XINT_csbth_0100\endcsname {4}% \expandafter\def\csname XINT_csbth_0101\endcsname {5}% \expandafter\def\csname XINT_csbth_0110\endcsname {6}% \expandafter\def\csname XINT_csbth_0111\endcsname {7}% \expandafter\def\csname XINT_csbth_1000\endcsname {8}% \expandafter\def\csname XINT_csbth_1001\endcsname {9}% \expandafter\def\csname XINT_csbth_1010\endcsname {A}% \expandafter\def\csname XINT_csbth_1011\endcsname {B}% \expandafter\def\csname XINT_csbth_1100\endcsname {C}% \expandafter\def\csname XINT_csbth_1101\endcsname {D}% \expandafter\def\csname XINT_csbth_1110\endcsname {E}% \expandafter\def\csname XINT_csbth_1111\endcsname {F}% \expandafter\def\csname XINT_csbto_000\endcsname {0}% \expandafter\def\csname XINT_csbto_001\endcsname {1}% \expandafter\def\csname XINT_csbto_010\endcsname {2}% \expandafter\def\csname XINT_csbto_011\endcsname {3}% \expandafter\def\csname XINT_csbto_100\endcsname {4}% \expandafter\def\csname XINT_csbto_101\endcsname {5}% \expandafter\def\csname XINT_csbto_110\endcsname {6}% \expandafter\def\csname XINT_csbto_111\endcsname {7}% \expandafter\def\csname XINT_cshtb_0\endcsname {0000}% \expandafter\def\csname XINT_cshtb_1\endcsname {0001}% \expandafter\def\csname XINT_cshtb_2\endcsname {0010}% \expandafter\def\csname XINT_cshtb_3\endcsname {0011}% \expandafter\def\csname XINT_cshtb_4\endcsname {0100}% \expandafter\def\csname XINT_cshtb_5\endcsname {0101}% \expandafter\def\csname XINT_cshtb_6\endcsname {0110}% \expandafter\def\csname XINT_cshtb_7\endcsname {0111}% \expandafter\def\csname XINT_cshtb_8\endcsname {1000}% \expandafter\def\csname XINT_cshtb_9\endcsname {1001}% \def\XINT_cshtb_A {1010}% \def\XINT_cshtb_B {1011}% \def\XINT_cshtb_C {1100}% \def\XINT_cshtb_D {1101}% \def\XINT_cshtb_E {1110}% \def\XINT_cshtb_F {1111}% \expandafter\def\csname XINT_csotb_0\endcsname {000}% \expandafter\def\csname XINT_csotb_1\endcsname {001}% \expandafter\def\csname XINT_csotb_2\endcsname {010}% \expandafter\def\csname XINT_csotb_3\endcsname {011}% \expandafter\def\csname XINT_csotb_4\endcsname {100}% \expandafter\def\csname XINT_csotb_5\endcsname {101}% \expandafter\def\csname XINT_csotb_6\endcsname {110}% \expandafter\def\csname XINT_csotb_7\endcsname {111}% \def\XINT_tmpa#1#2{% \ifx#1\relax\else \expandafter\def\csname XINT_lower #1\endcsname{#1}% \expandafter\def\csname XINT_upper #1\endcsname{#2}% \expandafter\def\csname XINT_lower #2\endcsname{#1}% \expandafter\def\csname XINT_upper #2\endcsname{#2}% \expandafter\XINT_tmpa\fi }% \XINT_tmpa 00112233445566778899aAbBcCdDeEfF\relax\relax % \end{macrocode} % \subsection{Helper macros} % We need at |1.4n| to ensure lengths either multiple of 5, 4 or 3. % For multiples of three we simply imitate what we had in 2017 % for multiples of four. For multiples of five we will do it % rather ``in place'' appealing to \csbxint{Length} and % \csbxint{Replicate} for convenience. I suspected grabbing % five by five (as we can't do ten by ten) would prove less % efficient, but I am not motivated enough at this stage to % devote the time needed for implementing and comparing. % \subsubsection{\csh{XINT_zeroes_foriv}} %\noindent %\begin{lverb} %( \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}$% %: \R{0\R}{00\R}{000\R}\R\W %) % expands to or 0 or 00 or 000 as needed to prepend to #1 % to extend it to length 4N. %\end{lverb} % \begin{macrocode} \def\XINT_zeroes_foriv #1#2#3#4#5#6#7#8% {% \xint_gob_til_R #8\XINT_zeroes_foriv_end\R\XINT_zeroes_foriv }% \def\XINT_zeroes_foriv_end\R\XINT_zeroes_foriv #1#2\W {\XINT_zeroes_foriv_done #1}% \def\XINT_zeroes_foriv_done #1\R{ #1}% % \end{macrocode} % \subsubsection{\csh{XINT_zeroes_foriii}} % \added{1.4n} %\begin{lverb} %( \romannumeral0\XINT_zeroes_foriii #1\R{0\R}{00\R}$% %: \R{0\R}{00\R}$% %: \R{0\R}{00\R}\R\W %) % expands to or 0 or 00 as needed to prepend to #1 % to extend it to length 3N. %\end{lverb} % \begin{macrocode} \def\XINT_zeroes_foriii #1#2#3#4#5#6#7#8#9% {% \xint_gob_til_R #9\XINT_zeroes_foriii_end\R\XINT_zeroes_foriii }% \def\XINT_zeroes_foriii_end\R\XINT_zeroes_foriii #1#2\W {\XINT_zeroes_foriii_done #1}% \def\XINT_zeroes_foriii_done #1\R{ #1}% % \end{macrocode} % \subsection{\csh{xintDecToHex}} % % Now that illicit tools such as \ctanpackage{unravel} exist, we can not hide % anymore too much the crux of the matter. Let's simply say that the decimal % input is tacitly converted into a sequence of successive elementary steps % ``multiply by 10000 and add a base 10000 digit''. This is made to act on a % sequence of radix $16^4$ digits (note that $10000<16^4$). Those radix % $16^4$ digits are of course manipulated via \cs{numexpr} as $10^5$-based % digits (note that $16^4<10^5$ and that not only $16^4\cdot 1000< 10^9 % <2^{31}$ but also $10^9+16^4\cdot 1000<2^{31}$ which helps in ensuring % certain operations expand to a fixed number of digit tokens). When the % sequence of elementary steps is complete, the base-$16^4$ digits only need % to be converted to hexadecimal notation and purged of separators. Of course % doing the whole thing expandably requires some skill. This was done when I % was not yet an old man, and obviously was still very clever. Enjoy. % % % \changed{1.2m} Rewritten from scratch using the \xintcorenameimp % |1.2| style. Now guards against non terminated inputs. % % \changed{1.2n} % Coding improvements, \cs{csname}-governed expansion, increased maximal size. % % \changed{1.2o} % Again coding improvements (efficiency gain about 6\%). % % \changed{1.4n} % Replacement of \cs{csname}-based expansion by usage of \cs{expanded}. This % has increased the maximal input size from 12035 to 16042 digits (depends on % nesting level; evaluated with TL2025 default \TeX{} memory parameters, see % user manual). I noticed a slight performance decrease of the order of 1\% % but did not test extensively. % % Perhaps \cs{expanded} could be used to a deeper refactoring but... I % preferred to make minimal changes, not having kept in mind all subtle % details of the 2017 code. % \begin{macrocode} \def\xintDecToHex {\romannumeral0\xintdectohex }% \def\xintdectohex #1% {% \expandafter\XINT_dth_checkin\romannumeral`&&@#1\xint: }% \def\XINT_dth_checkin #1% {% \xint_UDsignfork #1\XINT_dth_neg -{\XINT_dth_main #1}% \krof }% \def\XINT_dth_neg {\expandafter-\romannumeral0\XINT_dth_main}% \def\XINT_dth_main #1\xint: {% \expandafter\XINT_dth_finish \romannumeral`&&@\expandafter\XINT_dthb_start \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1\xint_bye\XINT_dth_tohex }% \def\XINT_dthb_start #1#2#3#4#5% {% \xint_bye#5\XINT_dthb_small\xint_bye\XINT_dthb_start_a #1#2#3#4#5% }% \def\XINT_dthb_small\xint_bye\XINT_dthb_start_a #1\xint_bye#2{#2#1!}% \def\XINT_dthb_start_a #1#2#3#4#5#6#7#8#9% {% \expandafter\XINT_dthb_again \the\numexpr\expandafter\XINT_dthb_update \the\numexpr#1#2#3#4% \xint_bye#9\XINT_dthb_lastpass\xint_bye #5#6#7#8!\XINT_dthb_exclam\relax\XINT_dthb_nextfour #9% }% % \end{macrocode} %\begin{lverb} % The 1.2n inserted % exclamations marks, which when bumping back from \XINT_dthb_again gave rise % to a \numexpr-loop which gathered the ! delimited arguments and inserted % \expandafter\XINT_dthb_update\the\numexpr dynamically. The 1.2o trick is to % insert it here immediately. Then at \XINT_dthb_again the \numexpr will % trigger an already prepared chain. % % The crux of the thing is handling of #3 at \XINT_dthb_update_a. %\end{lverb} % \begin{macrocode} \def\XINT_dthb_exclam {!\XINT_dthb_exclam\relax \expandafter\XINT_dthb_update\the\numexpr}% \def\XINT_dthb_update #1!% {% \expandafter\XINT_dthb_update_a \the\numexpr (#1+\xint_c_ii^xv)/\xint_c_ii^xvi-\xint_c_i\xint: #1\xint:% }% % \end{macrocode} % The four zeros here will get appended to prior digits. They enact % the multiplication by 10000. % \begin{macrocode} \def\XINT_dthb_update_a #1\xint:#2\xint:#3% {% 0000+#1\expandafter#3\the\numexpr#2-#1*\xint_c_ii^xvi }% \def\XINT_dthb_nextfour #1#2#3#4#5% {% \xint_bye#5\XINT_dthb_lastpass\xint_bye #1#2#3#4!\XINT_dthb_exclam\relax\XINT_dthb_nextfour#5% }% \def\XINT_dthb_lastpass\xint_bye #1!#2\xint_bye#3{#1!#3!}% \def\XINT_dthb_again #1!#2#3% {% \ifx#3\relax \expandafter\xint_firstoftwo \else \expandafter\xint_secondoftwo \fi {\expandafter\XINT_dthb_again \the\numexpr \ifnum #1>\xint_c_ \xint_afterfi{\expandafter\XINT_dthb_update\the\numexpr#1}% \fi}% {\ifnum #1>\xint_c_ \xint_dothis{#2#1!}\fi\xint_orthat{!#2!}}% }% % \end{macrocode} % |1.4n| replaces here \cs{csname}'s method by simpler \cs{expanded} control. % This is the part of the algorithm which rewrites base $16^4$ (kept in decimal) % digits into four hexadecimal digits. % \begin{macrocode} \def\XINT_dth_tohex {% \expandafter\XINT_dth_tohex_a\expanded\XINT_tofourhex }% \def\XINT_dth_tohex_a{!\XINT_dth_tohex!}% \def\XINT_tofourhex #1!% {% {\iffalse}\fi\expandafter\XINT_tofourhex_a \the\numexpr (#1+\xint_c_ii^vii)/\xint_c_ii^viii-\xint_c_i\xint: #1\xint: }% \def\XINT_tofourhex_a #1\xint:#2\xint: {% \expandafter\XINT_tofourhex_c \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: #1\xint: #2-\xint_c_ii^viii*#1!% }% \def\XINT_tofourhex_c #1\xint:#2\xint: {% \csname XINT_csdth_#1\endcsname \csname XINT_csdth_\the\numexpr #2-\xint_c_xvi*#1\endcsname \expandafter\XINT_tofourhex_d\the\numexpr }% \def\XINT_tofourhex_d #1!% {% \expandafter\XINT_tofourhex_e \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: #1\xint: }% \def\XINT_tofourhex_e #1\xint:#2\xint: {% \csname XINT_csdth_#1\endcsname \csname XINT_csdth_\the\numexpr #2-\xint_c_xvi*#1\endcsname \iffalse{\fi}% }% % \end{macrocode} % We only clean up up to 3 hexadecimal zeros, as output is produced in chunks % of 4 hex digits, and (this comment added at |1.4n|) as far as I understand % the leading chunk can be |0000| only if input was vanishing. % % The coding for this simple trimming may not be the most efficient, but this % code is executed only once. I remember from 2017 that I had gotten tired to % always try to optimize and did not even try to test efficiency. % \begin{macrocode} \def\XINT_dth_finish !\XINT_dth_tohex!#1#2#3% {% \unless\if#10\xint_dothis{ #1#2#3}\fi \unless\if#20\xint_dothis{ #2#3}\fi \unless\if#30\xint_dothis{ #3}\fi \xint_orthat{ }% }% % \end{macrocode} % \subsection{\csh{xintDecToOct}} % \added{1.4n} % % This late extension to the package is imitated from (the \cs{expanded} % updated) \csbxint{DecToHex}. % % It does not share macros with \csbxint{DecToHeX} to same extent as % \csbxint{DecToBin} does (those macros with |_dthb_| in their names), because % the input gets converted to radix |8^5|, not radix |16^4|. % % Note that we have $10000<8^5<100000$ and refer to \csbxint{DecToHex} for % some information on the algorithm. % \begin{macrocode} \def\xintDecToOct {\romannumeral0\xintdectooct }% \def\xintdectooct #1% {% \expandafter\XINT_dto_checkin\romannumeral`&&@#1\xint: }% \def\XINT_dto_checkin #1% {% \xint_UDsignfork #1\XINT_dto_neg -{\XINT_dto_main #1}% \krof }% \def\XINT_dto_neg {\expandafter-\romannumeral0\XINT_dto_main}% \def\XINT_dto_main #1\xint: {% \expandafter\XINT_dto_finish \romannumeral`&&@\expandafter\XINT_dto_start \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1\xint_bye\XINT_dto_tooct }% \def\XINT_dto_start #1#2#3#4#5% {% \xint_bye#5\XINT_dto_small\xint_bye\XINT_dto_start_a #1#2#3#4#5% }% \def\XINT_dto_small\xint_bye\XINT_dto_start_a #1\xint_bye#2{#2#1!}% \def\XINT_dto_start_a #1#2#3#4#5#6#7#8#9% {% \expandafter\XINT_dto_again\the\numexpr\expandafter\XINT_dto_update \the\numexpr#1#2#3#4% \xint_bye#9\XINT_dto_lastpass\xint_bye #5#6#7#8!\XINT_dto_exclam\relax\XINT_dto_nextfour #9% }% \def\XINT_dto_exclam {!\XINT_dto_exclam\relax \expandafter\XINT_dto_update\the\numexpr}% \def\XINT_dto_update #1!% {% \expandafter\XINT_dto_update_a \the\numexpr (#1+\xint_c_ii^xiv)/\xint_c_ii^xv-\xint_c_i\xint: #1\xint:% }% \def\XINT_dto_update_a #1\xint:#2\xint:#3% {% 0000+#1\expandafter#3\the\numexpr#2-#1*\xint_c_ii^xv }% \def\XINT_dto_nextfour #1#2#3#4#5% {% \xint_bye#5\XINT_dto_lastpass\xint_bye #1#2#3#4!\XINT_dto_exclam\relax\XINT_dto_nextfour#5% }% \def\XINT_dto_lastpass\xint_bye #1!#2\xint_bye#3{#1!#3!}% \def\XINT_dto_again #1!#2#3% {% \ifx#3\relax \expandafter\xint_firstoftwo \else \expandafter\xint_secondoftwo \fi {\expandafter\XINT_dto_again \the\numexpr \ifnum #1>\xint_c_ \xint_afterfi{\expandafter\XINT_dto_update\the\numexpr#1}% \fi}% {\ifnum #1>\xint_c_ \xint_dothis{#2#1!}\fi\xint_orthat{!#2!}}% }% \def\XINT_dto_tooct {% \expandafter\XINT_dto_tooct_a\expanded\XINT_tofiveoct }% \def\XINT_dto_tooct_a{!\XINT_dto_tooct!}% \def\XINT_tofiveoct #1!% {% {\iffalse}\fi\expandafter\XINT_tofiveoct_a \the\numexpr (#1+\xint_c_ii^viii)/\xint_c_ii^ix-\xint_c_i\xint: #1\xint: }% \def\XINT_tofiveoct_a #1\xint:#2\xint: {% \expandafter\XINT_tofiveoct_c \the\numexpr (#1+\xint_c_iv)/\xint_c_viii-\xint_c_i\xint:#1\xint: #2-\xint_c_ii^ix*#1!% }% \def\XINT_tofiveoct_c #1\xint:#2\xint: {% #1\the\numexpr #2-\xint_c_viii*#1\relax \expandafter\XINT_tofiveoct_d\the\numexpr }% \def\XINT_tofiveoct_d #1!% {% \expandafter\XINT_tofiveoct_e \the\numexpr (#1+\xint_c_ii^v)/\xint_c_ii^vi-\xint_c_i\xint: #1\xint: }% \def\XINT_tofiveoct_e #1\xint:#2\xint: {% #1\expandafter\XINT_tofiveoct_f\the\numexpr #2-\xint_c_ii^vi*#1!% }% \def\XINT_tofiveoct_f #1!% {% \expandafter\XINT_tofiveoct_g \the\numexpr (#1+\xint_c_iv)/\xint_c_viii-\xint_c_i\xint: #1\xint: }% \def\XINT_tofiveoct_g #1\xint:#2\xint: {% #1\the\numexpr #2-\xint_c_viii*#1\iffalse{\fi}% }% % \end{macrocode} % We only clean-up up to 4 zero octal digits, as output was % produced in chunks of 5 octal digits and as far as this author % understands his own code, the leading block can not be vanishing, % except when input was itself only with zeros. % \begin{macrocode} \def\XINT_dto_finish !\XINT_dto_tooct!#1#2#3#4% {% \unless\if#10\xint_dothis{ #1#2#3#4}\fi \unless\if#20\xint_dothis{ #2#3#4}\fi \unless\if#30\xint_dothis{ #3#4}\fi \unless\if#40\xint_dothis{ #4}\fi \xint_orthat{ }% }% % \end{macrocode} % \subsection{\csh{xintDecToBin}} % An input without leading zeroes gives an output without leading zeroes. % % Macros with |_dtohb| in their names are shared with \csbxint{DecToHex}. % % \changed{1.2m} % Complete rewrite in the |1.2| style. Also, |1.2m| version is robust % against non terminated inputs. % % \changed{1.2n} % Increased maximal size from using \cs{csname}-based expansion. % % \changed{1.4n} % Same use of \cs{expanded} as in \csbxint{DecToHex}. % \begin{macrocode} \def\xintDecToBin {\romannumeral0\xintdectobin }% \def\xintdectobin #1% {% \expandafter\XINT_dtb_checkin\romannumeral`&&@#1\xint: }% \def\XINT_dtb_checkin #1% {% \xint_UDsignfork #1\XINT_dtb_neg -{\XINT_dtb_main #1}% \krof }% \def\XINT_dtb_neg {\expandafter-\romannumeral0\XINT_dtb_main}% \def\XINT_dtb_main #1\xint: {% \expandafter\XINT_dtb_finish \romannumeral`&&@\expandafter\XINT_dthb_start \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1\xint_bye\XINT_dtb_tobin }% \def\XINT_dtb_tobin {% \expandafter\XINT_dtb_tobin_a\expanded\XINT_tosixteenbits }% \def\XINT_dtb_tobin_a{!\XINT_dtb_tobin!}% \def\XINT_tosixteenbits #1!% {% {\iffalse}\fi\expandafter\XINT_tosixteenbits_a \the\numexpr (#1+\xint_c_ii^vii)/\xint_c_ii^viii-\xint_c_i\xint: #1\xint: }% \def\XINT_tosixteenbits_a #1\xint:#2\xint: {% \expandafter\XINT_tosixteenbits_c \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: #1\xint: #2-\xint_c_ii^viii*#1!% }% \def\XINT_tosixteenbits_c #1\xint:#2\xint: {% \csname XINT_csdtb_#1\endcsname \csname XINT_csdtb_\the\numexpr #2-\xint_c_xvi*#1\endcsname \expandafter\XINT_tosixteenbits_d\the\numexpr }% \def\XINT_tosixteenbits_d #1!% {% \expandafter\XINT_tosixteenbits_e \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: #1\xint: }% \def\XINT_tosixteenbits_e #1\xint:#2\xint: {% \csname XINT_csdtb_#1\endcsname \csname XINT_csdtb_\the\numexpr #2-\xint_c_xvi*#1\endcsname \iffalse{\fi}% }% \def\XINT_dtb_finish !\XINT_dtb_tobin!#1#2#3#4#5#6#7#8% {% \expandafter\XINT_dtb_finish_a\the\numexpr #1#2#3#4#5#6#7#8\relax }% \def\XINT_dtb_finish_a #1{% \def\XINT_dtb_finish_a ##1##2##3##4##5##6##7##8##9% {% \expandafter#1\the\numexpr ##1##2##3##4##5##6##7##8##9\relax }}\XINT_dtb_finish_a { }% % \end{macrocode} % \subsection{\csh{xintHexToDec}} %\begin{lverb} % Completely (and belatedly) rewritten at 1.2m in the 1.2 style. % % 1.2m version robust against non terminated inputs, but there is no primitive % from TeX which may generate hexadecimal digits and provoke expansion ahead, % afaik, except of course if decimal digits are treated as hexadecimal. This % robustness is not on purpose but from need to expand argument and then grab % it again. So we do it safely. % % Increased maximal size at 1.2n. % % 1.2m version robust against non terminated inputs. % % An input without leading zeroes gives an output without leading zeroes. %\end{lverb} % \begin{macrocode} \def\xintHexToDec {\romannumeral0\xinthextodec }% \def\xinthextodec #1% {% \expandafter\XINT_htd_checkin\romannumeral`&&@#1\xint: }% \def\XINT_htd_checkin #1% {% \xint_UDsignfork #1\XINT_htd_neg -{\XINT_htd_main #1}% \krof }% \def\XINT_htd_neg {\expandafter-\romannumeral0\XINT_htd_main}% \def\XINT_htd_main #1\xint: {% \expandafter\XINT_htd_startb \the\numexpr\expandafter\XINT_htd_starta \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\relax }% \def\XINT_htd_starta #1#2#3#4{"#1#2#3#4+\xint_c_e_v!}% \def\XINT_htd_startb 1#1% {% \if#10\expandafter\XINT_htd_startba\else \expandafter\XINT_htd_startbb \fi 1#1% }% \def\XINT_htd_startba 10#1!{\XINT_htd_again #1% \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\XINT_htd_nextfour}% \def\XINT_htd_startbb 1#1#2!{\XINT_htd_again #1!#2% \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\XINT_htd_nextfour}% % \end{macrocode} % It is a bit annoying to grab all to the end here. I had a % version, modeled on the |1.2n| variant of \csbxint{DecToHex} which solved % that problem, but it did not prove much (or at all) faster in my brief % testing and it had the defect of a reduced maximal allowed size of the % input. % \begin{macrocode} \def\XINT_htd_again #1\XINT_htd_nextfour #2% {% \xint_bye #2\XINT_htd_finish\xint_bye \expandafter\XINT_htd_A\the\numexpr \XINT_htd_a #1\XINT_htd_nextfour #2% }% \def\XINT_htd_a #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% #1\expandafter\XINT_htd_update \the\numexpr #2\expandafter\XINT_htd_update \the\numexpr #3\expandafter\XINT_htd_update \the\numexpr #4\expandafter\XINT_htd_update \the\numexpr #5\expandafter\XINT_htd_update \the\numexpr #6\expandafter\XINT_htd_update \the\numexpr #7\expandafter\XINT_htd_update \the\numexpr #8\expandafter\XINT_htd_update \the\numexpr #9\expandafter\XINT_htd_update \the\numexpr \XINT_htd_a }% \def\XINT_htd_nextfour #1#2#3#4% {% *\xint_c_ii^xvi+"#1#2#3#4+\xint_c_e_ix\relax\xint_bye!% 2!3!4!5!6!7!8!9!\xint_bye\XINT_htd_nextfour }% \def\XINT_htd_update 1#1#2#3#4#5% {% *\xint_c_ii^xvi+10000#1#2#3#4#5!% }% % \end{macrocode} % \changed{1.4n} % \csbXINT{_htd_A} small refactoring to introduce shared macros % with the octal conversion routine. Slight loss of efficiency. % \begin{macrocode} \def\XINT_htd_A {\XINT_hotd_A\XINT_htd_again}% \def\XINT_hotd_A #11#2% {% \if#20\expandafter\XINT_hotd_Aa\else \expandafter\XINT_hotd_Ab \fi #11#2% }% \def\XINT_hotd_Aa #110#2#3#4#5{#1#2#3#4#5!}% \def\XINT_hotd_Ab #11#2#3#4#5#6{#1#2!#3#4#5#6!}% \def\XINT_htd_finish\xint_bye \expandafter\XINT_htd_A\the\numexpr \XINT_htd_a #1\XINT_htd_nextfour {% \expandafter\XINT_htd_finish_cuz\the\numexpr0\XINT_htd_unsep_loop #1% }% \def\XINT_htd_unsep_loop #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \expandafter\XINT_unsep_clean \the\numexpr 1#1#2\expandafter\XINT_unsep_clean \the\numexpr 1#3#4\expandafter\XINT_unsep_clean \the\numexpr 1#5#6\expandafter\XINT_unsep_clean \the\numexpr 1#7#8\expandafter\XINT_unsep_clean \the\numexpr 1#9\XINT_htd_unsep_loop_a }% \def\XINT_htd_unsep_loop_a #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% #1\expandafter\XINT_unsep_clean \the\numexpr 1#2#3\expandafter\XINT_unsep_clean \the\numexpr 1#4#5\expandafter\XINT_unsep_clean \the\numexpr 1#6#7\expandafter\XINT_unsep_clean \the\numexpr 1#8#9\XINT_htd_unsep_loop }% \def\XINT_unsep_clean 1{\relax}% also in xintcore \def\XINT_htd_finish_cuz #1{% \def\XINT_htd_finish_cuz ##1##2##3##4##5% {\expandafter#1\the\numexpr ##1##2##3##4##5\relax}% }\XINT_htd_finish_cuz{ }% % \end{macrocode} % \subsection{\csh{xintOctToDec}} % \added{1.4n} % Yes, the explanations are somewhat lacking. Basically this imitates % \csbxint{xintHexToDec} the main difference being to handle 5 octal % digits at a time in place of 4 hexadecimal ones. % \begin{macrocode} \def\xintOctToDec {\romannumeral0\xintocttodec }% \def\xintocttodec #1% {% \expandafter\XINT_otd_checkin\romannumeral`&&@#1\xint: }% \def\XINT_otd_checkin #1% {% \xint_UDsignfork #1\XINT_otd_neg -{\XINT_otd_main #1}% \krof }% \def\XINT_otd_neg {\expandafter-\romannumeral0\XINT_otd_main}% % \end{macrocode} % First we inject leading octal zeroes to make the length a multiple of 5. We % do not try to code a direct way as with \csbXINT{_zeroes_foriv}, in part % because as we can't grab 10 by 10, we would have to proceed 5 by 5, which % for very long input may prove slower than using \csbxint{Length} combined % with \csbxint{Replicate}, as provided by \xintkernelnameimp. However, the % author is not motivated enough to do the alternative coding and compare its % efficiency with the one here. % \begin{macrocode} \def\XINT_otd_main #1\xint: {% \expandafter\XINT_otd_startb \the\numexpr\expandafter\XINT_otd_starta_i \romannumeral0\xintlength{#1}\xint: #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\relax }% \def\XINT_otd_starta_i #1\xint: {% \expandafter\XINT_otd_starta \romannumeral\xintreplicate{\xint_c_v*((#1+\xint_c_ii)/\xint_c_v)-#1}{0}% }% % \end{macrocode} % Now we grab five octal digits and convert to decimal in a \cs{numexpr}. % \begin{macrocode} \def\XINT_otd_starta #1#2#3#4#5{'#1#2#3#4#5+\xint_c_e_v!}% \def\XINT_otd_startb 1#1% {% \if#10\expandafter\XINT_otd_startba\else \expandafter\XINT_otd_startbb \fi 1#1% }% \def\XINT_otd_startba 10#1!{\XINT_otd_again #1% \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\XINT_otd_nextfive}% \def\XINT_otd_startbb 1#1#2!{\XINT_otd_again #1!#2% \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\XINT_otd_nextfive}% \def\XINT_otd_again #1\XINT_otd_nextfive #2% {% \xint_bye #2\XINT_otd_finish\xint_bye \expandafter\XINT_otd_A\the\numexpr \XINT_otd_a #1\XINT_otd_nextfive #2% }% \def\XINT_otd_a #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% #1\expandafter\XINT_otd_update \the\numexpr #2\expandafter\XINT_otd_update \the\numexpr #3\expandafter\XINT_otd_update \the\numexpr #4\expandafter\XINT_otd_update \the\numexpr #5\expandafter\XINT_otd_update \the\numexpr #6\expandafter\XINT_otd_update \the\numexpr #7\expandafter\XINT_otd_update \the\numexpr #8\expandafter\XINT_otd_update \the\numexpr #9\expandafter\XINT_otd_update \the\numexpr \XINT_otd_a }% \def\XINT_otd_nextfive #1#2#3#4#5% {% *\xint_c_ii^xv+'#1#2#3#4#5+\xint_c_e_ix\relax\xint_bye!% 2!3!4!5!6!7!8!9!\xint_bye\XINT_otd_nextfive }% \def\XINT_otd_update 1#1#2#3#4#5% {% *\xint_c_ii^xv+10000#1#2#3#4#5!% }% % \end{macrocode} % We can hook here into the \csbxint{HexToDec} final sub-routines. % \begin{macrocode} \def\XINT_otd_A {\XINT_hotd_A\XINT_otd_again}% \def\XINT_otd_finish\xint_bye \expandafter\XINT_otd_A\the\numexpr \XINT_otd_a #1\XINT_otd_nextfive {% \expandafter\XINT_htd_finish_cuz\the\numexpr0\XINT_htd_unsep_loop #1% }% % \end{macrocode} % \subsection{\csh{xintBinToDec}} %\begin{lverb} % Redone entirely for 1.2m. Starts by converting to hexadecimal % first. % % Increased maximal size at 1.2n. % % An input without leading zeroes gives an output without leading zeroes. % % Robust against non-terminated input. %\end{lverb} % \begin{macrocode} \def\xintBinToDec {\romannumeral0\xintbintodec }% \def\xintbintodec #1% {% \expandafter\XINT_btd_checkin\romannumeral`&&@#1\xint: }% \def\XINT_btd_checkin #1% {% \xint_UDsignfork #1\XINT_btd_N -{\XINT_btd_main #1}% \krof }% \def\XINT_btd_N {\expandafter-\romannumeral0\XINT_btd_main }% \def\XINT_btd_main #1\xint: {% \expandafter\XINT_btd_htd \expanded{\expandafter\XINT_bth_loop \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1nonenone\xint_bye}\xint: }% \def\XINT_btd_htd #1\xint: {% \expandafter\XINT_htd_startb \the\numexpr\expandafter\XINT_htd_starta \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\relax }% % \end{macrocode} % \subsection{\csh{xintHexToOct}} % % \added{1.4n} This is done the lazy way, from hexadecimal to binary to octal. % I am simply not motivated enough at this stage to implement a direct % conversion (3 hexa digits mapping to 4 octal ones), handle leading zeros, % and compare efficiency and size limits with the simple minded one here. % \begin{macrocode} \def\xintHexToOct {\romannumeral0\xinthextooct }% \def\xinthextooct #1% {% \expandafter\XINT_bto_checkin \romannumeral0\expandafter\XINT_htb_checkin\romannumeral`&&@#1.........\xint_bye \iffalse{\fi}% \xint: }% % \end{macrocode} % \subsection{\csh{xintHexToBin}} %\begin{lverb} % Completely rewritten for 1.2m. % % Only up to three zeros are removed on front of output: if the input had a % leading zero, there will be a leading zero (and then possibly 4n of them if % inputs had more leading zeroes) on output. % % Rewritten again at 1.2n for \csname governed expansion. %\end{lverb} % \changed{1.4n} % Use of \cs{expanded} (quasi globally, in contrast to the local uses % made in the decimal conversions).. Dramatic increase of upper limit % on the size of input. % % As a by-product the initial expansion of the argument |#1| is now % guarded at the end by (many) full stops, but anyhow I don't know % \TeX{} construct potentially creating hexadecimal digits and % potentially causing expansion of what comes next if not terminated. % \begin{macrocode} \def\xintHexToBin {\romannumeral0\xinthextobin }% \def\xinthextobin #1% {% \expandafter\XINT_htb_checkin\romannumeral`&&@#1.........\xint_bye \iffalse{\fi}% }% \def\XINT_htb_checkin #1% {% \xint_UDsignfork #1\XINT_htb_N -{\XINT_htb_main #1}% \krof }% \def\XINT_htb_N {\expandafter-\romannumeral0\XINT_htb_main }% \def\XINT_htb_main {% \expandafter\XINT_htb_cuz \expanded{\iffalse}\fi\XINT_htb_loop }% \def\XINT_htb_loop #1#2#3#4#5#6#7#8#9% {% \csname XINT_cshtb_#1\endcsname \csname XINT_cshtb_#2\endcsname \csname XINT_cshtb_#3\endcsname \csname XINT_cshtb_#4\endcsname \csname XINT_cshtb_#5\endcsname \csname XINT_cshtb_#6\endcsname \csname XINT_cshtb_#7\endcsname \csname XINT_cshtb_#8\endcsname \csname XINT_cshtb_#9\endcsname \XINT_htb_loop }% \expandafter\let\csname XINT_cshtb_.\endcsname\xint_bye \def\XINT_htb_cuz #1{% \def\XINT_htb_cuz ##1##2##3##4% {\expandafter#1\the\numexpr##1##2##3##4\relax}% }\XINT_htb_cuz { }% % \end{macrocode} % \subsection{\csh{xintCHexToBin}} %\begin{lverb} % The 1.08 macro had same functionality as \xintHexToBin, and slightly % different code, the 1.2m version has the same code as \xintHexToBin except % that it does not remove leading zeros from output: if the input had N % hexadecimal digits, the output will have exactly 4N binary digits. % % Rewritten again at 1.2n for \csname governed expansion. %\end{lverb} % \changed{1.4n} % Kept in sync with new \csbxint{HexToBin}. % \begin{macrocode} \def\xintCHexToBin {\romannumeral0\xintchextobin }% \def\xintchextobin #1% {% \expandafter\XINT_chtb_checkin\romannumeral`&&@#1.........\xint_bye \iffalse{\fi}% }% \def\XINT_chtb_checkin #1% {% \xint_UDsignfork #1\XINT_chtb_N -{\XINT_chtb_main #1}% \krof }% \def\XINT_chtb_N {\expandafter-\romannumeral0\XINT_chtb_main }% \def\XINT_chtb_main {\expanded{ \iffalse}\fi\XINT_htb_loop}% % \end{macrocode} % \subsection{\csh{xintOctToHex}} % % \added{1.4n} This is done the lazy way, from octal to binary to hexadecimal. % \begin{macrocode} \def\xintOctToHex {\romannumeral0\xintocttohex }% \def\xintocttohex #1% {% \expandafter\XINT_bth_checkin \romannumeral0\expandafter\XINT_otb_checkin\romannumeral`&&@#1.........\xint_bye \iffalse{\fi}% \xint: }% % \end{macrocode} % \subsection{\csh{xintBinToHex}} % \changed{1.2m} Complete rewrite. Much more efficient but smaller maximals sizes. % \changed{1.2n} % Again redone and now using \cs{csname} governed expansion: increased % maximal size. % % Size of output is ceil(size(input)/4). If the input has leading zeroes, % they may exist in the output too. % An input without leading zeroes gives an output without leading zeroes. % % \changed{1.4n} % Expansion is governed by \cs{expanded}. Tremendous increase of maximal % size. Note that for legacy reasons of the package history, the primary % trigger is via |\romannumeral0|, we could use \cs{expanded} upfront, % with some advantages. But well. % \begin{macrocode} \def\xintBinToHex {\romannumeral0\xintbintohex }% \def\xintbintohex #1% {% \expandafter\XINT_bth_checkin\romannumeral`&&@#1\xint: }% \def\XINT_bth_checkin #1% {% \xint_UDsignfork #1\XINT_bth_N -{\XINT_bth_main #1}% \krof }% \def\XINT_bth_N {\expandafter-\romannumeral0\XINT_bth_main }% \def\XINT_bth_main #1\xint: {% \expanded{ \expandafter\XINT_bth_loop \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W #1% nonenone\xint_bye}% }% \def\XINT_bth_loop #1#2#3#4#5#6#7#8% {% \csname XINT_csbth_#1#2#3#4\endcsname \csname XINT_csbth_#5#6#7#8\endcsname \XINT_bth_loop }% \let\XINT_csbth_none\xint_bye % \end{macrocode} % \subsection{\csh{xintOctToBin}} % \added{1.4n} % \begin{macrocode} \def\xintOctToBin {\romannumeral0\xintocttobin }% \def\xintocttobin #1% {% \expandafter\XINT_otb_checkin\romannumeral`&&@#1.........\xint_bye \iffalse{\fi}% }% \def\XINT_otb_checkin #1% {% \xint_UDsignfork #1\XINT_otb_N -{\XINT_otb_main #1}% \krof }% \def\XINT_otb_N {\expandafter-\romannumeral0\XINT_otb_main }% \def\XINT_otb_main {% \expandafter\XINT_otb_cuz \expanded{\iffalse}\fi \XINT_otb_loop }% \def\XINT_otb_loop #1#2#3#4#5#6#7#8#9% {% \csname XINT_csotb_#1\endcsname \csname XINT_csotb_#2\endcsname \csname XINT_csotb_#3\endcsname \csname XINT_csotb_#4\endcsname \csname XINT_csotb_#5\endcsname \csname XINT_csotb_#6\endcsname \csname XINT_csotb_#7\endcsname \csname XINT_csotb_#8\endcsname \csname XINT_csotb_#9\endcsname \XINT_otb_loop }% \expandafter\let\csname XINT_csotb_.\endcsname\xint_bye \def\XINT_otb_cuz #1{% \def\XINT_otb_cuz ##1##2##3% {\expandafter#1\the\numexpr##1##2##3\relax}% }\XINT_otb_cuz { }% % \end{macrocode} % \subsection{\csh{xintCOctToBin}} % \added{1.4n} % \begin{macrocode} \def\xintCOctToBin {\romannumeral0\xintcocttobin }% \def\xintcocttobin #1% {% \expandafter\XINT_cotb_checkin\romannumeral`&&@#1.........\xint_bye \iffalse{\fi}% }% \def\XINT_cotb_checkin #1% {% \xint_UDsignfork #1\XINT_cotb_N -{\XINT_cotb_main #1}% \krof }% \def\XINT_cotb_N {\expandafter-\romannumeral0\XINT_cotb_main }% \def\XINT_cotb_main {\expanded{ \iffalse}\fi\XINT_otb_loop}% % \end{macrocode} % \subsection{\csh{xintBinToOct}} % \added{1.4n} % \begin{macrocode} \def\xintBinToOct {\romannumeral0\xintbintooct }% \def\xintbintooct #1% {% \expandafter\XINT_bto_checkin\romannumeral`&&@#1\xint: }% \def\XINT_bto_checkin #1% {% \xint_UDsignfork #1\XINT_bto_N -{\XINT_bto_main #1}% \krof }% \def\XINT_bto_N {\expandafter-\romannumeral0\XINT_bto_main }% \def\XINT_bto_main #1\xint: {% \expanded{ \expandafter\XINT_bto_loop \romannumeral0\XINT_zeroes_foriii #1\R{0\R}{00\R}\R{0\R}{00\R}\R{0\R}{00\R}\R\W #1% endendend\xint_bye}% }% \def\XINT_bto_loop #1#2#3#4#5#6#7#8#9% {% \csname XINT_csbto_#1#2#3\endcsname \csname XINT_csbto_#4#5#6\endcsname \csname XINT_csbto_#7#8#9\endcsname \XINT_bto_loop }% \let\XINT_csbto_end\xint_bye % \end{macrocode} % \subsection{\csh{xintLowerHex}, \csh{xintUpperHex}} % \added[2025/09/15]{1.4p} % % I really hesitate breaking with the |\romannumeral0| expansion trigger which % is used throughout the codebase with very few exceptions. This adds to % documentation chores. Also there is no absolute necessity to keep defining % the lowercase |\xintlowerhex| but it can help when one needs to propagate % expansion. % % This is modeled on a \ctanpackage{bnumexpr} |1.7| addition. % % There is a deliberate space after |#1| to accomodate for empty input. % \begin{macrocode} \def\xintLowerHex{\expanded\xintlowerhex}% \def\xintlowerhex#1{% {\expandafter\XINT_lowerhex\romannumeral`&&@#1 % \xint_bye23456789\xint_bye\endcsname}% }% \def\XINT_lowerhex #1#2#3#4#5#6#7#8#9{% \csname XINT_lower #1\endcsname \csname XINT_lower #2\endcsname \csname XINT_lower #3\endcsname \csname XINT_lower #4\endcsname \csname XINT_lower #5\endcsname \csname XINT_lower #6\endcsname \csname XINT_lower #7\endcsname \csname XINT_lower #8\endcsname \csname XINT_lower #9\endcsname \XINT_lowerhex }% \expandafter\let\csname XINT_lower \endcsname\empty \def\xintUpperHex{\expanded\xintupperhex}% \def\xintupperhex#1{% {\expandafter\XINT_upperhex\romannumeral`&&@#1 % \xint_bye23456789\xint_bye\endcsname}% }% \def\XINT_upperhex #1#2#3#4#5#6#7#8#9{% \csname XINT_upper #1\endcsname \csname XINT_upper #2\endcsname \csname XINT_upper #3\endcsname \csname XINT_upper #4\endcsname \csname XINT_upper #5\endcsname \csname XINT_upper #6\endcsname \csname XINT_upper #7\endcsname \csname XINT_upper #8\endcsname \csname XINT_upper #9\endcsname \XINT_upperhex }% \expandafter\let\csname XINT_upper \endcsname\empty \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintbinhex} % \cleardoublepage\let\xintbinhexnameUp\undefined %\gardesactifs %\let\relax %\let<*xintgcd>\gardesinactifs %^^A------------------------------------------------- %<*xintgcd>^^A---------------------------------------------------- %^^A -*- ycoding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintgcdnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintgcdnameimp implementation} % \RaisedLabel{sec:gcdimp} % % \localtableofcontents % % \subsection{Introduction} % % The commenting is currently (\xintbndldate) very sparse. % % Release |1.09h| has % modified a bit the |\xintTypesetEuclideAlgorithm| and % |\xintTypesetBezoutAlgorithm| layout with respect to line indentation in % particular. And they use the \xinttoolsnameimp |\xintloop| rather than the % Plain \TeX{} or \LaTeX{}'s |\loop|. % % % Breaking change at |1.2p|: |\xintBezout{A}{B}| formerly had output % |{A}{B}{U}{V}{D}| with |AU-BV=D|, now it is |{U}{V}{D}| with |AU+BV=D|. % % From |1.1| to |1.3f| the package loaded only \xintcorenameimp. At |1.4| it % now automatically loads both of \xintnameimp and \xinttoolsnameimp (the % latter being in fact a requirement of \csbxint{TypesetEuclideAlgorithm} and % \csbxint{TypesetBezoutAlgorithm} since |1.09h|). % % \begin{framed} % At |1.4| \csbxint{GCD}, \csbxint{LCM}, \csbxint{GCDof}, and \csbxint{LCMof} % are \emph{removed} from the package:\IMPORTANTf they are provided only by % \xintfracnameimp and they handle general fractions, not only integers. % % The original\CHANGEDf{1.4} integer-only macros have been renamed into respectively % \csbxint{iiGCD}, \csbxint{iiLCM}, \csbxint{iiGCDof}, and \csbxint{iiLCMof} % and got relocated into \xintnameimp package. % \end{framed} % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintgcd.sty\endcsname \expandafter\let\expandafter\w\csname ver@xint.sty\endcsname \expandafter\let\expandafter\t\csname ver@xinttools.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintgcd Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintgcd}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xintgcd.sty \ifx\w\relax % but xint.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\input xint.sty\relax}% \fi \ifx\t\relax % but xinttools.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\input xinttools.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xint.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\RequirePackage{xint}}% \fi \ifx\t\relax % xinttools.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\RequirePackage{xinttools}}% \fi \else \def\z{\endgroup\endinput}% xintgcd already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintgcd}% [2026/11/01 v2.0a1 Euclide algorithm with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintBezout}} %\begin{lverb} % \xintBezout{#1}{#2} % produces {U}{V}{D} with UA+VB=D, D = PGCD(A,B) (non-positive), % where #1 and #2 f-expand to big integers A and B. % % I had not checked this macro for about three years when I realized in % January 2017 that \xintBezout{A}{B} was buggy for the cases A = 0 or B = 0. % I fixed that blemish in 1.2l but overlooked the other blemish that % \xintBezout{A}{B} with A multiple of B produced a coefficient U as -0 in % place of 0. % % Hence I rewrote again for 1.2p. On this occasion I modified the output % of the macro to be {U}{V}{D} with AU+BV=D, formerly it was % {A}{B}{U}{V}{D} with AU - BV = D. This is quite breaking change! % % Note in particular change of sign of V. % % I don't know why I had designed this macro to contain {A}{B} in its output. % Perhaps I initially intended to output {A//D}{B//D} (but forgot), as this is % actually possible from outcome of the last iteration, with no need of % actually dividing. Current code however arranges to skip this last update, % as U and V are already furnished by the iteration prior to realizing that % the last non-zero remainder was found. % % Also 1.2l raised InvalidOperation if both A and B vanished, but I removed % this behaviour at 1.2p. %\end{lverb} % \begin{macrocode} \def\xintBezout {\romannumeral0\xintbezout }% \def\xintbezout #1% {% \expandafter\XINT_bezout\expandafter {\romannumeral0\xintnum{#1}}% }% \def\XINT_bezout #1#2% {% \expandafter\XINT_bezout_fork \romannumeral0\xintnum{#2}\Z #1\Z }% % \end{macrocode} %\begin{lverb} % #3#4 = A, #1#2=B. Micro improvement for 1.2l. %\end{lverb} % \begin{macrocode} \def\XINT_bezout_fork #1#2\Z #3#4\Z {% \xint_UDzerosfork #1#3\XINT_bezout_botharezero #10\XINT_bezout_secondiszero #30\XINT_bezout_firstiszero 00\xint_UDsignsfork \krof #1#3\XINT_bezout_minusminus % A < 0, B < 0 #1-\XINT_bezout_minusplus % A > 0, B < 0 #3-\XINT_bezout_plusminus % A < 0, B > 0 --\XINT_bezout_plusplus % A > 0, B > 0 \krof {#2}{#4}#1#3% #1#2=B, #3#4=A }% \def\XINT_bezout_botharezero #1\krof#2#300{{0}{0}{0}}% \def\XINT_bezout_firstiszero #1\krof#2#3#4#5% {% \xint_UDsignfork #4{{0}{-1}{#2}}% -{{0}{1}{#4#2}}% \krof }% \def\XINT_bezout_secondiszero #1\krof#2#3#4#5% {% \xint_UDsignfork #5{{-1}{0}{#3}}% -{{1}{0}{#5#3}}% \krof }% % \end{macrocode} %\begin{lverb} % #4#2= A < 0, #3#1 = B < 0 %\end{lverb} % \begin{macrocode} \def\XINT_bezout_minusminus #1#2#3#4% {% \expandafter\XINT_bezout_mm_post \romannumeral0\expandafter\XINT_bezout_preloop_a \romannumeral0\XINT_ndivrawpair {#1}{#2}{#1}% }% \def\XINT_bezout_mm_post #1#2% {% \expandafter\XINT_bezout_mm_postb\expandafter {\romannumeral0\xintiiopp{#2}}{\romannumeral0\xintiiopp{#1}}% }% \def\XINT_bezout_mm_postb #1#2{\expandafter{#2}{#1}}% % \end{macrocode} %\begin{lverb} % minusplus #4#2= A > 0, B < 0 %\end{lverb} % \begin{macrocode} \def\XINT_bezout_minusplus #1#2#3#4% {% \expandafter\XINT_bezout_mp_post \romannumeral0\expandafter\XINT_bezout_preloop_a \romannumeral0\XINT_ndivrawpair {#1}{#4#2}{#1}% }% \def\XINT_bezout_mp_post #1#2% {% \expandafter\xint_exchangetwo_keepbraces\expandafter {\romannumeral0\xintiiopp {#2}}{#1}% }% % \end{macrocode} %\begin{lverb} % plusminus A < 0, B > 0 %\end{lverb} % \begin{macrocode} \def\XINT_bezout_plusminus #1#2#3#4% {% \expandafter\XINT_bezout_pm_post \romannumeral0\expandafter\XINT_bezout_preloop_a \romannumeral0\XINT_ndivrawpair {#3#1}{#2}{#3#1}% }% \def\XINT_bezout_pm_post #1{\expandafter{\romannumeral0\xintiiopp{#1}}}% % \end{macrocode} %\begin{lverb} % plusplus, B = #3#1 > 0, A = #4#2 > 0 %\end{lverb} % \begin{macrocode} \def\XINT_bezout_plusplus #1#2#3#4% {% \expandafter\XINT_bezout_preloop_a \romannumeral0\XINT_ndivrawpair {#3#1}{#4#2}{#3#1}% }% % \end{macrocode} %\begin{lverb} %( n = 0: BA1001 (B, A, e=1, vv, uu, v, u) %: r(1)=B, r(0)=A, après n étapes {r(n+1)}{r(n)}{vv}{uu}{v}{u} %: q(n) quotient de r(n-1) par r(n) %: si reste nul, exit et renvoie U = -e*uu, V = e*vv, A*U+B*V=D %: sinon mise à jour %: vv, v = q * vv + v, vv %: uu, u = q * uu + u, uu %: e = -e %: puis calcul quotient reste et itération %) % % We arrange for \xintiiMul sub-routine to be called only with positive % arguments, thus skipping some un-needed sign parsing there. For that though % we have to screen out the special cases A divides B, or B divides A. And we % first want to exchange A and B if A < B. These special cases are the only % one possibly leading to U or V zero (for A and B positive which is the case % here.) Thus the general case always leads to non-zero U and V's and assigning % a final sign is done simply adding a - to one of them, with no fear of % producing -0. %\end{lverb} % \begin{macrocode} \def\XINT_bezout_preloop_a #1#2#3% {% \if0#1\xint_dothis\XINT_bezout_preloop_exchange\fi \if0#2\xint_dothis\XINT_bezout_preloop_exit\fi \xint_orthat{\expandafter\XINT_bezout_loop_B}% \romannumeral0\XINT_ndivrawpair {#2}{#3}{#2}{#1}110% }% \def\XINT_bezout_preloop_exit \romannumeral0\XINT_ndivrawpair #1#2#3#4#5#6#7% {% {0}{1}{#2}% }% \def\XINT_bezout_preloop_exchange {% \expandafter\xint_exchangetwo_keepbraces \romannumeral0\expandafter\XINT_bezout_preloop_A }% \def\XINT_bezout_preloop_A #1#2#3#4% {% \if0#2\xint_dothis\XINT_bezout_preloop_exit\fi \xint_orthat{\expandafter\XINT_bezout_loop_B}% \romannumeral0\XINT_ndivrawpair {#2}{#3}{#2}{#1}% }% \def\XINT_bezout_loop_B #1#2% {% \if0#2\expandafter\XINT_bezout_exitA \else\expandafter\XINT_bezout_loop_C \fi {#1}{#2}% }% % \end{macrocode} %\begin{lverb} % We use the fact that the \romannumeral-`0 (or equivalent) done by \xintiiadd % will absorb the initial space token left by \XINT_mul_plusplus in its % output. % % We arranged for operands here to be always positive which is needed for % \XINT_mul_plusplus entry point (last time I checked...). Admittedly this % kind of optimization is not good for maintenance of code, but I can't resist % temptation of limiting the shuffling around of tokens... %\end{lverb} % \begin{macrocode} \def\XINT_bezout_loop_C #1#2#3#4#5#6#7% {% \expandafter\XINT_bezout_loop_D\expandafter {\romannumeral0\xintiiadd{\xintiimul{#1}{#4}}{#6}}% {\romannumeral0\xintiiadd{\xintiimul{#1}{#5}}{#7}}% {#2}{#3}{#4}{#5}% }% \def\XINT_bezout_loop_D #1#2% {% \expandafter\XINT_bezout_loop_E\expandafter{#2}{#1}% }% \def\XINT_bezout_loop_E #1#2#3#4% {% \expandafter\XINT_bezout_loop_b \romannumeral0\XINT_ndivrawpair {#3}{#4}{#3}{#2}{#1}% }% \def\XINT_bezout_loop_b #1#2% {% \if0#2\expandafter\XINT_bezout_exita \else\expandafter\XINT_bezout_loop_c \fi {#1}{#2}% }% \def\XINT_bezout_loop_c #1#2#3#4#5#6#7% {% \expandafter\XINT_bezout_loop_d\expandafter {\romannumeral0\xintiiadd{\xintiimul{#1}{#4}}{#6}}% {\romannumeral0\xintiiadd{\xintiimul{#1}{#5}}{#7}}% {#2}{#3}{#4}{#5}% }% \def\XINT_bezout_loop_d #1#2% {% \expandafter\XINT_bezout_loop_e\expandafter{#2}{#1}% }% \def\XINT_bezout_loop_e #1#2#3#4% {% \expandafter\XINT_bezout_loop_B \romannumeral0\XINT_ndivrawpair {#3}{#4}{#3}{#2}{#1}% }% % \end{macrocode} %\begin{lverb} % sortir U, V, D mais on a travaillé avec vv, uu, v, u dans cet ordre.$\ % The code is structured so that #4 and #5 are guaranteed non-zero % if we exit here, hence we can not create a -0 in output. %\end{lverb} % \begin{macrocode} \def\XINT_bezout_exita #1#2#3#4#5#6#7{{-#5}{#4}{#3}}% \def\XINT_bezout_exitA #1#2#3#4#5#6#7{{#5}{-#4}{#3}}% % \end{macrocode} % \subsection{\csh{xintEuclideAlgorithm}} %\begin{lverb} % Pour Euclide: % {N}{A}{D=r(n)}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0}$\ % u<2n> = u<2n+3>u<2n+2> + u<2n+4> à la n ième étape. % % Formerly, used \xintiabs, but got deprecated at 1.2o. %\end{lverb} % \begin{macrocode} \def\xintEuclideAlgorithm {\romannumeral0\xinteuclidealgorithm }% \def\xinteuclidealgorithm #1% {% \expandafter\XINT_euc\expandafter{\romannumeral0\xintiiabs{\xintNum{#1}}}% }% \def\XINT_euc #1#2% {% \expandafter\XINT_euc_fork\romannumeral0\xintiiabs{\xintNum{#2}}\Z #1\Z }% % \end{macrocode} %\begin{lverb} % Ici #3#4=A, #1#2=B %\end{lverb} % \begin{macrocode} \def\XINT_euc_fork #1#2\Z #3#4\Z {% \xint_UDzerofork #1\XINT_euc_BisZero #3\XINT_euc_AisZero 0\XINT_euc_a \krof {0}{#1#2}{#3#4}{{#3#4}{#1#2}}{}\Z }% % \end{macrocode} %\begin{lverb} % Le {} pour protéger {{A}{B}} si on s'arrête après une étape (B divise % A). % On va renvoyer:$\ % {N}{A}{D=r(n)}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0} %\end{lverb} % \begin{macrocode} \def\XINT_euc_AisZero #1#2#3#4#5#6{{1}{0}{#2}{#2}{0}{0}}% \def\XINT_euc_BisZero #1#2#3#4#5#6{{1}{0}{#3}{#3}{0}{0}}% % \end{macrocode} %\begin{lverb} % {n}{rn}{an}{{qn}{rn}}...{{A}{B}}{}\Z$\ % a(n) = r(n-1). Pour n=0 on a juste {0}{B}{A}{{A}{B}}{}\Z$\ % \XINT_ndivrawpair {u}{v} divise v par u %\end{lverb} % \begin{macrocode} \def\XINT_euc_a #1#2#3% {% \expandafter\XINT_euc_b\the\numexpr #1+\xint_c_i\expandafter.% \romannumeral0\XINT_ndivrawpair {#2}{#3}{#2}% }% % \end{macrocode} %\begin{lverb} % {n+1}{q(n+1)}{r(n+1)}{rn}{{qn}{rn}}... %\end{lverb} % \begin{macrocode} \def\XINT_euc_b #1.#2#3#4% {% \XINT_euc_c #3\Z {#1}{#3}{#4}{{#2}{#3}}% }% % \end{macrocode} %\begin{lverb} % r(n+1)\Z {n+1}{r(n+1)}{r(n)}{{q(n+1)}{r(n+1)}}{{qn}{rn}}...$\ % Test si r(n+1) est nul. %\end{lverb} % \begin{macrocode} \def\XINT_euc_c #1#2\Z {% \xint_gob_til_zero #1\XINT_euc_end0\XINT_euc_a }% % \end{macrocode} %\begin{lverb} % {n+1}{r(n+1)}{r(n)}{{q(n+1)}{r(n+1)}}...{}\Z % Ici r(n+1) = 0. On arrête on se prépare à inverser % {n+1}{0}{r(n)}{{q(n+1)}{r(n+1)}}.....{{q1}{r1}}{{A}{B}}{}\Z$\ % On veut renvoyer: {N=n+1}{A}{D=r(n)}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0} %\end{lverb} % \begin{macrocode} \def\XINT_euc_end0\XINT_euc_a #1#2#3#4\Z% {% \expandafter\XINT_euc_end_a \romannumeral0% \XINT_rord_main {}#4{{#1}{#3}}% \xint: \xint_bye\xint_bye\xint_bye\xint_bye \xint_bye\xint_bye\xint_bye\xint_bye \xint: }% \def\XINT_euc_end_a #1#2#3{{#1}{#3}{#2}}% % \end{macrocode} % \subsection{\csh{xintBezoutAlgorithm}} %\begin{lverb} % Pour Bezout: objectif, renvoyer$\ % {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ % {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}$\ % alpha0=1, beta0=0, alpha(-1)=0, beta(-1)=1 %\end{lverb} % \begin{macrocode} \def\xintBezoutAlgorithm {\romannumeral0\xintbezoutalgorithm }% \def\xintbezoutalgorithm #1% {% \expandafter \XINT_bezalg \expandafter{\romannumeral0\xintiiabs{\xintNum{#1}}}% }% \def\XINT_bezalg #1#2% {% \expandafter\XINT_bezalg_fork\romannumeral0\xintiiabs{\xintNum{#2}}\Z #1\Z }% % \end{macrocode} %\begin{lverb} % Ici #3#4=A, #1#2=B %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_fork #1#2\Z #3#4\Z {% \xint_UDzerofork #1\XINT_bezalg_BisZero #3\XINT_bezalg_AisZero 0\XINT_bezalg_a \krof 0{#1#2}{#3#4}1001{{#3#4}{#1#2}}{}\Z }% \def\XINT_bezalg_AisZero #1#2#3\Z{{1}{0}{0}{1}{#2}{#2}{1}{0}{0}{0}{0}{1}}% \def\XINT_bezalg_BisZero #1#2#3#4\Z{{1}{0}{0}{1}{#3}{#3}{1}{0}{0}{0}{0}{1}}% % \end{macrocode} %\begin{lverb} % pour préparer l'étape n+1 il faut % {n}{r(n)}{r(n-1)}{alpha(n)}{beta(n)}{alpha(n-1)}{beta(n-1)}& % {{q(n)}{r(n)}{alpha(n)}{beta(n)}}... % division de #3 par #2 %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_a #1#2#3% {% \expandafter\XINT_bezalg_b\the\numexpr #1+\xint_c_i\expandafter.% \romannumeral0\XINT_ndivrawpair {#2}{#3}{#2}% }% % \end{macrocode} %\begin{lverb} % {n+1}{q(n+1)}{r(n+1)}{r(n)}{alpha(n)}{beta(n)}{alpha(n-1)}{beta(n-1)}... %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_b #1.#2#3#4#5#6#7#8% {% \expandafter\XINT_bezalg_c\expandafter {\romannumeral0\xintiiadd {\xintiiMul {#6}{#2}}{#8}}% {\romannumeral0\xintiiadd {\xintiiMul {#5}{#2}}{#7}}% {#1}{#2}{#3}{#4}{#5}{#6}% }% % \end{macrocode} %\begin{lverb} % {beta(n+1)}{alpha(n+1)}{n+1}{q(n+1)}{r(n+1)}{r(n)}{alpha(n)}{beta(n}} %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_c #1#2#3#4#5#6% {% \expandafter\XINT_bezalg_d\expandafter {#2}{#3}{#4}{#5}{#6}{#1}% }% % \end{macrocode} %\begin{lverb} % {alpha(n+1)}{n+1}{q(n+1)}{r(n+1)}{r(n)}{beta(n+1)} %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_d #1#2#3#4#5#6#7#8% {% \XINT_bezalg_e #4\Z {#2}{#4}{#5}{#1}{#6}{#7}{#8}{{#3}{#4}{#1}{#6}}% }% % \end{macrocode} %\begin{lverb} % r(n+1)\Z {n+1}{r(n+1)}{r(n)}{alpha(n+1)}{beta(n+1)}$\ % {alpha(n)}{beta(n)}{q,r,alpha,beta(n+1)}$\ % Test si r(n+1) est nul. %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_e #1#2\Z {% \xint_gob_til_zero #1\XINT_bezalg_end0\XINT_bezalg_a }% % \end{macrocode} %\begin{lverb} % Ici r(n+1) = 0. On arrête on se prépare à inverser.$\ % {n+1}{r(n+1)}{r(n)}{alpha(n+1)}{beta(n+1)}{alpha(n)}{beta(n)}$\ % {q,r,alpha,beta(n+1)}...{{A}{B}}{}\Z$\ % On veut renvoyer$\ % {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ % {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D} %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_end0\XINT_bezalg_a #1#2#3#4#5#6#7#8\Z {% \expandafter\XINT_bezalg_end_a \romannumeral0% \XINT_rord_main {}#8{{#1}{#3}}% \xint: \xint_bye\xint_bye\xint_bye\xint_bye \xint_bye\xint_bye\xint_bye\xint_bye \xint: }% % \end{macrocode} %\begin{lverb} % {N}{D}{A}{B}{q1}{r1}{alpha1=q1}{beta1=1}{q2}{r2}{alpha2}{beta2}$\ % ....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}$\ % On veut renvoyer$\ % {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ % {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D} %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_end_a #1#2#3#4{{#1}{#3}{0}{1}{#2}{#4}{1}{0}}% % \end{macrocode} % \subsection{\csh{xintTypesetEuclideAlgorithm}} %\begin{lverb} % TYPESETTING % % Organisation: % % {N}{A}{D}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0}$\ % \U1 = N = nombre d'étapes, \U3 = PGCD, \U2 = A, \U4=B % q1 = \U5, q2 = \U7 --> qn = \U<2n+3>, rn = \U<2n+4> % bn = rn. B = r0. A=r(-1) % % r(n-2) = q(n)r(n-1)+r(n) (n e étape) % % \U{2n} = \U{2n+3} \times \U{2n+2} + \U{2n+4}, n e étape. % (avec n entre 1 et N) % % 1.09h uses \xintloop, and \par rather than \endgraf; and \par rather than % \hfill\break %\end{lverb} % \begin{macrocode} \def\xintTypesetEuclideAlgorithm {% \unless\ifdefined\xintAssignArray \errmessage {xintgcd: package xinttools is required for \string\xintTypesetEuclideAlgorithm}% \expandafter\xint_gobble_iii \fi \XINT_TypesetEuclideAlgorithm }% \def\XINT_TypesetEuclideAlgorithm #1#2% {% l'algo remplace #1 et #2 par |#1| et |#2| \par \begingroup \xintAssignArray\xintEuclideAlgorithm {#1}{#2}\to\U \edef\A{\U2}\edef\B{\U4}\edef\N{\U1}% \setbox 0 \vbox{\halign {$##$\cr \A\cr \B \cr}}% \count 255 1 \xintloop \indent\hbox to \wd 0 {\hfil$\U{\numexpr 2*\count255\relax}$}% ${} = \U{\numexpr 2*\count255 + 3\relax} \times \U{\numexpr 2*\count255 + 2\relax} + \U{\numexpr 2*\count255 + 4\relax}$% \ifnum \count255 < \N \par \advance \count255 1 \repeat \endgroup }% % \end{macrocode} % \subsection{\csh{xintTypesetBezoutAlgorithm}} %\begin{lverb} % Pour Bezout on a: % {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ % {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}% % Donc 4N+8 termes: % U1 = N, U2= A, U5=D, U6=B, q1 = U9, qn = U{4n+5}, n au moins 1$\ % rn = U{4n+6}, n au moins -1$\ % alpha(n) = U{4n+7}, n au moins -1$\ % beta(n) = U{4n+8}, n au moins -1 % % 1.09h uses \xintloop, and \par rather than \endgraf; and no more \parindent0pt %\end{lverb} % \begin{macrocode} \def\xintTypesetBezoutAlgorithm {% \unless\ifdefined\xintAssignArray \errmessage {xintgcd: package xinttools is required for \string\xintTypesetBezoutAlgorithm}% \expandafter\xint_gobble_iii \fi \XINT_TypesetBezoutAlgorithm }% \def\XINT_TypesetBezoutAlgorithm #1#2% {% \par \begingroup \xintAssignArray\xintBezoutAlgorithm {#1}{#2}\to\BEZ \edef\A{\BEZ2}\edef\B{\BEZ6}\edef\N{\BEZ1}% A = |#1|, B = |#2| \setbox 0 \vbox{\halign {$##$\cr \A\cr \B \cr}}% \count255 1 \xintloop \indent\hbox to \wd 0 {\hfil$\BEZ{4*\count255 - 2}$}% ${} = \BEZ{4*\count255 + 5} \times \BEZ{4*\count255 + 2} + \BEZ{4*\count255 + 6}$\hfill\break \hbox to \wd 0 {\hfil$\BEZ{4*\count255 +7}$}% ${} = \BEZ{4*\count255 + 5} \times \BEZ{4*\count255 + 3} + \BEZ{4*\count255 - 1}$\hfill\break \hbox to \wd 0 {\hfil$\BEZ{4*\count255 +8}$}% ${} = \BEZ{4*\count255 + 5} \times \BEZ{4*\count255 + 4} + \BEZ{4*\count255 }$ \par \ifnum \count255 < \N \advance \count255 1 \repeat \edef\U{\BEZ{4*\N + 4}}% \edef\V{\BEZ{4*\N + 3}}% \edef\D{\BEZ5}% \ifodd\N $\U\times\A - \V\times \B = -\D$% \else $\U\times\A - \V\times\B = \D$% \fi \par \endgroup }% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintgcd} % \cleardoublepage\let\xintgcdnameUp\undefined %\gardesactifs %\let\relax %\let<*xintfrac>\gardesinactifs %^^A---------------------------------------------------- %<*xintfrac>^^A--------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 72; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintfracnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintfracnameimp implementation} % \RaisedLabel{sec:fracimp} % % \localtableofcontents % % \subsection{Introduction} % % The commenting is currently (\xintbndldate) very sparse. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \catcode35=6 % # \def\odef#1{\expandafter\def\expandafter#1\expandafter}% \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \def\odef#1{\expandafter\def\expandafter#1\expandafter}% \expandafter\let\expandafter\x\csname ver@xintfrac.sty\endcsname \expandafter\let\expandafter\c\csname ver@calxfp.sty\endcsname \expandafter\let\expandafter\w\csname ver@xint.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xint Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xint}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xintfrac.sty \ifx\w\relax % but xint.sty not yet loaded. \odef\z{\z\input xint.sty\relax}% \fi \ifx\c\relax % but calxfp.sty not yet loaded. \odef\z{\z\input calxfp.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xint.sty not yet loaded. \odef\z{\z\RequirePackage{xint}}% \fi \ifx\c\relax % calxfp.sty not yet loaded. \odef\z{\z\RequirePackage{calxfp}}% \fi \else \def\z{\endgroup\endinput}% xintfrac already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintfrac}% [2026/11/01 v2.0a1 Expandable operations on fractions (JFB)]% % \end{macrocode} % \subsection{\csh{XINT_cntSgnFork}} %\begin{lverb} % 1.09i. Used internally, #1 must expand to \m@ne, \z@, or \@ne or % equivalent. \XINT_cntSgnFork does not insert a romannumeral stopper. %\end{lverb} % \begin{macrocode} \def\XINT_cntSgnFork #1% {% \ifcase #1\expandafter\xint_secondofthree \or\expandafter\xint_thirdofthree \else\expandafter\xint_firstofthree \fi }% % \end{macrocode} % \subsection{\cshnolabel{xintLen}} %\begin{lverb} % The used formula is disputable, the idea is that A/1 and A should have % same length. Venerable code rewritten for 1.2i, following updates to % \xintLength in xintkernel.sty. And sadly, I forgot on this % occasion that this macro is not supposed to count the sign... Fixed in 1.2k. %\end{lverb} % \begin{macrocode} \def\xintLen {\romannumeral0\xintlen }% \def\xintlen #1% {% \expandafter\XINT_flen\romannumeral0\XINT_infrac {#1}% }% \def\XINT_flen#1{\def\XINT_flen ##1##2##3% {% \expandafter#1% \the\numexpr \XINT_abs##1+% \XINT_len_fork ##2##3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye-\xint_c_i \relax }}\XINT_flen{ }% % \end{macrocode} % \subsection{\csh{XINT_outfrac}} % \changed{1.06b} %\begin{lverb} % 1.06b version now outputs 0/1[0] and not 0[0] in case of zero. More generally % all macros have been checked in xintfrac, xintseries, xintcfrac, to make sure % the output format for fractions was always A/B[n]. (except \xintIrr, % \xintJrr, \xintRawWithZeros). % % Months later (2014/10/22): perhaps I should document what this macro does % before I forget? from {e}{N}{D} it outputs N/D[e], checking in passing if % D=0 or if N=0. It also makes sure D is not < 0. I am not sure but I don't % think there is any place in the code which could call \XINT_outfrac with a D % < 0, but I should check. %\end{lverb} % \begin{macrocode} \def\XINT_outfrac #1#2#3% {% \ifcase\XINT_cntSgn #3\xint: \expandafter \XINT_outfrac_divisionbyzero \or \expandafter \XINT_outfrac_P \else \expandafter \XINT_outfrac_N \fi {#2}{#3}[#1]% }% \def\XINT_outfrac_divisionbyzero #1#2[#3]% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero: #1/#2.}{}{ 0/1[0]}% }% \def\XINT_outfrac_P#1{% \def\XINT_outfrac_P ##1##2% {\if0\XINT_Sgn ##1\xint:\expandafter\XINT_outfrac_Zero\fi#1##1/##2}% }\XINT_outfrac_P{ }% \def\XINT_outfrac_Zero #1[#2]{ 0/1[0]}% \def\XINT_outfrac_N #1#2% {% \expandafter\XINT_outfrac_N_a\expandafter {\romannumeral0\XINT_opp #2}{\romannumeral0\XINT_opp #1}% }% \def\XINT_outfrac_N_a #1#2% {% \expandafter\XINT_outfrac_P\expandafter {#2}{#1}% }% % \end{macrocode} % \subsection{\csh{XINT_infrac}} % \added{1.03} %\begin{lverb} % Parses fraction, scientific notation, etc... and produces {n}{A}{B} % corresponding to A/B times 10^n. No reduction to smallest terms. %\end{lverb} % \changed{1.07} %\begin{lverb} % Extended in 1.07 to accept scientific notation on input. With lowercase % e only. The \xintexpr parser does accept uppercase E also. Ah, by the way, % perhaps I should at least say what this macro does? (belated addition % 2014/10/22...), before I forget! It prepares the fraction in the internal % format {exponent}{Numerator}{Denominator} where Denominator is at least 1. %\end{lverb} % \changed[2015/10/09]{1.2} %\begin{lverb} % This venerable macro from the very early days % has gotten a lifting for release 1.2. There were two kinds of issues: % % 1) use of \W, \Z, \T delimiters was very poor choice as this could clash with % user input, % % 2) the new \XINT_frac_gen handles macros (possibly empty) in the input as % general as \A.\Be\C/\D.\Ee\F. The earlier version would not have expanded % the \B or \E$empty: digits after decimal mark were constrained to arise from % expansion of the first token. Thus the 1.03 original code would have % expanded only \A, \D, \C, and \F for this input. % % This reminded me think I should revisit the remaining earlier % portions of code, as I was still learning TeX coding when I wrote them. % % Also I thought about parsing even faster the A/B[N] input, not expanding B, % but this turned out to clash with some established uses in the documentation % such as 1/\xintiiSqr{...}[0]. For the implementation, careful here about % potential brace removals with parameter patterns such as like #1/#2#3[#4]for % example. % % While I was at it 1.2 added \numexpr parsing of the N, which earlier was % restricted to be only explicit digits. I allowed [] with empty N, but the % way I did it in 1.2 with \the\numexpr 0#1 was buggy, as it did not allow #1 % to be a \count for example or itself a \numexpr (although such inputs were % not previously allowed, I later turned out to use them in the code itself, % e.g. the float factorial of version 1.2f). The better way would be % \the\numexpr#1+\xint_c_ but 1.2f finally does only \the\numexpr #1 and #1 is % not allowed to be empty. % % The 1.2 \XINT_frac_gen had two locations with such a problematic \numexpr % 0#1 which I replaced for 1.2f with \numexpr#1+\xint_c_. % % Regarding calling the macro with an argument A[], a / inthe % expression must be suitably hidden for example in \firstofone type % constructs. % % Note: when the numerator is found to be zero \XINT_infrac *always* returns % {0}{0}{1}. This behaviour must not change because 1.2g \xintFloat and % XINTinFloat (for example) rely upon it: if the denominator on output is not % 1, then \xintFloat assumes that the numerator is not zero. % % As described in the manual, if the input contains a (final) [N] part, it is % assumed that it is in the shape A[N] or A/B[N] with A (and B) not containing % neither decimal mark nor scientific part, moreover B must be positive and A % have at most one minus sign (and no plus sign). Else there will be errors, % for example -0/2[0] would not be recognized as being zero at this stage and % this could cause issues afterwards. When there is no ending [N] part, both % numerator and denominator will be parsed for the more general format % allowing decimal digits and scientific part and possibly multiple leading % signs. %\end{lverb} % \changed{1.2l} %\begin{lverb} % 1.2l fixes frailty of \XINT_infrac (hence basically of all xintfrac macros) % respective to non terminated \numexpr input: \xintRaw{\the\numexpr1} for % example. The issue was that \numexpr sees the / and expands what's next. % But even \numexpr 1// for example creates an error, and to my mind this is % a defect of \numexpr. It should be able to trace back and see that / was % used as delimiter not as operator. Anyway, I thus fixed this problem % belatedly here regarding \XINT_infrac. %\end{lverb} % \changed{1.4l} %\begin{lverb} % Deprecate venerable \XINT_inFrac, whose new name is \xintRawBraced. % Should have been removed then. %\end{lverb} % \changed[2025/07/25]{1.4n} %\begin{lverb} % Remove \XINT_inFrac. %\end{lverb} % \begin{macrocode} \def\XINT_infrac #1% the core xintfrac in-parser; triggered by \romannumeral0 {% \expandafter\XINT_infrac_fork\romannumeral`&&@#1\xint:/\XINT_W[\XINT_W\XINT_T }% \def\XINT_infrac_fork #1[#2% {% \xint_UDXINTWfork #2\XINT_frac_gen % input has no brackets [N] \XINT_W\XINT_infrac_res_a % there is some [N], must be strict A[N] or A/B[N] input \krof #1[#2% }% \def\XINT_infrac_res_a #1% {% \xint_gob_til_zero #1\XINT_infrac_res_zero 0\XINT_infrac_res_b #1% }% % \end{macrocode} %\begin{lverb} % Note that input exponent is here ignored and forced to be zero. %\end{lverb} % \begin{macrocode} \def\XINT_infrac_res_zero 0\XINT_infrac_res_b #1\XINT_T {{0}{0}{1}}% \def\XINT_infrac_res_b #1/#2% {% \xint_UDXINTWfork #2\XINT_infrac_res_ca % it was A[N] input \XINT_W\XINT_infrac_res_cb % it was A/B[N] input \krof #1/#2% }% % \end{macrocode} %\begin{lverb} % An empty [] is not allowed. (this was authorized in 1.2, removed in % 1.2f). %\end{lverb} % \begin{macrocode} \def\XINT_infrac_res_ca #1[#2]\xint:/\XINT_W[\XINT_W\XINT_T {\expandafter{\the\numexpr #2}{#1}{1}}% \def\XINT_infrac_res_cb #1/#2[% {\expandafter\XINT_infrac_res_cc\romannumeral`&&@#2~#1[}% \def\XINT_infrac_res_cc #1~#2[#3]\xint:/\XINT_W[\XINT_W\XINT_T {\expandafter{\the\numexpr #3}{#2}{#1}}% % \end{macrocode} % \subsection{\csh{XINT_frac_gen}} % \changed{1.07} %\begin{lverb} % Extended at to recognize and accept scientific notation both at % the numerator and (possible) denominator. Only a lowercase e will do here, % but uppercase E is possible within an \xintexpr..\relax %\end{lverb} % \changed{1.2} %\begin{lverb} % Completely rewritten. The parsing handles inputs such as % \A.\Be\C/\D.\Ee\F where each of \A, \B, \D, and \E may need f-expansion and % \C and \F will end up in \numexpr. %\end{lverb} % \changed{1.2f} %\begin{lverb} % 1.2f corrects an issue to allow \C and \F to be \count variable (or % expressions with \numexpr): 1.2 did a bad \numexpr0#1 which allowed only % explicit digits for expanded #1. %\end{lverb} % \begin{macrocode} \def\XINT_frac_gen #1/#2% {% \xint_UDXINTWfork #2\XINT_frac_gen_A % there was no / \XINT_W\XINT_frac_gen_B % there was a / \krof #1/#2% }% % \end{macrocode} %\begin{lverb} % Note that #1 is only expanded so far up to decimal mark or "e". % % calx: native values reaching xintfrac (in \xinteval: a nested % \xintfloatexpr or \xintiiexpr, a float or ii variable, a float or ii % function). Input without [ and without /, hence also F, M, I values. % \CALX_fga tests the first token (empty input: the e of ee., then % \CALX_infr_o restores the original path, as for any other letter). % F: \CALX_ftoraw gives A[N]; M: blocks by \CALX_ntoraw, exponent 8e % (calxint's \CALX_infr_m); output {N}{A}{1} as \XINT_infrac. I: % InvalidOperation, 0. %\end{lverb} % \begin{macrocode} \def\XINT_frac_gen_A #1\xint:/\XINT_W [\XINT_W {\CALX_fga #1ee.\XINT_W }% \def\CALX_fga #1{\ifnum`#1>57 \CALX_infr #1\fi\XINT_frac_gen_C 0~1!#1}% \def\CALX_infr #1\fi\XINT_frac_gen_C 0~1!#2ee.\XINT_W\XINT_T {\fi\if I#1\xint_dothis\CALX_infr_i\fi \if M#1\xint_dothis\CALX_infr_m\fi \if F#1\xint_dothis\CALX_infr_f\fi \xint_orthat\CALX_infr_o{#2}}% \def\CALX_infr_o #1{\XINT_frac_gen_C 0~1!#1ee.\XINT_W\XINT_T}% \def\CALX_infr_f #1{\expandafter\CALX_infr_a\romannumeral0\CALX_ftoraw{#1}}% \def\CALX_infr_a #1[#2]{{#2}{#1}{1}}% \def\CALX_infr_i #1% {\XINT_signalcondition{InvalidOperation}{#1 has no xintfrac value}{}% {{0}{0}{1}}}% \def\XINT_frac_gen_B #1/#2\xint:/\XINT_W[%\XINT_W {% \expandafter\XINT_frac_gen_Ba \romannumeral`&&@#2ee.\XINT_W\XINT_Z #1ee.%\XINT_W }% \def\XINT_frac_gen_Ba #1.#2% {% \xint_UDXINTWfork #2\XINT_frac_gen_Bb \XINT_W\XINT_frac_gen_Bc \krof #1.#2% }% \def\XINT_frac_gen_Bb #1e#2e#3\XINT_Z {\expandafter\XINT_frac_gen_C\the\numexpr #2+\xint_c_~#1!}% \def\XINT_frac_gen_Bc #1.#2e% {% \expandafter\XINT_frac_gen_Bd\romannumeral`&&@#2.#1e% }% \def\XINT_frac_gen_Bd #1.#2e#3e#4\XINT_Z {% \expandafter\XINT_frac_gen_C\the\numexpr #3-% \numexpr\XINT_length_loop #1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye ~#2#1!% }% \def\XINT_frac_gen_C #1!#2.#3% {% \xint_UDXINTWfork #3\XINT_frac_gen_Ca \XINT_W\XINT_frac_gen_Cb \krof #1!#2.#3% }% \def\XINT_frac_gen_Ca #1~#2!#3e#4e#5\XINT_T {% \expandafter\XINT_frac_gen_F\the\numexpr #4-#1\expandafter ~\romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z~#3~% }% \def\XINT_frac_gen_Cb #1.#2e% {% \expandafter\XINT_frac_gen_Cc\romannumeral`&&@#2.#1e% }% \def\XINT_frac_gen_Cc #1.#2~#3!#4e#5e#6\XINT_T {% \expandafter\XINT_frac_gen_F\the\numexpr #5-#2-% \numexpr\XINT_length_loop #1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye \relax\expandafter~% \romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop #3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z ~#4#1~% }% \def\XINT_frac_gen_F #1~#2% {% \xint_UDzerominusfork #2-\XINT_frac_gen_Gdivbyzero 0#2{\XINT_frac_gen_G -{}}% 0-{\XINT_frac_gen_G {}#2}% \krof #1~% }% \def\XINT_frac_gen_Gdivbyzero #1~~#2~% {% \expandafter\XINT_frac_gen_Gdivbyzero_a \romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z~#1~% }% \def\XINT_frac_gen_Gdivbyzero_a #1~#2~% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero: #1/0.}{}{{#2}{#1}{0}}% }% \def\XINT_frac_gen_G #1#2#3~#4~#5~% {% \expandafter\XINT_frac_gen_Ga \romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop #1#5\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z~#3~{#2#4}% }% \def\XINT_frac_gen_Ga #1#2~#3~% {% \xint_gob_til_zero #1\XINT_frac_gen_zero 0% {#3}{#1#2}% }% \def\XINT_frac_gen_zero 0#1#2#3{{0}{0}{1}}% % \end{macrocode} % \subsection{\csh{XINT_factortens}} %\begin{lverb} % This is the core macro for \xintREZ. To be used as % \romannumeral0\XINT_factortens{...}. Output is A.N. (formerly {A}{N}) where % A is the integer stripped from trailing zeroes and N is the number of % removed zeroes. Only for positive strict integers! %\end{lverb} % \changed{1.3a} %\begin{lverb} % Completely rewritten at 1.3a to replace a double \xintReverseOrder by a % direct \numexpr governed expansion to the end and back, à la 1.2. I should % comment more... and perhaps improve again in future. % % Testing shows significant gain at 100 digits or more. %\end{lverb} % \changed{1.4p} %\begin{lverb} % \XINT_factortens_cc had an unnecessary \if#90 test, the false branch % was never taken. %\end{lverb} % \begin{macrocode} \def\XINT_factortens #1{\expandafter\XINT_factortens_z \romannumeral0\XINT_factortens_a#1% \XINT_factortens_b123456789.}% \def\XINT_factortens_z.\XINT_factortens_y{ }% \def\XINT_factortens_a #1#2#3#4#5#6#7#8#9% {\expandafter\XINT_factortens_x \the\numexpr 1#1#2#3#4#5#6#7#8#9\XINT_factortens_a}% \def\XINT_factortens_b#1\XINT_factortens_a#2#3.% {.\XINT_factortens_cc 000000000-#2.}% \def\XINT_factortens_x1#1.#2{#2#1}% \def\XINT_factortens_y{.\XINT_factortens_y}% \def\XINT_factortens_cc #1#2#3#4#5#6#7#8#9% {\expandafter\XINT_factortens_d\the\numexpr #8#7#6#5#4#3#2#1\relax \xint_c_i 2345678.}% \def\XINT_factortens_yy #1#2.{.\XINT_factortens_y#1.0.}% \def\XINT_factortens_c #1#2#3#4#5#6#7#8#9% {\if#90\xint_dothis {\expandafter\XINT_factortens_d\the\numexpr #8#7#6#5#4#3#2#1\relax \xint_c_i 2345678.}\fi \xint_orthat{.\XINT_factortens_y #1#2#3#4#5#6#7#8#9.}}% \def\XINT_factortens_d #1#2#3#4#5#6#7#8#9% {\if#10\expandafter\XINT_factortens_e\fi \XINT_factortens_f #9#9#8#7#6#5#4#3#2#1.}% \def\XINT_factortens_f #1#2\xint_c_i#3.#4.#5.% {\expandafter\XINT_factortens_g\the\numexpr#1+#5.#3.}% \def\XINT_factortens_g #1.#2.{.\XINT_factortens_y#2.#1.}% \def\XINT_factortens_e #1..#2.% {\expandafter.\expandafter\XINT_factortens_c \the\numexpr\xint_c_ix+#2.}% % \end{macrocode} % \subsection{\xintListWithSep{, } % {\xintApply{ \csh}{{xintEq}{xintNotEq}{xintGt}{xintLt}{xintGtorEq} % {xintLtorEq}{xintIsZero}{xintIsNotZero}{xintOdd} % {xintEven}{xintifSgn}{xintifCmp}{xintifEq}{xintifGt}{xintifLt} % {xintifZero}{xintifNotZero}{xintifOne}{xintifOdd}}}} % %\begin{lverb} % Moved here at 1.3. Formerly these macros were already defined in % xint.sty or even xintcore.sty. They are slim wrappers of macros defined % elsewhere in xintfrac. %\end{lverb} % \begin{macrocode} \def\xintEq {\romannumeral0\xinteq }% \def\xinteq #1#2{\xintifeq{#1}{#2}{1}{0}}% \def\xintNotEq#1#2{\romannumeral0\xintifeq {#1}{#2}{0}{1}}% \def\xintGt {\romannumeral0\xintgt }% \def\xintgt #1#2{\xintifgt{#1}{#2}{1}{0}}% \def\xintLt {\romannumeral0\xintlt }% \def\xintlt #1#2{\xintiflt{#1}{#2}{1}{0}}% \def\xintGtorEq #1#2{\romannumeral0\xintiflt {#1}{#2}{0}{1}}% \def\xintLtorEq #1#2{\romannumeral0\xintifgt {#1}{#2}{0}{1}}% \def\xintIsZero {\romannumeral0\xintiszero }% \def\xintiszero #1{\if0\xintSgn{#1}\xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% \def\xintIsNotZero{\romannumeral0\xintisnotzero }% \def\xintisnotzero #1{\if0\xintSgn{#1}\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% \def\xintOdd {\romannumeral0\xintodd }% \def\xintodd #1% {% \ifodd\xintLDg{\xintNum{#1}} %<- intentional space \xint_afterfi{ 1}% \else \xint_afterfi{ 0}% \fi }% \def\xintEven {\romannumeral0\xinteven }% \def\xinteven #1% {% \ifodd\xintLDg{\xintNum{#1}} %<- intentional space \xint_afterfi{ 0}% \else \xint_afterfi{ 1}% \fi }% \def\xintifSgn{\romannumeral0\xintifsgn }% \def\xintifsgn #1% {% \ifcase \xintSgn{#1} \expandafter\xint_stop_atsecondofthree \or\expandafter\xint_stop_atthirdofthree \else\expandafter\xint_stop_atfirstofthree \fi }% \def\xintifCmp{\romannumeral0\xintifcmp }% \def\xintifcmp #1#2% {% \ifcase\xintCmp {#1}{#2} \expandafter\xint_stop_atsecondofthree \or\expandafter\xint_stop_atthirdofthree \else\expandafter\xint_stop_atfirstofthree \fi }% \def\xintifEq {\romannumeral0\xintifeq }% \def\xintifeq #1#2% {% \if0\xintCmp{#1}{#2}% \expandafter\xint_stop_atfirstoftwo \else\expandafter\xint_stop_atsecondoftwo \fi }% \def\xintifGt {\romannumeral0\xintifgt }% \def\xintifgt #1#2% {% \if1\xintCmp{#1}{#2}% \expandafter\xint_stop_atfirstoftwo \else\expandafter\xint_stop_atsecondoftwo \fi }% \def\xintifLt {\romannumeral0\xintiflt }% \def\xintiflt #1#2% {% \ifnum\xintCmp{#1}{#2}<\xint_c_ \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% \def\xintifZero {\romannumeral0\xintifzero }% \def\xintifzero #1% {% \if0\xintSgn{#1}% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% \def\xintifNotZero{\romannumeral0\xintifnotzero }% \def\xintifnotzero #1% {% \if0\xintSgn{#1}% \expandafter\xint_stop_atsecondoftwo \else \expandafter\xint_stop_atfirstoftwo \fi }% \def\xintifOne {\romannumeral0\xintifone }% \def\xintifone #1% {% \if1\xintIsOne{#1}% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% \def\xintifOdd {\romannumeral0\xintifodd }% \def\xintifodd #1% {% \if\xintOdd{#1}1% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintRaw}} % \added{1.07} %\begin{lverb} % 1.07: this macro simply prints in a user readable form the fraction after its % initial scanning. Useful when put inside braces in an \xintexpr, when the % input is not yet in the A/B[n] form. %\end{lverb} % \begin{macrocode} \def\xintRaw {\romannumeral0\xintraw }% \def\xintraw {% \expandafter\XINT_raw\romannumeral0\XINT_infrac }% \def\XINT_raw #1#2#3{ #2/#3[#1]}% % \end{macrocode} % \subsection{\csh{xintRawBraced}} % \added{1.4l} %\begin{lverb} % User level interface to core \romannumeral0\XINT_infrac. Replaces % \XINT_inFrac which was defined but nowhere used by the xint packages. %\end{lverb} % \begin{macrocode} \def\xintRawBraced {\romannumeral0\xintrawbraced }% \let\xintrawbraced \XINT_infrac % \end{macrocode} % \subsection{\csh{xintiLogTen}} % \added{1.3e} %\begin{lverb} % The exponent a, such that 10^a<= abs(x) < 10^(a+1). No rounding done on x, % handled as an exact fraction. %\end{lverb} % \begin{macrocode} \def\xintiLogTen {\the\numexpr\xintilogten}% \def\xintilogten {% \expandafter\XINT_ilogten\romannumeral0\xintraw }% \def\XINT_ilogten #1% {% \xint_UDzerominusfork 0#1\XINT_ilogten_p #1-\XINT_ilogten_z 0-{\XINT_ilogten_p#1}% \krof }% \def\XINT_ilogten_z #1[#2]{-"7FFF8000\relax}% \def\XINT_ilogten_p #1/#2[#3]% {% #3+\expandafter\XINT_ilogten_a \the\numexpr\xintLength{#1}\expandafter.\the\numexpr\xintLength{#2}.#1.#2.% }% \def\XINT_ilogten_a #1.#2.% {% #1-#2\ifnum#1>#2 \expandafter\XINT_ilogten_aa \else \expandafter\XINT_ilogten_ab \fi #1.#2.% }% \def\XINT_ilogten_aa #1.#2.#3.#4.% {% \xintiiifLt{#3}{\XINT_dsx_addzerosnofuss{#1-#2}#4;}{-1}{}\relax }% \def\XINT_ilogten_ab #1.#2.#3.#4.% {% \xintiiifLt{\XINT_dsx_addzerosnofuss{#2-#1}#3;}{#4}{-1}{}\relax }% % \end{macrocode} % \subsection{\csh{xintPRaw}} % \added{1.09b} % \begin{macrocode} \def\xintPRaw {\romannumeral0\xintpraw }% \def\xintpraw {% \expandafter\XINT_praw\romannumeral0\XINT_infrac }% \def\XINT_praw #1% {% \ifnum #1=\xint_c_ \expandafter\XINT_praw_a\fi \XINT_praw_A {#1}% }% \def\XINT_praw_A #1#2#3% {% \if\XINT_isOne{#3}1\expandafter\xint_firstoftwo \else\expandafter\xint_secondoftwo \fi { #2[#1]}{ #2/#3[#1]}% }% \def\XINT_praw_a\XINT_praw_A #1#2#3% {% \if\XINT_isOne{#3}1\expandafter\xint_firstoftwo \else\expandafter\xint_secondoftwo \fi { #2}{ #2/#3}% }% % \end{macrocode} % \subsection{\csh{xintSPRaw}} %\begin{lverb} % This private macro was for internal usage by \xinttheexpr. % It got moved here % at 1.4 and is not used anymore by the package. % % It checks if input has a [N] part, if yes uses \xintPRaw, else % simply lets the input pass through as is. %\end{lverb} % \begin{macrocode} \def\xintSPRaw {\romannumeral0\xintspraw }% \def\xintspraw #1{\expandafter\XINT_spraw\romannumeral`&&@#1[\W]}% \def\XINT_spraw #1[#2#3]{\xint_gob_til_W #2\XINT_spraw_a\W\XINT_spraw_p #1[#2#3]}% \def\XINT_spraw_a\W\XINT_spraw_p #1[\W]{ #1}% \def\XINT_spraw_p #1[\W]{\xintpraw {#1}}% % \end{macrocode} % \subsection{\csh{xintFracToSci}} % \added{1.4l} %\begin{lverb} % The macro with this name which was added here at 1.4 then had % various changes and finally was moved to $xintexprnameimp at 1.4k % is now called there % \xint_FracToSci_x and is private. The present macro is public and % behaves like the other $xintfracnameimp macros: f-expandable and % accepts general input. Its output is exactly the same as % \xint_FracToSci_x for same inputs, with the exception of the empty % input which \xintFracToSci will output as 0 but \xint_FracToSci_x % as empty. But the latter is not used by \xinteval for an empty % leaf as it employs then \xintexprEmptyItem. %\end{lverb} % \begin{macrocode} \def\xintFracToSci{\romannumeral0\xintfractosci}% \def\xintfractosci#1{\expandafter\XINT_fractosci\romannumeral0\xintraw{#1}}% \def\XINT_fractosci#1#2/#3[#4]{\expanded{ % \ifnum#4=\xint_c_ #1#2\else \romannumeral0\expandafter\XINT_pfloat_a_fork\romannumeral0\xintrez{#1#2[#4]}% \fi \if\XINT_isOne{#3}1\else\if#10\else/#3\fi\fi}% }% % \end{macrocode} % \subsection{\csh{xintFracToDecimal}} % \added{1.4l} %\begin{lverb} % The macro with this name which was added at 1.4k to % $xintexprnameimp has been removed. The public variant here % behaves like the other % $xintfracnameimp macros: f-expandable and accepts general input. %\end{lverb} % \begin{macrocode} \def\xintFracToDecimal{\romannumeral0\xintfractodecimal}% \def\xintfractodecimal#1{\expandafter\XINT_fractodecimal\romannumeral0\xintraw{#1}}% \def\XINT_fractodecimal #1#2/#3[#4]{\expanded{ % \ifnum#4=\xint_c_ #1#2\else \romannumeral0\expandafter\XINT_dectostr\romannumeral0\xintrez{#1#2[#4]}% \fi \if\XINT_isOne{#3}1\else\if#10\else/#3\fi\fi}% }% % \end{macrocode} % \subsection{\csh{xintRawWithZeros}} %\begin{lverb} % This was called \xintRaw in versions earlier than 1.07 %\end{lverb} % \begin{macrocode} \def\xintRawWithZeros {\romannumeral0\xintrawwithzeros }% \def\xintrawwithzeros {% \expandafter\XINT_rawz_fork\romannumeral0\XINT_infrac }% \def\XINT_rawz_fork #1% {% \ifnum#1<\xint_c_ \expandafter\XINT_rawz_Ba \else \expandafter\XINT_rawz_A \fi #1.% }% \def\XINT_rawz_A #1.#2#3{\XINT_dsx_addzeros{#1}#2;/#3}% \def\XINT_rawz_Ba -#1.#2#3{\expandafter\XINT_rawz_Bb \expandafter{\romannumeral0\XINT_dsx_addzeros{#1}#3;}{#2}}% \def\XINT_rawz_Bb #1#2{ #2/#1}% % \end{macrocode} % \subsection{\csh{xintDecToString}} % \added{1.3} %\begin{lverb} % This is a backport from polexpr 0.4. It is definitely not in % final form, consider it to be an unstable macro. %\end{lverb} % \begin{macrocode} \def\xintDecToString{\romannumeral0\xintdectostring}% \def\xintdectostring#1{\expandafter\XINT_dectostr\romannumeral0\xintraw{#1}}% \def\XINT_dectostr #1/#2[#3]{\xintiiifZero {#1}% \XINT_dectostr_z {\if1\XINT_isOne{#2}\expandafter\XINT_dectostr_a \else\expandafter\XINT_dectostr_b \fi}% #1/#2[#3]% }% \def\XINT_dectostr_z#1[#2]{ 0}% \def\XINT_dectostr_a#1/#2[#3]{% \ifnum#3<\xint_c_\xint_dothis{\xinttrunc{-#3}{#1[#3]}}\fi \xint_orthat{\xintiie{#1}{#3}}% }% \def\XINT_dectostr_b#1/#2[#3]{% just to handle this somehow \ifnum#3<\xint_c_\xint_dothis{\xinttrunc{-#3}{#1[#3]}/#2}\fi \xint_orthat{\xintiie{#1}{#3}/#2}% }% % \end{macrocode} % \subsection{\csh{xintDecToStringREZ}} % \added{1.4e} %\begin{lverb} % And I took this opportunity to improve documentation in manual. %\end{lverb} % \begin{macrocode} \def\xintDecToStringREZ{\romannumeral0\xintdectostringrez}% \def\xintdectostringrez#1{\expandafter\XINT_dectostr\romannumeral0\xintrez{#1}}% % \end{macrocode} % \subsection{\csh{xintFloor}, \csh{xintiFloor}} % \added{1.09a} %\begin{lverb} % By calxfp's \CALX_fintp on the parts {N}{A}{B} of \XINT_infrac: s sign, % T digits of |trunc(X)|, z = 1 if X is not an integer. floor(X) = T (s = % +) or -(T + z); ceil(X) = T + z (s = +) or -T. +1 by xintcore's % \xintinc. \xintFloor, \xintCeil append /1[0]. %\end{lverb} % \begin{macrocode} \def\xintFloor {\romannumeral0\xintfloor }% \def\xintfloor #1{\expandafter\XINT_fl_q\romannumeral0\xintifloor{#1}\xint:}% \def\XINT_fl_q #1\xint:{ #1/1[0]}% \def\xintiFloor {\romannumeral0\xintifloor }% \def\xintifloor #1% {\expandafter\XINT_ifloor\romannumeral0\XINT_infrac{#1}\XINT_ifloor_f}% \def\XINT_ifloor #1#2#3#4{\expandafter#4\romannumeral0\CALX_fintp{#2}{#3}{#1}}% \def\XINT_ifloor_f #1#2.#3#4% {\if-#1\xint_dothis{\XINT_ifloor_m#4{#2}}\fi\xint_orthat{ #2}}% \def\XINT_ifloor_m #1#2% {% \if1#1\xint_dothis{\expandafter-\romannumeral0\xintinc{#2}}\fi \xint_orthat{ -#2}% }% % \end{macrocode} % \subsection{\csh{xintCeil}, \csh{xintiCeil}} % \added{1.09a} % \begin{macrocode} \def\xintCeil {\romannumeral0\xintceil }% \def\xintceil #1{\expandafter\XINT_fl_q\romannumeral0\xinticeil{#1}\xint:}% \def\xintiCeil {\romannumeral0\xinticeil }% \def\xinticeil #1% {\expandafter\XINT_ifloor\romannumeral0\XINT_infrac{#1}\XINT_iceil_f}% \def\XINT_iceil_f #1#2.#3#4% {% \if-#1\xint_dothis{\XINT_iceil_m #2\xint:}\fi \if1#4\xint_dothis{\xintinc{#2}}\fi \xint_orthat{ #2}% }% \def\XINT_iceil_m #1#2\xint:{\if0#1\xint_dothis{ 0}\fi\xint_orthat{ -#1#2}}% % \end{macrocode} % \subsection{\csh{xintNumerator}} % \begin{macrocode} \def\xintNumerator {\romannumeral0\xintnumerator }% \def\xintnumerator {% \expandafter\XINT_numer\romannumeral0\XINT_infrac }% \def\XINT_numer #1% {% \ifcase\XINT_cntSgn #1\xint: \expandafter\XINT_numer_B \or \expandafter\XINT_numer_A \else \expandafter\XINT_numer_B \fi {#1}% }% \def\XINT_numer_A #1#2#3{\XINT_dsx_addzeros{#1}#2;}% \def\XINT_numer_B #1#2#3{ #2}% % \end{macrocode} % \subsection{\csh{xintDenominator}} % \begin{macrocode} \def\xintDenominator {\romannumeral0\xintdenominator }% \def\xintdenominator {% \expandafter\XINT_denom_fork\romannumeral0\XINT_infrac }% \def\XINT_denom_fork #1% {% \ifnum#1<\xint_c_ \expandafter\XINT_denom_B \else \expandafter\XINT_denom_A \fi #1.% }% \def\XINT_denom_A #1.#2#3{ #3}% \def\XINT_denom_B -#1.#2#3{\XINT_dsx_addzeros{#1}#3;}% % \end{macrocode} % \subsection{\csh{xintTeXFrac}} % \added{1.03} %\begin{lverb} % Useless typesetting macro. %\end{lverb} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintFrac. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \ifdefined\PackageWarning \def\xintfracTeXDeprecation#1#2{% \PackageWarning{xintfrac}{\string#1 is deprecated. Use \string#2\MessageBreak to suppress this warning}#2% }% \else \edef\xintfracTeXDeprecation#1#2{{\newlinechar10 \immediate\noexpand\write128{&&JPackage xintfrac Warning: \noexpand\string#1 is deprecated. Use \noexpand\string#2&&J% (xintfrac)\xintReplicate{16}{ }to suppress this warning on input line \noexpand\the\inputlineno.&&J}}#2% }% \fi \ifdefined\PackageError \def\xintfracTeXError#1#2{% \PackageError{xintfrac}{\string#1 has been removed.\MessageBreak Use \string#2 to suppress this error}% {I will fix it for now if you hit the `Return' key.}#2% }% \else \edef\xintfracTeXError#1#2{{\newlinechar10 \errhelp{I will fix it for now if you hit the `Return' key.}% \errmessage{Package xintfrac Error: \noexpand\string#1 has been removed.&&J% (xintfrac)\xintReplicate{16}{ }Use \noexpand\string#2 to suppress this error}}#2% }% \fi \def\xintFrac {\xintfracTeXError\xintFrac\xintTeXFrac}% \def\xintTeXFrac{\romannumeral0\xintfrac }% \def\xintfrac #1% {% \expandafter\XINT_fracfrac_A\romannumeral0\XINT_infrac {#1}% }% \def\XINT_fracfrac_A #1{\XINT_fracfrac_B #1\Z }% \catcode`^=7 \def\XINT_fracfrac_B #1#2\Z {% \xint_gob_til_zero #1\XINT_fracfrac_C 0\XINT_fracfrac_D {10^{#1#2}}% }% \def\XINT_fracfrac_C 0\XINT_fracfrac_D #1#2#3% {% \if1\XINT_isOne {#3}% \xint_afterfi {\expandafter\xint_stop_atfirstoftwo\xint_gobble_ii }% \fi \space \frac {#2}{#3}% }% \def\XINT_fracfrac_D #1#2#3% {% \if1\XINT_isOne {#3}\XINT_fracfrac_E\fi \space \frac {#2}{#3}#1% }% \def\XINT_fracfrac_E \fi\space\frac #1#2{\fi \space #1\cdot }% % \end{macrocode} % \subsection{\csh{xintTeXsignedFrac}} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintSignedFrac. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \def\xintSignedFrac {\xintfracTeXError\xintSignedFrac\xintTeXsignedFrac}% \def\xintTeXsignedFrac{\romannumeral0\xintsignedfrac }% \def\xintsignedfrac #1% {% \expandafter\XINT_sgnfrac_a\romannumeral0\XINT_infrac {#1}% }% \def\XINT_sgnfrac_a #1#2% {% \XINT_sgnfrac_b #2\Z {#1}% }% \def\XINT_sgnfrac_b #1% {% \xint_UDsignfork #1\XINT_sgnfrac_N -{\XINT_sgnfrac_P #1}% \krof }% \def\XINT_sgnfrac_P #1\Z #2% {% \XINT_fracfrac_A {#2}{#1}% }% \def\XINT_sgnfrac_N {% \expandafter-\romannumeral0\XINT_sgnfrac_P }% % \end{macrocode} % \subsection{\csh{xintTeXFromSci}} % \added{1.4g} %\begin{lverb} % The main problem is how to name this and related macros. % % I use \expanded here, as \xintFracToSci is not f-expandable. % % Some complications as I want this to be usable on output of \xintFracToSci % hence need to handle the case of a /B. After some hesitations I ended with % the following which looks reasonable: %(- if no scientific part, use \frac (or \over) for A/B %:- if scientific part, postfix /B as \cdot B^{-1} %) %\end{lverb} % \changed{1.4l} %\begin{lverb} % Suppress external \expanded. Keep internal one. % % Rename \xintTeXFromSci from \xintTeXfromSci. Keep deprecated old name % for the moment. % % Add \xintTeXFromScifracmacro. Make it \protected. % % Nota bene: catcode of ^ is normal one here (else nothing would work). %\end{lverb} % \begin{macrocode} \def\xintTeXfromSci{\xintfracTeXDeprecated\xintTeXfromSci\xintTeXFromSci}% \def\xintTeXFromSci#1% {% \expandafter\XINT_texfromsci\expanded{#1}/\relax/\xint: }% \def\XINT_texfromsci #1/#2#3/#4\xint: {% \XINT_texfromsci_a #1e\relax e\xint: {\ifx\relax#2\xint_dothis\xint_firstofone\fi \xint_orthat{\xintTeXFromScifracmacro{#2#3}}}% {\unless\ifx\relax#2\cdot{#2#3}^{-1}\fi}% }% \def\XINT_texfromsci_a #1e#2#3e#4\xint:#5#6% {% \ifx\relax#2#5{#1}\else#1\cdot10^{#2#3}#6\fi }% \ifdefined\frac \protected\def\xintTeXFromScifracmacro#1#2{\frac{#2}{#1}}% \else \protected\def\xintTeXFromScifracmacro#1#2{{#2\over#1}}% \fi % \end{macrocode} % \subsection{\csh{xintTeXOver}} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintFwOver. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \def\xintFwOver {\xintfracTeXError\xintFwOver\xintTeXOver}% \def\xintTeXOver{\romannumeral0\xintfwover }% \def\xintfwover #1% {% \expandafter\XINT_fwover_A\romannumeral0\XINT_infrac {#1}% }% \def\XINT_fwover_A #1{\XINT_fwover_B #1\Z }% \def\XINT_fwover_B #1#2\Z {% \xint_gob_til_zero #1\XINT_fwover_C 0\XINT_fwover_D {10^{#1#2}}% }% \catcode`^=11 \def\XINT_fwover_C #1#2#3#4#5% {% \if0\XINT_isOne {#5}\xint_afterfi { {#4\over #5}}% \else\xint_afterfi { #4}% \fi }% \def\XINT_fwover_D #1#2#3% {% \if0\XINT_isOne {#3}\xint_afterfi { {#2\over #3}}% \else\xint_afterfi { #2\cdot }% \fi #1% }% % \end{macrocode} % \subsection{\csh{xintTeXsignedOver}} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintSignedFwOver. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \def\xintSignedFwOver {\xintfracTeXError\xintSignedFwOver\xintTeXsignedOver}% \def\xintTeXsignedOver{\romannumeral0\xintsignedfwover }% \def\xintsignedfwover #1% {% \expandafter\XINT_sgnfwover_a\romannumeral0\XINT_infrac {#1}% }% \def\XINT_sgnfwover_a #1#2% {% \XINT_sgnfwover_b #2\Z {#1}% }% \def\XINT_sgnfwover_b #1% {% \xint_UDsignfork #1\XINT_sgnfwover_N -{\XINT_sgnfwover_P #1}% \krof }% \def\XINT_sgnfwover_P #1\Z #2% {% \XINT_fwover_A {#2}{#1}% }% \def\XINT_sgnfwover_N {% \expandafter-\romannumeral0\XINT_sgnfwover_P }% % \end{macrocode} % \subsection{\csh{xintREZ}} %\begin{lverb} % Removes trailing zeros from A and B and adjust the N in A/B[N]. % % The macro really doing the job \XINT_factortens was redone at 1.3a. But % speed gain really noticeable only beyond about 100 digits. %\end{lverb} % \begin{macrocode} \def\xintREZ {\romannumeral0\xintrez }% \def\xintrez {% \expandafter\XINT_rez_A\romannumeral0\XINT_infrac }% \def\XINT_rez_A #1#2% {% \XINT_rez_AB #2\Z {#1}% }% \def\XINT_rez_AB #1% {% \xint_UDzerominusfork #1-\XINT_rez_zero 0#1\XINT_rez_neg 0-{\XINT_rez_B #1}% \krof }% \def\XINT_rez_zero #1\Z #2#3{ 0/1[0]}% \def\XINT_rez_neg {\expandafter-\romannumeral0\XINT_rez_B }% \def\XINT_rez_B #1\Z {% \expandafter\XINT_rez_C\romannumeral0\XINT_factortens {#1}% }% \def\XINT_rez_C #1.#2.#3#4% {% \expandafter\XINT_rez_D\romannumeral0\XINT_factortens {#4}#3+#2.#1.% }% \def\XINT_rez_D #1.#2.#3.% {% \expandafter\XINT_rez_E\the\numexpr #3-#2.#1.% }% \def\XINT_rez_E #1.#2.#3.{ #3/#2[#1]}% % \end{macrocode} % \subsection{\csh{xintE}} % \added{1.07} %\begin{lverb} % The fraction is the first argument contrarily to \xintTrunc and % \xintRound. %\end{lverb} % \changed{1.1} %\begin{lverb} % 1.1 modifies and moves \xintiiE to xint.sty. %\end{lverb} % \begin{macrocode} \def\xintE {\romannumeral0\xinte }% \def\xinte #1% {% \expandafter\XINT_e \romannumeral0\XINT_infrac {#1}% }% \def\XINT_e #1#2#3#4% {% \expandafter\XINT_e_end\the\numexpr #1+#4.{#2}{#3}% }% \def\XINT_e_end #1.#2#3{ #2/#3[#1]}% % \end{macrocode} % \subsection{\csh{xintIrr}, \csh{xintPIrr}} % \changed{1.04} %\begin{lverb} % fixes a buggy \xintIrr {0}. %\end{lverb} % \changed{1.05} %\begin{lverb} % modifies the initial parsing and post-processing to use \xintrawwithzeros % and to more quickly deal with an input denominator equal to 1. %\end{lverb} % \changed{1.08} %\begin{lverb} % this version does not remove a /1 denominator. %\end{lverb} % \changed{1.3} %\begin{lverb} % added \xintPIrr (partial Irr, which ignores the decimal part). %\end{lverb} % \begin{macrocode} \def\xintIrr {\romannumeral0\xintirr }% \def\xintPIrr{\romannumeral0\xintpirr }% \def\xintirr #1% {% \expandafter\XINT_irr_start\romannumeral0\xintrawwithzeros {#1}\Z }% \def\xintpirr #1% {% \expandafter\XINT_pirr_start\romannumeral0\xintraw{#1}% }% \def\XINT_irr_start #1#2/#3\Z {% \if0\XINT_isOne {#3}% \xint_afterfi {\xint_UDsignfork #1\XINT_irr_negative -{\XINT_irr_nonneg #1}% \krof}% \else \xint_afterfi{\XINT_irr_denomisone #1}% \fi #2\Z {#3}% }% \def\XINT_pirr_start #1#2/#3[% {% \if0\XINT_isOne {#3}% \xint_afterfi {\xint_UDsignfork #1\XINT_irr_negative -{\XINT_irr_nonneg #1}% \krof}% \else \xint_afterfi{\XINT_irr_denomisone #1}% \fi #2\Z {#3}[% }% \def\XINT_irr_denomisone #1\Z #2{ #1/1}% changed in 1.08 \def\XINT_irr_negative #1\Z #2{\XINT_irr_D #1\Z #2\Z -}% \def\XINT_irr_nonneg #1\Z #2{\XINT_irr_D #1\Z #2\Z \space}% \def\XINT_irr_D #1#2\Z #3#4\Z {% \xint_UDzerosfork #3#1\XINT_irr_indeterminate #30\XINT_irr_divisionbyzero #10\XINT_irr_zero 00\XINT_irr_loop_a \krof {#3#4}{#1#2}{#3#4}{#1#2}% }% \def\XINT_irr_indeterminate #1#2#3#4#5% {% \XINT_legacysignalcondition{DivisionUndefined}{0/0 indeterminate fraction.}{}{ 0/1}% }% \def\XINT_irr_divisionbyzero #1#2#3#4#5% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero: #5#2/0.}{}{ 0/1}% }% \def\XINT_irr_zero #1#2#3#4#5{ 0/1}% changed in 1.08 \def\XINT_irr_loop_a #1#2% {% \expandafter\XINT_irr_loop_d \romannumeral0\XINT_ndivrawpair {#1}{#2}{#1}% }% \def\XINT_irr_loop_d #1#2% {% \XINT_irr_loop_e #2\Z }% \def\XINT_irr_loop_e #1#2\Z {% \xint_gob_til_zero #1\XINT_irr_loop_exit0\XINT_irr_loop_a {#1#2}% }% \def\XINT_irr_loop_exit0\XINT_irr_loop_a #1#2#3#4% {% \expandafter\XINT_irr_loop_exitb\expandafter {\romannumeral0\xintiiquo {#3}{#2}}% {\romannumeral0\xintiiquo {#4}{#2}}% }% \def\XINT_irr_loop_exitb #1#2% {% \expandafter\XINT_irr_finish\expandafter {#2}{#1}% }% \def\XINT_irr_finish #1#2#3{#3#1/#2}% changed in 1.08 % \end{macrocode} % \subsection{\csh{xintifInt}} % \begin{macrocode} \def\xintifInt {\romannumeral0\xintifint }% \def\xintifint #1{\expandafter\XINT_ifint\romannumeral0\xintrawwithzeros {#1}.}% \def\XINT_ifint #1/#2.% {% \if 0\xintiiRem {#1}{#2}% \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{\csh{xintIsInt}} %\begin{lverb} % Added at 1.3d only, for isint() xintexpr function. %\end{lverb} % \begin{macrocode} \def\xintIsInt {\romannumeral0\xintisint }% \def\xintisint #1% {\expandafter\XINT_ifint\romannumeral0\xintrawwithzeros {#1}.10}% % \end{macrocode} % \subsection{\csh{xintJrr}} % \begin{macrocode} \def\xintJrr {\romannumeral0\xintjrr }% \def\xintjrr #1% {% \expandafter\XINT_jrr_start\romannumeral0\xintrawwithzeros {#1}\Z }% \def\XINT_jrr_start #1#2/#3\Z {% \if0\XINT_isOne {#3}\xint_afterfi {\xint_UDsignfork #1\XINT_jrr_negative -{\XINT_jrr_nonneg #1}% \krof}% \else \xint_afterfi{\XINT_jrr_denomisone #1}% \fi #2\Z {#3}% }% \def\XINT_jrr_denomisone #1\Z #2{ #1/1}% changed in 1.08 \def\XINT_jrr_negative #1\Z #2{\XINT_jrr_D #1\Z #2\Z -}% \def\XINT_jrr_nonneg #1\Z #2{\XINT_jrr_D #1\Z #2\Z \space}% \def\XINT_jrr_D #1#2\Z #3#4\Z {% \xint_UDzerosfork #3#1\XINT_jrr_indeterminate #30\XINT_jrr_divisionbyzero #10\XINT_jrr_zero 00\XINT_jrr_loop_a \krof {#3#4}{#1#2}1001% }% \def\XINT_jrr_indeterminate #1#2#3#4#5#6#7% {% \XINT_legacysignalcondition{DivisionUndefined}{0/0 indeterminate fraction.}{}{ 0/1}% }% \def\XINT_jrr_divisionbyzero #1#2#3#4#5#6#7% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero: #7#2/0.}{}{ 0/1}% }% \def\XINT_jrr_zero #1#2#3#4#5#6#7{ 0/1}% changed in 1.08 \def\XINT_jrr_loop_a #1#2% {% \expandafter\XINT_jrr_loop_b \romannumeral0\XINT_ndivrawpair {#1}{#2}{#1}% }% \def\XINT_jrr_loop_b #1#2#3#4#5#6#7% {% \expandafter \XINT_jrr_loop_c \expandafter {\romannumeral0\xintiiadd{\xintiimul{#4}{#1}}{#6}}% {\romannumeral0\xintiiadd{\xintiimul{#5}{#1}}{#7}}% {#2}{#3}{#4}{#5}% }% \def\XINT_jrr_loop_c #1#2% {% \expandafter \XINT_jrr_loop_d \expandafter{#2}{#1}% }% \def\XINT_jrr_loop_d #1#2#3#4% {% \XINT_jrr_loop_e #3\Z {#4}{#2}{#1}% }% \def\XINT_jrr_loop_e #1#2\Z {% \xint_gob_til_zero #1\XINT_jrr_loop_exit0\XINT_jrr_loop_a {#1#2}% }% \def\XINT_jrr_loop_exit0\XINT_jrr_loop_a #1#2#3#4#5#6% {% \XINT_irr_finish {#3}{#4}% }% % \end{macrocode} % \subsection{\csh{xintTFrac}} % \added{1.09i} %\begin{lverb} % For frac in \xintexpr. And \xintFrac is already assigned. T for % truncation. However, potentially not very efficient with numbers in scientific % notations, with big exponents. Will have to think it again some day. I % hesitated how to call the macro. Same convention as in maple, but some people % reserve fractional part to x - floor(x). Also, not clear if I had to make it % negative (or zero) if x < 0, or rather always positive. There should be in % fact such a thing for each rounding function, trunc, round, floor, ceil. %\end{lverb} % \begin{macrocode} \def\xintTFrac {\romannumeral0\xinttfrac }% \def\xinttfrac #1{\expandafter\XINT_tfrac_fork\romannumeral0\xintrawwithzeros {#1}\Z }% \def\XINT_tfrac_fork #1% {% \xint_UDzerominusfork #1-\XINT_tfrac_zero 0#1{\xintiiopp\XINT_tfrac_P }% 0-{\XINT_tfrac_P #1}% \krof }% \def\XINT_tfrac_zero #1\Z { 0/1[0]}% \def\XINT_tfrac_P #1/#2\Z {\expandafter\XINT_rez_AB \romannumeral0\xintiirem{#1}{#2}\Z {0}{#2}}% % \end{macrocode} % \subsection{\csh{xintTrunc}, \csh{xintiTrunc}} %\begin{lverb} % Syntax: \xinttrunc{n}{X}, \xintitrunc{n}{X} (with \romannumeral0). % calxfp's \CALX_fintp on A/B[N+n], {N}{A}{B} from \XINT_infrac: . % (sign of X, digits of |trunc(X 10^n)|, first omitted digit, z = 1 if % the omitted part is not zero). The post-processor (\XINT_trunc_b, or % \XINT_round_b which adds 1 to T if d >= 5) hands T.. to the % final macro \XINT_trunc_G (decimal output) or \XINT_itrunc_G (integer); % the sign token is - or \space. Zero input (T = 0 and z = 0): 0. %\end{lverb} % \changed[2020/02/18]{1.4a} %\begin{lverb} % % Adds handling of a negative first argument. % % Zero input still gives single digit 0 output as I did not want to complicate % the code. But if quantization gives 0, the exponent [D] will be there. Well % actually eD because of problem that sign of original is preserved in output % so we can have -0 and I can not use -0[D] notation as it is not legal for % strict format. So I will use -0eD hence eD generally even though this means % so slight suboptimality for trunc() function in \xintexpr. % % The idea to give a meaning to negative D (in the context of optional % argument to \xintiexpr) was suggested a long time ago by Kpym (October 20, % 2015). His suggestion was then to treat it as positive D but trim trailing % zeroes. But since then, there is \xintDecToString which can be combined with % \xintREZ, and I feel matters of formatting output require a whole module (or % rather use existing third-party tools), and I decided to opt rather for an % operation similar as the quantize() of Python Decimal module. I.e. we % truncate (or round) to an integer multiple of a given power of 10. % % Other reason to decide to do this is that it looks as if I don't even need % to understand the original code to hack into its ending via \XINT_trunc_G or % \XINT_itrunc_G. For the latter it looks as if logically I simply have to do % nothing. For the former I simply have to add some eD postfix. %\end{lverb} % \begin{macrocode} \def\xintTrunc {\romannumeral0\xinttrunc }% \def\xintiTrunc {\romannumeral0\xintitrunc}% \def\xinttrunc #1{\expandafter\XINT_trunc\the\numexpr#1.\XINT_trunc_G}% \def\xintitrunc #1{\expandafter\XINT_trunc\the\numexpr#1.\XINT_itrunc_G}% \def\XINT_trunc #1.#2#3% {\expandafter\XINT_trunc_a\romannumeral0\XINT_infrac{#3}#1.\XINT_trunc_b#2}% \def\XINT_trunc_a #1#2#3#4.#5% {\expandafter\XINT_trunc_c\the\numexpr#1+#4.{#2}{#3}#5#4.}% \def\XINT_trunc_c #1.#2#3#4% {\expandafter#4\romannumeral0\CALX_fintp{#2}{#3}{#1}}% \def\XINT_trunc_b #1#2#3.#4#5#6.#7% {% \if0#2\if0#5\XINT_trunc_z\fi\fi \if-#1\xint_dothis{#7#2#3.-#6.}\fi \xint_orthat{#7#2#3.\space#6.}% }% \def\XINT_trunc_z #1\xint_orthat#2{\fi\fi\space0}% \def\XINT_itrunc_G #1#2.#3#4.% {% \if#10\xint_dothis{ 0}\fi \xint_orthat{#3#1}#2% }% \def\XINT_trunc_G #1.#2#3#4.% {% \xint_gob_til_minus#3\XINT_trunc_Hc-% \expandafter\XINT_trunc_H \the\numexpr\romannumeral0\xintlength {#1}-#3#4.#3#4.{#1}#2% }% \def\XINT_trunc_Hc-\expandafter\XINT_trunc_H \the\numexpr\romannumeral0\xintlength #1.-#2.#3#4{#4#3e#2}% \def\XINT_trunc_H #1.#2.% {% \ifnum #1 > \xint_c_ \xint_dothis{\XINT_trunc_Ha {#2}}\fi \xint_orthat {\XINT_trunc_Hb {-#1}}% -0,--1,--2, .... }% \def\XINT_trunc_Ha% {% \expandafter\XINT_trunc_Haa\romannumeral0\xintdecsplit }% \def\XINT_trunc_Haa #1#2#3{#3#1.#2}% \def\XINT_trunc_Hb #1#2#3% {% \expandafter #3\expandafter0\expandafter.% \romannumeral\xintreplicate{#1}0#2% }% % \end{macrocode} % \subsection{\csh{xintTTrunc}} % \added{1.1} % \begin{macrocode} \def\xintTTrunc {\romannumeral0\xintttrunc }% \def\xintttrunc {\xintitrunc\xint_c_}% % \end{macrocode} % \subsection{\csh{xintNum}, \csh{xintnum}} % \begin{macrocode} \let\xintnum \xintttrunc % \end{macrocode} % \subsection{\csh{xintRound}, \csh{xintiRound}} %\begin{lverb} % As \xintTrunc, \xintiTrunc, with the post-processor \XINT_round_b: T + 1 % (xintcore's \xintinc) if the first omitted digit is at least 5 (round % half away from zero). A negative first argument is handled by % \XINT_trunc_G. %\end{lverb} % \begin{macrocode} \def\xintRound {\romannumeral0\xintround }% \def\xintiRound {\romannumeral0\xintiround }% \def\xintround #1{\expandafter\XINT_round\the\numexpr#1.\XINT_trunc_G}% \def\xintiround #1{\expandafter\XINT_round\the\numexpr#1.\XINT_itrunc_G}% \def\XINT_round #1.#2#3% {\expandafter\XINT_trunc_a\romannumeral0\XINT_infrac{#3}#1.\XINT_round_b#2}% \def\XINT_round_b #1#2.#3#4% {% \ifnum#3>\xint_c_iv \xint_dothis{\expandafter\XINT_round_c\romannumeral0\xintinc{#2}.#1#4}\fi \xint_orthat{\XINT_trunc_b #1#2.#3#4}% }% \def\XINT_round_c #1.#2#3{\XINT_trunc_b #2#1.0#3}% % \end{macrocode} % \subsection{\csh{xintXTrunc}} %\begin{lverb} % Temporarily use \xintTrunc: the former implementation was only % x-expandable and more efficient. Reimplement this entry completely later. %\end{lverb} % \begin{macrocode} \let\xintXTrunc\xintTrunc % \end{macrocode} % \subsection{\csh{xintAdd}} % \changed{1.3} %\begin{lverb} % Big change at 1.3: a/b+c/d uses lcm(b,d) as denominator. %\end{lverb} % \begin{macrocode} \def\xintAdd {\romannumeral0\xintadd }% \def\xintadd #1{\expandafter\XINT_fadd\romannumeral0\xintraw {#1}}% \def\XINT_fadd #1{\xint_gob_til_zero #1\XINT_fadd_Azero 0\XINT_fadd_a #1}% \def\XINT_fadd_Azero #1]{\xintraw }% \def\XINT_fadd_a #1/#2[#3]#4% {\expandafter\XINT_fadd_b\romannumeral0\xintraw {#4}{#3}{#1}{#2}}% \def\XINT_fadd_b #1{\xint_gob_til_zero #1\XINT_fadd_Bzero 0\XINT_fadd_c #1}% \def\XINT_fadd_Bzero #1]#2#3#4{ #3/#4[#2]}% \def\XINT_fadd_c #1/#2[#3]#4% {% \expandafter\XINT_fadd_Aa\the\numexpr #4-#3.{#3}{#4}{#1}{#2}% }% \def\XINT_fadd_Aa #1% {% \xint_UDzerominusfork #1-\XINT_fadd_B 0#1\XINT_fadd_Bb 0-\XINT_fadd_Ba \krof #1% }% \def\XINT_fadd_B #1.#2#3#4#5#6#7{\XINT_fadd_C {#4}{#5}{#7}{#6}[#3]}% \def\XINT_fadd_Ba #1.#2#3#4#5#6#7% {% \expandafter\XINT_fadd_C\expandafter {\romannumeral0\XINT_dsx_addzeros {#1}#6;}% {#7}{#5}{#4}[#2]% }% \def\XINT_fadd_Bb -#1.#2#3#4#5#6#7% {% \expandafter\XINT_fadd_C\expandafter {\romannumeral0\XINT_dsx_addzeros {#1}#4;}% {#5}{#7}{#6}[#3]% }% \def\XINT_fadd_iszero #1[#2]{ 0/1[0]}% ou [#2] originel? \def\XINT_fadd_C #1#2#3% {% \expandafter\XINT_fadd_D_b \romannumeral0\XINT_ndivrawpair{#2}{#3}{#2}{#2}{#3}{#1}% }% % \end{macrocode} %\begin{lverb} % Basically a clone of the \XINT_irr_loop_a loop. I should modify the % output of \XINT_ndivrawpair perhaps to be optimized for checking if % remainder vanishes. %\end{lverb} % \begin{macrocode} \def\XINT_fadd_D_a #1#2% {% \expandafter\XINT_fadd_D_b \romannumeral0\XINT_ndivrawpair {#1}{#2}{#1}% }% \def\XINT_fadd_D_b #1#2{\XINT_fadd_D_c #2\Z}% \def\XINT_fadd_D_c #1#2\Z {% \xint_gob_til_zero #1\XINT_fadd_D_exit0\XINT_fadd_D_a {#1#2}% }% \def\XINT_fadd_D_exit0\XINT_fadd_D_a #1#2#3% {% \expandafter\XINT_fadd_E \romannumeral0\xintiiquo {#3}{#2}.{#2}% }% \def\XINT_fadd_E #1.#2#3% {% \expandafter\XINT_fadd_F \romannumeral0\xintiimul{#1}{#3}.{\xintiiQuo{#3}{#2}}{#1}% }% \def\XINT_fadd_F #1.#2#3#4#5% {% \expandafter\XINT_fadd_G \romannumeral0\xintiiadd{\xintiiMul{#2}{#4}}{\xintiiMul{#3}{#5}}/#1% }% \def\XINT_fadd_G #1{% \def\XINT_fadd_G ##1{\if0##1\expandafter\XINT_fadd_iszero\fi#1##1}% }\XINT_fadd_G{ }% % \end{macrocode} % \subsection{\csh{xintSub}} % \changed{1.3} %\begin{lverb} % Since 1.3 will use least common multiple of denominators. %\end{lverb} % \begin{macrocode} \def\xintSub {\romannumeral0\xintsub }% \def\xintsub #1{\expandafter\XINT_fsub\romannumeral0\xintraw {#1}}% \def\XINT_fsub #1{\xint_gob_til_zero #1\XINT_fsub_Azero 0\XINT_fsub_a #1}% \def\XINT_fsub_Azero #1]{\xintopp }% \def\XINT_fsub_a #1/#2[#3]#4% {\expandafter\XINT_fsub_b\romannumeral0\xintraw {#4}{#3}{#1}{#2}}% \def\XINT_fsub_b #1{\xint_UDzerominusfork #1-\XINT_fadd_Bzero 0#1\XINT_fadd_c 0-{\XINT_fadd_c -#1}% \krof }% % \end{macrocode} % \subsection{\csh{xintSum}} %\begin{lverb} % There was (not documented anymore since 1.09d, 2013/10/22) a macro % \xintSumExpr, but it has been deleted at 1.2l. % % Empty items in the input are not accepted by this macro, but the input % may be empty. % % Refactored slightly at 1.4. \XINT_Sum used in xintexpr code. %\end{lverb} % \begin{macrocode} \def\xintSum {\romannumeral0\xintsum }% \def\xintsum #1{\expandafter\XINT_sum\romannumeral`&&@#1^}% \def\XINT_Sum{\romannumeral0\XINT_sum}% \def\XINT_sum#1% {% \xint_gob_til_^ #1\XINT_sum_empty ^% \expandafter\XINT_sum_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_sum_empty ^#1\xint:{ 0/1[0]}% \def\XINT_sum_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_sum_end ^% \expandafter\XINT_sum_loop \romannumeral0\xintadd{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_sum_end ^#1\xintadd #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintMul}} % \begin{macrocode} \def\xintMul {\romannumeral0\xintmul }% \def\xintmul #1{\expandafter\XINT_fmul\romannumeral0\xintraw {#1}.}% \def\XINT_fmul #1{\xint_gob_til_zero #1\XINT_fmul_zero 0\XINT_fmul_a #1}% \def\XINT_fmul_a #1[#2].#3% {\expandafter\XINT_fmul_b\romannumeral0\xintraw {#3}#1[#2.]}% \def\XINT_fmul_b #1{\xint_gob_til_zero #1\XINT_fmul_zero 0\XINT_fmul_c #1}% \def\XINT_fmul_c #1/#2[#3]#4/#5[#6.]% {% \expandafter\XINT_fmul_d \expandafter{\the\numexpr #3+#6\expandafter}% \expandafter{\romannumeral0\xintiimul {#5}{#2}}% {\romannumeral0\xintiimul {#4}{#1}}% }% \def\XINT_fmul_d #1#2#3% {% \expandafter \XINT_fmul_e \expandafter{#3}{#1}{#2}% }% \def\XINT_fmul_e #1#2{\XINT_outfrac {#2}{#1}}% \def\XINT_fmul_zero #1.#2{ 0/1[0]}% % \end{macrocode} % \subsection{\csh{xintSqr}} % \begin{macrocode} \def\xintSqr {\romannumeral0\xintsqr }% \def\xintsqr #1{\expandafter\XINT_fsqr\romannumeral0\xintraw {#1}}% \def\XINT_fsqr #1{\xint_gob_til_zero #1\XINT_fsqr_zero 0\XINT_fsqr_a #1}% \def\XINT_fsqr_a #1/#2[#3]% {% \expandafter\XINT_fsqr_b \expandafter{\the\numexpr #3+#3\expandafter}% \expandafter{\romannumeral0\xintiisqr {#2}}% {\romannumeral0\xintiisqr {#1}}% }% \def\XINT_fsqr_b #1#2#3{\expandafter \XINT_fmul_e \expandafter{#3}{#1}{#2}}% \def\XINT_fsqr_zero #1]{ 0/1[0]}% % \end{macrocode} % \subsection{\csh{xintPow}} % ATTENTION, it gets redefined by \xintexprnameimp. Check there. %\begin{lverb} % 1.2f: to be coherent with the "i" convention \xintiPow should parse also its % exponent via \xintNum when xintfrac.sty is loaded. This was not the case so % far. Cependant le problème est que le fait d'appliquer \xintNum rend % impossible certains inputs qui auraient pu être gérès par \numexpr. Le % \numexpr externe est ici pour intercepter trop grand input. %\end{lverb} % \begin{macrocode} \def\xintipow #1#2% {% \expandafter\xint_pow\the\numexpr \xintNum{#2}\expandafter .\romannumeral0\xintnum{#1}\xint: }% \def\xintPow {\romannumeral0\xintpow }% \def\xintpow #1% {% \expandafter\XINT_fpow\expandafter {\romannumeral0\XINT_infrac {#1}}% }% \def\XINT_fpow #1#2% {% \expandafter\XINT_fpow_fork\the\numexpr \xintNum{#2}\relax\Z #1% }% \def\XINT_fpow_fork #1#2\Z {% \xint_UDzerominusfork #1-\XINT_fpow_zero 0#1\XINT_fpow_neg 0-{\XINT_fpow_pos #1}% \krof {#2}% }% \def\XINT_fpow_zero #1#2#3#4{ 1/1[0]}% \def\XINT_fpow_pos #1#2#3#4#5% {% \expandafter\XINT_fpow_pos_A\expandafter {\the\numexpr #1#2*#3\expandafter}\expandafter {\romannumeral0\xintiipow {#5}{#1#2}}% {\romannumeral0\xintiipow {#4}{#1#2}}% }% \def\XINT_fpow_neg #1#2#3#4% {% \expandafter\XINT_fpow_pos_A\expandafter {\the\numexpr -#1*#2\expandafter}\expandafter {\romannumeral0\xintiipow {#3}{#1}}% {\romannumeral0\xintiipow {#4}{#1}}% }% \def\XINT_fpow_pos_A #1#2#3% {% \expandafter\XINT_fpow_pos_B\expandafter {#3}{#1}{#2}% }% \def\XINT_fpow_pos_B #1#2{\XINT_outfrac {#2}{#1}}% % \end{macrocode} % \subsection{\csh{xintFac}} %\begin{lverb} % Factorial coefficients: variant which can be chained with other % xintfrac macros. %\end{lverb} % \begin{macrocode} \def\xintFac {\romannumeral0\xintfac}% \def\xintfac #1{\expandafter\XINT_fac_fork\the\numexpr\xintNum{#1}.[0]}% % \end{macrocode} % \subsection{\csh{xintBinomial}} % \added{1.2f} % \begin{macrocode} \def\xintBinomial {\romannumeral0\xintbinomial}% \def\xintbinomial #1#2% {% \expandafter\XINT_binom_pre \the\numexpr\xintNum{#1}\expandafter.\the\numexpr\xintNum{#2}.[0]% }% % \end{macrocode} % \subsection{\csh{xintPFactorial}} % \added{1.2f} %\begin{lverb} % Partial factorial. For needs of xintexpr.sty. %\end{lverb} % \begin{macrocode} \def\xintipfactorial #1#2% {% \expandafter\XINT_pfac_fork \the\numexpr\xintNum{#1}\expandafter.\the\numexpr\xintNum{#2}.% }% \def\xintPFactorial {\romannumeral0\xintpfactorial}% \def\xintpfactorial #1#2% {% \expandafter\XINT_pfac_fork \the\numexpr\xintNum{#1}\expandafter.\the\numexpr\xintNum{#2}.[0]% }% % \end{macrocode} % \subsection{\csh{xintPrd}} %\begin{lverb} % Refactored at 1.4. After some hesitation the routine still does % not try to detect on the fly a zero item, to abort the loop. Indeed % this would add some overhead generally (as we need normalizing the item before % checking if it vanishes hence we must then grab things once more). %\end{lverb} % \begin{macrocode} \def\xintPrd {\romannumeral0\xintprd }% \def\xintprd #1{\expandafter\XINT_prd\romannumeral`&&@#1^}% \def\XINT_Prd{\romannumeral0\XINT_prd}% \def\XINT_prd#1% {% \xint_gob_til_^ #1\XINT_prd_empty ^% \expandafter\XINT_prd_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_prd_empty ^#1\xint:{ 1/1[0]}% \def\XINT_prd_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_prd_end ^% \expandafter\XINT_prd_loop \romannumeral0\xintmul{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_prd_end ^#1\xintmul #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintDiv}} % \begin{macrocode} \def\xintDiv {\romannumeral0\xintdiv }% \def\xintdiv #1% {% \expandafter\XINT_fdiv\expandafter {\romannumeral0\XINT_infrac {#1}}% }% \def\XINT_fdiv #1#2% {\expandafter\XINT_fdiv_A\romannumeral0\XINT_infrac {#2}#1}% \def\XINT_fdiv_A #1#2#3#4#5#6% {% \expandafter\XINT_fdiv_B \expandafter{\the\numexpr #4-#1\expandafter}% \expandafter{\romannumeral0\xintiimul {#2}{#6}}% {\romannumeral0\xintiimul {#3}{#5}}% }% \def\XINT_fdiv_B #1#2#3% {% \expandafter\XINT_fdiv_C \expandafter{#3}{#1}{#2}% }% \def\XINT_fdiv_C #1#2{\XINT_outfrac {#2}{#1}}% % \end{macrocode} % \subsection{\csh{xintDivFloor}} % \added{1.1} %\begin{lverb} % Changed at 1.2p to not append /1[0] ending but rather output a % big integer in strict format, like \xintDivTrunc and \xintDivRound. %\end{lverb} % \begin{macrocode} \def\xintDivFloor {\romannumeral0\xintdivfloor }% \def\xintdivfloor #1#2{\xintifloor{\xintDiv {#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintDivTrunc}} % \added{1.1} % \begin{macrocode} \def\xintDivTrunc {\romannumeral0\xintdivtrunc }% \def\xintdivtrunc #1#2{\xintttrunc {\xintDiv {#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintDivRound}} %\begin{lverb} % 1.1 %\end{lverb} % \begin{macrocode} \def\xintDivRound {\romannumeral0\xintdivround }% \def\xintdivround #1#2{\xintiround 0{\xintDiv {#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintModTrunc}} % \added{1.1} %\begin{lverb} % \xintModTrunc {q1}{q2} computes q1 - q2*t(q1/q2) with t(q1/q2) % equal to the truncated division of two fractions q1 and q2. % % Its former name, prior to 1.2p, was \xintMod. %\end{lverb} % \changed{1.3} %\begin{lverb} % At 1.3, uses least common multiple denominator, like \xintMod (next). %\end{lverb} % \begin{macrocode} \def\xintModTrunc {\romannumeral0\xintmodtrunc }% \def\xintmodtrunc #1{\expandafter\XINT_modtrunc_a\romannumeral0\xintraw{#1}.}% \def\XINT_modtrunc_a #1#2.#3% {\expandafter\XINT_modtrunc_b\expandafter #1\romannumeral0\xintraw{#3}#2.}% \def\XINT_modtrunc_b #1#2% #1 de A, #2 de B. {% \if0#2\xint_dothis{\XINT_modtrunc_divbyzero #1#2}\fi \if0#1\xint_dothis\XINT_modtrunc_aiszero\fi \if-#2\xint_dothis{\XINT_modtrunc_bneg #1}\fi \xint_orthat{\XINT_modtrunc_bpos #1#2}% }% \def\XINT_modtrunc_divbyzero #1#2[#3]#4.% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero: #1#4/(#2[#3]).}{}{ 0/1[0]}% }% \def\XINT_modtrunc_aiszero #1.{ 0/1[0]}% \def\XINT_modtrunc_bneg #1% {% \xint_UDsignfork #1{\xintiiopp\XINT_modtrunc_pos {}}% -{\XINT_modtrunc_pos #1}% \krof }% \def\XINT_modtrunc_bpos #1% {% \xint_UDsignfork #1{\xintiiopp\XINT_modtrunc_pos {}}% -{\XINT_modtrunc_pos #1}% \krof }% % \end{macrocode} %\begin{lverb} % Attention. This crucially uses that xint's \xintiiE{x}{e} is defined % to return x unchanged if e is negative (and x extended by e zeroes if e >= % 0). %\end{lverb} % \begin{macrocode} \def\XINT_modtrunc_pos #1#2/#3[#4]#5/#6[#7].% {% \expandafter\XINT_modtrunc_pos_a \the\numexpr\ifnum#7>#4 #4\else #7\fi\expandafter.% \romannumeral0\expandafter\XINT_mod_D_b \romannumeral0\XINT_ndivrawpair{#3}{#6}{#3}{#3}{#6}% {#1#5}{#7-#4}{#2}{#4-#7}% }% \def\XINT_modtrunc_pos_a #1.#2#3#4{\xintiirem {#3}{#4}/#2[#1]}% % \end{macrocode} % \subsection{\csh{xintDivMod}} % \added{1.2p} %\begin{lverb} % \xintDivMod{q1}{q2} outputs {floor(q1/q2)}{q1 - q2*floor(q1/q2)}. % Attention that it relies on \xintiiE{x}{e} returning x if e < 0. %\end{lverb} % \changed{1.3} %\begin{lverb} % Modified (like \xintAdd and \xintSub) at 1.3 to use a l.c.m for final % denominator of the "mod" part. %\end{lverb} % \begin{macrocode} \def\xintDivMod {\romannumeral0\xintdivmod }% \def\xintdivmod #1{\expandafter\XINT_divmod_a\romannumeral0\xintraw{#1}.}% \def\XINT_divmod_a #1#2.#3% {\expandafter\XINT_divmod_b\expandafter #1\romannumeral0\xintraw{#3}#2.}% \def\XINT_divmod_b #1#2% #1 de A, #2 de B. {% \if0#2\xint_dothis{\XINT_divmod_divbyzero #1#2}\fi \if0#1\xint_dothis\XINT_divmod_aiszero\fi \if-#2\xint_dothis{\XINT_divmod_bneg #1}\fi \xint_orthat{\XINT_divmod_bpos #1#2}% }% \def\XINT_divmod_divbyzero #1#2[#3]#4.% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero: #1#4/(#2[#3]).}{}% {{0}{0/1[0]}}% à revoir... }% \def\XINT_divmod_aiszero #1.{{0}{0/1[0]}}% \def\XINT_divmod_bneg #1% f // -g = (-f) // g, f % -g = - ((-f) % g) {% \expandafter\XINT_divmod_bneg_finish \romannumeral0\xint_UDsignfork #1{\XINT_divmod_bpos {}}% -{\XINT_divmod_bpos {-#1}}% \krof }% \def\XINT_divmod_bneg_finish#1#2% {% \expandafter\xint_exchangetwo_keepbraces\expandafter {\romannumeral0\xintiiopp#2}{#1}% }% \def\XINT_divmod_bpos #1#2/#3[#4]#5/#6[#7].% {% \expandafter\XINT_divmod_bpos_a \the\numexpr\ifnum#7>#4 #4\else #7\fi\expandafter.% \romannumeral0\expandafter\XINT_mod_D_b \romannumeral0\XINT_ndivrawpair{#3}{#6}{#3}{#3}{#6}% {#1#5}{#7-#4}{#2}{#4-#7}% }% \def\XINT_divmod_bpos_a #1.#2#3#4% {% \expandafter\XINT_divmod_bpos_finish \romannumeral0\xintiidivision{#3}{#4}{/#2[#1]}% }% \def\XINT_divmod_bpos_finish #1#2#3{{#1}{#2#3}}% % \end{macrocode} % \subsection{\csh{xintMod}} % \added{1.2p} %\begin{lverb} % \xintMod{q1}{q2} computes q1 - q2*floor(q1/q2). Attention that % it relies on \xintiiE{x}{e} returning x if e < 0. % % Prior to 1.2p, that macro had the meaning now attributed to \xintModTrunc. %\end{lverb} % \changed{1.3} %\begin{lverb} % Modified (like \xintAdd and \xintSub) at 1.3 to use a l.c.m for final % denominator. %\end{lverb} % \begin{macrocode} \def\xintMod {\romannumeral0\xintmod }% \def\xintmod #1{\expandafter\XINT_mod_a\romannumeral0\xintraw{#1}.}% \def\XINT_mod_a #1#2.#3% {\expandafter\XINT_mod_b\expandafter #1\romannumeral0\xintraw{#3}#2.}% \def\XINT_mod_b #1#2% #1 de A, #2 de B. {% \if0#2\xint_dothis{\XINT_mod_divbyzero #1#2}\fi \if0#1\xint_dothis\XINT_mod_aiszero\fi \if-#2\xint_dothis{\XINT_mod_bneg #1}\fi \xint_orthat{\XINT_mod_bpos #1#2}% }% % \end{macrocode} %\begin{lverb} % Attention to not move ModTrunc code beyond that point. %\end{lverb} % \begin{macrocode} \let\XINT_mod_divbyzero\XINT_modtrunc_divbyzero \let\XINT_mod_aiszero \XINT_modtrunc_aiszero \def\XINT_mod_bneg #1% f % -g = - ((-f) % g), for g > 0 {% \xintiiopp\xint_UDsignfork #1{\XINT_mod_bpos {}}% -{\XINT_mod_bpos {-#1}}% \krof }% \def\XINT_mod_bpos #1#2/#3[#4]#5/#6[#7].% {% \expandafter\XINT_mod_bpos_a \the\numexpr\ifnum#7>#4 #4\else #7\fi\expandafter.% \romannumeral0\expandafter\XINT_mod_D_b \romannumeral0\XINT_ndivrawpair{#3}{#6}{#3}{#3}{#6}% {#1#5}{#7-#4}{#2}{#4-#7}% }% \def\XINT_mod_D_a #1#2% {% \expandafter\XINT_mod_D_b \romannumeral0\XINT_ndivrawpair {#1}{#2}{#1}% }% \def\XINT_mod_D_b #1#2{\XINT_mod_D_c #2\Z}% \def\XINT_mod_D_c #1#2\Z {% \xint_gob_til_zero #1\XINT_mod_D_exit0\XINT_mod_D_a {#1#2}% }% \def\XINT_mod_D_exit0\XINT_mod_D_a #1#2#3% {% \expandafter\XINT_mod_E \romannumeral0\xintiiquo {#3}{#2}.{#2}% }% \def\XINT_mod_E #1.#2#3% {% \expandafter\XINT_mod_F \romannumeral0\xintiimul{#1}{#3}.{\xintiiQuo{#3}{#2}}{#1}% }% \def\XINT_mod_F #1.#2#3#4#5#6#7% {% {#1}{\xintiiE{\xintiiMul{#4}{#3}}{#5}}% {\xintiiE{\xintiiMul{#6}{#2}}{#7}}% }% \def\XINT_mod_bpos_a #1.#2#3#4{\xintiirem {#3}{#4}/#2[#1]}% % \end{macrocode} % \subsection{\csh{xintIsOne}} % \added{1.09a} %\begin{lverb} % Could be more efficient. For fractions with big % powers of tens, it is better to use \xintCmp{f}{1}. Restyled in 1.09i. %\end{lverb} % \begin{macrocode} \def\xintIsOne {\romannumeral0\xintisone }% \def\xintisone #1{\expandafter\XINT_fracisone \romannumeral0\xintrawwithzeros{#1}\Z }% \def\XINT_fracisone #1/#2\Z {\if0\xintiiCmp {#1}{#2}\xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% % \end{macrocode} % \subsection{\csh{xintGeq}} % \begin{macrocode} \def\xintGeq {\romannumeral0\xintgeq }% \def\xintgeq #1% {% \expandafter\XINT_fgeq\expandafter {\romannumeral0\xintabs {#1}}% }% \def\XINT_fgeq #1#2% {% \expandafter\XINT_fgeq_A \romannumeral0\xintabs {#2}#1% }% \def\XINT_fgeq_A #1% {% \xint_gob_til_zero #1\XINT_fgeq_Zii 0% \XINT_fgeq_B #1% }% \def\XINT_fgeq_Zii 0\XINT_fgeq_B #1[#2]#3[#4]{ 1}% \def\XINT_fgeq_B #1/#2[#3]#4#5/#6[#7]% {% \xint_gob_til_zero #4\XINT_fgeq_Zi 0% \expandafter\XINT_fgeq_C\expandafter {\the\numexpr #7-#3\expandafter}\expandafter {\romannumeral0\xintiimul {#4#5}{#2}}% {\romannumeral0\xintiimul {#6}{#1}}% }% \def\XINT_fgeq_Zi 0#1#2#3#4#5#6#7{ 0}% \def\XINT_fgeq_C #1#2#3% {% \expandafter\XINT_fgeq_D\expandafter {#3}{#1}{#2}% }% \def\XINT_fgeq_D #1#2#3% {% \expandafter\XINT_cntSgnFork\romannumeral`&&@\expandafter\XINT_cntSgn \the\numexpr #2+\xintLength{#3}-\xintLength{#1}\relax\xint: { 0}{\XINT_fgeq_E #2\Z {#3}{#1}}{ 1}% }% \def\XINT_fgeq_E #1% {% \xint_UDsignfork #1\XINT_fgeq_Fd -{\XINT_fgeq_Fn #1}% \krof }% \def\XINT_fgeq_Fd #1\Z #2#3% {% \expandafter\XINT_fgeq_Fe \romannumeral0\XINT_dsx_addzeros {#1}#3;\xint:#2\xint: }% \def\XINT_fgeq_Fe #1\xint:#2#3\xint:{\XINT_geq_plusplus #2#1\xint:#3\xint:}% \def\XINT_fgeq_Fn #1\Z #2#3% {% \expandafter\XINT_fgeq_Fo \romannumeral0\XINT_dsx_addzeros {#1}#2;\xint:#3\xint: }% \def\XINT_fgeq_Fo #1#2\xint:#3\xint:{\XINT_geq_plusplus #1#3\xint:#2\xint:}% % \end{macrocode} % \subsection{\csh{xintMax}} % \begin{macrocode} \def\xintMax {\romannumeral0\xintmax }% \def\xintmax #1% {% \expandafter\XINT_fmax\expandafter {\romannumeral0\xintraw {#1}}% }% \def\XINT_fmax #1#2% {% \expandafter\XINT_fmax_A\romannumeral0\xintraw {#2}#1% }% \def\XINT_fmax_A #1#2/#3[#4]#5#6/#7[#8]% {% \xint_UDsignsfork #1#5\XINT_fmax_minusminus -#5\XINT_fmax_firstneg #1-\XINT_fmax_secondneg --\XINT_fmax_nonneg_a \krof #1#5{#2/#3[#4]}{#6/#7[#8]}% }% \def\XINT_fmax_minusminus --% {\expandafter-\romannumeral0\XINT_fmin_nonneg_b }% \def\XINT_fmax_firstneg #1-#2#3{ #1#2}% \def\XINT_fmax_secondneg -#1#2#3{ #1#3}% \def\XINT_fmax_nonneg_a #1#2#3#4% {% \XINT_fmax_nonneg_b {#1#3}{#2#4}% }% \def\XINT_fmax_nonneg_b #1#2% {% \if0\romannumeral0\XINT_fgeq_A #1#2% \xint_afterfi{ #1}% \else \xint_afterfi{ #2}% \fi }% % \end{macrocode} % \subsection{\csh{xintMaxof}} %\begin{lverb} % 1.2l protects \xintMaxof against items with non terminated % \the\numexpr expressions. % % 1.4 renders the macro compatible with an empty argument and it also defines % an accessor \XINT_Maxof suitable for xintexpr usage (formerly xintexpr % had its own macro handling comma separated values, but it changed % internal representation at 1.4). % %\end{lverb} % \begin{macrocode} \def\xintMaxof {\romannumeral0\xintmaxof }% \def\xintmaxof #1{\expandafter\XINT_maxof\romannumeral`&&@#1^}% \def\XINT_Maxof{\romannumeral0\XINT_maxof}% \def\XINT_maxof#1% {% \xint_gob_til_^ #1\XINT_maxof_empty ^% \expandafter\XINT_maxof_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_maxof_empty ^#1\xint:{ 0/1[0]}% \def\XINT_maxof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_maxof_e ^% \expandafter\XINT_maxof_loop \romannumeral0\xintmax{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_maxof_e ^#1\xintmax #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintMin}} % \begin{macrocode} \def\xintMin {\romannumeral0\xintmin }% \def\xintmin #1% {% \expandafter\XINT_fmin\expandafter {\romannumeral0\xintraw {#1}}% }% \def\XINT_fmin #1#2% {% \expandafter\XINT_fmin_A\romannumeral0\xintraw {#2}#1% }% \def\XINT_fmin_A #1#2/#3[#4]#5#6/#7[#8]% {% \xint_UDsignsfork #1#5\XINT_fmin_minusminus -#5\XINT_fmin_firstneg #1-\XINT_fmin_secondneg --\XINT_fmin_nonneg_a \krof #1#5{#2/#3[#4]}{#6/#7[#8]}% }% \def\XINT_fmin_minusminus --% {\expandafter-\romannumeral0\XINT_fmax_nonneg_b }% \def\XINT_fmin_firstneg #1-#2#3{ -#3}% \def\XINT_fmin_secondneg -#1#2#3{ -#2}% \def\XINT_fmin_nonneg_a #1#2#3#4% {% \XINT_fmin_nonneg_b {#1#3}{#2#4}% }% \def\XINT_fmin_nonneg_b #1#2% {% \if0\romannumeral0\XINT_fgeq_A #1#2% \xint_afterfi{ #2}% \else \xint_afterfi{ #1}% \fi }% % \end{macrocode} % \subsection{\csh{xintMinof}} %\begin{lverb} % 1.2l protects \xintMinof against items with non terminated % \the\numexpr expressions. % % 1.4 version is compatible with an empty input (empty items are handled as zero). %\end{lverb} % \begin{macrocode} \def\xintMinof {\romannumeral0\xintminof }% \def\xintminof #1{\expandafter\XINT_minof\romannumeral`&&@#1^}% \def\XINT_Minof{\romannumeral0\XINT_minof}% \def\XINT_minof#1% {% \xint_gob_til_^ #1\XINT_minof_empty ^% \expandafter\XINT_minof_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_minof_empty ^#1\xint:{ 0/1[0]}% \def\XINT_minof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_minof_e ^% \expandafter\XINT_minof_loop\romannumeral0\xintmin{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_minof_e ^#1\xintmin #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintCmp}} % \begin{macrocode} \def\xintCmp {\romannumeral0\xintcmp }% \def\xintcmp #1% {% \expandafter\XINT_fcmp\expandafter {\romannumeral0\xintraw {#1}}% }% \def\XINT_fcmp #1#2% {% \expandafter\XINT_fcmp_A\romannumeral0\xintraw {#2}#1% }% \def\XINT_fcmp_A #1#2/#3[#4]#5#6/#7[#8]% {% \xint_UDsignsfork #1#5\XINT_fcmp_minusminus -#5\XINT_fcmp_firstneg #1-\XINT_fcmp_secondneg --\XINT_fcmp_nonneg_a \krof #1#5{#2/#3[#4]}{#6/#7[#8]}% }% \def\XINT_fcmp_minusminus --#1#2{\XINT_fcmp_B #2#1}% \def\XINT_fcmp_firstneg #1-#2#3{ -1}% \def\XINT_fcmp_secondneg -#1#2#3{ 1}% \def\XINT_fcmp_nonneg_a #1#2% {% \xint_UDzerosfork #1#2\XINT_fcmp_zerozero 0#2\XINT_fcmp_firstzero #10\XINT_fcmp_secondzero 00\XINT_fcmp_pos \krof #1#2% }% \def\XINT_fcmp_zerozero #1#2#3#4{ 0}% \def\XINT_fcmp_firstzero #1#2#3#4{ -1}% \def\XINT_fcmp_secondzero #1#2#3#4{ 1}% \def\XINT_fcmp_pos #1#2#3#4% {% \XINT_fcmp_B #1#3#2#4% }% \def\XINT_fcmp_B #1/#2[#3]#4/#5[#6]% {% \expandafter\XINT_fcmp_C\expandafter {\the\numexpr #6-#3\expandafter}\expandafter {\romannumeral0\xintiimul {#4}{#2}}% {\romannumeral0\xintiimul {#5}{#1}}% }% \def\XINT_fcmp_C #1#2#3% {% \expandafter\XINT_fcmp_D\expandafter {#3}{#1}{#2}% }% \def\XINT_fcmp_D #1#2#3% {% \expandafter\XINT_cntSgnFork\romannumeral`&&@\expandafter\XINT_cntSgn \the\numexpr #2+\xintLength{#3}-\xintLength{#1}\relax\xint: { -1}{\XINT_fcmp_E #2\Z {#3}{#1}}{ 1}% }% \def\XINT_fcmp_E #1% {% \xint_UDsignfork #1\XINT_fcmp_Fd -{\XINT_fcmp_Fn #1}% \krof }% \def\XINT_fcmp_Fd #1\Z #2#3% {% \expandafter\XINT_fcmp_Fe \romannumeral0\XINT_dsx_addzeros {#1}#3;\xint:#2\xint: }% \def\XINT_fcmp_Fe #1\xint:#2#3\xint:{\XINT_cmp_plusplus #2#1\xint:#3\xint:}% \def\XINT_fcmp_Fn #1\Z #2#3% {% \expandafter\XINT_fcmp_Fo \romannumeral0\XINT_dsx_addzeros {#1}#2;\xint:#3\xint: }% \def\XINT_fcmp_Fo #1#2\xint:#3\xint:{\XINT_cmp_plusplus #1#3\xint:#2\xint:}% % \end{macrocode} % \subsection{\csh{xintAbs}} % \begin{macrocode} \def\xintAbs {\romannumeral0\xintabs }% \def\xintabs #1{\expandafter\XINT_abs\romannumeral0\xintraw {#1}}% % \end{macrocode} % \subsection{\csh{xintOpp}} % \begin{macrocode} \def\xintOpp {\romannumeral0\xintopp }% \def\xintopp #1{\expandafter\XINT_opp\romannumeral0\xintraw {#1}}% % \end{macrocode} % \subsection{\csh{xintInv}} % \changed{1.3d} % \begin{macrocode} \def\xintInv {\romannumeral0\xintinv }% \def\xintinv #1{\expandafter\XINT_inv\romannumeral0\xintraw {#1}}% \def\XINT_inv #1% {% \xint_UDzerominusfork #1-\XINT_inv_iszero 0#1\XINT_inv_a 0-{\XINT_inv_a {}}% \krof #1% }% \def\XINT_inv_iszero #1]% {\XINT_legacysignalcondition{DivisionByZero}{Inverse of zero: inv(#1]).}{}{ 0/1[0]}}% \def\XINT_inv_a #1#2/#3[#4#5]% {% \xint_UDzerominusfork #4-\XINT_inv_expiszero 0#4\XINT_inv_b 0-{\XINT_inv_b -#4}% \krof #5.{#1#3/#2}% }% \def\XINT_inv_expiszero #1.#2{ #2[0]}% \def\XINT_inv_b #1.#2{ #2[#1]}% % \end{macrocode} % \subsection{\csh{xintSgn}} % \begin{macrocode} \def\xintSgn {\romannumeral0\xintsgn }% \def\xintsgn #1{\expandafter\XINT_sgn\romannumeral0\xintraw {#1}\xint:}% % \end{macrocode} % \subsection{\csh{xintSignBit}} % \added{1.4l} % \begin{macrocode} \def\xintSignBit {\romannumeral0\xintsignbit }% \def\xintsignbit #1{\expandafter\XINT_signbit\romannumeral0\xintraw {#1}\xint:}% \def\XINT_signbit #1#2\xint: {% \xint_UDzerominusfork #1-{ 0}% 0#1{ 1}% 0-{ 0}% \krof }% % \end{macrocode} % \subsection{\csh{xintGCD}} % \changed{1.4} % They replace the former \xintgcdnameimp macros of the same names which % truncated to integers their arguments. Fraction-producing |gcd()| and % |lcm()| functions were available since |1.3d| \xintexprnameimp, with % non-public support macros handling comma separated values. % % \changed{1.4d} % Somewhat strangely \csh{xintGCD} was formerly \csh{xintGCDof} used with only two % arguments, as the latter directly implemented a fractionl gcd algorithm % using \csh{xintMod} repeatedly for two arguments. % % Now \csh{xintGCD} contains the pairwise gcd routine and \csh{xintGCDof} % is only a wrapper. And the pairwise gcd is reduced to integer-only % computations to hopefully reduce fraction overhead. % % Each input is filtered via |\xintPIrr| and |\xintREZ| to reduce size % of maniuplate integers in algebra. % % But hesitation about applying |\xintPIrr| to output, and/or |\xintREZ|. % (as it is applied on input). % % But as the code is now used for frational lcm's we actually need to do % some reduction of output else lcm's of integers will not be necessarily % printed by |\xinteval| as integers. % % Well finally I apply |\xintIrr| (but not |\xintREZ| to output). % Hesitations here (thinking of inputs with large [n] parts, the output % will have many zeros). So I do this only for the user macro but % the core routine as used by |\xintGCDof| will not do it. % % Also at |1.4d| the code uses |\expanded|. % \begin{macrocode} \def\xintGCD {\romannumeral0\xintgcd}% \def\xintgcd #1% {% \expandafter\XINT_fgcd_in \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_fgcd_in #1#2\xint:#3% {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_fgcd_chkzeros\expandafter#1% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#3}}}\xint:#1#2\xint: }% \def\XINT_fgcd_out#1[#2]{\xintirr{#1[#2]}[0]}% \def\XINT_fgcd_chkzeros #1#2% {% \xint_UDzerofork #1\XINT_fgcd_aiszero #2\XINT_fgcd_biszero 0\XINT_fgcd_main \krof #2% }% \def\XINT_fgcd_aiszero #1\xint:#2\xint:{ #1}% \def\XINT_fgcd_biszero #1\xint:#2\xint:{ #2}% \def\XINT_fgcd_main #1/#2[#3]\xint:#4/#5[#6]\xint: {% \expandafter\XINT_fgcd_a \romannumeral0\xintiigcd{#2}{#5}\xint: #2\xint:#5\xint:#1\xint:#4\xint:#3.#6.% }% \def\XINT_fgcd_a #1\xint:#2\xint: {% \expandafter\XINT_fgcd_b \romannumeral0\xintiiquo{#2}{#1}\xint:#1\xint:#2\xint: }% \def\XINT_fgcd_b #1\xint:#2\xint:#3\xint:#4\xint:#5\xint:#6\xint:#7.#8.% {% \expanded{% \xintiigcd{\xintiiE{\xintiiMul{#5}{\xintiiQuo{#4}{#2}}}{#7-#8}}% {\xintiiE{\xintiiMul{#6}{#1}}{#8-#7}}% /\xintiiMul{#1}{#4}% [\ifnum#7>#8 #8\else #7\fi]% }% }% % \end{macrocode} % \subsection{\csh{xintGCDof}} % \changed{1.4} % This inherits from former non public \xintexprnameimp macro called % |\xintGCDof:csv|, which handled comma separated items. % % It handles fractions presented as braced items and is the support macro % for the |gcd()| function in |\xintexpr| and |\xintfloatexpr|. The support % macro for the |gcd()| function in |\xintiiexpr| is \csbxint{iiGCDof}, from % \xintnameimp. % % An empty input is allowed but I have some hesitations on the return % value of 1. % % \changed{1.4d} % Sadly the |1.4| version had multiple problems: % \begin{itemize} % \item broken if first argument vanished, % \item broken if some argument was not in strict format, for example % had leading chains of signs or zeros (|\xintGCDof{2}{03}|). % This bug originates in the fact the original macro % was used only in \xintexprnameimp sanitized context. % \end{itemize} % % Also, output is now always an irreducible fraction (ending with |[0]|). % \begin{macrocode} \def\xintGCDof {\romannumeral0\xintgcdof}% \def\xintgcdof #1{\expandafter\XINT_fgcdof\romannumeral`&&@#1^}% \def\XINT_GCDof{\romannumeral0\XINT_fgcdof}% \def\XINT_fgcdof #1% {% \expandafter\XINT_fgcdof_chkempty\romannumeral`&&@#1\xint: }% \def\XINT_fgcdof_chkempty #1% {% \xint_gob_til_^#1\XINT_fgcdof_empty ^\XINT_fgcdof_in #1% }% \def\XINT_fgcdof_empty #1\xint:{ 1/1[0]}% hesitation, should it be infinity? O? \def\XINT_fgcdof_in #1\xint: {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_fgcdof_loop \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_fgcdof_loop #1\xint:#2% {% \expandafter\XINT_fgcdof_chkend\romannumeral`&&@#2\xint:#1\xint:\xint: }% \def\XINT_fgcdof_chkend #1% {% \xint_gob_til_^#1\XINT_fgcdof_end ^\XINT_fgcdof_loop_pair #1% }% \def\XINT_fgcdof_end #1\xint:#2\xint:\xint:{ #2}% \def\XINT_fgcdof_loop_pair #1\xint:#2% {% \expandafter\XINT_fgcdof_loop \romannumeral0\expandafter\XINT_fgcd_chkzeros\expandafter#2% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint:#2% }% % \end{macrocode} % \subsection{\csh{xintLCM}} % Same comments as for \csh{xintGCD}. % Entirely redone for |1.4d|. % Well, actually we can express it in terms of fractional gcd. % \begin{macrocode} \def\xintLCM {\romannumeral0\xintlcm}% \def\xintlcm #1% {% \expandafter\XINT_flcm_in \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_flcm_in #1#2\xint:#3% {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_flcm_chkzeros\expandafter#1% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#3}}}\xint:#1#2\xint: }% \def\XINT_flcm_chkzeros #1#2% {% \xint_UDzerofork #1\XINT_flcm_zero #2\XINT_flcm_zero 0\XINT_flcm_main \krof #2% }% \def\XINT_flcm_zero #1\xint:#2\xint:{ 0/1[0]}% \def\XINT_flcm_main #1/#2[#3]\xint:#4/#5[#6]\xint: {% \xintinv {% \romannumeral0\XINT_fgcd_main #2/#1[-#3]\xint:#5/#4[-#6]\xint: }% }% % \end{macrocode} % \subsection{\csh{xintLCMof}} % See comments for |\xintGCDof|. \xintnameimp provides the integer only % \csbxint{iiLCMof}. % % \changed{1.4d}{} % Sadly, although a public \xintfracnameimp macro, it did not (since |1.4|) % sanitize its arguments like other \xintfracnameimp macros. % % \begin{macrocode} \def\xintLCMof {\romannumeral0\xintlcmof}% \def\xintlcmof #1{\expandafter\XINT_flcmof\romannumeral`&&@#1^}% \def\XINT_LCMof{\romannumeral0\XINT_flcmof}% \def\XINT_flcmof #1% {% \expandafter\XINT_flcmof_chkempty\romannumeral`&&@#1\xint: }% \def\XINT_flcmof_chkempty #1% {% \xint_gob_til_^#1\XINT_flcmof_empty ^\XINT_flcmof_in #1% }% \def\XINT_flcmof_empty #1\xint:{ 0/1[0]}% hesitation \def\XINT_flcmof_in #1\xint: {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_flcmof_loop \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_flcmof_loop #1\xint:#2% {% \expandafter\XINT_flcmof_chkend\romannumeral`&&@#2\xint:#1\xint:\xint: }% \def\XINT_flcmof_chkend #1% {% \xint_gob_til_^#1\XINT_flcmof_end ^\XINT_flcmof_loop_pair #1% }% \def\XINT_flcmof_end #1\xint:#2\xint:\xint:{ #2}% \def\XINT_flcmof_loop_pair #1\xint:#2% {% \expandafter\XINT_flcmof_chkzero \romannumeral0\expandafter\XINT_flcm_chkzeros\expandafter#2% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint:#2% }% \def\XINT_flcmof_chkzero #1% {% \xint_gob_til_zero#1\XINT_flcmof_zero0\XINT_flcmof_loop#1% }% \def\XINT_flcmof_zero#1^{ 0/1[0]}% % \end{macrocode} % \subsection{Floating point macros} % % ATTENTION % THE COMMENTS HERE ARE COMPLETELY OBSOLETE SINCE THE ADVANT OF CALX. % THEY WILL BE REMOVED WHEN VERSION 2.0a1 WIL GET FINALIZED FOR RELEASE. % DEFINITION OF \csbxint{Digits} and \csbxint{SetDigits} ARE ALREADY % MOVED TO \calxfpnameimp. THE COMMENTED OUT PREPARATION FOR A USER % INTERAFACE FOR THE EXTRA GUARD DIGITES USED INTERNALLY FOR xintlog AND % xintirg WAS DELETED DURING THIS TRANSFER. % % For a long time the float routines dating back to releases |1.07/1.08a| % (May-June 2013) were not modified. % % Since |1.2f| (March 2016) the four operations first round their arguments to % |\xinttheDigits|-floats (or |P|-floats), not (|\xinttheDigits+2|)-floats or % (|P+2|)-floats as was the case with earlier releases. % % The four operations addition, subtraction, multiplication, division have % always produced the correct rounding of the theoretical exact value to |P| % or |\xinttheDigits| digits when the inputs are decimal numbers with at most % |P| digits, and arbitrary decimal exponent part. % % From |1.08a| to |1.2j|, |\xintFloat| (and |\XINTinFloat| which is used to % parse inputs to other float macros) handled a fractional input |A/B| via an % initial replacement to |A'/B'| where |A'| and |B'| were |A| and |B| % truncated to |Q+2| digits (where asked-for precision is |Q|), and then they % correctly rounded |A'/B'| to |Q| digits. But this meant that this rounding of % the input could differ (by up to one unit in the last place) from the % correct rounding of the original |A/B| to the asked-for number of % digits (which until |1.2f| in uses as auxiliary to the macros for the basic % operations was 2 more than the prevailing precision). % % Since |1.2k| all inputs are correctly rounded to the asked-for number of % digits (this was, I think, the case in the |1.07| release -- there are no % code comments -- but was, afaicr, not very efficiently done, and this is why % the |1.08a| release opeted for truncation of the numerator and denominator.) % % Notice that in float expressions, the |/| is treated as operator, hence the % above discussion makes a difference only for the special input form % |qfloat(A/B)| or for an |\xintexpr A/B\relax| embedded in the float % expression, with |A| or |B| having more digits than the prevailing float % precision. % % \begin{framed} % Internally there is no inner representation of |P|-floats as such !!!!! % % The input parser will again compute the length of the mantissa on each use % !!! This is obviously something that must be improved upon before % implementation of higher functions. % % Currently, special tricks are used to quickly recognize inputs having no % denominators, or fractions whose numerators and denominators are not too % long compared to the target precision |P|, and in particular |P|-floats or % quotients of two such. % % Another long-standing issue is that float multiplication will first % compute the |2P| or |2P-1| digits of the exact product, and then round it % to |P| digits. This is sub-optimal for large |P| particularly as the % multiplication algorithm is basically the schoolbook one, hence % \emph{worse} than quadratic in the \TeX\ implementation which has extra % cost of fetching long sequences of tokens. % \end{framed} % %\begin{lverb} % Changes at 1.4e (done 2021/04/15; undone 2021/04/29) % % Macros named \XINTinFloat are not public user-level but were designed % a long time ago for \xintfloatexpr context as a very preliminary step % towards attempting to preserve some internal format, here A[N] type. % % When is lowercased it means it needs a \romannumeral0 trigger % (\XINTinfloatS keeps an uppercase S). % % Most were coded to check for an optional argument [D], and to use % D=\XINTdigits in its place if absent but it turned out only \XINTinfloatpow, % \XINTinfloatmul, \XINTinfloatadd were actually used with an optional % argument and this happened only in macros from the very old xintseries.sty, % so I changed all of them to not check for optional argument [D] anymore, % keeping only some private interface for the xintseries.sty use case. Some % required being used with [D], some still had names ending in "digits" % indicating they would use \XINTdigits always. % % Indeed basically all algebra is done "exactly" and the [D] governs rules of % float-rounding on input and output. % % During development of 1.4e we fleetingly experimented with letting the value % used in place of D be \XINTdigitsx to 1.4e, i.e. \XINTdigits with guard % digits, a situation which was motivated by the implementation of % trigonometrical functions at high level, i.e. using \xintdeffloatfunc which % had no mechanism to make intermediate calculations with guard digits. % % Simply doing everything "as is" but with 2 guard digits proved very good % (surprisingly efficient, even) to the trigonometrical functions. However % using them systematically raises many issues (for example, the correct % rounding at P digits is destroyed if we obtain it a D=P+2 then round from % P+2 to P digits so we definitely can not do this as default, so some % interface is needed to define intermediate functions only using such guard % digits and keeping them in their output). % % Finally, an approach limited to the xinttrig.sty scope was used and I % removed all \XINTdigitsx related matters from 1.4e. But this left some % modifications of the interfaces of the "float" macros here which this list % tries to document, mainly for the author's benefit. % %( Macros always using \XINTdigits and now not allowing [P] option %: \XINTinFloatAdd %: \XINTinFloatSub %: \XINTinFloatMul %: \XINTinFloatSqr %: \XINTinFloatDiv %: \XINTinFloatPow %: \XINTinFloatPower %: \XINTinFloatPFactorial %: \XINTinFloatBinomial %: %: Macros which already did not allow [P] option prior to 1.4e refactoring %: \XINTinFloatFrac (renamed from \XINTinFloatFracdigits) %: %: Macros requiring a [P]. Some of the "_wopt" named macros are& % renamings of macros formerly requiring [P]. %: \XINTinFloat %: \XINTinFloatS %: \XINTFloatiLogTen %: \XINTinRandomFloatS (this one has only the [P] mandatory argument) %: \XINTinFloatFac %: \XINTinFloatSqrt %: \XINTinFloatAdd_wopt, \XINTinfloatadd_wopt %: \XINTinFloatSub_wopt, \XINTinfloatsub_wopt %: \XINTinFloatMul_wopt, \XINTinfloatmul_wopt %: \XINTinFloatSqr_wopt %: \XINTinfloatpow_wopt (not FloatPow) %: \XINTinFloatDiv_wopt %: %: Specially named macros indicating usage of \XINTdigits %: \XINTinFloatdigits %: \XINTinFloatSdigits %: \XINTFloatiLogTendigits %: \XINTinRandomFloatSdigits %: \XINTinFloatFacdigits %: \XINTinFloatSqrtdigits %) %\end{lverb} % % % \subsection{\csh{xintFloat}, \csh{xintFloatZero}} %\begin{lverb} % 1.2f and 1.2g brought some refactoring which resulted in faster treatment of % decimal inputs. 1.2i dropped use of some old routines dating back to pre 1.2 % era in favor of more modern \xintDSRr for rounding. Then 1.2k improves % again the handling of denominators B with few digits. % % But the main change with 1.2k is a complete rewrite of the B>1 case in % order to achieve again correct rounding in all cases. % % The original version from 1.07 (May 2013) computed the exact rounding % to P digits for all inputs. But from 1.08 on (June 2013), the macro handled % A/B input by first truncating both A and B to at most P+2 digits. This meant % that decimal input (arbitrarily long, with scientific part) was correctly % rounded, but in case of fractional input there could be up to 0.6 unit in % the last place difference of the produced rounding to the input, hence the % output could differ from the correct rounding. % % Example with 16 digits (the default): \xintFloat {1/17597472569900621233}$newline % with xintfrac 1.07: 5.682634230727187e-20$newline % with xintfrac 1.08b--1.2j: 5.682634230727188e-20$newline % with xintfrac 1.2k: 5.682634230727187e-20$newline % The exact value is 5.682634230727187499924124...e-20, showing that 1.07 and % 1.2k % produce the correct rounding. % % Currently the code ends in a more costly branch in about 1 case among 500, % where it does some extra operations (a multiplication in particular). There % is a free parameter delta (here set at 4), I have yet to make some numerical % explorations, to see if it could be favorable to set it to a higher value % (with delta=5, there is only 1 exceptional case in 5000, etc...). % % I have always hesitated about the policy of printing 10.00...0 in case of % rounding upwards to the next power of ten. Already since 1.2f \XINTinFloat % always produced a mantissa with exactly P digits (except for the zero % value). Starting with 1.2k, \xintFloat drops this habit of printing % 10.00..0 in such cases. Side note: the rounding-up detection worked when the % input A/B was with numerator A and denominator B having each less than P+2 % digits, or with B=1, else, it could happen that the output was a power of % ten but not detected to be a rounding up of the original fraction. The value % was ok, but printed 1.0...0eN with P-1 zeroes, not 10.0...0e(N-1). % % I decided it was not worth the effort to enhance the algorithm to detect % with 100$% fiability all cases of rounding up to next % power of ten, hence 1.2k dropped this. % % To avoid duplication of code, and any extra burden on \XINTinFloat, which is % the macro used internally by the float macros for parsing their inputs, we % simply make now \xintFloat a wrapper of \XINTinFloat. %\end{lverb} % \begin{macrocode} \def\xintFloatZero{0.0e0}% 1.4k breaking change. Replaces hard-coded 0.e0 \def\xintFloat {\romannumeral0\xintfloat }% \def\xintfloat #1{\XINT_float_chkopt #1\xint:}% \def\XINT_float_chkopt #1% {% \ifx [#1\expandafter\XINT_float_opt \else\expandafter\XINT_float_noopt \fi #1% }% \def\XINT_float_noopt #1\xint:% {% \expandafter\XINT_float_post \romannumeral0\XINTinfloat[\XINTdigits]{#1}\XINTdigits.% }% \def\XINT_float_opt [\xint: {% \expandafter\XINT_float_opt_a\the\numexpr }% \def\XINT_float_opt_a #1]#2% {% \expandafter\XINT_float_post \romannumeral0\XINTinfloat[#1]{#2}#1.% }% \def\XINT_float_post #1% {% \xint_UDzerominusfork #1-\XINT_float_zero 0#1\XINT_float_neg 0-\XINT_float_pos \krof #1% }%[ \def\XINT_float_zero #1]#2.{\expanded{ \xintFloatZero}}% \def\XINT_float_neg-{\expandafter-\romannumeral0\XINT_float_pos}% \def\XINT_float_pos #1#2[#3]#4.% {% \expandafter\XINT_float_pos_done\the\numexpr#3+#4-\xint_c_i.#1.#2;% }% \def\XINT_float_pos_done #1.#2;{ #2e#1}% % \end{macrocode} % \subsection{\csh{xintFloatBraced}} % \added{1.4l} %\begin{lverb} % Je ne le fais pas comme un wrapper au-dessus de \xintFloat % car c'est pénible avec argument optionnel donc finalemnt % on est obligé de rajouter overhead comme ici. % %( Hésitation si on obéit à \xintFloatZero ou pas. Finalement non. %: Hésitation si on renvoie avec séparateur décimal ou pas. %: Hésitation si on met l'exposant scientifique en premier. %: Hésitation si on sépare le signe pour le mettre en premier. %: Hésitation si on renvoie un exposant pour mantisse normalisée& % ou pas normalisée. %) % % Finalement je décide {signe}{exposant}{mantisse sans point décimal}. % Avec en fait 0 ou 1 pour signe (mais ce sign bit mais ça n'a pas grand % sens en décimal...). Non finalement mantisse avec point décimal. %\end{lverb} % \begin{macrocode} \def\xintFloatBraced{\romannumeral0\xintfloatbraced }% \def\xintfloatbraced#1{\XINT_floatbr_chkopt #1\xint:}% \def\XINT_floatbr_chkopt #1% {% \ifx [#1\expandafter\XINT_floatbr_opt \else\expandafter\XINT_floatbr_noopt \fi #1% }% \def\XINT_floatbr_noopt #1\xint:% {% \expandafter\XINT_floatbr_post \romannumeral0\XINTinfloat[\XINTdigits]{#1}\XINTdigits.% }% \def\XINT_floatbr_opt [\xint: {% \expandafter\XINT_floatbr_opt_a\the\numexpr }% \def\XINT_floatbr_opt_a #1]#2% {% \expandafter\XINT_floatbr_post \romannumeral0\XINTinfloat[#1]{#2}#1.% }% \def\XINT_floatbr_post #1% {% \xint_UDzerominusfork #1-\XINT_floatbr_zero 0#1\XINT_floatbr_neg 0-\XINT_floatbr_pos \krof #1% }% % \end{macrocode} %\begin{lverb} % Hésitation à faire %( \def\XINT_floatbr_zero #1]#2.{\expandafter\XINT_floatbr_zero_a\xintFloatZero e0e\relax}% %: \def\XINT_floatbr_zero_a#1e#2e#3\relax{{#1}{#2}}% %) % Finalement non. Et même je décide de renvoyer autant de zéros que P. % De plus depuis j'ai opté pour {sign bit}{exposant}{mantisse} % Hésitation si mantisse avec ou sans le séparateur décimal. % Est-ce que je devrais mettre plutôt -0+ au début? %\end{lverb} % \begin{macrocode} \def\XINT_floatbr_zero #1]#2.{\expanded{{0}{0}{0.\xintReplicate{#2-\xint_c_i}0}}}% \def\XINT_floatbr_neg-{\expandafter\XINT_floatbr_neg_a\romannumeral0\XINT_floatbr_pos}% \def\XINT_floatbr_neg_a#1{{1}}% \def\XINT_floatbr_pos #1#2[#3]#4.% {% \expanded{{0}{\the\numexpr#3+#4-\xint_c_i}}{#1.#2}% }% % \end{macrocode} % \subsection{\csh{XINTinFloat}, \csh{XINTinFloatS}} %\begin{lverb} % This routine is like \xintFloat but produces an output of the shape A[N] % which is then parsed faster as input to other float macros. % Float operations in \xintfloatexpr...\relax use internally this format. % % It must be used in form \XINTinFloat[P]{f}: the optional [P] is % mandatory. % % Since 1.2f, the mantissa always has exactly P digits even in case of % rounding up to next power of ten. This simplifies other routines. % % (but the zero value must always be checked for, as it outputs 0[0]) % % 1.2g added a variant \XINTinFloatS which, in case of decimal input with less % than the asked for precision P will not add extra zeros to the mantissa. For % example it may output 2[0] even if P=500, rather than the canonical % representation 200...000[-499]. This is how \xintFloatMul and \xintFloatDiv % parse their inputs, which speeds-up follow-up processing. But \xintFloatAdd % and \xintFloatSub still use \XINTinFloat for parsing their inputs; anyway % this will have to be changed again when inner structure will carry upfront % at least the length of mantissa as data. % % Each time \XINTinFloat is called it at least computes a length. Naturally if % we had some format for floats that would be dispensed of...$newline % something like % .mantissa.exponent, etc... not yet. % % Since 1.2k, \XINTinFloat always correctly rounds its argument, even if it % is a fraction with very big numerator and denominator. See the discussion of % \xintFloat. %\end{lverb} % \begin{macrocode} \def\XINTinFloat {\romannumeral0\XINTinfloat }% \def\XINTinfloat {\expandafter\XINT_infloat_clean\romannumeral0\XINT_infloat}% % \end{macrocode} %\begin{lverb} % Attention que ici le fait que l'on grabbe #1 est important car il % pourrait y avoir un zéro (en particulier dans le cas où input est nul). %\end{lverb} % \begin{macrocode} \def\XINT_infloat_clean #1% {\if #1!\xint_dothis\XINT_infloat_clean_a\fi\xint_orthat{ }#1}% % \end{macrocode} %\begin{lverb} % Ici on ajoute les zeros pour faire exactement avec P chiffres. % Car le #1 = P - L avec L la longueur de #2, (ou plutôt de abs(#2), % car ici le #2 peut avoir un signe) et L < P %\end{lverb} % \begin{macrocode} \def\XINT_infloat_clean_a !#1.#2[#3]% {% \expandafter\XINT_infloat_done \the\numexpr #3-#1\expandafter.% \romannumeral0\XINT_dsx_addzeros {#1}#2;;% }% \def\XINT_infloat_done #1.#2;{ #2[#1]}% % \end{macrocode} %\begin{lverb} % variant which allows output with shorter mantissas. %\end{lverb} % \begin{macrocode} \def\XINTinFloatS {\romannumeral0\XINTinfloatS}% \def\XINTinfloatS {\expandafter\XINT_infloatS_clean\romannumeral0\XINT_infloat}% \def\XINT_infloatS_clean #1% {\if #1!\xint_dothis\XINT_infloatS_clean_a\fi\xint_orthat{ }#1}% \def\XINT_infloatS_clean_a !#1.{ }% % \end{macrocode} %\begin{lverb} % début de la routine proprement dite, % l'argument optionnel est obligatoire. %\end{lverb} % \begin{macrocode} \def\XINT_infloat [#1]%#2% {% \expandafter\XINT_infloat_a\the\numexpr #1\expandafter.% \romannumeral0\XINT_infrac% {#2}% }% % \end{macrocode} %\begin{lverb} % #1=P, #2=n, #3=A, #4=B. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_a #1.#2#3#4% {% % \end{macrocode} %\begin{lverb} % micro boost au lieu d'utiliser \XINT_isOne{#4}, mais pas bon style. %\end{lverb} % \begin{macrocode} \if1\XINT_is_One#4XY% \expandafter\XINT_infloat_sp \else\expandafter\XINT_infloat_fork \fi #3.{#1}{#2}{#4}% }% % \end{macrocode} %\begin{lverb} % Special quick treatment of B=1 case (1.2f then again 1.2g.)$newline % maintenant: A.{P}{N}{1} % Il est possible que A soit nul. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp #1% {% \xint_UDzerominusfork #1-\XINT_infloat_spzero 0#1\XINT_infloat_spneg 0-\XINT_infloat_sppos \krof #1% }% % \end{macrocode} %\begin{lverb} % Attention surtout pas 0/1[0] ici. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_spzero 0.#1#2#3{ 0[0]}% \def\XINT_infloat_spneg-% {\expandafter\XINT_infloat_spnegend\romannumeral0\XINT_infloat_sppos}% \def\XINT_infloat_spnegend #1% {\if#1!\expandafter\XINT_infloat_spneg_needzeros\fi -#1}% \def\XINT_infloat_spneg_needzeros -!#1.{!#1.-}% % \end{macrocode} %\begin{lverb} % in: A.{P}{N}{1}$newline % out: P-L.A.P.N. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sppos #1.#2#3#4% {% \expandafter\XINT_infloat_sp_b\the\numexpr#2-\xintLength{#1}.#1.#2.#3.% }% % \end{macrocode} %\begin{lverb} % #1= P-L. Si c'est positif ou nul il faut retrancher #1 à l'exposant, et % ajouter autant de zéros. On regarde premier token. % P-L.A.P.N. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp_b #1% {% \xint_UDzerominusfork #1-\XINT_infloat_sp_quick 0#1\XINT_infloat_sp_c 0-\XINT_infloat_sp_needzeros \krof #1% }% % \end{macrocode} %\begin{lverb} % Ici P=L. Le cas usuel dans \xintfloatexpr. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp_quick 0.#1.#2.#3.{ #1[#3]}% % \end{macrocode} %\begin{lverb} % Ici #1=P-L est >0. L'exposant sera N-(P-L). #2=A. #3=P. #4=N.$newline % 18 mars 2016. En fait dans certains contextes il est sous-optimal d'ajouter les % zéros. Par exemple quand c'est appelé par la multiplication ou la division, % c'est idiot de convertir 2 en 200000...00000[-499]. % Donc je redéfinis addzeros en needzeroes. Si on appelle sous la forme % \XINTinFloatS, on ne fait pas l'addition de zeros. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp_needzeros #1.#2.#3.#4.{!#1.#2[#4]}% % \end{macrocode} %\begin{lverb} % L-P=#1.A=#2#3.P=#4.N=#5.$newline % Ici P0. L'exposant final sera N+L-P, % sauf dans le cas spécial, il sera alors N+L-P+1. L'ajustement final % est fait par \XINT_infloat_Y. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp_c -#1.#2#3.#4.#5.% {% \expandafter\XINT_infloat_Y \the\numexpr #5+#1\expandafter.% \romannumeral0\expandafter\XINT_infloat_sp_round \romannumeral0\XINT_split_fromleft (\xint_c_i+#4).#2#3\xint_bye2345678\xint_bye..#2% }% \def\XINT_infloat_sp_round #1.#2.% {% \XINT_dsrr#1\xint_bye\xint_Bye3456789\xint_bye/\xint_c_x\relax.% }% % \end{macrocode} %\begin{lverb} % General branch for A/B with B>1 inputs. It achieves correct rounding % always since 1.2k (done January 2, 2017.) This branch is never taken for A=0 % because \XINT_infrac will have returned B=1 then. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_fork #1% {% \xint_UDsignfork #1\XINT_infloat_J -\XINT_infloat_K \krof #1% }% \def\XINT_infloat_J-{\expandafter-\romannumeral0\XINT_infloat_K }% % \end{macrocode} %\begin{lverb} % A.{P}{n}{B} avec B>1. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_K #1.#2% {% \expandafter\XINT_infloat_L \the\numexpr\xintLength{#1}\expandafter.\the\numexpr #2+\xint_c_iv.{#1}{#2}% }% % \end{macrocode} %\begin{lverb} % |A|.P+4.{A}{P}{n}{B}. We check if A already has length % <= P+4. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_L #1.#2.% {% \ifnum #1>#2 \expandafter\XINT_infloat_Ma \else \expandafter\XINT_infloat_Mb \fi #1.#2.% }% % \end{macrocode} %\begin{lverb} % |A|.P+4.{A}{P}{n}{B}. We will keep only the first P+4 % digits of A, denoted A'' in what follows. % % output: u=-0.A''.junk.P+4.|A|.{A}{P}{n}{B} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Ma #1.#2.#3% {% \expandafter\XINT_infloat_MtoN\expandafter-\expandafter0\expandafter.% \romannumeral0\XINT_split_fromleft#2.#3\xint_bye2345678\xint_bye..% #2.#1.{#3}% }% % \end{macrocode} %\begin{lverb} % |A|.P+4.{A}{P}{n}{B}.$newline % Here A is short. We set u = P+4-|A|, and A''=A (A' = 10^u A) % % output: u.A''..P+4.|A|.{A}{P}{n}{B} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Mb #1.#2.#3% {% \expandafter\XINT_infloat_MtoN\the\numexpr#2-#1.% #3..#2.#1.{#3}% }% % \end{macrocode} %\begin{lverb} % input u.A''.junk.P+4.|A|.{A}{P}{n}{B}$newline % output |B|.P+4.{B}u.A''.P.|A|.n.{A}{B} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_MtoN #1.#2.#3.#4.#5.#6#7#8#9% {% \expandafter\XINT_infloat_N \the\numexpr\xintLength{#9}.#4.{#9}#1.#2.#7.#5.#8.{#6}{#9}% }% \def\XINT_infloat_N #1.#2.% {% \ifnum #1>#2 \expandafter\XINT_infloat_Oa \else \expandafter\XINT_infloat_Ob \fi #1.#2.% }% % \end{macrocode} %\begin{lverb} % input |B|.P+4.{B}u.A''.P.|A|.n.{A}{B}$newline % output v=-0.B''.junk.|B|.u.A''.P.|A|.n.{A}{B} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Oa #1.#2.#3% {% \expandafter\XINT_infloat_P\expandafter-\expandafter0\expandafter.% \romannumeral0\XINT_split_fromleft#2.#3\xint_bye2345678\xint_bye..% #1.% }% % \end{macrocode} %\begin{lverb} % output v=P+4-|B|>=0.B''.junk.|B|.u.A''.P.|A|.n.{A}{B} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Ob #1.#2.#3% {% \expandafter\XINT_infloat_P\the\numexpr#2-#1.#3..#1.% }% % \end{macrocode} %\begin{lverb} % input v.B''.junk.|B|.u.A''.P.|A|.n.{A}{B}$newline % output Q1.P.|B|.|A|.n.{A}{B}$newline % Q1 = division euclidienne de A''.10^{u-v+P+3} par B''. % % Special detection of cases with A and B both having length at most P+4: this % will happen when called from \xintFloatDiv as A and B (produced then via % \XINTinFloatS) will have at most P digits. We then only need integer division % with P+1 extra zeros, not P+3. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_P #1#2.#3.#4.#5.#6#7.#8.#9.% {% \csname XINT_infloat_Q\if-#1\else\if-#6\else q\fi\fi\expandafter\endcsname \romannumeral0\xintiiquo {\romannumeral0\XINT_dsx_addzerosnofuss {#6#7-#1#2+#9+\xint_c_iii\if-#1\else\if-#6\else-\xint_c_ii\fi\fi}#8;}% {#3}.#9.#5.% }% % \end{macrocode} %\begin{lverb} % «quick» branch. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Qq #1.#2.% {% \expandafter\XINT_infloat_Rq \romannumeral0\XINT_split_fromleft#2.#1\xint_bye2345678\xint_bye..#2.% }% \def\XINT_infloat_Rq #1.#2#3.% {% \ifnum#2<\xint_c_v \expandafter\XINT_infloat_SEq \else\expandafter\XINT_infloat_SUp \fi {\if.#3.\xint_c_\else\xint_c_i\fi}#1.% }% % \end{macrocode} %\begin{lverb} % standard branch which will have to handle undecided rounding, if too % close to a mid-value. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Q #1.#2.% {% \expandafter\XINT_infloat_R \romannumeral0\XINT_split_fromleft#2.#1\xint_bye2345678\xint_bye..#2.% }% \def\XINT_infloat_R #1.#2#3#4#5.% {% \if.#5.\expandafter\XINT_infloat_Sa\else\expandafter\XINT_infloat_Sb\fi #2#3#4#5.#1.% }% % \end{macrocode} %\begin{lverb} % trailing digits.Q.P.|B|.|A|.n.{A}{B}$newline % #1=trailing digits (they may have leading zeros.) %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Sa #1.% {% \ifnum#1>500 \xint_dothis\XINT_infloat_SUp\fi \ifnum#1<499 \xint_dothis\XINT_infloat_SEq\fi \xint_orthat\XINT_infloat_X\xint_c_ }% \def\XINT_infloat_Sb #1.% {% \ifnum#1>5009 \xint_dothis\XINT_infloat_SUp\fi \ifnum#1<4990 \xint_dothis\XINT_infloat_SEq\fi \xint_orthat\XINT_infloat_X\xint_c_i }% % \end{macrocode} %\begin{lverb} % epsilon #2=Q.#3=P.#4=|B|.#5=|A|.#6=n.{A}{B}$newline % exposant final est n+|A|-|B|-P+epsilon %\end{lverb} % \begin{macrocode} \def\XINT_infloat_SEq #1#2.#3.#4.#5.#6.#7#8% {% \expandafter\XINT_infloat_SY \the\numexpr #6+#5-#4-#3+#1.#2.% }% \def\XINT_infloat_SY #1.#2.{ #2[#1]}% % \end{macrocode} %\begin{lverb} % initial digit #2 put aside to check for case of rounding up to % next power of ten, which will need adjustment of mantissa and % exponent. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_SUp #1#2#3.#4.#5.#6.#7.#8#9% {% \expandafter\XINT_infloat_Y \the\numexpr#7+#6-#5-#4+#1\expandafter.% \romannumeral0\xintinc{#2#3}.#2% }% % \end{macrocode} %\begin{lverb} % epsilon Q.P.|B|.|A|.n.{A}{B}$newline % % \xintDSH{-x}{U} multiplies U by 10^x. When x is negative, this means % it truncates (i.e. it drops the last -x digits). % % We don't try to optimize too much macro calls here, the odds are 2 per 1000 % for this branch to be taken. Perhaps in future I will use higher free % parameter d, which currently is set at 4. % % #1=epsilon, #2#3=Q, #4=P, #5=|B|, #6=|A|, #7=n, #8=A, #9=B %\end{lverb} % \begin{macrocode} \def\XINT_infloat_X #1#2#3.#4.#5.#6.#7.#8#9% {% \expandafter\XINT_infloat_Y \the\numexpr #7+#6-#5-#4+#1\expandafter.% \romannumeral`&&@\romannumeral0\xintiiiflt {\xintDSH{#6-#5-#4+#1}{\xintDouble{#8}}}% {\xintiiMul{\xintInc{\xintDouble{#2#3}}}{#9}}% \xint_firstofone \xintinc{#2#3}.#2% }% % \end{macrocode} %\begin{lverb} % check for rounding up to next power of ten. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Y #1{% \def\XINT_infloat_Y ##1.##2##3.##4% {% \if##49\if##21\expandafter\expandafter\expandafter\XINT_infloat_Z\fi\fi #1##2##3[##1]% }}\XINT_infloat_Y{ }% % \end{macrocode} %\begin{lverb} % #1=1, #2=0. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Z #1#2#3[#4]% {% \expandafter\XINT_infloat_ZZ\the\numexpr#4+\xint_c_i.#3.% }% \def\XINT_infloat_ZZ #1.#2.{ 1#2[#1]}% % \end{macrocode} % \subsection{\csh{XINTFloatiLogTen}} % \added{1.3e} %\begin{lverb} % Le comportement pour un input nul est non % encore finalisé. Il changera lorsque NaN, +Inf, -Inf existeront. % % The optional argument [#1] is in fact mandatory and #1 is % not pre-expanded in a \numexpr. % % The return value here 2^31-2^15 is highly undecided. %\end{lverb} % \begin{macrocode} \def\XINTFloatiLogTen {\the\numexpr\XINTfloatilogten}% \def\XINTfloatilogten [#1]#2% {\expandafter\XINT_floatilogten\romannumeral0\XINT_infloat[#1]{#2}#1.}% \def\XINTFloatiLogTendigits{\the\numexpr\XINTfloatilogten[\XINTdigits]}% \def\XINT_floatilogten #1{% \if #10\xint_dothis\XINT_floatilogten_z\fi \if #1!\xint_dothis\XINT_floatilogten_a\fi \xint_orthat\XINT_floatilogten_b #1% }% \def\XINT_floatilogten_z 0[0]#1.{-"7FFF8000\relax}% \def\XINT_floatilogten_a !#1.#2[#3]#4.{#3-#1+#4-\xint_c_i\relax}% \def\XINT_floatilogten_b #1[#2]#3.{#2+#3-\xint_c_i\relax}% % \end{macrocode} % \subsection{\csh{xintPFloat}} % \added{1.1} % \changed{1.4e} %\begin{lverb} % % xint has not yet incorporated a general formatter as it was % not a priority during development and external solutions exist % (I did not check for a while but I think LaTeX3 has implemented % a general formatter in the printf or Python ".format" spirit) % % But when one starts using really the package, especially in % an interactive way (xintsession 2021), one needs the default % output to be as nice as possible. % % The \xintPFloat macro was added at 1.1 as a "prettifying printer" % for floats, basically influenced by Maple. % %( The rules were: %: 0. The input is float-rounded to either Digits or the optional argument %: 1. zero is printed as "0." %: 2. x.yz...eK is printed "as is" if K>5 or K<-5. %: 3. if -5<=K<=5, fixed point decimal notation is used. %: 4. in cases 2. and 3., no trimming of trailing zeroes. %) % % 1.4b added \xintPFloatE to customize whether to use % e or E. % % % 1.4e, with some hesitation, decided to make a breaking change and to modify % the behaviour. % %( The new rules: %: 0. The input is float-rounded to either Digits or the optional argument %: 1. zero is printed as 0.0 %: 2. x.yz...eK is printed in decimal fixed point if -4<=K<=+5& % (notice the change, formerly K=-5 used fixed point notation in output)& % else it is printed in scientific notation %: 3. trailing zeros of the mantissa are trimmed always %: 4. in case of decimal fixed point for an integer, there& % is a trailing ".0" %: 5. in case of scientific notation with a one-digit trimmed mantissa& % there is an added ".0" too %) % % Further, \xintPFloatE can now also be redefined as a macro with a parameter % delimited by a dot, with the dot also present as final token in its output. % It would then grab the scientific exponent K as explicit digit % possibly prefixed by a minus sign. The macro must be f-expandable. % % The macro \xintPFloat_wopt is only there for a micro gain as the package % does % % \let\xintfloatexprPrintOne\xintPFloat_wopt % % as it knows it will % be used always with a [P] argument in the xintexpr.sty context. %\end{lverb} % \changed{1.4k} %\begin{lverb} % Addition of customization via \xintPFloatZero, \xintPFloatLengthOneSuffix, % \xintPFloatNoSciEmax, \xintPFloatNoSciEmin which replace formerly % hard-coded behaviour. % % Breaking change to not add ".0" suffix to integers (when scientific % notation dropped) or to one-digit mantissas. % % In my own practice I started being annoyed by the automatic trimming of % zeros added at 1.4e. % % This change had been influenced by using Python in interactive mode % which since 3.1 prints floats (in decimal conversion) choosing the % shortest string. In particular it trims trailing zeros, and it drops % the scientific notation in favor of decimal notation for something % like -4<= K <= 15, with K the scientific exponent. % % At 1.4e I was still influenced by my experience with Maple and % did for -4 <= K <= 5. Not very well thought anyhow (one may wish % to use decimal notation when sending things to PostScript, so perhaps % I should have kept with -5). % % But, the main problem is with trimming trailing zeros: although in % interactive sessions, this has its logic, as soon as one does tables % with numbers, dropping a trailing zero upsets alignments or creates % visual holes compared to other lines and this is in the end very % annoying. % % After much hesitation, I decided to slightly modifify only the former % behaviour: trimming only if that removes at least 4 zeros. I had also % experimented with another condition: trimmed mantissas should be at % most 6 digits (for example) wide, else use no trimming. % % Threshold customizable via \xintPFloatMinTrimmed. %\end{lverb} % \changed[2022/05/22]{1.4l} %\begin{lverb} % The 1.4k check for canceling the trimming of trailing zeros % took over priority over the later check for being an integer when % decimal fixed point notation was used (or being only with a one-digit % trimmed mantissa). In particular if user set \xintPFloatMinTrimmed to % the value of Digits (or P) to avoid trimming it also prevented % recognition of some integers (but not all). Fixed at 1.4l %\end{lverb} % % \changed{2.0a1} %\begin{lverb} % The formatting core (\XINT_pfloat_fork to \XINT_pfloat_Ps, with % \XINT_pfloat_a_fork) and the defaults of \xintPFloatE, \xintPFloatNoSciEmax, % \xintPFloatNoSciEmin, \xintPFloatIntSuffix, \xintPFloatLengthOneSuffix, % \xintPFloatZero, \xintPFloatMinTrimmed moved verbatim to calxfp.sty at % 2.0a1. %\end{lverb} % \begin{macrocode} \def\xintPFloat {\romannumeral0\xintpfloat }% \def\xintpfloat #1{\XINT_pfloat_chkopt #1\xint:}% \def\xintPFloat_wopt[#1]#2% {% \romannumeral0\expandafter\XINT_pfloat \romannumeral0\XINTinfloatS[#1]{#2}#1.% }% \def\XINT_pfloat_chkopt #1% {% \ifx [#1\expandafter\XINT_pfloat_opt \else\expandafter\XINT_pfloat_noopt \fi #1% }% \def\XINT_pfloat_noopt #1\xint:% {% \expandafter\XINT_pfloat\romannumeral0\XINTinfloatS[\XINTdigits]{#1}% \XINTdigits.% }% \def\XINT_pfloat_opt [\xint:{\expandafter\XINT_pfloat_opt_a\the\numexpr}% \def\XINT_pfloat_opt_a #1]#2% {% \expandafter\XINT_pfloat\romannumeral0\XINTinfloatS[#1]{#2}% #1.% }% \def\XINT_pfloat#1]% {% \expandafter\XINT_pfloat_fork\romannumeral0\xintrez{#1]}% }% % \end{macrocode} % \subsection{\csh{xintFloatToDecimal}} % \added{1.4k} % \begin{macrocode} \def\xintFloatToDecimal {\romannumeral0\xintfloattodecimal }% \def\xintfloattodecimal #1{\XINT_floattodec_chkopt #1\xint:}% \def\XINT_floattodec_chkopt #1% {% \ifx [#1\expandafter\XINT_floattodec_opt \else\expandafter\XINT_floattodec_noopt \fi #1% }% \def\XINT_floattodec_noopt #1\xint:% {% \expandafter\XINT_floattodec\romannumeral0\XINTinfloatS[\XINTdigits]{#1}% }% \def\XINT_floattodec_opt [\xint:#1]% {% \expandafter\XINT_floattodec\romannumeral0\XINTinfloatS[#1]% }% % \end{macrocode} %\begin{lverb} % Temptation to try to use direct access to lower entry points % from \xintREZ, but it dates back from very early days and uses old \Z % delimiters (same remarks for the code jumping from \xintFracToSci % to \xintrez) %\end{lverb} % \begin{macrocode} \def\XINT_floattodec#1]% {% \expandafter\XINT_dectostr\romannumeral0\xintrez{#1]}% }% % \end{macrocode} % % \subsection{\csh{xintFloatAdd}, \cshnolabel{XINTinFloatAdd}} % % The \csbXINT{inFloatAdd} interface is kept at 2.0a1 for \ctanpackage{polexpr}. % And \csbXINT{infloatadd} is kept for \xintseriesnameimp. % %\begin{lverb} % First included in release 1.07. % % 1.09ka improved a bit the efficiency. However the add, sub, mul, div % routines were provisory and supposed to be revised soon. % % Which didn't happen until 1.2f. Now, the inputs are first rounded to P % digits, not P+2 as earlier. % % See general introduction for important changes at 1.4e relative to % the \XINTinFloat macros. % %\end{lverb} % \begin{macrocode} \def\xintFloatAdd {\romannumeral0\xintfloatadd}% \def\xintfloatadd #1{\XINT_fladd_chkopt \xintfloat #1\xint:}% \def\XINTinFloatAdd{\romannumeral0\XINTinfloatadd }% \def\XINTinfloatadd{\XINT_fladd_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinfloatadd_wopt[#1]{\expandafter\XINT_fladd_opt_a\the\numexpr#1.\XINTinfloatS}% \def\XINT_fladd_chkopt #1#2% {% \ifx [#2\expandafter\XINT_fladd_opt \else\expandafter\XINT_fladd_noopt \fi #1#2% }% \def\XINT_fladd_noopt #1#2\xint:#3% {% #1[\XINTdigits]% {\expandafter\XINT_FL_add_a \romannumeral0\XINTinfloat[\XINTdigits]{#2}\XINTdigits.{#3}}% }% \def\XINT_fladd_opt #1[\xint:#2]%#3#4% {% \expandafter\XINT_fladd_opt_a\the\numexpr #2.#1% }% \def\XINT_fladd_opt_a #1.#2#3#4% {% #2[#1]{\expandafter\XINT_FL_add_a\romannumeral0\XINTinfloat[#1]{#3}#1.{#4}}% }% \def\XINT_FL_add_a #1% {% \xint_gob_til_zero #1\XINT_FL_add_zero 0\XINT_FL_add_b #1% }% \def\XINT_FL_add_zero #1.#2{#2}%[[ \def\XINT_FL_add_b #1]#2.#3% {% \expandafter\XINT_FL_add_c\romannumeral0\XINTinfloat[#2]{#3}#2.#1]% }% \def\XINT_FL_add_c #1% {% \xint_gob_til_zero #1\XINT_FL_add_zero 0\XINT_FL_add_d #1% }% % \end{macrocode} % \changed{1.4p} % Fix long-standing regression which was introduced % at |1.2f| (|2016/03/12|). % %\begin{lverb} % The bug caused the rounding to not be the correct one % if one argument x (after initial rounding to P digits) is +-10^n and the % other y has opposite sign, scientific exponent exactly n-P-1, and % |y| > 5 10^{n-P-1}. Affects \xintFloatAdd and \xintFloatSub, and also % of course the \xintexpr context. % Fixed by testing >1 and not>0 for the short path. %\end{lverb} % \begin{macrocode} \def\XINT_FL_add_d #1[#2]#3.#4[#5]% {% \ifnum\numexpr #2-#3-#5>\xint_c_i\xint_dothis\xint_firstoftwo\fi \ifnum\numexpr #5-#3-#2>\xint_c_i\xint_dothis\xint_secondoftwo\fi \xint_orthat\xintAdd {#1[#2]}{#4[#5]}% }% % \end{macrocode} % \subsection{\csh{xintFloatSub}, \cshnolabel{XINTinFloatSub}} % \added{1.07} % \changed{1.2f} %\begin{lverb} % Starting with 1.2f the arguments undergo an intial rounding to the target % precision P not P+2. %\end{lverb} % % \begin{macrocode} \def\xintFloatSub {\romannumeral0\xintfloatsub}% \def\xintfloatsub #1{\XINT_flsub_chkopt \xintfloat #1\xint:}% \def\XINT_flsub_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flsub_opt \else\expandafter\XINT_flsub_noopt \fi #1#2% }% \def\XINT_flsub_noopt #1#2\xint:#3% {% #1[\XINTdigits]% {\expandafter\XINT_FL_add_a \romannumeral0\XINTinfloat[\XINTdigits]{#2}\XINTdigits.{\xintOpp{#3}}}% }% \def\XINT_flsub_opt #1[\xint:#2]%#3#4% {% \expandafter\XINT_flsub_opt_a\the\numexpr #2.#1% }% \def\XINT_flsub_opt_a #1.#2#3#4% {% #2[#1]{\expandafter\XINT_FL_add_a\romannumeral0\XINTinfloat[#1]{#3}#1.{\xintOpp{#4}}}% }% % \end{macrocode} % \subsection{\csh{xintFloatMul}, \cshnolabel{XINTinFloatMul}} % % The \csbXINT{inFloatMul} interface is kept at 2.0a1 for \ctanpackage{polexpr}. % And \csbXINT{infloatmul} is kept for \xintseriesnameimp. % % \added{1.07} % \changed{1.2d} %\begin{lverb} % Starting with 1.2f the arguments are rounded to the target precision P not % P+2. %\end{lverb} % \changed{1.2g} %\begin{lverb} % 1.2g handles the inputs via \XINTinFloatS which will be more efficient when % the precision is large and the input is for example a small constant like 2. %\end{lverb} % \begin{macrocode} \def\xintFloatMul {\romannumeral0\xintfloatmul}% \def\xintfloatmul #1{\XINT_flmul_chkopt \xintfloat #1\xint:}% \def\XINTinFloatMul{\romannumeral0\XINTinfloatmul}% \def\XINTinfloatmul{\XINT_flmul_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinfloatmul_wopt[#1]{\expandafter\XINT_flmul_opt_a\the\numexpr#1.\XINTinfloatS}% \def\XINT_flmul_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flmul_opt \else\expandafter\XINT_flmul_noopt \fi #1#2% }% \def\XINT_flmul_noopt #1#2\xint:#3% {% #1[\XINTdigits]% {\expandafter\XINT_FL_mul_a \romannumeral0\XINTinfloatS[\XINTdigits]{#2}\XINTdigits.{#3}}% }% \def\XINT_flmul_opt #1[\xint:#2]%#3#4% {% \expandafter\XINT_flmul_opt_a\the\numexpr #2.#1% }% \def\XINT_flmul_opt_a #1.#2#3#4% {% #2[#1]{\expandafter\XINT_FL_mul_a\romannumeral0\XINTinfloatS[#1]{#3}#1.{#4}}% }% \def\XINT_FL_mul_a #1[#2]#3.#4% {% \expandafter\XINT_FL_mul_b\romannumeral0\XINTinfloatS[#3]{#4}#1[#2]% }% \def\XINT_FL_mul_b #1[#2]#3[#4]{\xintiiMul{#3}{#1}/1[#4+#2]}% % \end{macrocode} % \subsection{\csh{xintFloatSqr}, \cshnolabel{XINTinFloatSqr}} % \added{1.4e} %\begin{lverb} % Strangely \xintFloatSqr had never been defined so far. % % An \XINTinFloatSqr{#1} was defined in xintexpr.sty directly as % \XINTinFloatMul[\XINTdigits]{#1}{#1}, to support the sqr() function. The % {#1}{#1} causes no problem as #1 in this context is always pre-expanded so % we don't need to worry about this, and the \xintdeffloatfunc mechanism % should hopefully take care to add the needed argument pre-expansion if need % be. % % Anyway let's do this finally properly here. %\end{lverb} % \begin{macrocode} \def\xintFloatSqr {\romannumeral0\xintfloatsqr}% \def\xintfloatsqr #1{\XINT_flsqr_chkopt \xintfloat #1\xint:}% \def\XINT_flsqr_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flsqr_opt \else\expandafter\XINT_flsqr_noopt \fi #1#2% }% \def\XINT_flsqr_noopt #1#2\xint: {% #1[\XINTdigits]% {\expandafter\XINT_FL_sqr_a\romannumeral0\XINTinfloatS[\XINTdigits]{#2}}% }% \def\XINT_flsqr_opt #1[\xint:#2]% {% \expandafter\XINT_flsqr_opt_a\the\numexpr #2.#1% }% \def\XINT_flsqr_opt_a #1.#2#3% {% #2[#1]{\expandafter\XINT_FL_sqr_a\romannumeral0\XINTinfloatS[#1]{#3}}% }% \def\XINT_FL_sqr_a #1[#2]{\xintiiSqr{#1}/1[#2+#2]}% % \end{macrocode} % \subsection{\csh{xintFloatDiv}, \cshnolabel{XINTinFloatDiv}} % \added{1.07} % \changed{1.2f} %\begin{lverb} % Starting with 1.2f the arguments are rounded to the target precision P not % P+2. %\end{lverb} % \changed{1.2g} %\begin{lverb} % 1.2g handles the inputs via \XINTinFloatS which will be more efficient when % the precision is large and the input is for example a small constant like 2. % % The actual rounding of the quotient is handled via \xintfloat (or % \XINTinfloatS). %\end{lverb} % \changed{1.2k} %\begin{lverb} % 1.2k does the same kind of improvement in \XINT_FL_div_b as for % multiplication: earlier code was unnecessarily high level. %\end{lverb} % \begin{macrocode} \def\xintFloatDiv {\romannumeral0\xintfloatdiv}% \def\xintfloatdiv #1{\XINT_fldiv_chkopt \xintfloat #1\xint:}% \def\XINT_fldiv_chkopt #1#2% {% \ifx [#2\expandafter\XINT_fldiv_opt \else\expandafter\XINT_fldiv_noopt \fi #1#2% }% % \end{macrocode} %\begin{lverb} % 1.4g adds here intercept of second argument being zero, % else a low level error will arise at later stage from the % the fall-back value returned by core iidivision being 0 % and not having expected number of digits at \XINT_infloat_Qq % and split from left returning some empty value breaking the % \ifnum test in \XINT_infloat_Rq. %\end{lverb} % \begin{macrocode} \def\XINT_fldiv_noopt #1#2\xint:#3% {% #1[\XINTdigits]% {\expandafter\XINT_FL_div_aa \romannumeral0\XINTinfloatS[\XINTdigits]{#3}\XINTdigits.{#2}}% }% \def\XINT_FL_div_aa #1% {% \xint_gob_til_zero#1\XINT_FL_div_Bzero0\XINT_FL_div_a #1% }% \def\XINT_FL_div_Bzero0\XINT_FL_div_a#1[#2]#3.#4% {% \XINT_legacysignalcondition{DivisionByZero}{Division by zero (#1[#2]) of #4}{}{ 0[0]}% }% \def\XINT_fldiv_opt #1[\xint:#2]%#3#4% {% \expandafter\XINT_fldiv_opt_a\the\numexpr #2.#1% }% % \end{macrocode} %\begin{lverb} % Also here added early check at 1.4g if divisor is zero. %\end{lverb} % \begin{macrocode} \def\XINT_fldiv_opt_a #1.#2#3#4% {% #2[#1]{\expandafter\XINT_FL_div_aa\romannumeral0\XINTinfloatS[#1]{#4}#1.{#3}}% }% \def\XINT_FL_div_a #1[#2]#3.#4% {% \expandafter\XINT_FL_div_b\romannumeral0\XINTinfloatS[#3]{#4}/#1e#2% }% \def\XINT_FL_div_b #1[#2]{#1e#2}% % \end{macrocode} % \subsection{\csh{xintFloatPow}, \cshnolabel{XINTinFloatPow}} % \added{1.07} % %\begin{lverb} % 1.09j has re-organized the core loop. % % 2015/12/07. I have hesitated to map ^ in expressions to \xintFloatPow rather % than \xintFloatPower. But for 1.234567890123456 to the power 2145678912 with % P=16, using Pow rather than Power seems to bring only about 5$char37 $space % gain. % % This routine requires the exponent x to be compatible with \numexpr parsing. %\end{lverb} % % \changed{1.2f} %\begin{lverb} % 1.2f has rewritten the code for better efficiency. Also, now the argument A % for A^x is first rounded to P digits before switching to the increased % working precision (which depends upon x). %\end{lverb} % \begin{macrocode} \def\xintFloatPow {\romannumeral0\xintfloatpow}% \def\xintfloatpow #1{\XINT_flpow_chkopt \xintfloat #1\xint:}% \def\XINTinfloatpow{\XINT_flpow_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinfloatpow_wopt[#1]{\expandafter\XINT_flpow_opt_a\the\numexpr#1.\XINTinfloatS}% \def\XINT_flpow_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flpow_opt \else\expandafter\XINT_flpow_noopt \fi #1#2% }% \def\XINT_flpow_noopt #1#2\xint:#3% {% \expandafter\XINT_flpow_checkB_a \the\numexpr #3.\XINTdigits.{#2}{#1[\XINTdigits]}% }% \def\XINT_flpow_opt #1[\xint:#2]% {% \expandafter\XINT_flpow_opt_a\the\numexpr #2.#1% }% \def\XINT_flpow_opt_a #1.#2#3#4% {% \expandafter\XINT_flpow_checkB_a\the\numexpr #4.#1.{#3}{#2[#1]}% }% \def\XINT_flpow_checkB_a #1% {% \xint_UDzerominusfork #1-\XINT_flpow_BisZero 0#1{\XINT_flpow_checkB_b -}% 0-{\XINT_flpow_checkB_b {}#1}% \krof }% \def\XINT_flpow_BisZero .#1.#2#3{#3{1[0]}}% \def\XINT_flpow_checkB_b #1#2.#3.% {% \expandafter\XINT_flpow_checkB_c \the\numexpr\xintLength{#2}+\xint_c_iii.#3.#2.{#1}% }% \def\XINT_flpow_checkB_c #1.#2.% {% \expandafter\XINT_flpow_checkB_d\the\numexpr#1+#2.#1.#2.% }% % \end{macrocode} %\begin{lverb} % % 1.2f rounds input to P digits, first. %\end{lverb} % \begin{macrocode} \def\XINT_flpow_checkB_d #1.#2.#3.#4.#5#6% {% \expandafter \XINT_flpow_aa \romannumeral0\XINTinfloat [#3]{#6}{#2}{#1}{#4}{#5}% }% \def\XINT_flpow_aa #1[#2]#3% {% \expandafter\XINT_flpow_ab\the\numexpr #2-#3\expandafter.% \romannumeral\XINT_rep #3\endcsname0.#1.% }% \def\XINT_flpow_ab #1.#2.#3.{\XINT_flpow_a #3#2[#1]}% \def\XINT_flpow_a #1% {% \xint_UDzerominusfork #1-\XINT_flpow_zero 0#1{\XINT_flpow_b \iftrue}% 0-{\XINT_flpow_b \iffalse#1}% \krof }% \def\XINT_flpow_zero #1[#2]#3#4#5#6% {% #6{\if 1#51\xint_dothis {0[0]}\fi \xint_orthat {\XINT_legacysignalcondition{DivisionByZero}{0 raised to power -#4.}{}{ 0[0]}}% }% }% \def\XINT_flpow_b #1#2[#3]#4#5% {% \XINT_flpow_loopI #5.#3.#2.#4.{#1\ifodd #5 \xint_c_i\fi\fi}% }% \def\XINT_flpow_truncate #1.#2.#3.% {% \expandafter\XINT_flpow_truncate_a \romannumeral0\XINT_split_fromleft #3.#2\xint_bye2345678\xint_bye..#1.#3.% }% \def\XINT_flpow_truncate_a #1.#2.#3.{#3+\xintLength{#2}.#1.}% \def\XINT_flpow_loopI #1.% {% \ifnum #1=\xint_c_i\expandafter\XINT_flpow_ItoIII\fi \ifodd #1 \expandafter\XINT_flpow_loopI_odd \else \expandafter\XINT_flpow_loopI_even \fi #1.% }% \def\XINT_flpow_ItoIII\ifodd #1\fi #2.#3.#4.#5.#6% {% \expandafter\XINT_flpow_III\the\numexpr #6+\xint_c_.#3.#4.#5.% }% \def\XINT_flpow_loopI_even #1.#2.#3.%#4.% {% \expandafter\XINT_flpow_loopI \the\numexpr #1/\xint_c_ii\expandafter.% \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.% }% \def\XINT_flpow_loopI_odd #1.#2.#3.#4.% {% \expandafter\XINT_flpow_loopII \the\numexpr #1/\xint_c_ii-\xint_c_i\expandafter.% \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.#2.#3.% }% \def\XINT_flpow_loopII #1.% {% \ifnum #1 = \xint_c_i\expandafter\XINT_flpow_IItoIII\fi \ifodd #1 \expandafter\XINT_flpow_loopII_odd \else \expandafter\XINT_flpow_loopII_even \fi #1.% }% \def\XINT_flpow_loopII_even #1.#2.#3.%#4.% {% \expandafter\XINT_flpow_loopII \the\numexpr #1/\xint_c_ii\expandafter.% \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.% }% \def\XINT_flpow_loopII_odd #1.#2.#3.#4.#5.#6.% {% \expandafter\XINT_flpow_loopII_odda \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr#2+#5\expandafter.\romannumeral0\xintiimul{#3}{#6}.#4.% #1.#2.#3.% }% \def\XINT_flpow_loopII_odda #1.#2.#3.#4.#5.#6.% {% \expandafter\XINT_flpow_loopII \the\numexpr #4/\xint_c_ii-\xint_c_i\expandafter.% \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#5\expandafter.\romannumeral0\xintiisqr{#6}.#3.% #1.#2.% }% \def\XINT_flpow_IItoIII\ifodd #1\fi #2.#3.#4.#5.#6.#7.#8% {% \expandafter\XINT_flpow_III\the\numexpr #8+\xint_c_\expandafter.% \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr#3+#6\expandafter.\romannumeral0\xintiimul{#4}{#7}.#5.% }% % \end{macrocode} %\begin{lverb} % This ending is common with \xintFloatPower. % % In the case of negative exponent we need to inverse the Q-digits mantissa. % This requires no special attention now as 1.2k's \xintFloat does correct % rounding of fractions hence it is easy to bound the total error. It can be % checked that the algorithm after final rounding to the target precision % computes a value Z whose distance to the exact theoretical will be less than % 0.52 ulp(Z) (and worst cases can only be slightly worse than 0.51 ulp(Z)). % % In the case of the half-integer exponent (only via the expression % interface,) the computation (which proceeds via \XINTinFloatPowerH) ends % with a square root. This square root extraction is done with 3 guard digits % (the power operations were done with more.) Then the value is rounded to the % target precision. There is thus this rounding to 3 guard digits (in the case % of negative exponent the reciprocal is computed before the square-root), % then the square root is (computed with exact rounding for these 3 guard % digits), and then there is the final rounding of this to the target % precision. The total error (for positive as well as negative exponent) has % been estimated to at worst possibly exceed slightly 0.5125 ulp(Z), and at % any rate it is less than 0.52 ulp(Z). %\end{lverb} % \begin{macrocode} \def\XINT_flpow_III #1.#2.#3.#4.#5% {% \expandafter\XINT_flpow_IIIend \xint_UDsignfork #5{{1/#3[-#2]}}% -{{#3[#2]}}% \krof #1% }% \def\XINT_flpow_IIIend #1#2#3% {#3{\if#21\xint_afterfi{\expandafter-\romannumeral`&&@}\fi#1}}% % \end{macrocode} % \subsection{\csh{xintFloatPower}, \cshnolabel{XINTinFloatPower}} % \added{1.07} %\begin{lverb} % The core loop has been re-organized in 1.09j for some slight % efficiency gain. The exponent B is given to \xintNum. The ^ in expressions % is mapped to this routine. %\end{lverb} % \changed{1.2f} %\begin{lverb} % Same modifications as in \xintFloatPow for 1.2f. % % 1.2f \XINTinFloatPowerH (now moved to $xintlognameimp, and renamed). It % truncated the exponent to an integer of half-integer, and in the latter case % use Square-root extraction. At 1.2k this was improved as 1.2f stupidly % rounded to Digits before, not after the square root extraction, 1.2k kept 3 % guard digits for this last step. And the initial step was % changed to a rounding rather than truncating. %\end{lverb} % \changed{1.4e} %\begin{lverb} % Until 1.4e this \XINTinFloatPowerH was the macro for a^b in expressions, % but of course it behaved strangely for b not an integer or an half-integer! % At 1.4e, the non-integer, non-half-integer exponents will be handled via % log10() and pow10() support macros, see $xintlognameimp. The code % has now been relocated there. %\end{lverb} % \begin{macrocode} \def\xintFloatPower {\romannumeral0\xintfloatpower}% \def\xintfloatpower #1{\XINT_flpower_chkopt \xintfloat #1\xint:}% % \end{macrocode} %\begin{lverb} % Start of macro. Check for optional argument. %\end{lverb} % \begin{macrocode} \def\XINT_flpower_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flpower_opt \else\expandafter\XINT_flpower_noopt \fi #1#2% }% \def\XINT_flpower_noopt #1#2\xint:#3% {% \expandafter\XINT_flpower_checkB_a \romannumeral0\xintnum{#3}.\XINTdigits.{#2}{#1[\XINTdigits]}% }% \def\XINT_flpower_opt #1[\xint:#2]% {% \expandafter\XINT_flpower_opt_a\the\numexpr #2.#1% }% \def\XINT_flpower_opt_a #1.#2#3#4% {% \expandafter\XINT_flpower_checkB_a \romannumeral0\xintnum{#4}.#1.{#3}{#2[#1]}% }% \def\XINT_flpower_checkB_a #1% {% \xint_UDzerominusfork #1-{\XINT_flpower_BisZero 0}% 0#1{\XINT_flpower_checkB_b -}% 0-{\XINT_flpower_checkB_b {}#1}% \krof }% \def\XINT_flpower_BisZero 0.#1.#2#3{#3{1[0]}}% \def\XINT_flpower_checkB_b #1#2.#3.% {% \expandafter\XINT_flpower_checkB_c \the\numexpr\xintLength{#2}+\xint_c_iii.#3.#2.{#1}% }% \def\XINT_flpower_checkB_c #1.#2.% {% \expandafter\XINT_flpower_checkB_d\the\numexpr#1+#2.#1.#2.% }% \def\XINT_flpower_checkB_d #1.#2.#3.#4.#5#6% {% \expandafter \XINT_flpower_aa \romannumeral0\XINTinfloat [#3]{#6}{#2}{#1}{#4}{#5}% }% \def\XINT_flpower_aa #1[#2]#3% {% \expandafter\XINT_flpower_ab\the\numexpr #2-#3\expandafter.% \romannumeral\XINT_rep #3\endcsname0.#1.% }% \def\XINT_flpower_ab #1.#2.#3.{\XINT_flpower_a #3#2[#1]}% \def\XINT_flpower_a #1% {% \xint_UDzerominusfork #1-\XINT_flpow_zero 0#1{\XINT_flpower_b \iftrue}% 0-{\XINT_flpower_b \iffalse#1}% \krof }% \def\XINT_flpower_b #1#2[#3]#4#5% {% \XINT_flpower_loopI #5.#3.#2.#4.{#1\xintiiOdd{#5}\fi}% }% \def\XINT_flpower_loopI #1.% {% \if1\XINT_isOne {#1}\xint_dothis\XINT_flpower_ItoIII\fi \ifodd\xintLDg{#1} %<- intentional space \xint_dothis{\expandafter\XINT_flpower_loopI_odd}\fi \xint_orthat{\expandafter\XINT_flpower_loopI_even}% \romannumeral0\XINT_half #1\xint_bye\xint_Bye345678\xint_bye *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax.% }% \def\XINT_flpower_ItoIII #1.#2.#3.#4.#5% {% \expandafter\XINT_flpow_III\the\numexpr #5+\xint_c_.#2.#3.#4.% }% \def\XINT_flpower_loopI_even #1.#2.#3.#4.% {% \expandafter\XINT_flpower_toloopI \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.#1.% }% \def\XINT_flpower_toloopI #1.#2.#3.#4.{\XINT_flpower_loopI #4.#1.#2.#3.}% \def\XINT_flpower_loopI_odd #1.#2.#3.#4.% {% \expandafter\XINT_flpower_toloopII \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.% #1.#2.#3.% }% \def\XINT_flpower_toloopII #1.#2.#3.#4.{\XINT_flpower_loopII #4.#1.#2.#3.}% \def\XINT_flpower_loopII #1.% {% \if1\XINT_isOne{#1}\xint_dothis\XINT_flpower_IItoIII\fi \ifodd\xintLDg{#1} %<- intentional space \xint_dothis{\expandafter\XINT_flpower_loopII_odd}\fi \xint_orthat{\expandafter\XINT_flpower_loopII_even}% \romannumeral0\XINT_half#1\xint_bye\xint_Bye345678\xint_bye *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax.% }% \def\XINT_flpower_loopII_even #1.#2.#3.#4.% {% \expandafter\XINT_flpower_toloopII \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.#1.% }% \def\XINT_flpower_loopII_odd #1.#2.#3.#4.#5.#6.% {% \expandafter\XINT_flpower_loopII_odda \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr#2+#5\expandafter.\romannumeral0\xintiimul{#3}{#6}.#4.% #1.#2.#3.% }% \def\XINT_flpower_loopII_odda #1.#2.#3.#4.#5.#6.% {% \expandafter\XINT_flpower_toloopII \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr\xint_c_ii*#5\expandafter.\romannumeral0\xintiisqr{#6}.#3.% #4.#1.#2.% }% \def\XINT_flpower_IItoIII #1.#2.#3.#4.#5.#6.#7% {% \expandafter\XINT_flpow_III\the\numexpr #7+\xint_c_\expandafter.% \the\numexpr\expandafter\XINT_flpow_truncate \the\numexpr#2+#5\expandafter.\romannumeral0\xintiimul{#3}{#6}.#4.% }% % \end{macrocode} % \subsection{\csh{xintFloatFac}, \csh{XINTFloatFac}} % \added{1.2} % \begin{macrocode} \def\xintFloatFac {\romannumeral0\xintfloatfac}% \def\xintfloatfac #1{\XINT_flfac_chkopt \xintfloat #1\xint:}% \def\XINTinFloatFac{\romannumeral0\XINTinfloatfac}% \def\XINTinfloatfac[#1]{\expandafter\XINT_flfac_opt_a\the\numexpr#1.\XINTinfloatS}% \def\XINT_flfac_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flfac_opt \else\expandafter\XINT_flfac_noopt \fi #1#2% }% \def\XINT_flfac_noopt #1#2\xint: {% \expandafter\XINT_FL_fac_fork_a \the\numexpr \xintNum{#2}.{\XINTdigits}{#1[\XINTdigits]}% }% \def\XINT_flfac_opt #1[\xint:#2]% {% \expandafter\XINT_flfac_opt_a\the\numexpr #2.#1% }% \def\XINT_flfac_opt_a #1.#2#3% {% \expandafter\XINT_FL_fac_fork_a\the\numexpr \xintNum{#3}.{#1}{#2[#1]}% }% \def\XINT_FL_fac_fork_a #1% {% \xint_UDzerominusfork #1-\XINT_FL_fac_iszero 0#1\XINT_FL_fac_isneg 0-{\XINT_FL_fac_fork_b #1}% \krof }% \def\XINT_FL_fac_iszero #1.#2#3{#3{1[0]}}% % \end{macrocode} %\begin{lverb} % 1.2f XINT_FL_fac_isneg returns 0, earlier versions used 1 here. % % calx: the factorial of an integer 0 < n < 10^8 is computed by calxfp's % \CALX_ffac_fork_b (xintfrac's former engine, native output rounded to % the target precision P), converted to raw by \CALX_ftoraw for the final % macro (\xintfloat or \XINTinfloatS) at P. %\end{lverb} % \begin{macrocode} \def\XINT_FL_fac_isneg #1.#2#3% {% #3{\XINT_legacysignalcondition{InvalidOperation} {Factorial argument is negative: -#1.}{}{ 0[0]}}% }% \def\XINT_FL_fac_fork_b #1.% {% \ifnum #1>\xint_c_e_viii_mone\xint_dothis\XINT_FL_fac_toobig\fi \xint_orthat\XINT_FL_fac_go #1.% }% \def\XINT_FL_fac_toobig #1.#2#3% {% #3{\XINT_legacysignalcondition{InvalidOperation} {Factorial argument is too large: #1>=10^8.}{}{ 0[0]}}% }% \def\XINT_FL_fac_go #1.#2#3% {% #3{\romannumeral0\CALX_ftoraw{\romannumeral0\CALX_ffac_fork_b #1.\xint_c_i{#2+\xint_c_ii}\CALX_ffac_out{#2}}}% }% % \end{macrocode} % \subsection{\csh{xintFloatPFactorial}, \cshnolabel{XINTinFloatPFactorial}} % \added[2015/11/29]{1.2f} %\begin{lverb} % Partial factorial pfactorial(a,b)=(a+1)...b, % only for non-negative integers with a<=b<10^8. %\end{lverb} % \changed[2016/11/20]{1.2h} %\begin{lverb} % Now avoids raising \xintError:OutOfRangePFac if the % condition 0<=a<=b<10^8 is violated. Same as for \xintiiPFactorial. %\end{lverb} % \changed{1.4e} %\begin{lverb} % 1.4e extends the precision in floating point context adding some overhead % but well. %\end{lverb} % \begin{macrocode} \def\xintFloatPFactorial {\romannumeral0\xintfloatpfactorial}% \def\xintfloatpfactorial #1{\XINT_flpfac_chkopt \xintfloat #1\xint:}% \def\XINT_flpfac_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flpfac_opt \else\expandafter\XINT_flpfac_noopt \fi #1#2% }% \def\XINT_flpfac_noopt #1#2\xint:#3% {% \expandafter\XINT_FL_pfac_fork \the\numexpr \xintNum{#2}\expandafter.% \the\numexpr \xintNum{#3}.\xint_c_i{\XINTdigits}{#1[\XINTdigits]}% }% \def\XINT_flpfac_opt #1[\xint:#2]% {% \expandafter\XINT_flpfac_opt_a\the\numexpr #2.#1% }% \def\XINT_flpfac_opt_a #1.#2#3#4% {% \expandafter\XINT_FL_pfac_fork \the\numexpr \xintNum{#3}\expandafter.% \the\numexpr \xintNum{#4}.\xint_c_i{#1}{#2[#1]}% }% \def\XINT_FL_pfac_fork #1#2.#3#4.% {% \unless\ifnum #1#2<#3#4 \xint_dothis\XINT_FL_pfac_one\fi \if-#3\xint_dothis\XINT_FL_pfac_neg \fi \if-#1\xint_dothis\XINT_FL_pfac_zero\fi \ifnum #3#4>\xint_c_e_viii_mone\xint_dothis\XINT_FL_pfac_outofrange\fi \xint_orthat \XINT_FL_pfac_go #1#2.#3#4.% }% \def\XINT_FL_pfac_outofrange #1.#2.#3#4#5% {% #5{\XINT_legacysignalcondition{InvalidOperation} {pFactorial with too large argument: #2 >= 10^8.}{}{ 0[0]}}% }% \def\XINT_FL_pfac_one #1.#2.#3#4#5{#5{1[0]}}% \def\XINT_FL_pfac_zero #1.#2.#3#4#5{#5{0[0]}}% \def\XINT_FL_pfac_neg -#1.-#2.% {% \ifnum #1>\xint_c_e_viii\xint_dothis\XINT_FL_pfac_outofrange\fi \xint_orthat {% \ifodd\numexpr#2-#1\relax\xint_afterfi{\expandafter-\romannumeral`&&@}\fi \expandafter\XINT_FL_pfac_go}% \the\numexpr #2-\xint_c_i\expandafter.\the\numexpr#1-\xint_c_i.% }% % \end{macrocode} %\begin{lverb} % calx: the product is computed by calxfp's \CALX_fpfac_increaseP % (xintfrac's former engine, native output rounded to the target precision % P), converted to raw by \CALX_ftoraw for the final macro at P. %\end{lverb} % \begin{macrocode} \def\XINT_FL_pfac_go #1.#2.#3#4#5% {% #5{\romannumeral0\CALX_ftoraw{\romannumeral0\CALX_fpfac_increaseP #1.#2.#3{#4+\xint_c_ii}{#4}}}% }% % \end{macrocode} % \subsection{\csh{xintFloatBinomial}, \cshnolabel{XINTinFloatBinomial}} % \added[2015/12/01]{1.2f} %\begin{lverb} % We compute binomial(x,y) as pfac(x-y,x)/y!, where the numerator % and denominator are computed with a relative error at most 4.10^{-P-2}, then % rounded (once I have a float truncation, I will use truncation rather) to % P+3 digits, and finally the quotient is correctly rounded to P digits. This % will guarantee that the exact value X differs from the computed one Y by at % most 0.6 ulp(Y). %\end{lverb} % \changed[2016/11/19]{1.2h} %\begin{lverb} % As for \xintiiBinomial, hard to understand why last % year I coded this to raise an error if y<0 or y>x ! The question of the % Gamma function is for another occasion, here x and y must be (small) % integers. % % 1.4e: same remarks as for factorial and partial factorial about added % overhead due to extra guard digits. %\end{lverb} % \begin{macrocode} \def\xintFloatBinomial {\romannumeral0\xintfloatbinomial}% \def\xintfloatbinomial #1{\XINT_flbinom_chkopt \xintfloat #1\xint:}% \def\XINT_flbinom_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flbinom_opt \else\expandafter\XINT_flbinom_noopt \fi #1#2% }% \def\XINT_flbinom_noopt #1#2\xint:#3% {% \expandafter\XINT_FL_binom_a \the\numexpr\xintNum{#2}\expandafter.% \the\numexpr\xintNum{#3}\expandafter.\the\numexpr\XINTdigits.#1% }% \def\XINT_flbinom_opt #1[\xint:#2]#3#4% {% \expandafter\XINT_FL_binom_a \the\numexpr\xintNum{#3}\expandafter.\the\numexpr\xintNum{#4}\expandafter.% \the\numexpr #2.#1% }% \def\XINT_FL_binom_a #1.#2.% {% \expandafter\XINT_FL_binom_fork \the\numexpr #1-#2.#2.#1.% }% \def\XINT_FL_binom_fork #1#2.#3#4.#5#6.% {% \if-#5\xint_dothis \XINT_FL_binom_neg\fi \if-#1\xint_dothis \XINT_FL_binom_zero\fi \if-#3\xint_dothis \XINT_FL_binom_zero\fi \if0#1\xint_dothis \XINT_FL_binom_one\fi \if0#3\xint_dothis \XINT_FL_binom_one\fi \ifnum #5#6>\xint_c_e_viii_mone \xint_dothis\XINT_FL_binom_toobig\fi \ifnum #1#2>#3#4 \xint_dothis\XINT_FL_binom_ab \fi \xint_orthat\XINT_FL_binom_aa #1#2.#3#4.#5#6.% }% \def\XINT_FL_binom_neg #1.#2.#3.#4.#5% {% #5[#4]{\XINT_legacysignalcondition{InvalidOperation} {Binomial with negative argument: #3.}{}{ 0[0]}}% }% \def\XINT_FL_binom_toobig #1.#2.#3.#4.#5% {% #5[#4]{\XINT_legacysignalcondition{InvalidOperation} {Binomial with too large argument: #3 >= 10^8.}{}{ 0[0]}}% }% \def\XINT_FL_binom_one #1.#2.#3.#4.#5{#5[#4]{1[0]}}% \def\XINT_FL_binom_zero #1.#2.#3.#4.#5{#5[#4]{0[0]}}% \def\XINT_FL_binom_aa #1.#2.#3.#4.#5% {#5[#4]{\romannumeral0\CALX_ftoraw {\romannumeral0\CALX_fbinom_aa #1.#2.#3.#4.}}}% \def\XINT_FL_binom_ab #1.#2.#3.#4.#5% {#5[#4]{\romannumeral0\CALX_ftoraw {\romannumeral0\CALX_fbinom_aa #2.#1.#3.#4.}}}% % \end{macrocode} % \subsection{\csh{xintFloatSqrt}, \cshnolabel{XINTinFloatSqrt}} % \added{1.08} % \changed{1.2f} %\begin{lverb} % % The float version was developed at the same time as the integer one and even % a bit earlier. As a result the integer variant had some sub-optimal parts. % Anyway, for 1.2f I have rewritten the integer variant, and the float variant % delegates all preparatory wrok for it until the last step. In particular the % very low precisions are not penalized anymore from doing computations for at % least 17 or 18 digits. Both the large and small precisions give quite % shorter computation times. % % Also, after examining more closely the achieved precision I decided to % extend the float version in order for it to obtain the correct rounding (for % inputs already of at most P digits with P the precision) of the theoretical % exact value. % % Beyond about 500 digits of precision the efficiency decreases swiftly, % as is the case generally speaking with xintcore/xint/xintfrac arithmetic % macros. % % Final note: with 1.2f the input is always first rounded to P significant % places. %\end{lverb} % \begin{macrocode} \def\xintFloatSqrt {\romannumeral0\xintfloatsqrt}% \def\xintfloatsqrt #1{\XINT_flsqrt_chkopt \xintfloat #1\xint:}% \def\XINT_flsqrt_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flsqrt_opt \else\expandafter\XINT_flsqrt_noopt \fi #1#2% }% \def\XINT_flsqrt_noopt #1#2\xint:% {% \expandafter\XINT_FL_sqrt_a \romannumeral0\XINTinfloat[\XINTdigits]{#2}\XINTdigits.#1% }% \def\XINT_flsqrt_opt #1[\xint:#2]%#3% {% \expandafter\XINT_flsqrt_opt_a\the\numexpr #2.#1% }% \def\XINT_flsqrt_opt_a #1.#2#3% {% \expandafter\XINT_FL_sqrt_a\romannumeral0\XINTinfloat[#1]{#3}#1.#2% }% \def\XINT_FL_sqrt_a #1% {% \xint_UDzerominusfork #1-\XINT_FL_sqrt_iszero 0#1\XINT_FL_sqrt_isneg 0-{\XINT_FL_sqrt_pos #1}% \krof }%[ \def\XINT_FL_sqrt_iszero #1]#2.#3{#3[#2]{0[0]}}% \def\XINT_FL_sqrt_isneg #1]#2.#3% {% #3[#2]{\XINT_legacysignalcondition{InvalidOperation} {Square root of negative: -#1].}{}{ 0[0]}}% }% % \end{macrocode} %\begin{lverb} % calx (s58): the square root of the positive A[N] (rounded to P digits by % \XINTinfloat) is calxfp's \CALX_fsqrt (correctly rounded, as before) on % its exact F value (\CALX_ffromraw), back to raw by \CALX_ftoraw for the % output wrapper #4 (\xintfloat or \XINTinfloatS) at P. The former % \XINT_flsqrt* chain, which used xint's big integer square root, is % deleted. %\end{lverb} % \begin{macrocode} \def\XINT_FL_sqrt_pos #1[#2]#3.#4% {#4[#3]{\romannumeral0\CALX_ftoraw {\romannumeral0\CALX_fsqrt{#3}{\romannumeral0\CALX_ffromraw{#1[#2]}}}}}% % \end{macrocode} % \subsection{\csh{xintFloatE}} % \added{1.07} %\begin{lverb} % The fraction is the first argument contrarily to \xintTrunc and % \xintRound. %\end{lverb} % \begin{macrocode} \def\xintFloatE {\romannumeral0\xintfloate }% \def\xintfloate #1{\XINT_floate_chkopt #1\xint:}% \def\XINT_floate_chkopt #1% {% \ifx [#1\expandafter\XINT_floate_opt \else\expandafter\XINT_floate_noopt \fi #1% }% \def\XINT_floate_noopt #1\xint:% {% \expandafter\XINT_floate_post \romannumeral0\XINTinfloat[\XINTdigits]{#1}\XINTdigits.% }% \def\XINT_floate_opt [\xint:#1]% {% \expandafter\XINT_floate_opt_a\the\numexpr #1.% }% \def\XINT_floate_opt_a #1.#2% {% \expandafter\XINT_floate_post \romannumeral0\XINTinfloat[#1]{#2}#1.% }% \def\XINT_floate_post #1% {% \xint_UDzerominusfork #1-\XINT_floate_zero 0#1\XINT_floate_neg 0-\XINT_floate_pos \krof #1% }%[ \def\XINT_floate_zero #1]#2.#3{ 0.e0}% \def\XINT_floate_neg-{\expandafter-\romannumeral0\XINT_floate_pos}% \def\XINT_floate_pos #1#2[#3]#4.#5% {% \expandafter\XINT_float_pos_done\the\numexpr#3+#4+#5-\xint_c_i.#1.#2;% }% % \end{macrocode} % \subsection{\csh{xintifFloatInt}} % \added{1.3a} %\begin{lverb} % For ifint() function in \xintfloatexpr. %\end{lverb} % \begin{macrocode} \def\xintifFloatInt {\romannumeral0\xintiffloatint}% \def\xintiffloatint #1{\expandafter\XINT_iffloatint \romannumeral0\xintrez{\XINTinFloatS[\XINTdigits]{#1}}}% \def\XINT_iffloatint #1#2/1[#3]% {% \if 0#1\xint_dothis\xint_stop_atfirstoftwo\fi \ifnum#3<\xint_c_\xint_dothis\xint_stop_atsecondoftwo\fi \xint_orthat\xint_stop_atfirstoftwo }% % \end{macrocode} % \subsection{\csh{xintFloatIsInt}} % \added{1.3d} %\begin{lverb} % For isint() function in \xintfloatexpr. %\end{lverb} % \begin{macrocode} \def\xintFloatIsInt {\romannumeral0\xintfloatisint}% \def\xintfloatisint #1{\expandafter\XINT_iffloatint \romannumeral0\xintrez{\XINTinFloatS[\XINTdigits]{#1}}10}% % \end{macrocode} % \subsection{\csh{xintFloatIntType}} % \added{1.4e} %\begin{lverb} % For fractional powers. Expands to \xint_c_mone if argument is not an % integer, to \xint_c_ if it is an even integer and to \xint_c_i if it is an % odd integer. %\end{lverb} % \begin{macrocode} \def\xintFloatIntType {\romannumeral`&&@\xintfloatinttype}% \def\xintfloatinttype #1% {% \expandafter\XINT_floatinttype \romannumeral0\xintrez{\XINTinFloatS[\XINTdigits]{#1}}% }% \def\XINT_floatinttype #1#2/1[#3]% {% \if 0#1\xint_dothis\xint_c_\fi \ifnum#3<\xint_c_\xint_dothis\xint_c_mone\fi \ifnum#3>\xint_c_\xint_dothis\xint_c_\fi \ifodd\xintLDg{#1#2} \xint_dothis\xint_c_i\fi \xint_orthat\xint_c_ }% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintfrac} % \cleardoublepage\let\xintfracnameUp\undefined %\gardesactifs %\let\relax %\let<*xintseries>\gardesinactifs %^^A--------------------------------------------------- %<*xintseries>^^A------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintseriesnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintseriesnameimp implementation} % \RaisedLabel{sec:seriesimp} % % \localtableofcontents % % \subsection{Introduction} % % The commenting is currently (\xintbndldate) very sparse. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintseries.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintseries Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintseries}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xintseries.sty \ifx\w\relax % but xintfrac.sty not yet loaded. \def\z{\endgroup\input xintfrac.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xintfrac.sty not yet loaded. \def\z{\endgroup\RequirePackage{xintfrac}}% \fi \else \def\z{\endgroup\endinput}% xintseries already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintseries}% [2026/11/01 v2.0a1 Expandable partial sums with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintSeries}} % \begin{macrocode} \def\xintSeries {\romannumeral0\xintseries }% \def\xintseries #1#2% {% \expandafter\XINT_series\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_series #1#2#3% {% \ifnum #2<#1 \xint_afterfi { 0/1[0]}% \else \xint_afterfi {\XINT_series_loop {#1}{0}{#2}{#3}}% \fi }% \def\XINT_series_loop #1#2#3#4% {% \ifnum #3>#1 \else \XINT_series_exit \fi \expandafter\XINT_series_loop\expandafter {\the\numexpr #1+1\expandafter }\expandafter {\romannumeral0\xintadd {#2}{#4{#1}}}% {#3}{#4}% }% \def\XINT_series_exit \fi #1#2#3#4#5#6#7#8% {% \fi\xint_gobble_ii #6% }% % \end{macrocode} % \subsection{\csh{xintiSeries}} % \begin{macrocode} \def\xintiSeries {\romannumeral0\xintiseries }% \def\xintiseries #1#2% {% \expandafter\XINT_iseries\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_iseries #1#2#3% {% \ifnum #2<#1 \xint_afterfi { 0}% \else \xint_afterfi {\XINT_iseries_loop {#1}{0}{#2}{#3}}% \fi }% \def\XINT_iseries_loop #1#2#3#4% {% \ifnum #3>#1 \else \XINT_iseries_exit \fi \expandafter\XINT_iseries_loop\expandafter {\the\numexpr #1+1\expandafter }\expandafter {\romannumeral0\xintiiadd {#2}{#4{#1}}}% {#3}{#4}% }% \def\XINT_iseries_exit \fi #1#2#3#4#5#6#7#8% {% \fi\xint_gobble_ii #6% }% % \end{macrocode} % \subsection{\csh{xintPowerSeries}} %\begin{lverb} % The 1.03 version was very lame and created a build-up of denominators. % (this was at a time \xintAdd always multiplied denominators, by the way) % The Horner scheme for polynomial evaluation is used in 1.04, this % cures the denominator problem and drastically improves the efficiency % of the macro. % Modified in 1.06 to give the indices first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % 1.08a adds the forgotten optimization following that previous change. %\end{lverb} % \begin{macrocode} \def\xintPowerSeries {\romannumeral0\xintpowerseries }% \def\xintpowerseries #1#2% {% \expandafter\XINT_powseries\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_powseries #1#2#3#4% {% \ifnum #2<#1 \xint_afterfi { 0/1[0]}% \else \xint_afterfi {\XINT_powseries_loop_i {#3{#2}}{#1}{#2}{#3}{#4}}% \fi }% \def\XINT_powseries_loop_i #1#2#3#4#5% {% \ifnum #3>#2 \else\XINT_powseries_exit_i\fi \expandafter\XINT_powseries_loop_ii\expandafter {\the\numexpr #3-1\expandafter}\expandafter {\romannumeral0\xintmul {#1}{#5}}{#2}{#4}{#5}% }% \def\XINT_powseries_loop_ii #1#2#3#4% {% \expandafter\XINT_powseries_loop_i\expandafter {\romannumeral0\xintadd {#4{#1}}{#2}}{#3}{#1}{#4}% }% \def\XINT_powseries_exit_i\fi #1#2#3#4#5#6#7#8#9% {% \fi \XINT_powseries_exit_ii #6{#7}% }% \def\XINT_powseries_exit_ii #1#2#3#4#5#6% {% \xintmul{\xintPow {#5}{#6}}{#4}% }% % \end{macrocode} % \subsection{\csh{xintPowerSeriesX}} %\begin{lverb} % Same as \xintPowerSeries except for the initial expansion of the x parameter. % Modified in 1.06 to give the indices first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % 1.08a adds the forgotten optimization following that previous change. %\end{lverb} % \begin{macrocode} \def\xintPowerSeriesX {\romannumeral0\xintpowerseriesx }% \def\xintpowerseriesx #1#2% {% \expandafter\XINT_powseriesx\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_powseriesx #1#2#3#4% {% \ifnum #2<#1 \xint_afterfi { 0/1[0]}% \else \xint_afterfi {\expandafter\XINT_powseriesx_pre\expandafter {\romannumeral`&&@#4}{#1}{#2}{#3}% }% \fi }% \def\XINT_powseriesx_pre #1#2#3#4% {% \XINT_powseries_loop_i {#4{#3}}{#2}{#3}{#4}{#1}% }% % \end{macrocode} % \subsection{\csh{xintRationalSeries}} %\begin{lverb} % This computes F(a)+...+F(b) on the basis of the value of F(a) and the % ratios F(n)/F(n-1). As in \xintPowerSeries we use an iterative scheme which % has the great advantage to avoid denominator build-up. This makes exact % computations possible with exponential type series, which would be completely % inaccessible to \xintSeries. % #1=a, #2=b, #3=F(a), #4=ratio function % Modified in 1.06 to give the indices first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % 1.08a adds the forgotten optimization following that previous change. %\end{lverb} % \begin{macrocode} \def\xintRationalSeries {\romannumeral0\xintratseries }% \def\xintratseries #1#2% {% \expandafter\XINT_ratseries\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_ratseries #1#2#3#4% {% \ifnum #2<#1 \xint_afterfi { 0/1[0]}% \else \xint_afterfi {\XINT_ratseries_loop {#2}{1}{#1}{#4}{#3}}% \fi }% \def\XINT_ratseries_loop #1#2#3#4% {% \ifnum #1>#3 \else\XINT_ratseries_exit_i\fi \expandafter\XINT_ratseries_loop\expandafter {\the\numexpr #1-1\expandafter}\expandafter {\romannumeral0\xintadd {1}{\xintMul {#2}{#4{#1}}}}{#3}{#4}% }% \def\XINT_ratseries_exit_i\fi #1#2#3#4#5#6#7#8% {% \fi \XINT_ratseries_exit_ii #6% }% \def\XINT_ratseries_exit_ii #1#2#3#4#5% {% \XINT_ratseries_exit_iii #5% }% \def\XINT_ratseries_exit_iii #1#2#3#4% {% \xintmul{#2}{#4}% }% % \end{macrocode} % \subsection{\csh{xintRationalSeriesX}} %\begin{lverb} % a,b,initial,ratiofunction,x$\ % This computes F(a,x)+...+F(b,x) on the basis of the value of F(a,x) and the % ratios F(n,x)/F(n-1,x). The argument x is first expanded and it is the value % resulting from this which is used then throughout. The initial term F(a,x) % must be defined as one-parameter macro which will be given x. % Modified in 1.06 to give the indices first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % 1.08a adds the forgotten optimization following that previous change. %\end{lverb} % \begin{macrocode} \def\xintRationalSeriesX {\romannumeral0\xintratseriesx }% \def\xintratseriesx #1#2% {% \expandafter\XINT_ratseriesx\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_ratseriesx #1#2#3#4#5% {% \ifnum #2<#1 \xint_afterfi { 0/1[0]}% \else \xint_afterfi {\expandafter\XINT_ratseriesx_pre\expandafter {\romannumeral`&&@#5}{#2}{#1}{#4}{#3}% }% \fi }% \def\XINT_ratseriesx_pre #1#2#3#4#5% {% \XINT_ratseries_loop {#2}{1}{#3}{#4{#1}}{#5{#1}}% }% % \end{macrocode} % \subsection{\csh{xintFxPtPowerSeries}} %\begin{lverb} % I am not two happy with this piece of code. Will make it more economical % another day. % Modified in 1.06 to give the indices first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % 1.08a: forgot last time some optimization from the change to \numexpr. %\end{lverb} % \begin{macrocode} \def\xintFxPtPowerSeries {\romannumeral0\xintfxptpowerseries }% \def\xintfxptpowerseries #1#2% {% \expandafter\XINT_fppowseries\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_fppowseries #1#2#3#4#5% {% \ifnum #2<#1 \xint_afterfi { 0}% \else \xint_afterfi {\expandafter\XINT_fppowseries_loop_pre\expandafter {\romannumeral0\xinttrunc {#5}{\xintPow {#4}{#1}}}% {#1}{#4}{#2}{#3}{#5}% }% \fi }% \def\XINT_fppowseries_loop_pre #1#2#3#4#5#6% {% \ifnum #4>#2 \else\XINT_fppowseries_dont_i \fi \expandafter\XINT_fppowseries_loop_i\expandafter {\the\numexpr #2+\xint_c_i\expandafter}\expandafter {\romannumeral0\xintitrunc {#6}{\xintMul {#5{#2}}{#1}}}% {#1}{#3}{#4}{#5}{#6}% }% \def\XINT_fppowseries_dont_i \fi\expandafter\XINT_fppowseries_loop_i {\fi \expandafter\XINT_fppowseries_dont_ii }% \def\XINT_fppowseries_dont_ii #1#2#3#4#5#6#7{\xinttrunc {#7}{#2[-#7]}}% \def\XINT_fppowseries_loop_i #1#2#3#4#5#6#7% {% \ifnum #5>#1 \else \XINT_fppowseries_exit_i \fi \expandafter\XINT_fppowseries_loop_ii\expandafter {\romannumeral0\xinttrunc {#7}{\xintMul {#3}{#4}}}% {#1}{#4}{#2}{#5}{#6}{#7}% }% \def\XINT_fppowseries_loop_ii #1#2#3#4#5#6#7% {% \expandafter\XINT_fppowseries_loop_i\expandafter {\the\numexpr #2+\xint_c_i\expandafter}\expandafter {\romannumeral0\xintiiadd {#4}{\xintiTrunc {#7}{\xintMul {#6{#2}}{#1}}}}% {#1}{#3}{#5}{#6}{#7}% }% \def\XINT_fppowseries_exit_i\fi\expandafter\XINT_fppowseries_loop_ii {\fi \expandafter\XINT_fppowseries_exit_ii }% \def\XINT_fppowseries_exit_ii #1#2#3#4#5#6#7% {% \xinttrunc {#7} {\xintiiadd {#4}{\xintiTrunc {#7}{\xintMul {#6{#2}}{#1}}}[-#7]}% }% % \end{macrocode} % \subsection{\csh{xintFxPtPowerSeriesX}} %\begin{lverb} % a,b,coeff,x,D$\ % Modified in 1.06 to give the indices first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % 1.08a adds the forgotten optimization following that previous change. %\end{lverb} % \begin{macrocode} \def\xintFxPtPowerSeriesX {\romannumeral0\xintfxptpowerseriesx }% \def\xintfxptpowerseriesx #1#2% {% \expandafter\XINT_fppowseriesx\expandafter {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% }% \def\XINT_fppowseriesx #1#2#3#4#5% {% \ifnum #2<#1 \xint_afterfi { 0}% \else \xint_afterfi {\expandafter \XINT_fppowseriesx_pre \expandafter {\romannumeral`&&@#4}{#1}{#2}{#3}{#5}% }% \fi }% \def\XINT_fppowseriesx_pre #1#2#3#4#5% {% \expandafter\XINT_fppowseries_loop_pre\expandafter {\romannumeral0\xinttrunc {#5}{\xintPow {#1}{#2}}}% {#2}{#1}{#3}{#4}{#5}% }% % \end{macrocode} % \subsection{\csh{xintFloatPowerSeries}} %\begin{lverb} % 1.08a. I still have to re-visit \xintFxPtPowerSeries; temporarily I % just adapted the code to the case of floats. % % Usage of new names % \XINTinfloatpow_wopt \XINTinfloatmul_wopt, \XINTinfloatadd_wopt to track % xintfrac.sty changes at 1.4e. %\end{lverb} % \begin{macrocode} \def\xintFloatPowerSeries {\romannumeral0\xintfloatpowerseries }% \def\xintfloatpowerseries #1{\XINT_flpowseries_chkopt #1\xint:}% \def\XINT_flpowseries_chkopt #1% {% \ifx [#1\expandafter\XINT_flpowseries_opt \else\expandafter\XINT_flpowseries_noopt \fi #1% }% \def\XINT_flpowseries_noopt #1\xint:#2% {% \expandafter\XINT_flpowseries\expandafter {\the\numexpr #1\expandafter}\expandafter {\the\numexpr #2}\XINTdigits }% \def\XINT_flpowseries_opt [\xint:#1]#2#3% {% \expandafter\XINT_flpowseries\expandafter {\the\numexpr #2\expandafter}\expandafter {\the\numexpr #3\expandafter}{\the\numexpr #1}% }% \def\XINT_flpowseries #1#2#3#4#5% {% \ifnum #2<#1 \xint_afterfi { 0.e0}% \else \xint_afterfi {\expandafter\XINT_flpowseries_loop_pre\expandafter {\romannumeral0\XINTinfloatpow_wopt[#3]{#5}{#1}}% {#1}{#5}{#2}{#4}{#3}% }% \fi }% \def\XINT_flpowseries_loop_pre #1#2#3#4#5#6% {% \ifnum #4>#2 \else\XINT_flpowseries_dont_i \fi \expandafter\XINT_flpowseries_loop_i\expandafter {\the\numexpr #2+\xint_c_i\expandafter}\expandafter {\romannumeral0\XINTinfloatmul_wopt[#6]{#5{#2}}{#1}}% {#1}{#3}{#4}{#5}{#6}% }% \def\XINT_flpowseries_dont_i \fi\expandafter\XINT_flpowseries_loop_i {\fi \expandafter\XINT_flpowseries_dont_ii }% \def\XINT_flpowseries_dont_ii #1#2#3#4#5#6#7{\xintfloat [#7]{#2}}% \def\XINT_flpowseries_loop_i #1#2#3#4#5#6#7% {% \ifnum #5>#1 \else \XINT_flpowseries_exit_i \fi \expandafter\XINT_flpowseries_loop_ii\expandafter {\romannumeral0\XINTinfloatmul_wopt[#7]{#3}{#4}}% {#1}{#4}{#2}{#5}{#6}{#7}% }% \def\XINT_flpowseries_loop_ii #1#2#3#4#5#6#7% {% \expandafter\XINT_flpowseries_loop_i\expandafter {\the\numexpr #2+\xint_c_i\expandafter}\expandafter {\romannumeral0\XINTinfloatadd_wopt[#7]{#4}% {\XINTinfloatmul_wopt[#7]{#6{#2}}{#1}}}% {#1}{#3}{#5}{#6}{#7}% }% \def\XINT_flpowseries_exit_i\fi\expandafter\XINT_flpowseries_loop_ii {\fi \expandafter\XINT_flpowseries_exit_ii }% \def\XINT_flpowseries_exit_ii #1#2#3#4#5#6#7% {% \xintfloatadd[#7]{#4}{\XINTinfloatmul_wopt[#7]{#6{#2}}{#1}}% }% % \end{macrocode} % \subsection{\csh{xintFloatPowerSeriesX}} %\begin{lverb} % 1.08a % % See \xintFloatPowerSeries for 1.4e comments. %\end{lverb} % \begin{macrocode} \def\xintFloatPowerSeriesX {\romannumeral0\xintfloatpowerseriesx }% \def\xintfloatpowerseriesx #1{\XINT_flpowseriesx_chkopt #1\xint:}% \def\XINT_flpowseriesx_chkopt #1% {% \ifx [#1\expandafter\XINT_flpowseriesx_opt \else\expandafter\XINT_flpowseriesx_noopt \fi #1% }% \def\XINT_flpowseriesx_noopt #1\xint:#2% {% \expandafter\XINT_flpowseriesx\expandafter {\the\numexpr #1\expandafter}\expandafter {\the\numexpr #2}\XINTdigits }% \def\XINT_flpowseriesx_opt [\xint:#1]#2#3% {% \expandafter\XINT_flpowseriesx\expandafter {\the\numexpr #2\expandafter}\expandafter {\the\numexpr #3\expandafter}{\the\numexpr #1}% }% \def\XINT_flpowseriesx #1#2#3#4#5% {% \ifnum #2<#1 \xint_afterfi { 0.e0}% \else \xint_afterfi {\expandafter \XINT_flpowseriesx_pre \expandafter {\romannumeral`&&@#5}{#1}{#2}{#4}{#3}% }% \fi }% \def\XINT_flpowseriesx_pre #1#2#3#4#5% {% \expandafter\XINT_flpowseries_loop_pre\expandafter {\romannumeral0\XINTinfloatpow_wopt[#5]{#1}{#2}}% {#2}{#1}{#3}{#4}{#5}% }% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintseries} % \cleardoublepage\let\xintseriesnameUp\undefined %\gardesactifs %\let\relax %\let<*xintcfrac>\gardesinactifs %^^A------------------------------------------------- %<*xintcfrac>^^A-------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintcfracnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintcfracnameimp implementation} % \RaisedLabel{sec:cfracimp} % % \localtableofcontents % % \subsection{Introduction} % % The commenting is currently (\xintbndldate) very sparse. Release |1.09m| % (|2014/02/26|) has modified a few things: |\xintFtoCs| and % |\xintCntoCs| insert spaces after the commas, |\xintCstoF| and % |\xintCstoCv| authorize spaces in the input also before the commas, % |\xintCntoCs| does not brace the produced coefficients, new macros % |\xintFtoC|, |\xintCtoF|, |\xintCtoCv|, |\xintFGtoC|, and % |\xintGGCFrac|. % % The macros |\xintCstoF| and |\xintCstoCv| use \xinttoolsnameimp's % \csbxint{CSVtoList}. Formerly, it was up to user to load \xinttoolsnameimp % to enable these macros. Starting at |1.4n| the loading is automatic. % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintcfrac.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname \expandafter\let\expandafter\t\csname ver@xinttools.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintcfrac Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintcfrac}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % not LaTeX, first loading of xintcfrac.sty \ifx\w\relax % but xintfrac.sty not yet loaded. \expandafter\def\expandafter\z\expandafter {\z\input xintfrac.sty\relax}% \fi \ifx\t\relax % but xinttools.sty not yet loaded. \expandafter\def\expandafter\z\expandafter {\z\input xinttools.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xintfrac not yet loaded. \expandafter\def\expandafter\z\expandafter {\z\RequirePackage{xintfrac}}% \fi \ifx\t\relax % xinttools not yet loaded. \expandafter\def\expandafter\z\expandafter {\z\RequirePackage{xinttools}}% \fi \else \def\z{\endgroup\endinput}% xintcfrac already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintcfrac}% [2026/11/01 v2.0a1 Expandable continued fractions with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintCFrac}} % \begin{macrocode} \def\xintCFrac {\romannumeral0\xintcfrac }% \def\xintcfrac #1% {% \XINT_cfrac_opt_a #1\xint: }% \def\XINT_cfrac_opt_a #1% {% \ifx[#1\XINT_cfrac_opt_b\fi \XINT_cfrac_noopt #1% }% \def\XINT_cfrac_noopt #1\xint: {% \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z \relax\relax }% \def\XINT_cfrac_opt_b\fi\XINT_cfrac_noopt [\xint:#1]% {% \fi\csname XINT_cfrac_opt#1\endcsname }% \def\XINT_cfrac_optl #1% {% \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z \relax\hfill }% \def\XINT_cfrac_optc #1% {% \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z \relax\relax }% \def\XINT_cfrac_optr #1% {% \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z \hfill\relax }% \def\XINT_cfrac_A #1/#2\Z {% \expandafter\XINT_cfrac_B\romannumeral0\xintiidivision {#1}{#2}{#2}% }% \def\XINT_cfrac_B #1#2% {% \XINT_cfrac_C #2\Z {#1}% }% \def\XINT_cfrac_C #1% {% \xint_gob_til_zero #1\XINT_cfrac_integer 0\XINT_cfrac_D #1% }% \def\XINT_cfrac_integer 0\XINT_cfrac_D 0#1\Z #2#3#4#5{ #2}% \def\XINT_cfrac_D #1\Z #2#3{\XINT_cfrac_loop_a {#1}{#3}{#1}{{#2}}}% \def\XINT_cfrac_loop_a {% \expandafter\XINT_cfrac_loop_d\romannumeral0\XINT_ndivrawpair }% \def\XINT_cfrac_loop_d #1#2% {% \XINT_cfrac_loop_e #2.{#1}% }% \def\XINT_cfrac_loop_e #1% {% \xint_gob_til_zero #1\xint_cfrac_loop_exit0\XINT_cfrac_loop_f #1% }% \def\XINT_cfrac_loop_f #1.#2#3#4% {% \XINT_cfrac_loop_a {#1}{#3}{#1}{{#2}#4}% }% \def\xint_cfrac_loop_exit0\XINT_cfrac_loop_f #1.#2#3#4#5#6% {\XINT_cfrac_T #5#6{#2}#4\Z }% \def\XINT_cfrac_T #1#2#3#4% {% \xint_gob_til_Z #4\XINT_cfrac_end\Z\XINT_cfrac_T #1#2{#4+\cfrac{#11#2}{#3}}% }% \def\XINT_cfrac_end\Z\XINT_cfrac_T #1#2#3% {% \XINT_cfrac_end_b #3% }% \def\XINT_cfrac_end_b \Z+\cfrac#1#2{ #2}% % \end{macrocode} % \subsection{\csh{xintGCFrac}} % Updated at |1.4g| to follow-up on renaming of |\xintFrac| into |\xintTeXFrac|. % \begin{macrocode} \def\xintGCFrac {\romannumeral0\xintgcfrac }% \def\xintgcfrac #1{\XINT_gcfrac_opt_a #1\xint:}% \def\XINT_gcfrac_opt_a #1% {% \ifx[#1\XINT_gcfrac_opt_b\fi \XINT_gcfrac_noopt #1% }% \def\XINT_gcfrac_noopt #1\xint:% {% \XINT_gcfrac #1+!/\relax\relax }% \def\XINT_gcfrac_opt_b\fi\XINT_gcfrac_noopt [\xint:#1]% {% \fi\csname XINT_gcfrac_opt#1\endcsname }% \def\XINT_gcfrac_optl #1% {% \XINT_gcfrac #1+!/\relax\hfill }% \def\XINT_gcfrac_optc #1% {% \XINT_gcfrac #1+!/\relax\relax }% \def\XINT_gcfrac_optr #1% {% \XINT_gcfrac #1+!/\hfill\relax }% \def\XINT_gcfrac {% \expandafter\XINT_gcfrac_enter\romannumeral`&&@% }% \def\XINT_gcfrac_enter {\XINT_gcfrac_loop {}}% \def\XINT_gcfrac_loop #1#2+#3/% {% \xint_gob_til_exclam #3\XINT_gcfrac_endloop!% \XINT_gcfrac_loop {{#3}{#2}#1}% }% \def\XINT_gcfrac_endloop!\XINT_gcfrac_loop #1#2#3% {% \XINT_gcfrac_T #2#3#1!!% }% \def\XINT_gcfrac_T #1#2#3#4{\XINT_gcfrac_U #1#2{\xintTeXFrac{#4}}}% \def\XINT_gcfrac_U #1#2#3#4#5% {% \xint_gob_til_exclam #5\XINT_gcfrac_end!\XINT_gcfrac_U #1#2{\xintTeXFrac{#5}% \ifcase\xintSgn{#4} +\or+\else-\fi \cfrac{#1\xintTeXFrac{\xintAbs{#4}}#2}{#3}}% }% \def\XINT_gcfrac_end!\XINT_gcfrac_U #1#2#3% {% \XINT_gcfrac_end_b #3% }% \def\XINT_gcfrac_end_b #1\cfrac#2#3{ #3}% % \end{macrocode} % \subsection{\csh{xintGGCFrac}} %\begin{lverb} % New with 1.09m %\end{lverb} % \begin{macrocode} \def\xintGGCFrac {\romannumeral0\xintggcfrac }% \def\xintggcfrac #1{\XINT_ggcfrac_opt_a #1\xint:}% \def\XINT_ggcfrac_opt_a #1% {% \ifx[#1\XINT_ggcfrac_opt_b\fi \XINT_ggcfrac_noopt #1% }% \def\XINT_ggcfrac_noopt #1\xint: {% \XINT_ggcfrac #1+!/\relax\relax }% \def\XINT_ggcfrac_opt_b\fi\XINT_ggcfrac_noopt [\xint:#1]% {% \fi\csname XINT_ggcfrac_opt#1\endcsname }% \def\XINT_ggcfrac_optl #1% {% \XINT_ggcfrac #1+!/\relax\hfill }% \def\XINT_ggcfrac_optc #1% {% \XINT_ggcfrac #1+!/\relax\relax }% \def\XINT_ggcfrac_optr #1% {% \XINT_ggcfrac #1+!/\hfill\relax }% \def\XINT_ggcfrac {% \expandafter\XINT_ggcfrac_enter\romannumeral`&&@% }% \def\XINT_ggcfrac_enter {\XINT_ggcfrac_loop {}}% \def\XINT_ggcfrac_loop #1#2+#3/% {% \xint_gob_til_exclam #3\XINT_ggcfrac_endloop!% \XINT_ggcfrac_loop {{#3}{#2}#1}% }% \def\XINT_ggcfrac_endloop!\XINT_ggcfrac_loop #1#2#3% {% \XINT_ggcfrac_T #2#3#1!!% }% \def\XINT_ggcfrac_T #1#2#3#4{\XINT_ggcfrac_U #1#2{#4}}% \def\XINT_ggcfrac_U #1#2#3#4#5% {% \xint_gob_til_exclam #5\XINT_ggcfrac_end!\XINT_ggcfrac_U #1#2{#5+\cfrac{#1#4#2}{#3}}% }% \def\XINT_ggcfrac_end!\XINT_ggcfrac_U #1#2#3% {% \XINT_ggcfrac_end_b #3% }% \def\XINT_ggcfrac_end_b #1\cfrac#2#3{ #3}% % \end{macrocode} % \subsection{\csh{xintGCtoGCx}} % \begin{macrocode} \def\xintGCtoGCx {\romannumeral0\xintgctogcx }% \def\xintgctogcx #1#2#3% {% \expandafter\XINT_gctgcx_start\expandafter {\romannumeral`&&@#3}{#1}{#2}% }% \def\XINT_gctgcx_start #1#2#3{\XINT_gctgcx_loop_a {}{#2}{#3}#1+!/}% \def\XINT_gctgcx_loop_a #1#2#3#4+#5/% {% \xint_gob_til_exclam #5\XINT_gctgcx_end!% \XINT_gctgcx_loop_b {#1{#4}}{#2{#5}#3}{#2}{#3}% }% \def\XINT_gctgcx_loop_b #1#2% {% \XINT_gctgcx_loop_a {#1#2}% }% \def\XINT_gctgcx_end!\XINT_gctgcx_loop_b #1#2#3#4{ #1}% % \end{macrocode} % \subsection{\csh{xintFtoCs}} %\begin{lverb} % Modified in 1.09m: a space is added after the inserted commas. %\end{lverb} % \begin{macrocode} \def\xintFtoCs {\romannumeral0\xintftocs }% \def\xintftocs #1% {% \expandafter\XINT_ftc_A\romannumeral0\xintrawwithzeros {#1}\Z }% \def\XINT_ftc_A #1/#2\Z {% \expandafter\XINT_ftc_B\romannumeral0\xintiidivision {#1}{#2}{#2}% }% \def\XINT_ftc_B #1#2% {% \XINT_ftc_C #2.{#1}% }% \def\XINT_ftc_C #1% {% \xint_gob_til_zero #1\XINT_ftc_integer 0\XINT_ftc_D #1% }% \def\XINT_ftc_integer 0\XINT_ftc_D 0#1.#2#3{ #2}% \def\XINT_ftc_D #1.#2#3{\XINT_ftc_loop_a {#1}{#3}{#1}{#2, }}% 1.09m adds a space \def\XINT_ftc_loop_a {% \expandafter\XINT_ftc_loop_d\romannumeral0\XINT_ndivrawpair }% \def\XINT_ftc_loop_d #1#2% {% \XINT_ftc_loop_e #2.{#1}% }% \def\XINT_ftc_loop_e #1% {% \xint_gob_til_zero #1\xint_ftc_loop_exit0\XINT_ftc_loop_f #1% }% \def\XINT_ftc_loop_f #1.#2#3#4% {% \XINT_ftc_loop_a {#1}{#3}{#1}{#4#2, }% 1.09m has an added space here }% \def\xint_ftc_loop_exit0\XINT_ftc_loop_f #1.#2#3#4{ #4#2}% % \end{macrocode} % \subsection{\csh{xintFtoCx}} % \begin{macrocode} \def\xintFtoCx {\romannumeral0\xintftocx }% \def\xintftocx #1#2% {% \expandafter\XINT_ftcx_A\romannumeral0\xintrawwithzeros {#2}\Z {#1}% }% \def\XINT_ftcx_A #1/#2\Z {% \expandafter\XINT_ftcx_B\romannumeral0\xintiidivision {#1}{#2}{#2}% }% \def\XINT_ftcx_B #1#2% {% \XINT_ftcx_C #2.{#1}% }% \def\XINT_ftcx_C #1% {% \xint_gob_til_zero #1\XINT_ftcx_integer 0\XINT_ftcx_D #1% }% \def\XINT_ftcx_integer 0\XINT_ftcx_D 0#1.#2#3#4{ #2}% \def\XINT_ftcx_D #1.#2#3#4{\XINT_ftcx_loop_a {#1}{#3}{#1}{{#2}#4}{#4}}% \def\XINT_ftcx_loop_a {% \expandafter\XINT_ftcx_loop_d\romannumeral0\XINT_ndivrawpair }% \def\XINT_ftcx_loop_d #1#2% {% \XINT_ftcx_loop_e #2.{#1}% }% \def\XINT_ftcx_loop_e #1% {% \xint_gob_til_zero #1\xint_ftcx_loop_exit0\XINT_ftcx_loop_f #1% }% \def\XINT_ftcx_loop_f #1.#2#3#4#5% {% \XINT_ftcx_loop_a {#1}{#3}{#1}{#4{#2}#5}{#5}% }% \def\xint_ftcx_loop_exit0\XINT_ftcx_loop_f #1.#2#3#4#5{ #4{#2}}% % \end{macrocode} % \subsection{\csh{xintFtoC}} %\begin{lverb} % New in 1.09m: this is the same as \xintFtoCx with empty separator. I % had temporarily during preparation of 1.09m removed braces from \xintFtoCx, % but I recalled later why that was useful (see doc), thus let's just here do % \xintFtoCx {} %\end{lverb} % \begin{macrocode} \def\xintFtoC {\romannumeral0\xintftoc }% \def\xintftoc {\xintftocx {}}% % \end{macrocode} % \subsection{\csh{xintFtoGC}} % \begin{macrocode} \def\xintFtoGC {\romannumeral0\xintftogc }% \def\xintftogc {\xintftocx {+1/}}% % \end{macrocode} % \subsection{\csh{xintFGtoC}} %\begin{lverb} % New with 1.09m of 2014/02/26. Computes the common initial coefficients % for the two fractions f and g, and outputs them as a sequence of braced % items. %\end{lverb} % \begin{macrocode} \def\xintFGtoC {\romannumeral0\xintfgtoc}% \def\xintfgtoc#1% {% \expandafter\XINT_fgtc_a\romannumeral0\xintrawwithzeros {#1}\Z }% \def\XINT_fgtc_a #1/#2\Z #3% {% \expandafter\XINT_fgtc_b\romannumeral0\xintrawwithzeros {#3}\Z #1/#2\Z { }% }% \def\XINT_fgtc_b #1/#2\Z {% \expandafter\XINT_fgtc_c\romannumeral0\xintiidivision {#1}{#2}{#2}% }% \def\XINT_fgtc_c #1#2#3#4/#5\Z {% \expandafter\XINT_fgtc_d\romannumeral0\xintiidivision {#4}{#5}{#5}{#1}{#2}{#3}% }% \def\XINT_fgtc_d #1#2#3#4%#5#6#7% {% \xintifEq {#1}{#4}{\XINT_fgtc_da {#1}{#2}{#3}{#4}}% {\xint_thirdofthree}% }% \def\XINT_fgtc_da #1#2#3#4#5#6#7% {% \XINT_fgtc_e {#2}{#5}{#3}{#6}{#7{#1}}% }% \def\XINT_fgtc_e #1% {% \xintiiifZero {#1}{\expandafter\xint_firstofone\xint_gobble_iii}% {\XINT_fgtc_f {#1}}% }% \def\XINT_fgtc_f #1#2% {% \xintiiifZero {#2}{\xint_thirdofthree}{\XINT_fgtc_g {#1}{#2}}% }% \def\XINT_fgtc_g #1#2#3% {% \expandafter\XINT_fgtc_h\romannumeral0\XINT_ndivrawpair {#1}{#3}{#1}{#2}% }% \def\XINT_fgtc_h #1#2#3#4#5% {% \expandafter\XINT_fgtc_d\romannumeral0\XINT_ndivrawpair {#4}{#5}{#4}{#1}{#2}{#3}% }% % \end{macrocode} % \subsection{\csh{xintFtoCC}} % \begin{macrocode} \def\xintFtoCC {\romannumeral0\xintftocc }% \def\xintftocc #1% {% \expandafter\XINT_ftcc_A\expandafter {\romannumeral0\xintrawwithzeros {#1}}% }% \def\XINT_ftcc_A #1% {% \expandafter\XINT_ftcc_B \romannumeral0\xintrawwithzeros {\xintAdd {1/2[0]}{#1[0]}}\Z {#1[0]}% }% \def\XINT_ftcc_B #1/#2\Z {% \expandafter\XINT_ftcc_C\expandafter {\romannumeral0\xintiiquo {#1}{#2}}% }% \def\XINT_ftcc_C #1#2% {% \expandafter\XINT_ftcc_D\romannumeral0\xintsub {#2}{#1}\Z {#1}% }% \def\XINT_ftcc_D #1% {% \xint_UDzerominusfork #1-\XINT_ftcc_integer 0#1\XINT_ftcc_En 0-{\XINT_ftcc_Ep #1}% \krof }% \def\XINT_ftcc_Ep #1\Z #2% {% \expandafter\XINT_ftcc_loop_a\expandafter {\romannumeral0\xintdiv {1[0]}{#1}}{#2+1/}% }% \def\XINT_ftcc_En #1\Z #2% {% \expandafter\XINT_ftcc_loop_a\expandafter {\romannumeral0\xintdiv {1[0]}{#1}}{#2+-1/}% }% \def\XINT_ftcc_integer #1\Z #2{ #2}% \def\XINT_ftcc_loop_a #1% {% \expandafter\XINT_ftcc_loop_b \romannumeral0\xintrawwithzeros {\xintAdd {1/2[0]}{#1}}\Z {#1}% }% \def\XINT_ftcc_loop_b #1/#2\Z {% \expandafter\XINT_ftcc_loop_c\expandafter {\romannumeral0\xintiiquo {#1}{#2}}% }% \def\XINT_ftcc_loop_c #1#2% {% \expandafter\XINT_ftcc_loop_d \romannumeral0\xintsub {#2}{#1[0]}\Z {#1}% }% \def\XINT_ftcc_loop_d #1% {% \xint_UDzerominusfork #1-\XINT_ftcc_end 0#1\XINT_ftcc_loop_N 0-{\XINT_ftcc_loop_P #1}% \krof }% \def\XINT_ftcc_end #1\Z #2#3{ #3#2}% \def\XINT_ftcc_loop_P #1\Z #2#3% {% \expandafter\XINT_ftcc_loop_a\expandafter {\romannumeral0\xintdiv {1[0]}{#1}}{#3#2+1/}% }% \def\XINT_ftcc_loop_N #1\Z #2#3% {% \expandafter\XINT_ftcc_loop_a\expandafter {\romannumeral0\xintdiv {1[0]}{#1}}{#3#2+-1/}% }% % \end{macrocode} % \subsection{\csh{xintCtoF}, \csh{xintCstoF}} % % |1.09m| uses \xinttoolsnameimp's \csbxint{CSVtoList} on the argument of % \csbxint{CstoF} to allow spaces also before the commas. And the original % \csbxint{CstoF} code became the one of the new \csbxint{CtoF} dealing with a % braced rather than comma separated list. % \begin{macrocode} \def\xintCstoF {\romannumeral0\xintcstof }% \def\xintcstof #1% {% \expandafter\XINT_ctf_prep \romannumeral0\xintcsvtolist{#1}!% }% \def\xintCtoF {\romannumeral0\xintctof }% \def\xintctof #1% {% \expandafter\XINT_ctf_prep \romannumeral`&&@#1!% }% \def\XINT_ctf_prep {% \XINT_ctf_loop_a 1001% }% \def\XINT_ctf_loop_a #1#2#3#4#5% {% \xint_gob_til_exclam #5\XINT_ctf_end!% \expandafter\XINT_ctf_loop_b \romannumeral0\xintrawwithzeros {#5}.{#1}{#2}{#3}{#4}% }% \def\XINT_ctf_loop_b #1/#2.#3#4#5#6% {% \expandafter\XINT_ctf_loop_c\expandafter {\romannumeral0\xintiimul{#2}{#4}}% {\romannumeral0\xintiimul{#2}{#3}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#6}}% {\xintiimul{#1}{#4}}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#5}}% {\xintiimul{#1}{#3}}}% }% \def\XINT_ctf_loop_c #1#2% {% \expandafter\XINT_ctf_loop_d\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_ctf_loop_d #1#2% {% \expandafter\XINT_ctf_loop_e\expandafter {\expandafter{#2}#1}% }% \def\XINT_ctf_loop_e #1#2% {% \expandafter\XINT_ctf_loop_a\expandafter{#2}#1% }% \def\XINT_ctf_end #1.#2#3#4#5{\xintrawwithzeros {#2/#3}}% 1.09b removes [0] % \end{macrocode} % \subsection{\csh{xintiCstoF}} % \begin{macrocode} \def\xintiCstoF {\romannumeral0\xinticstof }% \def\xinticstof #1% {% \expandafter\XINT_icstf_prep \romannumeral`&&@#1,!,% }% \def\XINT_icstf_prep {% \XINT_icstf_loop_a 1001% }% \def\XINT_icstf_loop_a #1#2#3#4#5,% {% \xint_gob_til_exclam #5\XINT_icstf_end!% \expandafter \XINT_icstf_loop_b \romannumeral`&&@#5.{#1}{#2}{#3}{#4}% }% \def\XINT_icstf_loop_b #1.#2#3#4#5% {% \expandafter\XINT_icstf_loop_c\expandafter {\romannumeral0\xintiiadd {#5}{\xintiimul{#1}{#3}}}% {\romannumeral0\xintiiadd {#4}{\xintiimul{#1}{#2}}}% {#2}{#3}% }% \def\XINT_icstf_loop_c #1#2% {% \expandafter\XINT_icstf_loop_a\expandafter {#2}{#1}% }% \def\XINT_icstf_end#1.#2#3#4#5{\xintrawwithzeros {#2/#3}}% 1.09b removes [0] % \end{macrocode} % \subsection{\csh{xintGCtoF}} % \begin{macrocode} \def\xintGCtoF {\romannumeral0\xintgctof }% \def\xintgctof #1% {% \expandafter\XINT_gctf_prep \romannumeral`&&@#1+!/% }% \def\XINT_gctf_prep {% \XINT_gctf_loop_a 1001% }% \def\XINT_gctf_loop_a #1#2#3#4#5+% {% \expandafter\XINT_gctf_loop_b \romannumeral0\xintrawwithzeros {#5}.{#1}{#2}{#3}{#4}% }% \def\XINT_gctf_loop_b #1/#2.#3#4#5#6% {% \expandafter\XINT_gctf_loop_c\expandafter {\romannumeral0\xintiimul{#2}{#4}}% {\romannumeral0\xintiimul{#2}{#3}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#6}}% {\xintiimul{#1}{#4}}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#5}}% {\xintiimul{#1}{#3}}}% }% \def\XINT_gctf_loop_c #1#2% {% \expandafter\XINT_gctf_loop_d\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_gctf_loop_d #1#2% {% \expandafter\XINT_gctf_loop_e\expandafter {\expandafter{#2}#1}% }% \def\XINT_gctf_loop_e #1#2% {% \expandafter\XINT_gctf_loop_f\expandafter {\expandafter{#2}#1}% }% \def\XINT_gctf_loop_f #1#2/% {% \xint_gob_til_exclam #2\XINT_gctf_end!% \expandafter\XINT_gctf_loop_g \romannumeral0\xintrawwithzeros {#2}.#1% }% \def\XINT_gctf_loop_g #1/#2.#3#4#5#6% {% \expandafter\XINT_gctf_loop_h\expandafter {\romannumeral0\xintiimul{#1}{#6}}% {\romannumeral0\xintiimul{#1}{#5}}% {\romannumeral0\xintiimul{#2}{#4}}% {\romannumeral0\xintiimul{#2}{#3}}% }% \def\XINT_gctf_loop_h #1#2% {% \expandafter\XINT_gctf_loop_i\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_gctf_loop_i #1#2% {% \expandafter\XINT_gctf_loop_j\expandafter {\expandafter{#2}#1}% }% \def\XINT_gctf_loop_j #1#2% {% \expandafter\XINT_gctf_loop_a\expandafter {#2}#1% }% \def\XINT_gctf_end #1.#2#3#4#5{\xintrawwithzeros {#2/#3}}% 1.09b removes [0] % \end{macrocode} % \subsection{\csh{xintiGCtoF}} % \begin{macrocode} \def\xintiGCtoF {\romannumeral0\xintigctof }% \def\xintigctof #1% {% \expandafter\XINT_igctf_prep \romannumeral`&&@#1+!/% }% \def\XINT_igctf_prep {% \XINT_igctf_loop_a 1001% }% \def\XINT_igctf_loop_a #1#2#3#4#5+% {% \expandafter\XINT_igctf_loop_b \romannumeral`&&@#5.{#1}{#2}{#3}{#4}% }% \def\XINT_igctf_loop_b #1.#2#3#4#5% {% \expandafter\XINT_igctf_loop_c\expandafter {\romannumeral0\xintiiadd {#5}{\xintiimul{#1}{#3}}}% {\romannumeral0\xintiiadd {#4}{\xintiimul{#1}{#2}}}% {#2}{#3}% }% \def\XINT_igctf_loop_c #1#2% {% \expandafter\XINT_igctf_loop_f\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_igctf_loop_f #1#2#3#4/% {% \xint_gob_til_exclam #4\XINT_igctf_end!% \expandafter\XINT_igctf_loop_g \romannumeral`&&@#4.{#2}{#3}#1% }% \def\XINT_igctf_loop_g #1.#2#3% {% \expandafter\XINT_igctf_loop_h\expandafter {\romannumeral0\xintiimul{#1}{#3}}% {\romannumeral0\xintiimul{#1}{#2}}% }% \def\XINT_igctf_loop_h #1#2% {% \expandafter\XINT_igctf_loop_i\expandafter {#2}{#1}% }% \def\XINT_igctf_loop_i #1#2#3#4% {% \XINT_igctf_loop_a {#3}{#4}{#1}{#2}% }% \def\XINT_igctf_end #1.#2#3#4#5{\xintrawwithzeros {#4/#5}}% 1.09b removes [0] % \end{macrocode} % \subsection{\csh{xintCtoCv}, \csh{xintCstoCv}} % % |1.09m| uses \xinttoolsnameimp's \csbxint{CSVtoList} on the argument of % \csbxint{CstoCv} to allow spaces also before the commas. The original % \csbxint{CstoCv} code became the one of the new \csbxint{CtoF} dealing with % a braced rather than comma separated list. % \begin{macrocode} \def\xintCstoCv {\romannumeral0\xintcstocv }% \def\xintcstocv #1% {% \expandafter\XINT_ctcv_prep\romannumeral0\xintcsvtolist{#1}!% }% \def\xintCtoCv {\romannumeral0\xintctocv }% \def\xintctocv #1% {% \expandafter\XINT_ctcv_prep\romannumeral`&&@#1!% }% \def\XINT_ctcv_prep {% \XINT_ctcv_loop_a {}1001% }% \def\XINT_ctcv_loop_a #1#2#3#4#5#6% {% \xint_gob_til_exclam #6\XINT_ctcv_end!% \expandafter\XINT_ctcv_loop_b \romannumeral0\xintrawwithzeros {#6}.{#2}{#3}{#4}{#5}{#1}% }% \def\XINT_ctcv_loop_b #1/#2.#3#4#5#6% {% \expandafter\XINT_ctcv_loop_c\expandafter {\romannumeral0\xintiimul{#2}{#4}}% {\romannumeral0\xintiimul{#2}{#3}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#6}}% {\xintiimul{#1}{#4}}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#5}}% {\xintiimul{#1}{#3}}}% }% \def\XINT_ctcv_loop_c #1#2% {% \expandafter\XINT_ctcv_loop_d\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_ctcv_loop_d #1#2% {% \expandafter\XINT_ctcv_loop_e\expandafter {\expandafter{#2}#1}% }% \def\XINT_ctcv_loop_e #1#2% {% \expandafter\XINT_ctcv_loop_f\expandafter{#2}#1% }% \def\XINT_ctcv_loop_f #1#2#3#4#5% {% \expandafter\XINT_ctcv_loop_g\expandafter {\romannumeral0\xintrawwithzeros {#1/#2}}{#5}{#1}{#2}{#3}{#4}% }% \def\XINT_ctcv_loop_g #1#2{\XINT_ctcv_loop_a {#2{#1}}}% 1.09b removes [0] \def\XINT_ctcv_end #1.#2#3#4#5#6{ #6}% % \end{macrocode} % \subsection{\csh{xintiCstoCv}} % \begin{macrocode} \def\xintiCstoCv {\romannumeral0\xinticstocv }% \def\xinticstocv #1% {% \expandafter\XINT_icstcv_prep \romannumeral`&&@#1,!,% }% \def\XINT_icstcv_prep {% \XINT_icstcv_loop_a {}1001% }% \def\XINT_icstcv_loop_a #1#2#3#4#5#6,% {% \xint_gob_til_exclam #6\XINT_icstcv_end!% \expandafter \XINT_icstcv_loop_b \romannumeral`&&@#6.{#2}{#3}{#4}{#5}{#1}% }% \def\XINT_icstcv_loop_b #1.#2#3#4#5% {% \expandafter\XINT_icstcv_loop_c\expandafter {\romannumeral0\xintiiadd {#5}{\xintiimul{#1}{#3}}}% {\romannumeral0\xintiiadd {#4}{\xintiimul{#1}{#2}}}% {{#2}{#3}}% }% \def\XINT_icstcv_loop_c #1#2% {% \expandafter\XINT_icstcv_loop_d\expandafter {#2}{#1}% }% \def\XINT_icstcv_loop_d #1#2% {% \expandafter\XINT_icstcv_loop_e\expandafter {\romannumeral0\xintrawwithzeros {#1/#2}}{{#1}{#2}}% }% \def\XINT_icstcv_loop_e #1#2#3#4{\XINT_icstcv_loop_a {#4{#1}}#2#3}% \def\XINT_icstcv_end #1.#2#3#4#5#6{ #6}% 1.09b removes [0] % \end{macrocode} % \subsection{\csh{xintGCtoCv}} % \begin{macrocode} \def\xintGCtoCv {\romannumeral0\xintgctocv }% \def\xintgctocv #1% {% \expandafter\XINT_gctcv_prep \romannumeral`&&@#1+!/% }% \def\XINT_gctcv_prep {% \XINT_gctcv_loop_a {}1001% }% \def\XINT_gctcv_loop_a #1#2#3#4#5#6+% {% \expandafter\XINT_gctcv_loop_b \romannumeral0\xintrawwithzeros {#6}.{#2}{#3}{#4}{#5}{#1}% }% \def\XINT_gctcv_loop_b #1/#2.#3#4#5#6% {% \expandafter\XINT_gctcv_loop_c\expandafter {\romannumeral0\xintiimul{#2}{#4}}% {\romannumeral0\xintiimul{#2}{#3}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#6}}% {\xintiimul{#1}{#4}}}% {\romannumeral0\xintiiadd {\xintiimul{#2}{#5}}% {\xintiimul{#1}{#3}}}% }% \def\XINT_gctcv_loop_c #1#2% {% \expandafter\XINT_gctcv_loop_d\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_gctcv_loop_d #1#2% {% \expandafter\XINT_gctcv_loop_e\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_gctcv_loop_e #1#2% {% \expandafter\XINT_gctcv_loop_f\expandafter {#2}#1% }% \def\XINT_gctcv_loop_f #1#2% {% \expandafter\XINT_gctcv_loop_g\expandafter {\romannumeral0\xintrawwithzeros {#1/#2}}{{#1}{#2}}% }% \def\XINT_gctcv_loop_g #1#2#3#4% {% \XINT_gctcv_loop_h {#4{#1}}{#2#3}% 1.09b removes [0] }% \def\XINT_gctcv_loop_h #1#2#3/% {% \xint_gob_til_exclam #3\XINT_gctcv_end!% \expandafter\XINT_gctcv_loop_i \romannumeral0\xintrawwithzeros {#3}.#2{#1}% }% \def\XINT_gctcv_loop_i #1/#2.#3#4#5#6% {% \expandafter\XINT_gctcv_loop_j\expandafter {\romannumeral0\xintiimul{#1}{#6}}% {\romannumeral0\xintiimul{#1}{#5}}% {\romannumeral0\xintiimul{#2}{#4}}% {\romannumeral0\xintiimul{#2}{#3}}% }% \def\XINT_gctcv_loop_j #1#2% {% \expandafter\XINT_gctcv_loop_k\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_gctcv_loop_k #1#2% {% \expandafter\XINT_gctcv_loop_l\expandafter {\expandafter{#2}#1}% }% \def\XINT_gctcv_loop_l #1#2% {% \expandafter\XINT_gctcv_loop_m\expandafter {\expandafter{#2}#1}% }% \def\XINT_gctcv_loop_m #1#2{\XINT_gctcv_loop_a {#2}#1}% \def\XINT_gctcv_end #1.#2#3#4#5#6{ #6}% % \end{macrocode} % \subsection{\csh{xintiGCtoCv}} % \begin{macrocode} \def\xintiGCtoCv {\romannumeral0\xintigctocv }% \def\xintigctocv #1% {% \expandafter\XINT_igctcv_prep \romannumeral`&&@#1+!/% }% \def\XINT_igctcv_prep {% \XINT_igctcv_loop_a {}1001% }% \def\XINT_igctcv_loop_a #1#2#3#4#5#6+% {% \expandafter\XINT_igctcv_loop_b \romannumeral`&&@#6.{#2}{#3}{#4}{#5}{#1}% }% \def\XINT_igctcv_loop_b #1.#2#3#4#5% {% \expandafter\XINT_igctcv_loop_c\expandafter {\romannumeral0\xintiiadd {#5}{\xintiimul{#1}{#3}}}% {\romannumeral0\xintiiadd {#4}{\xintiimul{#1}{#2}}}% {{#2}{#3}}% }% \def\XINT_igctcv_loop_c #1#2% {% \expandafter\XINT_igctcv_loop_f\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_igctcv_loop_f #1#2#3#4/% {% \xint_gob_til_exclam #4\XINT_igctcv_end_a!% \expandafter\XINT_igctcv_loop_g \romannumeral`&&@#4.#1#2{#3}% }% \def\XINT_igctcv_loop_g #1.#2#3#4#5% {% \expandafter\XINT_igctcv_loop_h\expandafter {\romannumeral0\xintiimul{#1}{#5}}% {\romannumeral0\xintiimul{#1}{#4}}% {{#2}{#3}}% }% \def\XINT_igctcv_loop_h #1#2% {% \expandafter\XINT_igctcv_loop_i\expandafter {\expandafter{#2}{#1}}% }% \def\XINT_igctcv_loop_i #1#2{\XINT_igctcv_loop_k #2{#2#1}}% \def\XINT_igctcv_loop_k #1#2% {% \expandafter\XINT_igctcv_loop_l\expandafter {\romannumeral0\xintrawwithzeros {#1/#2}}% }% \def\XINT_igctcv_loop_l #1#2#3{\XINT_igctcv_loop_a {#3{#1}}#2}%1.09i removes [0] \def\XINT_igctcv_end_a #1.#2#3#4#5% {% \expandafter\XINT_igctcv_end_b\expandafter {\romannumeral0\xintrawwithzeros {#2/#3}}% }% \def\XINT_igctcv_end_b #1#2{ #2{#1}}% 1.09b removes [0] % \end{macrocode} % \subsection{\csh{xintFtoCv}} %\begin{lverb} % Still uses \xinticstocv \xintFtoCs rather than \xintctocv \xintFtoC. %\end{lverb} % \begin{macrocode} \def\xintFtoCv {\romannumeral0\xintftocv }% \def\xintftocv #1% {% \xinticstocv {\xintFtoCs {#1}}% }% % \end{macrocode} % \subsection{\csh{xintFtoCCv}} % \begin{macrocode} \def\xintFtoCCv {\romannumeral0\xintftoccv }% \def\xintftoccv #1% {% \xintigctocv {\xintFtoCC {#1}}% }% % \end{macrocode} % \subsection{\csh{xintCntoF}} %\begin{lverb} % Modified in 1.06 to give the N first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. %\end{lverb} % \begin{macrocode} \def\xintCntoF {\romannumeral0\xintcntof }% \def\xintcntof #1% {% \expandafter\XINT_cntf\expandafter {\the\numexpr #1}% }% \def\XINT_cntf #1#2% {% \ifnum #1>\xint_c_ \xint_afterfi {\expandafter\XINT_cntf_loop\expandafter {\the\numexpr #1-1\expandafter}\expandafter {\romannumeral`&&@#2{#1}}{#2}}% \else \xint_afterfi {\ifnum #1=\xint_c_ \xint_afterfi {\expandafter\space \romannumeral`&&@#2{0}}% \else \xint_afterfi { }% 1.09m now returns nothing. \fi}% \fi }% \def\XINT_cntf_loop #1#2#3% {% \ifnum #1>\xint_c_ \else \XINT_cntf_exit \fi \expandafter\XINT_cntf_loop\expandafter {\the\numexpr #1-1\expandafter }\expandafter {\romannumeral0\xintadd {\xintDiv {1[0]}{#2}}{#3{#1}}}% {#3}% }% \def\XINT_cntf_exit \fi \expandafter\XINT_cntf_loop\expandafter #1\expandafter #2#3% {% \fi\xint_gobble_ii #2% }% % \end{macrocode} % \subsection{\csh{xintGCntoF}} %\begin{lverb} % Modified in 1.06 to give the N argument first to a \numexpr rather % than expanding twice. I just use \the\numexpr and maintain the previous code % after that. %\end{lverb} % \begin{macrocode} \def\xintGCntoF {\romannumeral0\xintgcntof }% \def\xintgcntof #1% {% \expandafter\XINT_gcntf\expandafter {\the\numexpr #1}% }% \def\XINT_gcntf #1#2#3% {% \ifnum #1>\xint_c_ \xint_afterfi {\expandafter\XINT_gcntf_loop\expandafter {\the\numexpr #1-1\expandafter}\expandafter {\romannumeral`&&@#2{#1}}{#2}{#3}}% \else \xint_afterfi {\ifnum #1=\xint_c_ \xint_afterfi {\expandafter\space\romannumeral`&&@#2{0}}% \else \xint_afterfi { }% 1.09m now returns nothing rather than 0/1[0] \fi}% \fi }% \def\XINT_gcntf_loop #1#2#3#4% {% \ifnum #1>\xint_c_ \else \XINT_gcntf_exit \fi \expandafter\XINT_gcntf_loop\expandafter {\the\numexpr #1-1\expandafter }\expandafter {\romannumeral0\xintadd {\xintDiv {#4{#1}}{#2}}{#3{#1}}}% {#3}{#4}% }% \def\XINT_gcntf_exit \fi \expandafter\XINT_gcntf_loop\expandafter #1\expandafter #2#3#4% {% \fi\xint_gobble_ii #2% }% % \end{macrocode} % \subsection{\csh{xintCntoCs}} %\begin{lverb} % Modified in 1.09m: added spaces after the commas in the produced list. % Moreover the coefficients are not braced anymore. A slight induced limitation % is that the macro argument should not contain some explicit comma (cf. % \XINT_cntcs_exit_b), hence \xintCntoCs {\macro,} with \def\macro,#1{} % would crash. Not a very serious limitation, I believe. %\end{lverb} % \begin{macrocode} \def\xintCntoCs {\romannumeral0\xintcntocs }% \def\xintcntocs #1% {% \expandafter\XINT_cntcs\expandafter {\the\numexpr #1}% }% \def\XINT_cntcs #1#2% {% \ifnum #1<0 \xint_afterfi { }% 1.09i: a 0/1[0] was here, now the macro returns nothing \else \xint_afterfi {\expandafter\XINT_cntcs_loop\expandafter {\the\numexpr #1-\xint_c_i\expandafter}\expandafter {\romannumeral`&&@#2{#1}}{#2}}% produced coeff not braced \fi }% \def\XINT_cntcs_loop #1#2#3% {% \ifnum #1>-\xint_c_i \else \XINT_cntcs_exit \fi \expandafter\XINT_cntcs_loop\expandafter {\the\numexpr #1-\xint_c_i\expandafter}\expandafter {\romannumeral`&&@#3{#1}, #2}{#3}% space added, 1.09m }% \def\XINT_cntcs_exit \fi \expandafter\XINT_cntcs_loop\expandafter #1\expandafter #2#3% {% \fi\XINT_cntcs_exit_b #2% }% \def\XINT_cntcs_exit_b #1,{}% romannumeral stopping space already there % \end{macrocode} % \subsection{\csh{xintCntoGC}} %\begin{lverb} % Modified in 1.06 to give the N first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. % % 1.09m maintains the braces, as the coeff are allowed to be fraction and the % slash can not be naked in the GC format, contrarily to what happens in % \xintCntoCs. Also the separators given to \xintGCtoGCx may then fetch the % coefficients as argument, as they are braced. %\end{lverb} % \begin{macrocode} \def\xintCntoGC {\romannumeral0\xintcntogc }% \def\xintcntogc #1% {% \expandafter\XINT_cntgc\expandafter {\the\numexpr #1}% }% \def\XINT_cntgc #1#2% {% \ifnum #1<0 \xint_afterfi { }% 1.09i there was as strange 0/1[0] here, removed \else \xint_afterfi {\expandafter\XINT_cntgc_loop\expandafter {\the\numexpr #1-\xint_c_i\expandafter}\expandafter {\expandafter{\romannumeral`&&@#2{#1}}}{#2}}% \fi }% \def\XINT_cntgc_loop #1#2#3% {% \ifnum #1>-\xint_c_i \else \XINT_cntgc_exit \fi \expandafter\XINT_cntgc_loop\expandafter {\the\numexpr #1-\xint_c_i\expandafter }\expandafter {\expandafter{\romannumeral`&&@#3{#1}}+1/#2}{#3}% }% \def\XINT_cntgc_exit \fi \expandafter\XINT_cntgc_loop\expandafter #1\expandafter #2#3% {% \fi\XINT_cntgc_exit_b #2% }% \def\XINT_cntgc_exit_b #1+1/{ }% % \end{macrocode} % \subsection{\csh{xintGCntoGC}} %\begin{lverb} % Modified in 1.06 to give the N first to a \numexpr rather than expanding % twice. I just use \the\numexpr and maintain the previous code after that. %\end{lverb} % \begin{macrocode} \def\xintGCntoGC {\romannumeral0\xintgcntogc }% \def\xintgcntogc #1% {% \expandafter\XINT_gcntgc\expandafter {\the\numexpr #1}% }% \def\XINT_gcntgc #1#2#3% {% \ifnum #1<0 \xint_afterfi { }% 1.09i now returns nothing \else \xint_afterfi {\expandafter\XINT_gcntgc_loop\expandafter {\the\numexpr #1-\xint_c_i\expandafter}\expandafter {\expandafter{\romannumeral`&&@#2{#1}}}{#2}{#3}}% \fi }% \def\XINT_gcntgc_loop #1#2#3#4% {% \ifnum #1>-\xint_c_i \else \XINT_gcntgc_exit \fi \expandafter\XINT_gcntgc_loop_b\expandafter {\expandafter{\romannumeral`&&@#4{#1}}/#2}{#3{#1}}{#1}{#3}{#4}% }% \def\XINT_gcntgc_loop_b #1#2#3% {% \expandafter\XINT_gcntgc_loop\expandafter {\the\numexpr #3-\xint_c_i \expandafter}\expandafter {\expandafter{\romannumeral`&&@#2}+#1}% }% \def\XINT_gcntgc_exit \fi \expandafter\XINT_gcntgc_loop_b\expandafter #1#2#3#4#5% {% \fi\XINT_gcntgc_exit_b #1% }% \def\XINT_gcntgc_exit_b #1/{ }% % \end{macrocode} % \subsection{\csh{xintCstoGC}} % \begin{macrocode} \def\xintCstoGC {\romannumeral0\xintcstogc }% \def\xintcstogc #1% {% \expandafter\XINT_cstc_prep \romannumeral`&&@#1,!,% }% \def\XINT_cstc_prep #1,{\XINT_cstc_loop_a {{#1}}}% \def\XINT_cstc_loop_a #1#2,% {% \xint_gob_til_exclam #2\XINT_cstc_end!% \XINT_cstc_loop_b {#1}{#2}% }% \def\XINT_cstc_loop_b #1#2{\XINT_cstc_loop_a {#1+1/{#2}}}% \def\XINT_cstc_end!\XINT_cstc_loop_b #1#2{ #1}% % \end{macrocode} % \subsection{\csh{xintGCtoGC}} % \begin{macrocode} \def\xintGCtoGC {\romannumeral0\xintgctogc }% \def\xintgctogc #1% {% \expandafter\XINT_gctgc_start \romannumeral`&&@#1+!/% }% \def\XINT_gctgc_start {\XINT_gctgc_loop_a {}}% \def\XINT_gctgc_loop_a #1#2+#3/% {% \xint_gob_til_exclam #3\XINT_gctgc_end!% \expandafter\XINT_gctgc_loop_b\expandafter {\romannumeral`&&@#2}{#3}{#1}% }% \def\XINT_gctgc_loop_b #1#2% {% \expandafter\XINT_gctgc_loop_c\expandafter {\romannumeral`&&@#2}{#1}% }% \def\XINT_gctgc_loop_c #1#2#3% {% \XINT_gctgc_loop_a {#3{#2}+{#1}/}% }% \def\XINT_gctgc_end!\expandafter\XINT_gctgc_loop_b {% \expandafter\XINT_gctgc_end_b }% \def\XINT_gctgc_end_b #1#2#3{ #3{#1}}% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintcfrac} % \cleardoublepage\let\xintcfracnameUp\undefined %\gardesactifs %\let\relax %\let<*xintexpr>\gardesinactifs %^^A-------------------------------------------------- %<*xintexpr>^^A--------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1) % \clearpage\csname xintexprnameUp\endcsname % \let\MakePrivateLetters\xintexprMakePrivateLetters % \section{Package \xintexprnameimp implementation} % \RaisedLabel{sec:exprimp} % \addedcalx{2.0a1} % % \localtableofcontents % % xintexpr.sty: **WIP** % Currently an empty wrapper loading calx.sty and xintfrac.sty. % In future |\xinteval| will be defined by this file not by calx.sty. % % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \catcode35=6 % # \def\odef#1{\expandafter\def\expandafter#1\expandafter}% \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintexpr.sty\endcsname \expandafter\let\expandafter\f\csname ver@xintfrac.sty\endcsname \expandafter\let\expandafter\c\csname ver@calx.sty\endcsname % I assume engines do not exist providing \expanded but not \numexpr \expandafter\ifx\csname expanded\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintexpr Warning:^^J% \space\space\space\space \expanded not available, aborting input.^^J}% \else \PackageWarningNoLine{xintexpr}{\expanded not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % not LaTeX (perhaps Plain+miniltx), first loading of xintexpr.sty \ifx\c\relax % but calx.sty not yet loaded. \odef\z{\z\input calx.sty\relax}% \fi \ifx\f\relax % but xintfrac.sty not yet loaded (made miniltx robust 2022/06/09) \odef\z{\z\input xintfrac.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\c\relax % calx not yet loaded. \odef\z{\z\RequirePackage{calx}}% \fi \ifx\f\relax % xintfrac not yet loaded. \odef\z{\z\RequirePackage{xintfrac}}% \fi \else \def\z{\endgroup\endinput}% xintexpr already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintexpr}% [2026/11/01 v2.0a1 Expandable fp, bigint and fraction expression parsers (JFB)]% \catcode`! 11 % \end{macrocode} % \subsection{\csh{XINTinFloatdigits}, \csh{XINTinFloatSdigits}} % \begin{macrocode} \def\XINTinFloatdigits {\XINTinFloat [\XINTdigits]}% \def\XINTinFloatSdigits{\XINTinFloatS[\XINTdigits]}% % \end{macrocode} % \subsection{Top level user \TeX{} interface: \cshnolabel{xinteval}} % \localtableofcontents % \subsubsection{\csh{xintexpr}, \csh{xintiexpr}} %\begin{lverb} % % \xintiexpr has an optional argument since 1.1. % % ATTENTION! 1.3d renamed $string$xinteval$space to \xintexpro etc... % (thus this old $string$xinteval$space isn't our current \xinteval). % % % Usage of \xintiRound{0} for \xintiexpr without optional [D] means that % \xintiexpr ... \relax wrapper can be used to insert rounded-to-integers % values in \xintiiexpr context: no post-fix [0] which would break it. % ^^^^^^ REVISE THE ABOVE BECAUSE NOW WE HAVE [0] ^^^^^ % % 1.4a add support for the optional argument [D] for \xintiexpr being negative % D, with same meaning as the 1.4a modified \xintRound from xintfrac.sty. % % \xintiexpr mechanism was refactored at 1.4e so that rounding due to [D] % optional argument uses raw format, not fixed point format on output, % delegating fixed point conversion to an \XINTiexprprint now separated from % \XINTexprprint. % % In case of negative [D], \xintiexpr [D]...\relax internally has the [0] % post-fix so it can not be inserted as sub-expression in \xintiiexpr without % a num() or \xintiexpr ...\relax (extra) wrapper. % %\end{lverb} % % \changed{1.4o} % \begin{macrocode} \def\xintexpr {\romannumeral0\xintexpro }% \def\xintiexpr {\romannumeral0\xintiexpro }% \def\xintexpro {\csname XINT_expr_wrap\expandafter\endcsname \romannumeral0\xintbareeval }% \def\xintiexpro #1% {% \ifx [#1\expandafter\XINT_iexpr_withopt\else\expandafter\XINT_iexpr_noopt \fi #1% }% \def\XINT_iexpr_noopt {% \csname XINT_iexpr_iiround\expandafter\endcsname\romannumeral0\xintbareeval }% \def\XINT_iexpr_iiround {% \expandafter\XINT_expr_wrap \expanded \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTiRoundzero_braced}% }% % \end{macrocode} % FIX THIS (for calx 2.0a1) % \begin{macrocode} \def\XINTiRoundzero_braced#1{{\xintiRound{0}{#1}}}% \def\XINT_iexpr_withopt [#1]% {% \csname XINT_iexpr_round\expandafter\endcsname \the\numexpr \xint_zapspaces #1 \xint_gobble_i\expandafter.% \romannumeral0\xintbareeval }% \def\XINT_iexpr_round #1.% {% \ifnum#1=\xint_c_\xint_dothis{\XINT_iexpr_iiround}\fi \xint_orthat{\XINT_iexpr_round_a #1.}% }% \def\XINT_iexpr_round_a #1.% {% \expandafter\XINT_iexpr_wrap \expanded \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTiRound_braced{#1}}% }% \def\XINTiRound_braced#1#2% {{\xintiRound{#1}{#2}[\the\numexpr\ifnum#1<\xint_c_i0\else-#1\fi]}}% % \end{macrocode} % \subsubsection{\csh{XINT_expr_wrap}, % \csh{XINT_iexpr_wrap}} %\begin{lverb} % 1.3e removes some leading space tokens which served nothing. % % 1.4e has \XINT_iexpr_wrap separated from \XINT_expr_wrap, thus simplifying % internal matters as output printer for \xintexpr will not have to handle % fixed point input but only extended-raw type input (i.e. A, A/B, A[N] or A/B[N]). %\end{lverb} % \begin{macrocode} \def\XINT_expr_wrap {\XINTfstop\XINTexprprint.}% \def\XINT_iexpr_wrap {\XINTfstop\XINTiexprprint.}% % \end{macrocode} % \subsubsection{\csh{XINTexprprint}, \csh{XINTiexprprint}} % \label{\xintimplabelprefix xintexprPrintOne} % \label{\xintimplabelprefix xintiexprPrintOne} % See comments in \calxnameimp. % \begin{macrocode} \protected\def\XINTexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintexprPrintOne}% \protected\def\XINTiexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintiexprPrintOne}% \let\xintiexprPrintOne\xintDecToString \protected\def\XINTboolexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintboolexprPrintOne}% \def\xintboolexprPrintOne#1{\calxifNotZero{#1}{true}{false}}% % \end{macrocode} % \subsubsection{\csh{xinttheexpr}, \csh{xinttheiexpr}} % See comments in \calxnameimp. % % \begin{macrocode} \def\xinttheexpr {\expanded\csname XINTexprprint\expandafter\endcsname \expandafter.\romannumeral0\xintbareeval}% \def\xinttheiexpr{\expanded\expandafter\xint_gobble_i\romannumeral0\xintiexpro}% % \end{macrocode} % \subsubsection{\csh{xintbareeval}} % See comments in \calxnameimp. % \begin{macrocode} \def\xintbareeval {\XINT_expr_start }% % \end{macrocode} % \subsubsection{\csh{xintthebareeval}} % See comments in \calxnameimp. % \begin{macrocode} \def\xintthebareeval{% \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbareeval }% % \end{macrocode} % \subsubsection{\csh{xinteval}, \csh{xintieval}} % See comments in \calxnameimp. % \begin{macrocode} \def\xinteval #1{% \expanded\csname XINTexprprint\expandafter\endcsname \expandafter.\romannumeral0\xintbareeval#1\relax }% % \end{macrocode} % Should I use |#{| rather delimited argument? (as for \csbxint{iieval} at |1.4n|). % \begin{macrocode} \def\xintieval{\expanded\expandafter\xint_ieval_chkopt\string}% \def\xint_ieval_chkopt #1% {% \ifx [#1\expandafter\xint_ieval_opt \else\expandafter\xint_ieval_noopt \fi #1% }% % \end{macrocode} % \changed{1.4p} Here too I don't know why I had been using % |\romannumeral`&&@\xintiexpr|. Replaced with |\romannumeral0\xintiexpro|. % And I couldn't resist the temptation to immediately jump to |_withopt|. % I did resist replacing |_withopt| with its expansion... this expansion % will inject the |\csname| for Babel. % \begin{macrocode} \def\xint_ieval_opt [#1]#2{% \expandafter\xint_gobble_i\romannumeral0\XINT_iexpr_withopt[#1]#2\relax }% \def\xint_ieval_noopt #1{\expandafter\xint_ieval\expandafter{\iffalse}\fi}% % \end{macrocode} % Attention that here the optional argument can come from the expression itself % (legacy syntax). % \begin{macrocode} \def\xint_ieval#1{% \expandafter\xint_gobble_i\romannumeral0\xintiexpro#1\relax }% % \end{macrocode} % \subsubsection{\csh{xintboolexpr}, \csh{XINT_boolexpr_print}, \csh{xinttheboolexpr}} %\begin{lverb} % Attention, the conversion to 1 or 0 is done only by the print macro. % Perhaps I should force it also inside raw result. %\end{lverb} % \begin{macrocode} \def\xintboolexpr{% \romannumeral0\expandafter\XINT_boolexpr_done\romannumeral0\xintexpro }% \def\XINT_boolexpr_done #1.{\XINTfstop\XINTboolexprprint.}% % \end{macrocode} % \changed{1.4o} A |\csname| for |\xinttheboolexpr| for Babel. % \begin{macrocode} \def\xinttheboolexpr{% \expanded\csname XINTboolexprprint\expandafter\endcsname \expandafter.\romannumeral0\xintbareeval }% % \end{macrocode} % \subsubsection{\csh{xintifboolexpr}} % See comments in \calxnameimp. % FIXME CHECK STATUS OF |\xintiiifnotzero| WHOSE USAGE HERE WAS AN ABUSE % ORIGINALLY % \begin{macrocode} \def\xintifboolexpr #1{% \romannumeral0\expandafter\CALX_ifnz \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbareeval #1\relax }% % \end{macrocode} % \subsubsection{\csh{xintifsgnexpr}} % \begin{macrocode} \def\xintifsgnexpr #1{% \romannumeral0\expandafter\CALX_ifsgn \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbareeval #1\relax }% % \end{macrocode} % \subsubsection{\csh{xint_FracToSci_x}} % \added{1.4} % TODO CLEAN UP COMMENTS WHICH HAVE MULTIPLE OBSOLETE COMPONENTS % Under the name of |\xintFracToSci| and defined in \xintfracnameimp. % \changed{1.4e} %\begin{lverb} % Refactored and much simplified % % It only needs to be x-expandable, and indeed the implementation here is only % x-expandable. %\end{lverb} %\begin{lverb} % % Finally for 1.4e release I modify. This is breaking change for all % \xinteval output in case of scientific notation: it will not be with an % integer mantissa, but with regular scientific notation, using the same rules % as \xintPFloat. % % Of course no float rounding! Also, as [0] will always or almost always be % present from an \xinteval, we want then to use integer not scientific % notation. But expression contained decimal fixed point input, or uses % scientific functions, then probably the N will not be zero and this will % trigger usage of scientific notation in output. % % Implementing these changes sort of ruin our previous efforts to minimize % grabbing the argument, but well. So the rules now are % %( Input: A, A/B, A[N], A/B[N] %: Output: A, A/B, A if N=0, A/B if N=0 %: If N is not zero, scientific notation like \xintPFloat,& % i.e. behaviour like \xintfloateval apart from the rounding& % to significands of width Digits.& % At 1.4k, trimming of zeros from A is always done, i.e.& % the \xintPFloatMinTrimmed is ignored to keep behaviour.& % unchanged. Trailing zeros of B are kept as is. %: The zero gives 0, except in A[N] and A/B[N] cases, it may give& % 0.0 %) %\end{lverb} % \changed{1.4k} % Moved from \xintfracnameimp to \xintexprnameimp. % \changed{1.4l} %\begin{lverb} % Renamed to \xint_FracToSci_x to make it private and provide in % $xintfracnameimp another \xintFracToSci with same output but which behaves % like other macros there: f-expandable and accepting the whole range of % inputs accepted by the xintfrac public macros. % % The private x-expandable macro here will have an empty output for an empty % input but is never used for an empty input (see \xintexprEmptyItem). %\end{lverb} % \begin{macrocode} \def\xint_FracToSci_x #1% {\expandafter\CALX_fts\romannumeral`&&@#1/\W[\R}% \def\XINT_FracToSci_x #1/#2#3[#4% {% \xint_gob_til_W #2\XINT_FracToSci_x_noslash\W \xint_gob_til_R #4\XINT_FracToSci_x_slash_noN\R \XINT_FracToSci_x_slash_N #1/#2#3[#4% }% \def\XINT_FracToSci_x_noslash#1\XINT_FracToSci_x_slash_N #2[#3% {% \xint_gob_til_R #3\XINT_FracToSci_x_noslash_noN\R \XINT_FracToSci_x_noslash_N #2[#3% }% \def\XINT_FracToSci_x_noslash_noN\R\XINT_FracToSci_x_noslash_N #1/\W[\R{#1}% \def\XINT_FracToSci_x_noslash_N #1[#2]/\W[\R% {% \ifnum#2=\xint_c_ #1\else \romannumeral0\expandafter\XINT_pfloat_a_fork\romannumeral0\xintrez{#1[#2]}% \fi }% \def\XINT_FracToSci_x_slash_noN\R\XINT_FracToSci_x_slash_N #1#2/#3/\W[\R% {% #1\xint_gob_til_zero#1\expandafter\iffalse\xint_gobble_ii0\iftrue #2\if\XINT_isOne{#3}1\else/#3\fi\fi }% \def\XINT_FracToSci_x_slash_N #1#2/#3[#4]/\W[\R% {% \ifnum#4=\xint_c_ #1#2\else \romannumeral0\expandafter\XINT_pfloat_a_fork\romannumeral0\xintrez{#1#2[#4]}% \fi \if\XINT_isOne{#3}1\else\if#10\else/#3\fi\fi }% % \end{macrocode} %\begin{lverb} % \xint_FracToSci_x also prints the native values of calx which reach % \xinteval (nested \xintfloatexpr or \xintiiexpr, float or ii variables % and functions): \CALX_fts tests the first token, a tag has character % code above `9. I+, I-, I? are printed as they are; an M value is % converted by calxint's \CALX_mtoraw (all digits), an F value by calxfp's % \CALX_ftoraw (A[N]), then printed by \XINT_FracToSci_x. %\end{lverb} % \begin{macrocode} \def\CALX_fts #1% {\ifnum`#1>57 \expandafter\CALX_fts_t\fi\XINT_FracToSci_x #1}% \def\CALX_fts_t\XINT_FracToSci_x #1#2/\W[\R {\if I#1\xint_dothis{#1#2}\fi \if M#1\xint_dothis{\expandafter\XINT_FracToSci_x \romannumeral0\CALX_mtoraw{#1#2}/\W[\R}\fi \xint_orthat{\expandafter\XINT_FracToSci_x \romannumeral0\CALX_ftoraw{#1#2}/\W[\R}}% \let\xintexprPrintOne\xint_FracToSci_x % \end{macrocode} % See \calxnameimp. % \begin{macrocode} \def\XINT_tmpa #1#2#3{% \def #1##1% {% \csname XINT_\ifcsname XINT_#3_func_##1\endcsname #3_func_##1\expandafter\endcsname\romannumeral`&&@\expandafter#2% \romannumeral\else \ifcsname XINT_#3_onliteral_##1\endcsname #3_onliteral_##1\expandafter\endcsname\romannumeral \else \ifcsname XINT_expr_var*_##1\endcsname expr_var*_##1\expandafter\endcsname\romannumeral \else #3_func_\XINT_expr_unknown_function {##1}% \expandafter\endcsname\romannumeral`&&@\expandafter#2% \romannumeral \fi\fi\fi\xint_c_ }% }% \expandafter\XINT_tmpa \csname XINT_expr_op_`\endcsname \XINT_expr_oparen {expr}% % \end{macrocode} % \subsection{Raw input of the float operations} %\begin{lverb} % Syntax (as in calxfp, where \CALX_fr_x is the raw input branch of % \CALX_fround): %( % \CALX_fr_x

.\xint: %: -> Y\xint: (Y: X rounded to P digits, native float) %) % calxfp accepts as raw values only A[N], A/B[N] (integers A, B without % leading zeros, B > 0). With xintexpr.sty, X is any xintfrac % input, as in xint 1.4: the arguments of macros made by \xintNewExpr and % similar, the argument of qfloat() and the arguments of the \calxFp % macros are not parsed by the expression parser. xintfrac's \XINTinFloat % rounds X to P digits (its A[N] branch does not look for a decimal mark % or an exponent), \CALX_ffromraw converts the A[N] result, and calxfp's % \CALX_fr_f finishes as for a native input. %\end{lverb} % \begin{macrocode} \def\CALX_fr_x #1.#2\xint:% {\expandafter\CALX_fr_f\the\numexpr#1\expandafter.% \romannumeral`&&@\CALX_ffromraw{\XINTinFloat[#1]{#2}}\xint:}% % \end{macrocode} % \subsection{Expansion spanning; opening and closing parentheses} % See comments in \calxnameimp. % \begin{macrocode} \catcode`) 11 \expandafter\XINT_def_start_and_check \csname XINT_expr_start\expandafter\endcsname \csname XINT_expr_check\expandafter\endcsname \csname XINT_expr_checkp\expandafter\endcsname \csname XINT_expr_op_-xii\expandafter\endcsname \csname XINT_expr_extra_)\endcsname {expr}% \expandafter\XINT_defop_oparen \csname XINT_expr_op_(\expandafter\endcsname \csname XINT_expr_op_)\expandafter\endcsname \csname XINT_expr_oparen\expandafter\endcsname \csname XINT_expr_check-_)\expandafter\endcsname \csname XINT_expr_checkp_)\expandafter\endcsname \csname XINT_expr_op_-xii\endcsname {expr}% \catcode`) 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{The comma as binary operator} %\begin{lverb} % New with 1.09a. Refactored at 1.4. %\end{lverb} % \begin{macrocode} \expandafter\XINT_defop_comma \csname XINT_expr_op_,\expandafter\endcsname \csname XINT_expr_exec_,\expandafter\endcsname \csname XINT_expr_check-_,\expandafter\endcsname \csname XINT_expr_checkp_,\expandafter\endcsname \csname XINT_expr_op_-xii\endcsname {expr}% % \end{macrocode} % \subsection{The minus as prefix operator of variable precedence level} % \begin{macrocode} \xintApplyInline{\XINT_defop_minus {expr}\xintOpp}{{xii}{xiv}{xvii}}% % \end{macrocode} % \subsection{The \texorpdfstring{\protect\lowast}{*}{} as Python-like «unpacking» prefix operator} % \begin{macrocode} \expandafter\XINT_defpost_unpack\csname XINT_expr_op_0\expandafter\endcsname \csname XINT_expr_until_unpack\endcsname {expr}% % \end{macrocode} % \subsection{\cshnolabel{xintPow}} %\begin{lverb} %(\xintPow{a}{b} -> raw value of a^b %) % xintexpr.sty redefines xintfrac's \xintPow: ^, ** and pow() of % \xinteval use it. b = 0: 1[0]. b an integer: exact power % (xintfrac) if numerator and denominator of the result have at most % about 10000 digits, else xintfrac's float power at \XINTdigits. b not % an integer (half-integers included): \calxFpPow, the power of % \xintfloateval, its result converted to raw. a = 0, b < 0: % InvalidOperation, value 0 (as 1/0 in \xinteval). %\end{lverb} % \begin{macrocode} \def\xintPow{\romannumeral0\xintpow}% \def\xintpow#1#2% {% \expandafter\XINT_scipow_a\romannumeral0\xintrez{#2}\XINT_pow_int{#1}% }% \def\XINT_scipow_a #1% {% \xint_gob_til_zero#1\XINT_scipow_Biszero0\XINT_scipow_b#1% }% \def\XINT_scipow_Biszero#1]#2#3{ 1[0]}% \def\XINT_scipow_b #1#2/#3[#4]#5% {% \unless\if1\XINT_is_One#3XY\xint_dothis\XINT_scipow_c\fi \ifnum#4<\xint_c_ \xint_dothis\XINT_scipow_c\fi \xint_orthat#5#1#2/#3[#4]% }% \def\XINT_scipow_c #1[#2]#3% {% \ifnum\xintSgn{#3}=\xint_c_ \expandafter\XINT_scipow_z \else\expandafter\XINT_scipow_e\fi #1[#2]{#3}% }% \def\XINT_scipow_e #1[#2]#3{\CALX_ftoraw{\calxFpPow{#3}{#1[#2]}}}% \def\XINT_scipow_z #1#2[#3]#4% {% \if-#1\xint_dothis{\XINT_legacysignalcondition{InvalidOperation}% {0 raised to power #1#2[#3].}{}{ 0[0]}}\fi \xint_orthat{ 0[0]}% }% \def\XINT_pow_int #1/1[#2]% {% \expandafter\XINT_pow_int_a\romannumeral0\XINT_dsx_addzeros{#2}#1;.% }% \def\XINT_pow_int_a #1#2.% {% \ifnum\if-#1\xintLength{#2}\else\xintLength{#1#2}\fi>\xint_c_iv \expandafter\XINT_pow_bigint \else\expandafter\XINT_pow_int_b \fi #1#2.% }% \def\XINT_pow_bigint #1.#2% {% \XINT_flpower_checkB_a#1.\XINTdigits.{#2}{\XINTinfloatS[\XINTdigits]}% }% \def\XINT_pow_int_b #1.#2% {% \expandafter\XINT_pow_int_c\romannumeral0\xintraw{#2}\xint:#1\xint: }% \def\XINT_pow_int_c#1#2/#3[#4]\xint:#5\xint: {% \if0\ifnum\numexpr\xint_c_e_iv/% (\xintLength{#1#2}\if-#1-\xint_c_i\fi)<\XINT_Abs#5 % 1\else \ifnum\numexpr\xint_c_e_iv/\xintLength{#3}<\XINT_Abs#5 % 1\else 0\fi\fi \expandafter\XINT_fpow_fork\else\expandafter\XINT_pow_bigint_i \fi #5\Z{#4}{#1#2}{#3}% }% \def\XINT_pow_bigint_i#1\Z#2#3#4% {% \XINT_flpower_checkB_a#1.\XINTdigits.{#3/#4[#2]}{\XINTinfloatS[\XINTdigits]}% }% \def\XINT_expr_func_pow #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintPow#3}}% }% % \end{macrocode} % \subsubsection{\&\&, \textbar\textbar, //, /:, +, % \textendash, \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, % \texorpdfstring{\protect\lowast\protect\lowast}{**}{}, \textquotesingle and\textquotesingle, \textquotesingle % or\textquotesingle, \textquotesingle xor\textquotesingle, and % \textquotesingle mod\textquotesingle} % \begin{macrocode} \XINT_expr_defbin_a {expr} {||} {6} {6} \calxOR \catcode`& 12 \XINT_expr_defbin_a {expr} {&&} {8} {8} \calxAND \catcode`& 7 \XINT_expr_defbin_a {expr} {xor}{6} {6} \calxXOR \XINT_expr_defbin_a {expr} {//} {14}{14}\xintDivFloor \XINT_expr_defbin_a {expr} {/:} {14}{14}\xintMod \XINT_expr_defbin_a {expr} + {12}{12}\xintAdd \XINT_expr_defbin_a {expr} - {12}{12}\xintSub \XINT_expr_defbin_a {expr} * {14}{14}\xintMul \XINT_expr_defbin_a {expr} / {14}{14}\xintDiv \XINT_expr_defbin_a {expr} ^ {18}{17}\xintPow \catcode`& 12 \expandafter\let\csname XINT_expr_op_and\expandafter\endcsname \csname XINT_expr_op_&&\endcsname \expandafter\let\csname XINT_expr_op_or\expandafter\endcsname \csname XINT_expr_op_||\endcsname \expandafter\let\csname XINT_expr_op_mod\expandafter\endcsname \csname XINT_expr_op_/:\endcsname \catcode`& 7 % \end{macrocode} % \subsubsection{.., ..[, and ].. for a..b and a..[b]..c syntax} %\begin{lverb} % a..[d]..b of \xinteval. Contrarily to a..b which is limited to small % integers, this works with a, b, and d (big) fractions. It will produce a «nil» list, if a>b and % d<0 or a0. %\end{lverb} % % \paragraph{\csh{xintSeqA}} % % \begin{macrocode} \def\xintSeqA {\expandafter\XINT_SeqA\romannumeral0\xintraw}% \def\XINT_SeqA #1]#2{\expandafter\XINT_SeqA_a\romannumeral0\xintraw {#2}#1]}% \def\XINT_SeqA_a #1{\xint_UDzerominusfork #1-{z}% 0#1{n}% 0-{p}% \krof #1}% % \end{macrocode} % \paragraph{\csh{xintSeqB:tl:x}} %\begin{lverb} % At 1.4, delayed expansion of start and step done here and not before, % for matters of \xintdeffunc and «NEhooks». % % The float variant at 1.4 is made identical to the exact variant. I.e. % stepping is exact and comparison to the range limit too. But recall that a/b % input will be converted to a float. To handle 1/3 step for example still % better to use \xintexpr 1..1/3..10\relax for example inside the \xintfloateval. % %\end{lverb} % \begin{macrocode} \def\xintSeqB:tl:x #1{\expandafter\XINT_SeqB:tl:x\romannumeral`&&@\xintSeqA#1}% \def\XINT_SeqB:tl:x #1{\csname XINT_SeqB#1:tl:x\endcsname}% \def\XINT_SeqBz:tl:x #1]#2]#3{{#2]}}% \def\XINT_SeqBp:tl:x #1]#2]#3% {\expandafter\XINT_SeqBp:tl:x_a\romannumeral0\xintraw{#3}#2]#1]}% \def\XINT_SeqBp:tl:x_a #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {}{{#2]}}{{#2]}\expandafter\XINT_SeqBp:tl:x_b\romannumeral0\xintadd{#3]}{#2]}#1]#3]}% }% \def\XINT_SeqBp:tl:x_b #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {{#1]}\expandafter\XINT_SeqBp:tl:x_b\romannumeral0\xintadd{#3]}{#1]}#2]#3]}{{#1]}}{}% }% \def\XINT_SeqBn:tl:x #1]#2]#3% {\expandafter\XINT_SeqBn:tl:x_a\romannumeral0\xintraw{#3}#2]#1]}% \def\XINT_SeqBn:tl:x_a #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {{#2]}\expandafter\XINT_SeqBn:tl:x_b\romannumeral0\xintadd{#3]}{#2]}#1]#3]}{{#2]}}{}% }% \def\XINT_SeqBn:tl:x_b #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {}{{#1]}}{{#1]}\expandafter\XINT_SeqBn:tl:x_b\romannumeral0\xintadd{#3]}{#1]}#2]#3]}% }% \XINT_expr_defbin_b {expr}% \XINT_expr_defbin_c {expr} {..}\xintSeq:tl:x \XINT_expr_defbin_c {expr} {]..}\xintSeqB:tl:x % \end{macrocode} % \subsubsection{<, >, ==, <=, >=, != with Python-like chaining} % \begin{macrocode} \XINT_expr_defbin_d {expr} <\xintLt \XINT_expr_defbin_d {expr} >\xintGt \XINT_expr_defbin_d {expr} {==}\xintEq \XINT_expr_defbin_d {expr} {<=}\xintLtorEq \XINT_expr_defbin_d {expr} {>=}\xintGtorEq \XINT_expr_defbin_d {expr} {!=}\xintNotEq % \end{macrocode} % \subsubsection{[...] as «oneple» constructor} % \begin{macrocode} \XINT_expr_defbin_e {expr}% % \end{macrocode} % \subsubsection{[...] brackets and : operator for NumPy-like slicing and item % indexing syntax} % \begin{macrocode} \XINT_expr_defbin_f {expr}% \XINT_expr_defbin_g {expr}% % \end{macrocode} % \subsection{Support for raw A/B[N]} % See comments in \calxnameimp. % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`& 11 }^^A % \begin{macrocode} \catcode0 11 \let\XINT_expr_precedence_&&@ \xint_c_xiv \def\XINT_expr_op_&&@ #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\xintE#1{\xint_zapspaces #2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \catcode2 11 \let\XINT_expr_op_&&B\XINT_flexpr_op_&&B \catcode2 12 \catcode3 11 \let\XINT_expr_op_&&C \XINT_flexpr_op_&&C \catcode3 12 \catcode0 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{? as two-way and ?? as three-way «short-circuit» conditionals} % \begin{macrocode} \catcode`- 11 % \end{macrocode} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT_expr_op_? {\XINT_expr_op__? \XINT_expr_op_-xii}% \catcode`- 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{! as postfix factorial operator} % \begin{macrocode} \def\XINT_expr_op_! #1% {% \expandafter\XINT_expr_put_op_first \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintFac#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} % \subsection{User defined variables: \csh{xintdefvar}} % \begin{macrocode} \def\xintdefvar {\xintexprSafeCatcodes\xintdefvar_a}% \def\xintdefvar_a#1={\XINT_expr_defvar\xintthebareeval{#1}}% % \end{macrocode} % \subsection{\cshnolabel{qfrac()} of \cshnolabel{xinteval}} %\begin{lverb} % The legacy qfrac() (\xintRaw: any xintfrac input, exact) for \xinteval % only; the \xintfloateval and \xintiieval ones are calx.sty's (strict % A/B) and are not changed. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_qfrac #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\xintRaw{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% % \end{macrocode} % \subsection{Regular built-in functions} % \begin{macrocode} \let\XINT_expr_func_num\XINT_iiexpr_func_num % \end{macrocode} %\begin{lverb} % reduce() and preduce() (xintfrac's \xintIrr, \xintPIrr) of \xinteval; % calx gives none for \xintfloateval: xintexpr.sty adds them, the same % macros. reduce(): \xintIrrz, \xintIrr's output with [0] appended (the % [0] follows the input of \XINT_irr_start, as the [N] of \xintPIrr). % Not user level. %\end{lverb} % \begin{macrocode} \def\xintIrrz {\romannumeral0\xintirrz }% \def\xintirrz #1% {% \expandafter\XINT_irr_start\romannumeral0\xintrawwithzeros {#1}\Z[0]% }% \def\XINT_expr_func_reduce #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintIrrz#3}}% }% \def\XINT_expr_func_preduce #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintPIrr#3}}% }% \let\XINT_flexpr_func_reduce\XINT_expr_func_reduce \let\XINT_flexpr_func_preduce\XINT_expr_func_preduce \def\XINT_expr_func_abs #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintAbs#3}}% }% \let\XINT_expr_func_sgn\XINT_iiexpr_func_sgn \def\XINT_expr_func_frac #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintTFrac#3}}% }% \def\XINT_expr_func_floor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintFloor#3}}% }% \def\XINT_expr_func_ceil #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintCeil#3}}% }% \def\XINT_expr_func_sqr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintSqr#3}}% }% \let\XINT_expr_func_? \XINT_iiexpr_func_? \let\XINT_expr_func_! \XINT_iiexpr_func_! \let\XINT_expr_func_not \XINT_iiexpr_func_not \def\XINT_expr_func_odd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintOdd#3}}% }% \def\XINT_expr_func_even #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintEven#3}}% }% \def\XINT_expr_func_isint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintIsInt#3}}% }% \def\XINT_expr_func_isone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintIsOne#3}}% }% \def\XINT_expr_func_factorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\xintFac\XINTinFloatFac }}% }% \let\XINT_expr_func_sqrt\XINT_flexpr_func_sqrt \def\XINT_expr_func_inv #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintInv#3}}% }% % \end{macrocode} % \changed{2.0a1} % % Eversince |1.4a| and the support for negative arguments the functions % round(x,n) and trunc(x,n) were half-broken in both \csbxint{eval} % and \csbxint{floateval} because the underlying \csbxint{Round} and % \csbxint{Trunc} with a negative rounding argument produced scientific % notation which is not acceptable in leaves which apply \cs{detokenize} % hence a catcode 12 e breaking \csbxint{floateval} printer. % \begin{macrocode} \def\xintRoundToRaw#1{\romannumeral0\expandafter\xintroundtoraw\the\numexpr#1.}% \def\xintroundtoraw#1.#2{\xintiround{#1}{#2}[-#1]}% \def\XINT_expr_func_round #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:tacitzeroifone:direct \XINT:expr:f:tacitzeroifone #3,!\xintiRound\xintRoundToRaw }}% }% \def\xintTruncToRaw#1{\romannumeral0\expandafter\xinttrunctoraw\the\numexpr#1.}% \def\xinttrunctoraw#1.#2{\xintitrunc{#1}{#2}[-#1]}% \def\XINT_expr_func_trunc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:tacitzeroifone:direct \XINT:expr:f:tacitzeroifone #3,!\xintiTrunc\xintTruncToRaw }}% }% \def\XINT_expr_func_float #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\XINTinFloatdigits\XINTinFloat }}% }% \def\XINT_expr_func_float_dgt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatdigits#3}}% }% \def\XINT_expr_func_sfloat #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\XINTinFloatSdigits\XINTinFloatS }}% }% \expandafter\def\csname XINT_expr_func_ilog10\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\xintiLogTen\XINTFloatiLogTen }}% }% \def\XINT_expr_func_divmod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintDivMod #3}}% }% \def\XINT_expr_func_mod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintMod#3}}% }% \def\XINT_expr_func_binomial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintBinomial #3}}% }% \def\XINT_expr_func_pfactorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintPFactorial #3}}% }% \let\XINT_expr_func_randrange\XINT_flexpr_func_randrange % \end{macrocode} %\begin{lverb} % gcd() and lcm() of \xinteval: xintfrac's \XINT_GCDof, \XINT_LCMof % (fractions, raw A/B[0] output). calx gives none for \xintfloateval: % xintexpr.sty adds them, the same macros (items converted to raw by % xintfrac's input parser, \CALX_infr; output left raw as legacy). %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_gcd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_GCDof#3^}}% }% \def\XINT_expr_func_lcm #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_LCMof#3^}}% }% \let\XINT_flexpr_func_gcd\XINT_expr_func_gcd \let\XINT_flexpr_func_lcm\XINT_expr_func_lcm \def\XINT_expr_func_max #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Maxof#3^}}% }% \def\XINT_expr_func_min #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Minof#3^}}% }% \expandafter \def\csname XINT_expr_func_+\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Sum#3^}}% }% \expandafter \def\csname XINT_expr_func_*\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Prd#3^}}% }% \let\XINT_expr_func_all\XINT_iiexpr_func_all \let\XINT_expr_func_any\XINT_iiexpr_func_any \let\XINT_expr_func_xor\XINT_iiexpr_func_xor \let\XINT_expr_func_len\XINT_iiexpr_func_len \let\XINT_expr_func_first\XINT_flexpr_func_first \let\XINT_expr_func_last\XINT_flexpr_func_last \let\XINT_expr_func_reversed\XINT_flexpr_func_reversed \let\XINT_expr_func_if\XINT_flexpr_func_if % \end{macrocode} %\begin{lverb} % ifint() and ifone() of \xinteval: xintfrac's \xintifInt, \xintifOne, for % its values (any xintfrac input, fractions); the calx ones of % \xintiieval and \xintfloateval are for the native values. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_ifint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifInt #3}}% }% \def\XINT_expr_func_ifone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifOne #3}}% }% \let\XINT_expr_func_ifsgn\XINT_flexpr_func_ifsgn \let\XINT_expr_func_nuple\XINT_flexpr_func_nuple \let\XINT_expr_func_unpack\XINT_flexpr_func_unpack \let\XINT_expr_func_flat\XINT_flexpr_func_flat \let\XINT_expr_func_zip\XINT_flexpr_func_zip % \end{macrocode} % \subsection{User declared functions} % The mysterious |\XINT_NewFunc| is defined at bottom of this file. % For comments see \calxnameimp. % \begin{macrocode} \def\xintdeffunc{\xintexprSafeCatcodes\xintdeffunc_a}% \XINT_def_deffunc \xintdeffunc_a{expr}\XINT_NewFunc{expr}\xintdeffunc_b \def\xintdefufunc{\xintexprSafeCatcodes\xintdefufunc_a}% \XINT_def_defufunc \xintdefufunc_a{expr}\XINT_NewFunc{expr}\xintdefufunc_b\xintdefufunc_c % \end{macrocode} % \subsubsection{\cshnolabel{xintunassignexprfunc}} % \begin{macrocode} \XINT_def_unassignfunc{expr}% % \end{macrocode} % \subsubsection{\csh{xintNewExpr}, \csh{xintNewIExpr}, \csh{xintNewBoolExpr}, % \csh{xintNewFloatExpr}, \csh{xintNewIIExpr}} %\begin{lverb} % 1.2c modifications to accomodate \XINT_expr_deffunc_newexpr etc.. % % 1.2f adds token \XINT_newexpr_clean to be able to have a different % \XINT_newfunc_clean. % % As \XINT_NewExpr always execute \XINT_expr_redefineprints since 1.3e whether % with \xintNewExpr or \XINT_NewFunc, it has been moved from argument to % hardcoded in replacement text. % % NO MORE \XINT_expr_redefineprints at 1.4 ! This allows better support for % \xinteval, \xinttheexpr as sub-entities inside an \xintNewExpr. And the % «cleaning» will remove the new \XINTfstop , to maintain backwards % compatibility with former behaviour that created macros expand to explicit % digits and not an encapsulated result. % % (obsolete:) The #2#3 in clean stands for \noexpand\XINTfstop. %\end{lverb} % \changed{1.4n} %\begin{lverb} % The #2#3 in previous paragraph is obsolete, the pattern used for % \XINT_newexpr_clean was formerly #1>#2#3 (not optimal, but legacy), but is % now simply #1\XINTfstop. This is simpler and allows compatibility with % LuaMetaTeX whose \meaning output differs from the one of other engines. %\end{lverb} % \begin{macrocode} \catcode`\~=12 \def\XINT_flexpr_getmacropar #1{% \def\XINT_flexpr_getmacropar ##1% {% \expanded{{{~xintRaw{#1##1}}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% }\expandafter\XINT_flexpr_getmacropar\string#% \def\XINT_iiexpr_getmacropar #1{% \def\XINT_iiexpr_getmacropar ##1% {% \expanded{{{~xintiNum{#1##1}}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% }\expandafter\XINT_iiexpr_getmacropar\string#% \catcode`\~=3 \def\xintNewFloatExpr{\begingroup \let\XINT_expr_getmacropar\XINT_flexpr_getmacropar \XINT_NewExpr_a\xint_firstofone\xintfloatexpr\XINT_newexpr_clean }% \def\xintNewIIExpr{\begingroup \let\XINT_expr_getmacropar\XINT_iiexpr_getmacropar \XINT_NewExpr_a\xint_firstofone\xintiiexpr\XINT_newexpr_clean }% \def\XINT_newexpr_clean #1\XINTfstop{\noexpand\expanded\noexpand\xintNEprinthook}% \def\xintNEprinthook#1.#2{\expanded{\xint_noxpd{#1.}{#2}}}% \def\xintNewExpr {\XINT_NewExpr\xint_firstofone\xintexpr \XINT_newexpr_clean}% \def\xintNewIExpr {\XINT_NewExpr\xint_firstofone\xintiexpr \XINT_newexpr_clean}% \def\xintNewBoolExpr {\XINT_NewExpr\xint_firstofone\xintboolexpr \XINT_newexpr_clean}% \def\XINT_NewFunc {\XINT_NewExpr\xint_gobble_i\xintthebareeval\XINT_newfunc_clean}% \let\XINT_tmpa\undefined \let\XINT_tmpb\undefined \let\XINT_tmpc\undefined \let\XINT_tmpd\undefined \let\XINT_tmpe\undefined \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {xintexpr} % \cleardoublepage\let\xintexprnameUp\undefined %\gardesactifs %\let\relax %\let<*calxcore>\gardesinactifs %^^A-------------------------------------------------- %<*calxcore>^^A--------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxcorenameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \calxcorenameimp implementation} % \RaisedLabel{sec:calxcoreimp} % \addedcalx{2.0a1} % % \localtableofcontents % %\begin{lverb} % The eight-digit block utilities shared by calx and legacy xint arithmetic % are defined here under their original XINT_ names. The native conversions % and arithmetic kernels remain in the CALX_ namespace. The legacy % xintcore.sty depends on calxcore.sty for the shared utilities. %\end{lverb} % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code of this subsection is copied over from the xint packages, with % the package names changed. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@calxcore.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage calxcore Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{calxcore}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of calxcore.sty \ifx\w\relax % but xintkernel.sty not yet loaded. \def\z{\endgroup\input xintkernel.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xintkernel.sty not yet loaded. \def\z{\endgroup\RequirePackage{xintkernel}}% \fi \else \def\z{\endgroup\endinput}% xintkernel already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{calxcore}% [2026/11/01 v2.0a1 Expandable arithmetic on big integers (JFB)]% % \end{macrocode} % %\odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11}^^A % % \subsection{\cshnolabel{xintNum}, \csh{xintiNum}} %\begin{lverb} % For example \xintNum {----+-+++---+----000000000000003} % % Very old routine got completely rewritten at 1.2l. % % New code uses \numexpr governed expansion and fixes some issues of former % version particularly regarding inputs of the \numexpr...\relax type without % \the or \number prefix, and/or possibly no terminating \relax. % % \xintiNum{\numexpr 1}\foo in earlier versions caused premature expansion of % \foo. % % \xintiNum{\the\numexpr 1} was ok, but a bit luckily so. % % Also, up to 1.2k inclusive, the macro fetched tokens eight by eight, and not % nine by nine as is done now. I have no idea why. %\end{lverb} % \begin{macrocode} \def\xintiNum {\romannumeral0\xintinum }% \def\xintinum #1% {% \expandafter\XINT_num_cleanup\the\numexpr\expandafter\XINT_num_loop \romannumeral`&&@#1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z }% \def\xintNum {\romannumeral0\xintnum }% \let\xintnum\xintinum % \end{macrocode} % Attention |\xintnum| (hence |\xintNum|) gets redefined by % \xintfracnameimp. Click on names to see the redefinition there. % \begin{macrocode} \def\XINT_num #1% {% \expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop #1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z }% \def\XINT_num_loop #1#2#3#4#5#6#7#8#9% {% \xint_gob_til_xint: #9\XINT_num_end\xint: #1#2#3#4#5#6#7#8#9% \ifnum \numexpr #1#2#3#4#5#6#7#8#9+\xint_c_ = \xint_c_ % \end{macrocode} %\begin{lverb} % means that so far only signs encountered, (if syntax is legal) then possibly % zeroes % or a terminated or not terminated \numexpr evaluating to zero % In that latter case a correct zero will be produced in the end. %\end{lverb} % \begin{macrocode} \expandafter\XINT_num_loop \else % \end{macrocode} %\begin{lverb} % non terminated \numexpr (with nine tokens total) are % safe as after \fi, there is then \xint: %\end{lverb} % \begin{macrocode} \expandafter\relax \fi }% \def\XINT_num_end\xint:#1\xint:{#1+\xint_c_\xint:}% empty input ok \def\XINT_num_cleanup #1\xint:#2\Z { #1}% % \end{macrocode} % \subsection{\csh{xintiiSgn}} % Moved to \calxcorenameimp for STUPID REASONS. Too painful to comment. %\begin{lverb} % 1.2l made \xintiiSgn robust against non terminated input. % % 1.2o deprecates here \xintSgn (it requires xintfrac.sty). %\end{lverb} % \begin{macrocode} \def\xintiiSgn {\romannumeral0\xintiisgn }% \def\xintiisgn #1% {% \expandafter\XINT_sgn \romannumeral`&&@#1\xint: }% \def\XINT_sgn #1#2\xint: {% \xint_UDzerominusfork #1-{ 0}% 0#1{-1}% 0-{ 1}% \krof }% \def\XINT_Sgn #1#2\xint: {% \xint_UDzerominusfork #1-{0}% 0#1{-1}% 0-{1}% \krof }% \def\XINT_cntSgn #1#2\xint: {% \xint_UDzerominusfork #1-\xint_c_ 0#1\xint_c_mone 0-\xint_c_i \krof }% % \end{macrocode} % \subsection{\csh{xintiiOpp}} % Moved to \calxcorenameimp for STUPID REASONS. Too painful to comment. %\begin{lverb} % Attention, \xintiiOpp non robust against non terminated inputs. % Reason is I don't want to have to grab a delimiter at the end, as everything % happens "upfront". %\end{lverb} % \begin{macrocode} \def\xintiiOpp {\romannumeral0\xintiiopp }% \def\xintiiopp #1% {% \expandafter\XINT_opp \romannumeral`&&@#1% }% \def\XINT_Opp #1{\romannumeral0\XINT_opp #1}% \def\XINT_opp #1% {% \xint_UDzerominusfork #1-{ 0}% zero 0#1{ }% negative 0-{ -#1}% positive \krof }% % \end{macrocode} % \subsection{\csh{xintiiCmp}} % The reason for it to be here is a completely silly situation which has % cost the author perhaps 6 hours due to incompetent assistant preferring % to work in secret and keep major decisions to itself. It may be provisory % but will not be modified for |2.0a1|. % \changed[2022/06/05]{1.4m} % Now uses the |\xintstrcmp| engine primitive. % \begin{macrocode} \def\xintiiCmp {\romannumeral0\xintiicmp }% \def\xintiicmp #1{\expandafter\XINT_iicmp\romannumeral`&&@#1\xint:}% \def\XINT_iicmp #1#2\xint:#3% {% \expandafter\XINT_cmp_nfork\expandafter #1\romannumeral`&&@#3\xint:#2\xint: }% \def\XINT_cmp_nfork #1#2% {% \xint_UDzerofork #1\XINT_cmp_firstiszero #2\XINT_cmp_secondiszero 0{}% \krof \xint_UDsignsfork #1#2\XINT_cmp_minusminus #1-\XINT_cmp_minusplus #2-\XINT_cmp_plusminus --\XINT_cmp_plusplus \krof #1#2% }% \def\XINT_cmp_firstiszero #1\krof 0#2#3\xint:#4\xint: {% \xint_UDzerominusfork #2-{ 0}% 0#2{ 1}% 0-{ -1}% \krof }% \def\XINT_cmp_secondiszero #1\krof #20#3\xint:#4\xint: {% \xint_UDzerominusfork #2-{ 0}% 0#2{ -1}% 0-{ 1}% \krof }% \def\XINT_cmp_plusminus #1\xint:#2\xint:{ 1}% \def\XINT_cmp_minusplus #1\xint:#2\xint:{ -1}% \def\XINT_cmp_minusminus --{\expandafter\XINT_opp\romannumeral0\XINT_cmp_plusplus {}{}}% % \end{macrocode} %\begin{lverb} % The \romannumeral0 trigger induces some complications here to terminate % nicely without grabbing too many tokens in the stream or deteriorating % expansion quality of the non-equal-length branches. % \expanded simplifies things. %\end{lverb} % \begin{macrocode} \def\XINT_cmp_plusplus #1#2#3\xint:#4\xint:{\expanded{ % \ifcase\expandafter\XINT_cntSgn\the\numexpr\xintLength{#1#4}-\xintLength{#2#3}\xint: \xintstrcmp{#1#4}{#2#3}\or1\else-1\fi }% }% % \end{macrocode} % \subsection{Exceptional conditions: signals, flags, handlers, traps} % The code of this section comes from the unfinished signal code of % |xintcore.sty| (dating back to |1.2l|), renamed, kept in the core module, % and completed. %\begin{lverb} % As per the Mike Cowlishaw/IBM's General Decimal Arithmetic Specification % % http://speleotrove.com/decimal/decarith.html % % and the Python3 implementation in its Decimal module. % % Clamped, ConversionSyntax, DivisionByZero, DivisionImpossible, % DivisionUndefined, Inexact, InsufficientStorage, InvalidContext, % InvalidOperation, Overflow, Inexact, Rounded, Subnormal, % Underflow. % % X3.274 rajoute LostDigits % % Python rajoute FloatOperation (et n'inclut pas InsufficientStorage) % % quote de decarith.pdf: % The Clamped, Inexact, Rounded, and Subnormal conditions can coincide with % each other or with other conditions. In these cases then any trap enabled % for another condition takes precedence over (is handled before) all of % these, any Subnormal trap takes precedence over Inexact, any Inexact trap % takes precedence over Rounded, and any Rounded trap takes precedence over % Clamped. % % This was initiated at 1.2l (2017/07/26), but the possibility to % customize handlers was never finished nor documented for users. % Completely redone for 2.0a1 (2026/11/01). % % Model: the decimal module of Python (as for the xintcore code), with the % IEEE 754 default % exception handling as default configuration: a condition raises a flag and % is handled, the handler returns a default result, and NO TeX error is % emitted. Emitting an (expandable) error is an opt-in, per signal, via % \calxsetup. % % Vocabulary (that of Python's decimal module): %- a CONDITION is what a calx macro detects and reports; %- each condition belongs to a SIGNAL; for most conditions, condition and % signal are the same; five conditions belong to signal InvalidOperation: %( ConversionSyntax (input which is not a number) %: DivisionImpossible (integer division result does not fit) %: DivisionUndefined (0/0) %: InvalidContext (invalid configuration) %: ControversialOperation (argument too large for a periodic function) %) %- there are eight signals: Clamped, DivisionByZero, Inexact, % InvalidOperation, Overflow, Rounded, Subnormal, Underflow; %- each SIGNAL has a FLAG (raised or not) and a TRAP (set or not); %- each CONDITION has a HANDLER. % % What happens when calx code signals a condition C of signal S, via %( \CALX_signalcondition{C}{}{}{} %) % (this is \CALX_signalcondition_a below, Python's Context._raise_error): %- 1. if S is "ignored" (control sequence \CALX_S_isignoredflag defined; % Python's Context._ignored_flags), the handler of S is applied to % , and that is all: no flag is raised; %- 2. otherwise the flag of S is raised; then %- 3. if S is not trapped (the default for all signals), the handler of C is % applied to , and its result is the result; %- 4. if S is trapped, an expandable error is emitted with , and the % result is , the value the calling macro would return % without the signal machinery (e.g. what xint returns: 0 on division by % zero). % % No calx code sets the "ignored" status at this stage; it is kept from % the xintcore code (and Python) for internal computations which must not % leave traces in the flags. It is set by \let\CALX_S_isignoredflag\relax (via % \csname) and cleared by \let to \XINT_undefined. % % Default handlers (Python's decimal: the "handle" method of each condition % class; a class without "handle" returns None in Python, meaning the caller % keeps the result it has computed, which here is the handler argument): %( condition handler argument result %: ------------------------------------------------------------------ %: InvalidOperation (ignored) I? (NaN) %: ConversionSyntax (ignored) I? %: DivisionImpossible (ignored) I? %: DivisionUndefined (ignored) I? %: InvalidContext (ignored) I? %: ControversialOperation (ignored) I? %: DivisionByZero sign + or - I+ or I- (+-Infinity) %: Overflow sign + or - I+ or I- %: Underflow computed result the argument %: Clamped computed result the argument %: Inexact computed result the argument %: Rounded computed result the argument %: Subnormal computed result the argument %) % I, ?, + and - in results are catcode 12 characters, the special value % markers of the calx internal format (I+ is +Infinity, I- is -Infinity, I? % is NaN). The sign handed to the DivisionByZero and Overflow handlers must be % a catcode 12 + or -. Printing the special values as NaN, Infinity, % -Infinity is not done here: it is the task of the output macros of the % arithmetic modules. % % Overflow: Python returns +-Infinity or the largest finite number, depending % on the rounding mode. calx rounds half away from zero, for which Python % (ROUND_HALF_UP) returns +-Infinity. % % FLAGS. A flag of signal S is raised when \CALX_SFlag_ON is defined. It is % raised EXPANDABLY by %( \expandafter\xint_gobble_i\csname CALX_SFlag_ON\endcsname %) % which uses the fact that \csname...\endcsname, if the name is undefined, % \let's it to \relax as a side effect. This assignment is ALWAYS LOCAL to % the current group (checked under etex: even with \globaldefs=1). Hence: %- a flag raised by a computation done inside a group (\begingroup or braces, % an \hbox, an alignment cell, ...) is down again after the group ends; %- a flag is raised only when the computation is actually expanded: inside % an \edef, an \expanded, a \message, a \csname, or f-expansion; storing % an unexpanded computation in a macro via \def raises nothing. % % A user wanting a flag to survive a group tests it before the group ends % and makes the information global by his own means. % % Testing (expandable) and lowering (NOT expandable): %( \calxifflagraised{S}{}{} %: \calxresetflag{S} %: \calxresetflags (the eight flags) %) % Lowering obeys \ifxintglobaldefs (via \XINT_global): it is global if % \xintglobaldefstrue, local otherwise. % % CONFIGURATION, \calxsetup. Same syntax and method as \bnumsetup of bnumexpr: % a comma separated list of key=value; spaces around keys are % removed; a final comma does no harm; each key performs a \let; assignments % are global if \xintglobaldefstrue, local otherwise (\XINT_global); with % \xintverbosetrue each assignment is reported on the terminal and in the log % (\xintMessage). % % Keys: %( .trap = true (or false) for each of the eight signals %: .handler = \macro for each of the thirteen conditions %) % e.g. %( \calxsetup{DivisionByZero.trap = true, InvalidOperation.trap = true} %) % gives back the behaviour of xint (expandable error, then xint's default % result) for these two signals. % % A handler is a macro with ONE argument, the handler argument; it must % expand to the result (in the contexts where calx macros use it, it is % expanded by f-expansion). For example a user preferring that conversion % errors give zero, in the calx internal format of zero, would \let the % ConversionSyntax handler to a macro expanding to that. The value of % .handler must be a single control sequence (the \let receives only % that). % % An unknown key, or a value other than true and false for a .trap key, is % reported by a (non expandable) TeX error, \calxsetup being itself not % expandable. %\end{lverb} % \begin{macrocode} \catcode`- 11 \def\CALX_ConversionSyntax-signal {{InvalidOperation}}% \let\CALX_DivisionImpossible-signal\CALX_ConversionSyntax-signal \let\CALX_DivisionUndefined-signal \CALX_ConversionSyntax-signal \let\CALX_InvalidContext-signal \CALX_ConversionSyntax-signal \let\CALX_ControversialOperation-signal\CALX_ConversionSyntax-signal \catcode`- 12 % \end{macrocode} % \subsubsection{\csh{CALX_signalcondition}} %\begin{lverb} % Syntax (f-expandable): %( % \CALX_signalcondition{C}{M}{H}{V} -> %) % C a signal or condition name (InvalidOperation, DivisionByZero, ...), % M the error message, H the handler argument, V the value returned if the % signal is trapped; : the handler's value (or V). % % \CALX_signalcondition$empty: identical to \XINT_signalcondition % (xintcore.sty of xint 1.4p), renamed. The first \romannumeral0 step turns % #1 into {}{}, then \CALX_signalcondition_a receives %( #1 = signal, #2 = condition, #3 = error message, %: #4 = handler argument, #5 = value returned if the signal is trapped. %) % Note that, as in Python, the "ignored" branch applies the handler of the % SIGNAL, the untrapped branch the handler of the CONDITION. % % The expansion is complete (handler included) under f-expansion. The handlers % defined here expand in one step to their result. %\end{lverb} % \begin{macrocode} \def\CALX_signalcondition #1{\expandafter\CALX_signalcondition_a \romannumeral0\ifcsname CALX_#1-signal\endcsname \xint_dothis{\csname CALX_#1-signal\endcsname}% \fi\xint_orthat{{#1}}{#1}}% \def\CALX_signalcondition_a % #1#2#3#4#5{% copied over from Python Decimal module \ifcsname CALX_#1_isignoredflag\endcsname \xint_dothis{\csname CALX_#1.handler\endcsname {#4}}% \fi \expandafter\xint_gobble_i\csname CALX_#1Flag_ON\endcsname \unless\ifcsname CALX_#1_istrapped\endcsname \xint_dothis{\csname CALX_#2.handler\endcsname {#4}}% \fi \xint_orthat{% % the flag raised is named after the signal #1, but we show condition % #2 \XINT_expandableerror{#3}% \xint_firstofone{#5}% }% }% \let\XINT_signalcondition\CALX_signalcondition % \end{macrocode} %\begin{lverb} % Flags. \CALX_RaiseFlag is xintcore's \XINT_RaiseFlag, for direct use by calx % code (raising a flag without going through a handler). The public test and % reset macros are xintcore's \XINT_ifFlagRaised, \XINT_resetFlag, % \XINT_resetFlags made public; the reset obeys \XINT_global, and resets all % eight flags (the xintcore version listed four). %\end{lverb} % \begin{macrocode} \def\CALX_RaiseFlag #1{\expandafter\xint_gobble_i\csname CALX_#1Flag_ON% \endcsname}% % \end{macrocode} % \subsubsection{\csh{calxifflagraised}, \csh{calxresetflag}, % \csh{calxresetflags}} % \begin{macrocode} \def\calxifflagraised #1{% \ifcsname CALX_#1Flag_ON\endcsname \expandafter\xint_firstoftwo \else \expandafter\xint_secondoftwo \fi}% % \end{macrocode} % \subsubsection{\csh{xintifNonFiniteSignalled}} %\begin{lverb} % True if InvalidOperation, DivisionByZero or Overflow was signalled in % the current group since the last corresponding flag reset. The flags % describe conditions, not the result: a handler can return a finite value. % Literal NaN/Infinity values alone do not raise flags. %\end{lverb} % \begin{macrocode} \def\xintifNonFiniteSignalled{% \calxifflagraised{InvalidOperation}{\xint_firstoftwo}{% \calxifflagraised{DivisionByZero}{\xint_firstoftwo}{% \calxifflagraised{Overflow}{\xint_firstoftwo}{\xint_secondoftwo}% }% }% }% \def\calxresetflag #1% {\XINT_global\expandafter\let\csname CALX_#1Flag_ON\endcsname% \XINT_undefined}% \def\calxresetflags {% \calxresetflag{Clamped}% \calxresetflag{DivisionByZero}% \calxresetflag{Inexact}% \calxresetflag{InvalidOperation}% \calxresetflag{Overflow}% \calxresetflag{Rounded}% \calxresetflag{Subnormal}% \calxresetflag{Underflow}% }% % \end{macrocode} %\begin{lverb} % Default handlers. The xintcore table had _NaN and _SignedInfinity(#1) as % placeholders; here they are the special value markers, catcode 12, % produced by \detokenize. Underflow, which the xintcore table sent to % _NaN, is the identity as in Python (Underflow is always accompanied by % Inexact and Subnormal, and the result is the rounded one). DivisionByZero % and Overflow both return signed infinity by default (round half up). %\end{lverb} % \begin{macrocode} \catcode`. 11 \let\CALX_Clamped.handler\xint_firstofone \edef\CALX_InvalidOperation.handler#1{\detokenize{I?}}% \let\CALX_ConversionSyntax.handler \CALX_InvalidOperation.handler \let\CALX_DivisionImpossible.handler\CALX_InvalidOperation.handler \let\CALX_DivisionUndefined.handler \CALX_InvalidOperation.handler \let\CALX_InvalidContext.handler \CALX_InvalidOperation.handler \let\CALX_ControversialOperation.handler\CALX_InvalidOperation.handler \edef\CALX_Overflow.handler#1{\detokenize{I}#1}% \let\CALX_DivisionByZero.handler\CALX_Overflow.handler \let\CALX_Inexact.handler\xint_firstofone \let\CALX_Rounded.handler\xint_firstofone \let\CALX_Subnormal.handler\xint_firstofone \let\CALX_Underflow.handler\xint_firstofone \catcode`. 12 % \end{macrocode} %\begin{lverb} % Traps: none is set at load time. (The xintcore code set all eight at load % time: \csname XINT__istrapped\endcsname.) % % \calxsetup$empty: the parsing loop is \bnumsetup's (bnumexpr.dtx), % with the key dispatched through \csname CALX_setup_\endcsname, one % such macro per valid key, defined below. The value is handed over complete % (not only its first token as in \bnumsetup) because .trap keys take a word. % Each CALX_setup_ macro receives {}{}. %\end{lverb} % \begin{macrocode} \catcode`! 3 % \end{macrocode} % \subsubsection{\csh{calxsetup}} % \begin{macrocode} \def\calxsetup #1{\CALX_parsekeys #1,=!,}% \def\CALX_parsekeys #1=#2,% {% \ifx!#2\expandafter\CALX_parsedone\fi \ifcsname CALX_setup_\xint_zapspaces #1 \xint_gobble_i\endcsname \xint_dothis{\csname CALX_setup_\xint_zapspaces #1 \xint_gobble_i% \endcsname}% \fi \xint_orthat{\CALX_setup_badkey}{#1}{#2}% \CALX_parsekeys }% \def\CALX_parsedone #1\CALX_parsekeys {}% \catcode`! 12 \def\CALX_settrap #1#2#3{% \ifnum\xintstrcmp{\xint_zapspaces #3 \xint_gobble_i}{true}=\xint_c_ \XINT_global\expandafter\let\csname CALX_#1_istrapped\endcsname\relax \CALX_setup_info{trap set for signal #1}% \else \ifnum\xintstrcmp{\xint_zapspaces #3 \xint_gobble_i}{false}=\xint_c_ \XINT_global\expandafter\let\csname CALX_#1_istrapped\endcsname% \XINT_undefined \CALX_setup_info{trap removed for signal #1}% \else \CALX_setup_error{value \detokenize{#3} of key \detokenize{#2} is neither true nor false}% \fi\fi }% \def\CALX_sethandler #1#2#3{% \XINT_global\expandafter\let\csname CALX_#1.handler\endcsname=#3% \CALX_setup_info{\string#3 assigned as handler of condition #1}% }% \def\CALX_setup_badkey #1#2{\CALX_setup_error{unknown key \detokenize{#1}}}% \def\CALX_setup_info #1{% \ifxintverbose \xintMessage{calxcore}{Info}{\ifxintglobaldefs (global) \fi #1}% \fi }% \def\CALX_setup_error #1{% \xintMessage{calxcore}{Error}{\string\calxsetup\space #1}% \errhelp{See the comments of calxcore.sty on \string\calxsetup.}% \errmessage{calxcore: invalid input to \string\calxsetup}% }% \def\CALX_tmpa #1{% \expandafter\def\csname CALX_setup_#1.trap\endcsname{\CALX_settrap{#1}}% }% \CALX_tmpa{Clamped}\CALX_tmpa{DivisionByZero}\CALX_tmpa{Inexact}% \CALX_tmpa{InvalidOperation}\CALX_tmpa{Overflow}\CALX_tmpa{Rounded}% \CALX_tmpa{Subnormal}\CALX_tmpa{Underflow}% \def\CALX_tmpa #1{% \expandafter\def\csname CALX_setup_#1.handler\endcsname{% \CALX_sethandler{#1}}% }% \CALX_tmpa{Clamped}\CALX_tmpa{DivisionByZero}\CALX_tmpa{Inexact}% \CALX_tmpa{InvalidOperation}\CALX_tmpa{Overflow}\CALX_tmpa{Rounded}% \CALX_tmpa{Subnormal}\CALX_tmpa{Underflow}% \CALX_tmpa{ConversionSyntax}\CALX_tmpa{DivisionImpossible}% \CALX_tmpa{DivisionUndefined}\CALX_tmpa{InvalidContext}% \CALX_tmpa{ControversialOperation}% \let\CALX_tmpa\XINT_undefined % \end{macrocode} % \subsection{Blocks of eight digits} % % \subsubsection{\csh{XINT_cuz_small}} %\begin{lverb} % \XINT_cuz_small removes leading zeroes from the first eight digits. Expands % following \romannumeral0. At least one digit is produced. %\end{lverb} % \begin{macrocode} \def\XINT_cuz_small#1{% \def\XINT_cuz_small ##1##2##3##4##5##6##7##8% {% \expandafter#1\the\numexpr ##1##2##3##4##5##6##7##8\relax }}\XINT_cuz_small{ }% % \end{macrocode} % \subsubsection{\csh{XINT_zeroes_forviii}} % %\begin{lverb} %( \romannumeral0\XINT_zeroes_forviii #1\R\R\R\R\R\R\R\R{10}0000001\W %) % produces a string of k 0's such that k+length(#1) is smallest bigger multiple % of eight. %\end{lverb} % \begin{macrocode} \def\XINT_zeroes_forviii #1#2#3#4#5#6#7#8% {% \xint_gob_til_R #8\XINT_zeroes_forviii_end\R\XINT_zeroes_forviii }% \def\XINT_zeroes_forviii_end#1{% \def\XINT_zeroes_forviii_end\R\XINT_zeroes_forviii ##1##2##3##4##5##6##7##8##9\W {% \expandafter#1\xint_gob_til_one ##2##3##4##5##6##7##8% }}\XINT_zeroes_forviii_end{ }% % \end{macrocode} % \subsubsection{\csh{XINT_rsepbyviii}} % %\begin{lverb} % This is used as %( \the\numexpr1\XINT_rsepbyviii <8Ndigits>$% %: \XINT_rsepbyviii_end_A 2345678$% %: \XINT_rsepbyviii_end_B 2345678\relax UV$% %) % and will produce %( 1<8digits>!1<8digits>\xint:1<8digits>!... %) % where the original % digits are organized by eight, and the order inside successive pairs of % blocks separated by \xint: has been reversed. Output ends either in % 1<8d>!1<8d>\xint:1U\xint: (even) or 1<8d>!1<8d>\xint:1V!1<8d>\xint: (odd) % % The U an V should be \numexpr1 stoppers (or will expand and be ended by !). % This macro is currently (1.2..1.2l) exclusively used in combination with % \XINT_sepandrev_andcount or \XINT_sepandrev. %\end{lverb} % \begin{macrocode} \def\XINT_rsepbyviii #1#2#3#4#5#6#7#8% {% \XINT_rsepbyviii_b {#1#2#3#4#5#6#7#8}% }% \def\XINT_rsepbyviii_b #1#2#3#4#5#6#7#8#9% {% #2#3#4#5#6#7#8#9\expandafter!\the\numexpr 1#1\expandafter\xint:\the\numexpr 1\XINT_rsepbyviii }% \def\XINT_rsepbyviii_end_B #1\relax #2#3{#2\xint:}% \def\XINT_rsepbyviii_end_A #11#2\expandafter #3\relax #4#5{#5!1#2\xint:}% % \end{macrocode} % \subsubsection{\csh{XINT_sepandrev_andcount}} %\begin{lverb} % This is used typically as %( \romannumeral0\XINT_sepandrev_andcount <8Ndigits>$% %: \XINT_rsepbyviii_end_A 2345678$% %: \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i %: \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi %: \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W %) % and will produce %( .1<8digits>!1<8digits>!1<8digits>!... %) % where the % blocks have been globally reversed and is the number of blocks. %\end{lverb} % \begin{macrocode} \def\XINT_sepandrev_andcount {% \expandafter\XINT_sepandrev_andcount_a\the\numexpr 1\XINT_rsepbyviii }% \def\XINT_sepandrev_andcount_a {\XINT_sepandrev_andcount_b 0!{}}% \def\XINT_sepandrev_andcount_b #1!#2#3\xint:#4\xint:#5\xint:#6\xint:#7\xint:#8\xint:#9\xint:% {% \xint_gob_til_R #9\XINT_sepandrev_andcount_end\R \expandafter\XINT_sepandrev_andcount_b \the\numexpr #1+\xint_c_i!% {#9!#8!#7!#6!#5!#4!#3!#2}% }% \def\XINT_sepandrev_andcount_end\R \expandafter\XINT_sepandrev_andcount_b\the\numexpr #1+\xint_c_i!#2#3#4\W {\expandafter\XINT_sepandrev_andcount_done\the\numexpr #3+\xint_c_xiv*#1!#2}% \def\XINT_sepandrev_andcount_done#1{% \def\XINT_sepandrev_andcount_done##1!##21##3!{\expandafter#1\the\numexpr##1-##3\xint:}% }\XINT_sepandrev_andcount_done{ }% % \end{macrocode} % \subsubsection{\csh{XINT_rev_nounsep}} %\begin{lverb} % This is used as %( \romannumeral0\XINT_rev_nounsep {}!>\R!\R!\R!\R!\R!\R!\R!\R!\W %) % It reverses the blocks, keeping the 1's and ! separators. Used multiple % times in the division algorithm. The inserted {} here is not optional. %\end{lverb} % \begin{macrocode} \def\XINT_rev_nounsep #1#2!#3!#4!#5!#6!#7!#8!#9!% {% \xint_gob_til_R #9\XINT_rev_nounsep_end\R \XINT_rev_nounsep {#9!#8!#7!#6!#5!#4!#3!#2!#1}% }% \def\XINT_rev_nounsep_end\R\XINT_rev_nounsep #1#2\W {\XINT_rev_nounsep_done #1}% \def\XINT_rev_nounsep_done #11{ 1}% % \end{macrocode} % \subsubsection{\csh{XINT_unrevbyviii}} %\begin{lverb} % Used as \romannumeral0\XINT_unrevbyviii 1<8d>!....1<8d>! terminated % by %( 1;!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W %) % The \romannumeral in unrevbyviii_a is for special effects (expand some token % which was put as 1! at the end of the original blocks). This % mechanism is used by 1.2 subtraction (still true for 1.2l). %\end{lverb} % \begin{macrocode} \def\XINT_unrevbyviii #11#2!1#3!1#4!1#5!1#6!1#7!1#8!1#9!% {% \xint_gob_til_R #9\XINT_unrevbyviii_a\R \XINT_unrevbyviii {#9#8#7#6#5#4#3#2#1}% }% \def\XINT_unrevbyviii_a#1{% \def\XINT_unrevbyviii_a\R\XINT_unrevbyviii ##1##2\W {\expandafter#1\romannumeral`&&@\xint_gob_til_sc ##1}% }\XINT_unrevbyviii_a{ }% % \end{macrocode} % \subsubsection{Aliases for native callers} %\begin{lverb} % The native arithmetic section uses I and N with catcode 12. Its callers % use CALX aliases of the common block utilities, whose implementations % remain under the XINT names for the legacy packages. %\end{lverb} % \begin{macrocode} \let\CALX_cuz_small\XINT_cuz_small \let\CALX_zeroes_forviii\XINT_zeroes_forviii \let\CALX_rsepbyviii\XINT_rsepbyviii \let\CALX_rsepbyviii_end_A\XINT_rsepbyviii_end_A \let\CALX_rsepbyviii_end_B\XINT_rsepbyviii_end_B \let\CALX_sepandrev_andcount\XINT_sepandrev_andcount \let\CALX_rev_nounsep\XINT_rev_nounsep \let\CALX_unrevbyviii\XINT_unrevbyviii % \end{macrocode} % \subsection{Core arithmetic} % % \subsubsection{\csh{CALX_add_a}} %\begin{lverb} % From this subsection of xintcore (\xintiiAdd$empty) calx copies only the % macros used by the native layer: \CALX_add_a, \CALX_add_b, \CALX_add_bi, % \CALX_add_c, \CALX_add_d, \CALX_add_di, \CALX_add_e, \CALX_add_f, % \CALX_add_fi, \CALX_add_g, \CALX_add_h, \CALX_add_hi, \CALX_add_i, % \CALX_add_k, \CALX_add_ke, \CALX_add_kf, \CALX_add_l, \CALX_add_lf, % \CALX_add_m, \CALX_add_n, \CALX_add_o. The other macros are not copied. %\end{lverb} % % \begin{macrocode} \def\CALX_add_a #1!#2!#3!#4!#5\W #6!#7!#8!#9!% {% \CALX_add_b #1!#6!#2!#7!#3!#8!#4!#9!% #5\W }% \def\CALX_add_b #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_add_bi ;% \expandafter\CALX_add_c\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_add_bi;\expandafter\CALX_add_c \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6!#7!#8!#9!\W {% \CALX_add_k #1#3!#5!#7!#9!% }% \def\CALX_add_c #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_add_d #1% }% \def\CALX_add_d #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_add_di ;% \expandafter\CALX_add_e\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_add_di;\expandafter\CALX_add_e \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6!#7!#8\W {% \CALX_add_k #1#3!#5!#7!% }% \def\CALX_add_e #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_add_f #1% }% \def\CALX_add_f #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_add_fi ;% \expandafter\CALX_add_g\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_add_fi;\expandafter\CALX_add_g \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6\W {% \CALX_add_k #1#3!#5!% }% \def\CALX_add_g #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_add_h #1% }% \def\CALX_add_h #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_add_hi ;% \expandafter\CALX_add_i\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_add_hi;% \expandafter\CALX_add_i\the\numexpr#1+#2+#3-\xint_c_ii\xint:#4\W {% \CALX_add_k #1#3!% }% \def\CALX_add_i #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_add_a #1% }% \def\CALX_add_k #1{\if #12\expandafter\CALX_add_ke\else\expandafter% \CALX_add_l \fi}% \def\CALX_add_ke #11;#2\W {\CALX_add_kf #11;!}% \def\CALX_add_kf 1{1\relax }% \def\CALX_add_l 1#1{\xint_gob_til_sc #1\CALX_add_lf ;\CALX_add_m 1#1}% \def\CALX_add_lf #1\W {1\relax 00000001!1;!}% \def\CALX_add_m #1!{\expandafter\CALX_add_n\the\numexpr\xint_c_i+#1\xint:}% \def\CALX_add_n #1#2\xint:{1#2\expandafter!\the\numexpr\CALX_add_o #1}% \def\CALX_add_o #1{\if #12\expandafter\CALX_add_l\else\expandafter% \CALX_add_ke \fi}% % \end{macrocode} % \subsubsection{\csh{CALX_mul_loop}, \csh{CALX_smallmul}, % \csh{CALX_verysmallmul}} %\begin{lverb} % From this subsection of xintcore (\xintiiMul$empty) calx copies only the % macros used by the native layer: \CALX_mul_loop, \CALX_mul_a, \CALX_mul_b, % \CALX_mul_e, \CALX_minimulwc_a, \CALX_minimulwc_b, \CALX_minimulwc_c, % \CALX_smallmul, \CALX_smallmul_a, \CALX_smallmul_e, \CALX_smallmul_f, % \CALX_verysmallmul, \CALX_verysmallmul_e, \CALX_verysmallmul_f, % \CALX_verysmallmul_a, \CALX_verysmallmul_bj, \CALX_verysmallmul_cj, % \CALX_verysmallmul_bi, \CALX_minimul_a, \CALX_minimul_b, \CALX_minimul_c. % The other macros are not copied. %\end{lverb} % % \begin{macrocode} \def\CALX_mul_loop #1\W #2\W 1#3!% {% \xint_gob_til_sc #3\CALX_mul_e ;% \expandafter\CALX_mul_a\the\numexpr \CALX_smallmul 1#3!#2\W #1\W #2\W }% \def\CALX_mul_a #1\W #2\W {% \expandafter\CALX_mul_b\the\numexpr \CALX_add_a \xint_c_ii #21;!1;!1;!\W #11;!1;!1;!\W\W }% \def\CALX_mul_b 1#1!{1#1\expandafter!\the\numexpr\CALX_mul_loop }% \def\CALX_mul_e;#1\W 1#2\W #3\W {1\relax #2}% % \end{macrocode} % % \begin{macrocode} \def\CALX_minimulwc_a 1#1\xint:#2\xint:#3!#4#5#6#7#8\xint:% {% \expandafter\CALX_minimulwc_b \the\numexpr \xint_c_e_ix+#1+#3*#8\xint: #3*#4#5#6#7+#2*#8\xint: #2*#4#5#6#7\xint:% }% \def\CALX_minimulwc_b 1#1#2#3#4#5#6\xint:#7\xint:% {% \expandafter\CALX_minimulwc_c \the\numexpr \xint_c_e_ix+#1#2#3#4#5+#7\xint:#6\xint:% }% \def\CALX_minimulwc_c 1#1#2#3#4#5#6\xint:#7\xint:#8\xint:% {% 1#6#7\expandafter!% \the\numexpr\expandafter\CALX_smallmul_a \the\numexpr \xint_c_e_viii+#1#2#3#4#5+#8\xint:% }% \def\CALX_smallmul 1#1#2#3#4#5!{\CALX_smallmul_a 100000000\xint:#1#2#3#4% \xint:#5!}% \def\CALX_smallmul_a #1\xint:#2\xint:#3!1#4!% {% \xint_gob_til_sc #4\CALX_smallmul_e;% \CALX_minimulwc_a #1\xint:#2\xint:#3!#4\xint:#2\xint:#3!% }% \def\CALX_smallmul_e;\CALX_minimulwc_a 1#1\xint:#2;#3!% {\xint_gob_til_eightzeroes #1\CALX_smallmul_f 000000001\relax #1!1;!}% \def\CALX_smallmul_f 000000001\relax 00000000!1{1\relax}% \def\CALX_verysmallmul #1\xint:#2!1#3!% {% \xint_gob_til_sc #3\CALX_verysmallmul_e;% \expandafter\CALX_verysmallmul_a \the\numexpr #2*#3+#1\xint:#2!% }% \def\CALX_verysmallmul_e;\expandafter\CALX_verysmallmul_a\the\numexpr #1+#2#3\xint:#4!% {\xint_gob_til_zero #2\CALX_verysmallmul_f 0\xint_c_e_viii+#2#3!1;!}% \def\CALX_verysmallmul_f #1!1{1\relax}% \def\CALX_verysmallmul_a #1#2\xint:% {% \unless\ifnum #1#2<\xint_c_e_ix \expandafter\CALX_verysmallmul_bi\else \expandafter\CALX_verysmallmul_bj\fi \the\numexpr \xint_c_e_ix+#1#2\xint:% }% \def\CALX_verysmallmul_bj{\expandafter\CALX_verysmallmul_cj }% \def\CALX_verysmallmul_cj 1#1#2\xint:% {1#2\expandafter!\the\numexpr\CALX_verysmallmul #1\xint:}% \def\CALX_verysmallmul_bi\the\numexpr\xint_c_e_ix+#1#2#3\xint:% {1#3\expandafter!\the\numexpr\CALX_verysmallmul #1#2\xint:}% % \end{macrocode} % % \begin{macrocode} \def\CALX_minimul_a #1\xint:#2!#3#4#5#6#7!% {% \expandafter\CALX_minimul_b \the\numexpr \xint_c_e_viii+#2*#7\xint:#2*#3#4#5#6+#1*#7\xint:#1*#3#4#5#6% \xint:% }% \def\CALX_minimul_b 1#1#2#3#4#5\xint:#6\xint:% {% \expandafter\CALX_minimul_c \the\numexpr \xint_c_e_ix+#1#2#3#4+#6\xint:#5\xint:% }% \def\CALX_minimul_c 1#1#2#3#4#5#6\xint:#7\xint:#8\xint:% {% 1#6#7\expandafter!\the\numexpr \xint_c_e_viii+#1#2#3#4#5+#8!% }% % \end{macrocode} % \subsubsection{\csh{CALX_smalldivx_a}} %\begin{lverb} % From this subsection of xintcore (\xintiiDivision$empty) calx copies only % the macros used by the native layer: \CALX_smalldivx_a, \CALX_smalldivx_b, % \CALX_smalldiv_c, \CALX_smalldiv_d, \CALX_smalldiv_end, \CALX_smalldiv_e, % \CALX_smalldiv_f, \CALX_smalldiv_fz, \CALX_smalldiv_g, \CALX_smalldiv_h, % \CALX_smalldiv_i, \CALX_smalldiv_j, \CALX_smalldiv_k. The other macros are % not copied. %\end{lverb} % % \begin{macrocode} \def\CALX_smalldivx_a #1\xint:1#2!1#3!% {% \expandafter\CALX_smalldivx_b \the\numexpr (#3+#1)/#2-\xint_c_i!#1\xint:#2!#3!% }% \def\CALX_smalldivx_b #1#2!% {% \if0#1\else \xint_c_e_viii+#1#2\xint_afterfi{\expandafter!\the\numexpr}\fi \CALX_smalldiv_c #1#2!% }% \def\CALX_smalldiv_c #1!#2\xint:#3!#4!% {% \expandafter\CALX_smalldiv_d\the\numexpr #4-#1*#3!#2\xint:#3!% }% \def\CALX_smalldiv_d #1!#2!1#3#4!% {% \xint_gob_til_sc #3\CALX_smalldiv_end ;% \CALX_smalldiv_e #1!#2!1#3#4!% }% \def\CALX_smalldiv_end;\CALX_smalldiv_e #1!#2!1;!{1!;!#1!}% \def\CALX_smalldiv_e #1!#2\xint:#3!% {% \expandafter\CALX_smalldiv_f\the\numexpr \xint_c_xi_e_viii_mone+#1*\xint_c_e_viii/#3!#2\xint:#3!#1!% }% \def\CALX_smalldiv_f 1#1#2#3#4#5#6!#7\xint:#8!% {% \xint_gob_til_zero #1\CALX_smalldiv_fz 0% \expandafter\CALX_smalldiv_g \the\numexpr\CALX_minimul_a #2#3#4#5\xint:#6!#8!#2#3#4#5#6!#7\xint:#8!% }% \def\CALX_smalldiv_fz 0% \expandafter\CALX_smalldiv_g\the\numexpr\CALX_minimul_a 9999\xint:9999!#1!99999999!#2!0!1#3!% {% \CALX_smalldiv_i \xint:#3!\xint_c_!#2!% }% \def\CALX_smalldiv_g 1#1!1#2!#3!#4!#5!#6!% {% \expandafter\CALX_smalldiv_h\the\numexpr 1#6-#1\xint:#2!#5!#3!#4!% }% \def\CALX_smalldiv_h 1#1#2\xint:#3!#4!% {% \expandafter\CALX_smalldiv_i\the\numexpr #4-#3+#1-\xint_c_i\xint:#2!% }% \def\CALX_smalldiv_i #1\xint:#2!#3!#4\xint:#5!% {% \expandafter\CALX_smalldiv_j\the\numexpr (#1#2+#4)/#5-% \xint_c_i!#3!#1#2!#4\xint:#5!% }% \def\CALX_smalldiv_j #1!#2!% {% \xint_c_e_viii+#1+#2\expandafter!\the\numexpr\CALX_smalldiv_k #1!% }% \def\CALX_smalldiv_k #1!#2!#3\xint:#4!% {% \expandafter\CALX_smalldiv_d\the\numexpr #2-#1*#4!#3\xint:#4!% }% % \end{macrocode} % \subsection{Native integer format} %\begin{lverb} % A calx integer in native format is the sequence of catcode 12 tokens %( N . ... %) %- N: type tag; %- : + or -, always present; zero is N+0. (no blocks); %- : number of blocks, decimal, terminated by a dot; %- the blocks are xint's blocks 1dddddddd! (the 1 protects leading zeros % for \numexpr), least significant block first; %- the most significant block (the last one) is not 00000000. % % The value is sum_{k=1}^{n} d_k 10^{8(k-1)} with d_k the 8 digits of % . There is no terminator: macros append their own delimiters. % % All macros below are used as \romannumeral0\CALX_n...{...}{...} and % deliver their result after a space token. Arguments are f-expanded first % (as in xintcore). % % Coding rules followed here (second pass, efficiency): %- block lists are copied as few times as possible: a macro parameter % holding blocks appears ONCE in each replacement text; branch selection % (\xint_dothis/\xint_orthat, \ifcase) only selects a macro token, the % arguments follow once after the selection; %- the header N. of a result is produced in front of the blocks % by \expandafter\CALX_sp\expandafter N\expandafter\the\numexpr. % so that the blocks, once grabbed to remove the kernel terminator 1;!, % are not grabbed again (\CALX_sp expands to the space which ends the % \romannumeral0 expansion); %- counting the blocks of a product skips them seven at a time. % % In this section N and I have catcode 12, so macro names here use neither % letter in upper case. %\end{lverb} % \begin{macrocode} \catcode`N=12 \catcode`I=12 % \end{macrocode} %\begin{lverb} % \CALX_sp expands to a space token; it ends the \romannumeral0 expansion of % the native macros. %\end{lverb} % \begin{macrocode} \def\CALX_sp{ }% % \end{macrocode} %\begin{lverb} % \CALX_pten{k} = 10^k, 0 <= k <= 8, k a \numexpr expression: one % \csname lookup of \CALX_pt (k in decimal), cheaper than an \ifcase % table. The other value tables and dispatches of calx are built in the % same way. %\end{lverb} % \begin{macrocode} \def\CALX_pten #1{\csname CALX_pt\the\numexpr#1\endcsname}% \expandafter\def\csname CALX_pt0\endcsname{1}% \expandafter\def\csname CALX_pt1\endcsname{10}% \expandafter\def\csname CALX_pt2\endcsname{100}% \expandafter\def\csname CALX_pt3\endcsname{1000}% \expandafter\def\csname CALX_pt4\endcsname{10000}% \expandafter\def\csname CALX_pt5\endcsname{100000}% \expandafter\def\csname CALX_pt6\endcsname{1000000}% \expandafter\def\csname CALX_pt7\endcsname{10000000}% \expandafter\def\csname CALX_pt8\endcsname{100000000}% % \end{macrocode} %\begin{lverb} % Digit counts without \ifnum (each \ifnum scans its two numbers: three % nested \ifnum on an 8-digit block cost about twice as much). The digits % are followed by a sentinel list and the ninth token is the answer % (xintfrac's \XINT_FL_fac_countdigits); \CALX_nd_b removes the leftover % sentinel up to \xint: and outputs the answer, so the macros are % f-expandable. %- \CALX_ndig{v}: number of digits of 0 <= v < 10^8 (1 for 0); v may have % leading zeros (removed by \numexpr); %- \CALX_ndigs{v}: same, v explicit digits without leading zeros; %- \CALX_nlz{v}: number of leading zeros of an 8-digit block v > 0. % % \CALX_nd_c ...\xint: (v: 1 to 10 explicit digits, no % leading zero; s_k: one token or a braced group) outputs s_k for % k = 11 - (number of digits of v), the eleventh token: a value per digit % count (sentinel list of the caller). %\end{lverb} % \begin{macrocode} \def\CALX_ndig #1% {\expandafter\CALX_nd_a\the\numexpr#1\relax 87654321\xint:}% \def\CALX_ndigs #1{\CALX_nd_a #187654321\xint:}% \def\CALX_nlz #1% {\expandafter\CALX_nd_a\the\numexpr#1\relax 01234567\xint:}% \def\CALX_nd_a #1#2#3#4#5#6#7#8#9{\CALX_nd_b #9}% \def\CALX_nd_b #1#2\xint:{#1}% \def\CALX_nd_c #1#2#3#4#5#6#7#8#9{\CALX_nd_d}% \def\CALX_nd_d #1#2#3\xint:{#2}% % \end{macrocode} % \subsubsection{\csh{CALX_nfromraw}} %\begin{lverb} % Syntax (use with \romannumeral0; R f-expanded): %( % \CALX_nfromraw{R} -> N. %) % Conversion from the raw integer format of xintcore (optional minus sign, no % leading zeros, zero is 0) to native. The shared \CALX_sepandrev_andcount, % as called by \XINT_add_pp_a, delivers \xint:, and % \CALX_nfromraw_c inserts the header without touching the blocks. %\end{lverb} % \begin{macrocode} \def\CALX_nfromraw #1{\expandafter\CALX_nfromraw_a\romannumeral`&&@#1\xint:}% \def\CALX_nfromraw_a #1{% \xint_UDzerominusfork #1-{\CALX_nfromraw_z}% 0#1{\CALX_nfromraw_b -}% 0-{\CALX_nfromraw_b +#1}% \krof }% \def\CALX_nfromraw_z #1\xint:{ N+0.}% \def\CALX_nfromraw_b #1#2\xint:{% \expandafter\CALX_nfromraw_c\expandafter#1% \romannumeral0\expandafter\CALX_sepandrev_andcount \romannumeral0\CALX_zeroes_forviii #2\R\R\R\R\R\R\R\R{10}0000001\W #2\CALX_rsepbyviii_end_A 2345678% \CALX_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R% \xint:\xint_c_vi \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W }% \def\CALX_nfromraw_c #1#2\xint:{ N#1#2.}% % \end{macrocode} % \subsubsection{\csh{CALX_ntoraw}} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded native integer): %( % \CALX_ntoraw{X} -> (xintcore format: -digits, digits, 0) %) % Conversion to raw: the shared \CALX_unrevbyviii then \CALX_cuz_small, % as in \XINT_add_out. The header is examined without grabbing the blocks. %\end{lverb} % \begin{macrocode} \def\CALX_ntoraw #1{\expandafter\CALX_ntoraw_a\romannumeral`&&@#1\xint:}% \def\CALX_ntoraw_a N#1#2.{% \ifnum#2=\xint_c_ \xint_dothis\CALX_ntoraw_z\fi \if-#1\xint_dothis\CALX_ntoraw_m\fi \xint_orthat\CALX_ntoraw_b }% \def\CALX_ntoraw_z #1\xint:{ 0}% \def\CALX_ntoraw_m {\expandafter-\romannumeral0\CALX_ntoraw_b}% \def\CALX_ntoraw_b #1\xint:{% \expandafter\CALX_cuz_small\romannumeral0\CALX_unrevbyviii {}#11;!% 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W }% % \end{macrocode} % \subsubsection{\csh{CALX_nskip}} %\begin{lverb} % Skipping blocks. \CALX_nskip . removes k blocks (k a % \numexpr expression, k>=0) and leaves in front of what follows. % The whole skip is done inside \romannumeral\csname, waits behind % an \expandafter. \CALX_nskip_a takes the first two tokens of k: if the % second one is the dot (k <= 9), \xint_gob_til_dot leaves \CALX_nskip_s, % which completes the name \CALX_nskip; this macro removes the k blocks % and expands to \xint_c_ (ends \romannumeral). Otherwise \CALX_nskip_g % removes eight blocks and loops. %\end{lverb} % \begin{macrocode} \def\CALX_nskip #1#2.{\expandafter#1\romannumeral \csname\expandafter\CALX_nskip_a\the\numexpr#2.}% \def\CALX_nskip_a #1#2% {\xint_gob_til_dot #2\CALX_nskip_s.\CALX_nskip_g #1#2}% \def\CALX_nskip_s.\CALX_nskip_g #1.{CALX_nskip#1\endcsname}% \def\CALX_nskip_g #1.#2!#3!#4!#5!#6!#7!#8!#9!% {\expandafter\CALX_nskip_a\the\numexpr#1-\xint_c_viii.}% \expandafter\let\csname CALX_nskip0\endcsname\xint_c_ \expandafter\def\csname CALX_nskip1\endcsname #1!{\xint_c_}% \expandafter\def\csname CALX_nskip2\endcsname #1!#2!{\xint_c_}% \expandafter\def\csname CALX_nskip3\endcsname #1!#2!#3!{\xint_c_}% \expandafter\def\csname CALX_nskip4\endcsname #1!#2!#3!#4!{\xint_c_}% \expandafter\def\csname CALX_nskip5\endcsname #1!#2!#3!#4!#5!{\xint_c_}% \expandafter\def\csname CALX_nskip6\endcsname #1!#2!#3!#4!#5!#6!{\xint_c_}% \expandafter\def\csname CALX_nskip7\endcsname #1!#2!#3!#4!#5!#6!#7!% {\xint_c_}% \expandafter\def\csname CALX_nskip8\endcsname #1!#2!#3!#4!#5!#6!#7!#8!% {\xint_c_}% \expandafter\def\csname CALX_nskip9\endcsname #1!#2!#3!#4!#5!#6!#7!#8!#9!% {\xint_c_}% % \end{macrocode} % \subsection{Sign and zero tests of values} % \subsubsection{\csh{CALX_ifnz}, \csh{CALX_ifsgn}} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded): %( % \CALX_ifnz{X}{A}{B} -> A (X <> 0) or B %: \CALX_ifnz_a \xint: -> (v <> 0) or %: \CALX_ifsgn{X}{A}{B}{C} -> A, B or C (X <0, =0, >0) %: \CALX_ifsgn_a \xint:{A}{B}{C} -> the same %) % The values are those of the three parsers, after f-expansion: native % N., M.., F.. (blocks after the header), I+, % I-, I?, or raw A, A[N], A/B[N] (A a raw integer without leading zeros, % B > 0). The low level forms take the value v already expanded, in front % of the \xint: that ends it; \CALX_ifnz_a also takes the two tokens % and which select a branch (\CALX_ifnz uses \xint_stop_atfirstoftwo, % \xint_stop_atsecondoftwo; loops use \xint_firstoftwo, \xint_secondoftwo, % which add no space). % % Only the first tokens are read, no xintfrac parsing: 0 is zero, - is % negative, another digit is positive; a token of character code above `9 % is a tag: I+ and I- are infinities, I? is non-zero for \CALX_ifnz and % signals InvalidOperation for \CALX_ifsgn, which then takes the zero % branch; after F, M, N comes the sign token, then the count, whose first % character is 0 only for zero. %\end{lverb} % \begin{macrocode} \def\CALX_ifnz #1{\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_stop_atfirstoftwo\xint_stop_atsecondoftwo}% \def\CALX_ifnz_a #1% {% \if0#1\xint_dothis\CALX_ifnz_z\fi \ifnum`#1>57 \xint_dothis\CALX_ifnz_t\fi \xint_orthat\CALX_ifnz_n #1% }% \def\CALX_ifnz_t #1#2% {\if I#1\expandafter\CALX_ifnz_n\else\expandafter\CALX_ifnz_c\fi}% \def\CALX_ifnz_c #1% {\if0#1\expandafter\CALX_ifnz_z\else\expandafter\CALX_ifnz_n\fi}% \def\CALX_ifnz_z #1\xint:#2#3{#3}% \def\CALX_ifnz_n #1\xint:#2#3{#2}% \def\CALX_ifsgn #1{\expandafter\CALX_ifsgn_a\romannumeral`&&@#1\xint:}% \def\CALX_ifsgn_a #1% {% \if0#1\xint_dothis\CALX_ifsgn_z\fi \if-#1\xint_dothis\CALX_ifsgn_m\fi \ifnum`#1>57 \xint_dothis\CALX_ifsgn_t\fi \xint_orthat\CALX_ifsgn_p #1% }% \def\CALX_ifsgn_t #1#2% {\if I#1\expandafter\CALX_ifsgn_i\else\expandafter\CALX_ifsgn_c\fi #2}% \def\CALX_ifsgn_c #1#2% {% \if0#2\xint_dothis\CALX_ifsgn_z\fi \if-#1\xint_dothis\CALX_ifsgn_m\fi \xint_orthat\CALX_ifsgn_p }% \def\CALX_ifsgn_i #1% {% \if-#1\xint_dothis\CALX_ifsgn_m\fi \if+#1\xint_dothis\CALX_ifsgn_p\fi \xint_orthat\CALX_ifsgn_q }% \def\CALX_ifsgn_q #1\xint:% {\expandafter\CALX_ifsgn_z\romannumeral`&&@% \CALX_signalcondition{InvalidOperation}{sign of I?}{}{}\xint:}% \def\CALX_ifsgn_z #1\xint:{\xint_stop_atsecondofthree}% \def\CALX_ifsgn_m #1\xint:{\xint_stop_atfirstofthree}% \def\CALX_ifsgn_p #1\xint:{\xint_stop_atthirdofthree}% % \end{macrocode} % \subsection{Native addition and subtraction} % \subsubsection{\csh{CALX_nadd}} %\begin{lverb} % Syntax (use with \romannumeral0; X, Y f-expanded, native integers or % I+, I-, I?): %( % \CALX_nadd{X}{Y} -> Z Z = X + Y %: \CALX_nsub{X}{Y} -> Z Z = X - Y %) % Z: native integer, or I+, I-, I? (special operands, rules of the % signals section). % % Addition and subtraction: dispatch. % % \CALX_nadd{X}{Y}: \CALX_nadd_x f-expands Y and leaves %( Y\xint:X1;!1;!1;!1;!\W\xint: %) % so that X is already followed by the kernel terminator. With P = Y % (count n, sign s) and Q = X (count m, sign t), \CALX_nadd_y grabs only % P's list and Q's header N. and runs a chain of tests. A test % that fires puts a "jumper" in its branch: a macro taking a few data % tokens, delimited by the \fi of that branch, which swallows the rest % of \CALX_nadd_y's body (P's list included) and starts with the \fi it % removed. Without jumper, the common case runs inline: same signs and % n<=m, kernel started with P's list, Q's list left where it is. %( n=0: Q \CALX_nadd_retx %: m=0: P \CALX_nadd_rety %: s<>t, nt, n>m: |P|-|Q|, sign s \CALX_ndiff_p %: s<>t, n=m: P-Q, possibly negative \CALX_ndiff_e %: s=t, n>m: Q shorter \CALX_nsum_q %: s=t, n<=m: inline %) % The count of the result (m, or n) is written BEFORE the kernel: %( \expandafter\CALX_naddm\expandafter\the\numexpr% %: \expandafter.\the\numexpr\CALX_nadd_a\xint_c_ii1;!1;!1;!1;!\W %: 1;!1;!1;!1;!\W\xint: %) % Lists grabbed: P's once more in the jumper cases, Q's once in % \CALX_ndiff_p, _e and \CALX_nsum_q, the result once by the final macro % (its header must precede it). % % Addition kernel: xintcore's \XINT_add_a ... \XINT_add_o (xintcore % l.598-668, code-only numbering), copied as \CALX_nadd_a ... \CALX_nadd_o. % % Contract: first list the SHORTER (or equal) one, both lists followed by % 1;!1;!1;!1;!\W, initial state 2; output: the LS-first sum blocks followed % by 1;!, then the tokens which followed the second list's \W. The only % place where the result gets one more block than the longer operand is % \XINT_add_lf, which appends block 00000001; its copy \CALX_nadd_lf also % emits +\xint_c_i after the 1;!, before the final \xint:. \CALX_naddm % grabs . the list and that optional increment. % % Subtraction kernel: xintcore's \XINT_sub_a ... \XINT_sub_i with % \XINT_sub_bi, _di, _fi, _hi (xintcore l.786-851, code-only numbering), % copied as \CALX_nsub_*. Contract: called as %( \CALX_nsub_a\xint_c_i 1;!1;!1;!1;!\W 1;!1;!1;!1;!\W %) % with S not longer than L, it computes L-S; each step produces a block and a % state digit, 1 for no borrow, 0 for borrow; when S is exhausted it calls %( \CALX_nsub_k 1;!1;!1;!1;!\W %) % xintcore's \XINT_sub_k and what follows are tied to its decimal output; the % end of the loop (\CALX_nsub_k and the following) is calx's own. It ends % the list with 1;! followed by one digit, before the final \xint:. % % Unequal lengths (n_L > n_S): remaining L blocks are not empty and % |L| > |S|, so a final borrow is absorbed by L: %- no borrow: copy the remaining blocks (\CALX_nsub_kc), digit 0; %- borrow: 00000000 blocks become 99999999 and the borrow goes on; the % first non zero block d becomes d-1, then copy (\CALX_nsub_kb). If d is % the top block (next is 1;!) and d=1, the block is dropped % (\CALX_nsub_kt) and the digit is 1: the blocks produced by the loop % below it may be zero (e.g. 10^16-(10^16-1)). This happens only when % n_L=n_S+1, the top block of L is 00000001 and absorbs a borrow. % % \CALX_nsubu: digit 0, the result is final; digit 1, \CALX_nsubrd takes % the n_L-1 blocks again with \CALX_ntakex and normalizes (\CALX_nnorm). % % Equal lengths: remaining L blocks are empty; \CALX_nsub_ke ends the list % and leaves the state as digit. State 0 means P complements them (\CALX_nnega), flips % the sign and goes to \CALX_nsubf. \CALX_nsubf examines the top block % (\CALX_ntop_c): if it is not zero, the count is n and the result is % final; otherwise \CALX_nsubr strips zero top blocks (\CALX_nnorm). % % \CALX_ntakex . takes exactly n blocks 1<8 digits>! from the input % stream and leaves them followed by 1;! (inside \numexpr chains): the % list then needs no delimiter, so the final result N. can be % left as is in the common case and taken again only in the rare ones. %\end{lverb} % \begin{macrocode} \def\CALX_nadd #1{\expandafter\CALX_nadd_x\romannumeral`&&@#1\xint:}% \def\CALX_nadd_x #1#2\xint:#3{\expandafter\CALX_nsp_t\expandafter\CALX_nadd_y \expandafter\CALX_nadd_sp\expandafter#1\romannumeral`&&@#3\xint:#1#2% 1;!1;!1;!1;!\W\xint:}% % \end{macrocode} %\begin{lverb} % Special values (SPEC_native D9). \CALX_nsp_t % (tags of X and Y, the stream continues with Y without its tag, then % \xint:X\xint:, see below): both tags N: , else % . For \CALX_nmul is empty. % % \CALX_nadd_sp ...\xint:...\xint: (the tail of X % is swallowed with it; s = second token: % sign, or + - ? after I): NaN in an operand: I?; Inf + finite: that Inf; % Inf + Inf: that Inf if same sign, else InvalidOperation (default I?). % % \CALX_nsub_sp flips sY (I? unchanged) and goes to \CALX_nadd_sp. %\end{lverb} % \begin{macrocode} \def\CALX_nsp_t #1#2#3#4% {\if\if N#3#4\else ?\fi N\xint_dothis{#1#4}\fi\xint_orthat{#2#3#4}}% \def\CALX_nadd_sp #1#2#3#4\xint:#5#6#7\xint:% {% \if ?#3\xint_dothis{ I?}\fi \if ?#6\xint_dothis{ I?}\fi \if N#2\xint_dothis{ I#6}\fi \if N#5\xint_dothis{ I#3}\fi \if #3#6\xint_dothis{ I#3}\fi \xint_orthat{\CALX_nsig{InvalidOperation}{inf - inf}{}}% }% \def\CALX_nadd_y N#1#2.#3\xint:N#4#5.% {% \ifnum#2=\xint_c_ \CALX_nadd_retx#4#5.\fi \ifnum#5=\xint_c_ \CALX_nadd_rety#1#2.\fi \if#1#4\else \ifnum#2<#5 \CALX_ndiff_q#4#5.\fi \ifnum#2>#5 \CALX_ndiff_p#1#2.\fi \CALX_ndiff_e#1#2.% \fi \ifnum#2>#5 \CALX_nsum_q#1#2.\fi \expandafter\CALX_naddm\expandafter#1\the\numexpr#5\expandafter.% \the\numexpr\CALX_nadd_a\xint_c_ii#31;!1;!1;!1;!\W }% \def\CALX_nadd_retx#1#2.\fi#3\W#41;!1;!1;!1;!\W\xint:{\fi\CALX_sp N#1#2.#4}% \def\CALX_nadd_rety#1#2.\fi#3\xint_c_ii#41;!1;!1;!1;!\W 1;!1;!1;!1;!\W\xint:{\fi\CALX_sp N#1#2.#4}% \def\CALX_nsum_q#1#2.\fi#3\xint_c_ii#41;!1;!1;!1;!\W #51;!1;!1;!1;!\W\xint:% {% \fi\expandafter\CALX_naddm\expandafter#1\the\numexpr#2\expandafter.% \the\numexpr\CALX_nadd_a\xint_c_ii#51;!1;!1;!1;!\W#41;!1;!1;!1;!\W\xint: }% \def\CALX_naddm #1#2.#31;!#4\xint:% {\expandafter\CALX_sp\expandafter N\expandafter#1\the\numexpr#2#4.#3}% \def\CALX_ndiff_q#1#2.\fi#3\xint_c_ii#41;!1;!1;!1;!\W {% \fi\fi\expandafter\CALX_nsubu\expandafter#1\the\numexpr#2\expandafter.% \the\numexpr\CALX_nsub_a\xint_c_i#41;!1;!1;!1;!\W }% \def\CALX_ndiff_p#1#2.\fi#3\xint_c_ii#41;!1;!1;!1;!\W #51;!1;!1;!1;!\W\xint:% {% \fi\fi\expandafter\CALX_nsubu\expandafter#1\the\numexpr#2\expandafter.% \the\numexpr\CALX_nsub_a\xint_c_i#51;!1;!1;!1;!\W#41;!1;!1;!1;!\W\xint: }% \def\CALX_ndiff_e#1#2.\fi#3\xint_c_ii#41;!1;!1;!1;!\W #51;!1;!1;!1;!\W\xint:% {% \fi\expandafter\CALX_nsube\expandafter#1\the\numexpr#2\expandafter.% \the\numexpr\CALX_nsub_a\xint_c_i#51;!1;!1;!1;!\W#41;!1;!1;!1;!\W\xint: }% \def\CALX_nsubu #1#2.#31;!#4\xint:% {% \ifnum#4=\xint_c_ \expandafter\CALX_sp\else\expandafter\CALX_nsubrd\fi N#1#2.#3% }% \def\CALX_nsube #1#2.#31;!#4\xint:% {% \if0#4\csname CALX_nsubng#1\expandafter\endcsname \else\expandafter\CALX_nsubf\fi #1#2.#31;!% }% \expandafter\def\csname CALX_nsubng+\endcsname #1#2.#31;!% {% \expandafter\CALX_nsubf\expandafter-\the\numexpr#2\expandafter.% \the\numexpr\CALX_nnega#31;!% }% \expandafter\def\csname CALX_nsubng-\endcsname #1#2.#31;!% {% \expandafter\CALX_nsubf\expandafter+\the\numexpr#2\expandafter.% \the\numexpr\CALX_nnega#31;!% }% \def\CALX_nsubf #1#2.#31;!% {% \ifnum\CALX_nskip\CALX_ntop_c #2-\xint_c_i.#3\xint:=\xint_c_ \expandafter\CALX_nsubr\else\expandafter\CALX_sp\fi N#1#2.#3% }% \def\CALX_nsubr N#1#2.% {\expandafter\CALX_nnorm\expandafter#1\the\numexpr\CALX_ntakex#2.}% \def\CALX_nsubrd N#1#2.% {% \expandafter\CALX_nnorm\expandafter#1\the\numexpr \expandafter\CALX_ntakex\the\numexpr#2-\xint_c_i.% }% \def\CALX_ntakex #1.% {% \ifnum#1=\xint_c_ \expandafter\CALX_ntakex_e\else \expandafter\CALX_ntakex_b\fi #1.% }% \def\CALX_ntakex_e #1.{1\relax;!}% \def\CALX_ntakex_b #1.1#2!% {% 1#2\expandafter!\the\numexpr \expandafter\CALX_ntakex\the\numexpr#1-\xint_c_i.% }% \def\CALX_ntop_c 1#1!#2\xint:{#1}% \def\CALX_nsub_k #1#2#3{% \xint_gob_til_sc #3\CALX_nsub_ke;% \xint_gob_til_zero #1\CALX_nsub_kz0\CALX_nsub_kc #2#3% }% \def\CALX_nsub_ke;\xint_gob_til_zero#1#2\W{1\relax;!#1}% \def\CALX_nsub_kz0\CALX_nsub_kc{\CALX_nsub_kb}% \def\CALX_nsub_kc #11;!1;!1;!1;!\W{#11;!0}% \def\CALX_nsub_kb 1#1!#2#3{% \xint_gob_til_sc #3\CALX_nsub_kt;% \ifnum#1=\xint_c_ \expandafter\CALX_nsub_kbz\else \expandafter\CALX_nsub_kbn\fi #1!#2#3% }% \def\CALX_nsub_kbz #1!{199999999\expandafter!\the\numexpr\CALX_nsub_kb}% \def\CALX_nsub_kbn #1!{1#1-\xint_c_i\expandafter!\the\numexpr\CALX_nsub_kc}% \def\CALX_nsub_kt;\ifnum#1=#2\W{% \ifnum#1=\xint_c_i \expandafter\CALX_nsub_kto\else \expandafter\CALX_nsub_ktn\fi #1!% }% \def\CALX_nsub_kto #1!{1\relax;!1}% \def\CALX_nsub_ktn #1!{1#1-\xint_c_i\relax!1;!0}% % \end{macrocode} % \subsubsection{\csh{CALX_nsub}} %\begin{lverb} % \CALX_nsub{X}{Y} = X-Y: flips the sign of Y and goes to the addition % (N-0. may arise transiently but is caught by the zero tests of % \CALX_nadd_y before any use of the sign). %\end{lverb} % \begin{macrocode} \def\CALX_nsub #1{\expandafter\CALX_nsub_x\romannumeral`&&@#1\xint:}% \def\CALX_nsub_x #1#2\xint:#3{\expandafter\CALX_nsp_t\expandafter\CALX_nsub_y \expandafter\CALX_nsub_sp\expandafter#1\romannumeral`&&@#3\xint:#1#2% 1;!1;!1;!1;!\W\xint:}% \def\CALX_nsub_sp #1#2#3% {% \if +#3\xint_dothis{\CALX_nadd_sp#1#2-}\fi \if -#3\xint_dothis{\CALX_nadd_sp#1#2+}\fi \xint_orthat{\CALX_nadd_sp#1#2#3}% }% \def\CALX_nsub_y N#1% {\if#1-\expandafter\CALX_nsub_yp\else\expandafter\CALX_nsub_ym\fi}% \def\CALX_nsub_yp{\CALX_nadd_y N+}% \def\CALX_nsub_ym{\CALX_nadd_y N-}% % \end{macrocode} % \subsubsection{\csh{CALX_nnega}, \csh{CALX_nnegb}, \csh{CALX_nnorm}, % \csh{CALX_nlast}, \csh{CALX_ntake}} %\begin{lverb} % \CALX_nnega$empty: 10^(8n)-R on LS-first blocks terminated by 1;! (R not % zero): low zero blocks stay, the first non zero block d becomes 10^8-d % (written 2*10^8-d to keep the protecting 1), the next ones 99999999-d % (written 199999999-d). %\end{lverb} % \begin{macrocode} \def\CALX_nnega 1#1!{% \ifnum#1=\xint_c_ 100000000\expandafter!\the\numexpr \expandafter\CALX_nnega \else \xint_c_ii*\xint_c_e_viii-#1\expandafter!\the\numexpr \expandafter\CALX_nnegb \fi }% \def\CALX_nnegb 1#1#2!{\xint_gob_til_sc #1\CALX_nnegz;% 199999999-#1#2\expandafter!\the\numexpr\CALX_nnegb}% \def\CALX_nnegz;#1\CALX_nnegb{1\relax;!}% % \end{macrocode} %\begin{lverb} % Syntax: %( % \CALX_nnorm 1;! -> N. %) % (blocks LS first, zero top blocks allowed; blocks' without them, N+0. if % all are zero.) % \CALX_nnorm 1;!: strips the zero top blocks and counts, in % two linear passes: \CALX_nlast finds the index of the last non zero block % (arguments are two numbers ..), then \CALX_ntake emits that % many blocks inside a \numexpr chain (xintcore's % 1\expandafter!\the\numexpr technique) and gobbles the rest up to % \xint:. Returns N+0. if all blocks are zero. %\end{lverb} % \begin{macrocode} \def\CALX_nnorm #1#21;!% {\expandafter\CALX_nnorm_b\romannumeral0\CALX_nlast 0.0.#21;!.#1#2\xint:}% \def\CALX_nlast #1.#2.1#3#4!{% \xint_gob_til_sc #3\CALX_nlast_e;% \ifnum#3#4=\xint_c_ \expandafter\CALX_nlast_z \else \expandafter\CALX_nlast_nz \fi #1.#2.% }% \def\CALX_nlast_z #1.#2.{\expandafter\CALX_nlast\the\numexpr#1+\xint_c_i.#2.}% \def\CALX_nlast_nz #1.#2.% {\expandafter\CALX_nlast\the\numexpr#1+\xint_c_i\expandafter.\the% \numexpr#1+\xint_c_i.}% \def\CALX_nlast_e;#1\fi #2.#3.{ #3}% \def\CALX_nnorm_b #1.{\ifnum#1=\xint_c_ \CALX_nnorm_z\fi\CALX_nnorm_c #1.}% \def\CALX_nnorm_z\fi#1\xint:{\fi\CALX_sp N+0.}% \def\CALX_nnorm_c #1.#2#3\xint:% {\expandafter\CALX_nnorm_d\the\numexpr\CALX_ntake #1.#31;!\xint:#2#1.}% \def\CALX_nnorm_d #11;!#2#3.{ N#2#3.#1}% \def\CALX_ntake #1.1#2!{% \ifnum#1=\xint_c_ \expandafter\CALX_ntake_e\fi 1#2\expandafter!\the\numexpr \expandafter\CALX_ntake\the\numexpr#1-\xint_c_i.% }% \def\CALX_ntake_e #1\xint:{1\relax;!}% % \end{macrocode} % \subsection{Native multiplication} % \subsubsection{\csh{CALX_nmul}} %\begin{lverb} % Syntax (use with \romannumeral0; X, Y f-expanded, native integers or % I+, I-, I?): %( % \CALX_nmul{X}{Y} -> Z Z = X Y (native integer, or I) %) % Multiplication. \CALX_nmul{X}{Y}. The kernels are used as they are, from % the renamed copy of xintcore (they are self contained, the addition they % use is the unmodified \CALX_add_a): \CALX_mul_loop, \CALX_smallmul, % \CALX_verysmallmul. Only the dispatch (xintcore's \XINT_mul_checklengths, % \XINT_mul_smallbyfirst/second) is rewritten, with the stored block counts, % and the output. % % Contracts (from the code, xintcore l.1013-1097 code-only): %- \the\numexpr\CALX_mul_loop 100000000!1;!\W 1;!\W 1;! computes % X*Y, iterating over the blocks of Y (the initial 100000000!1;! is the % zero accumulator); output: product blocks LS-first then 1;!, then the % tokens which followed Y's 1;!; %- \the\numexpr\CALX_smallmul 1!1;! for a single block y, and % \the\numexpr\CALX_verysmallmul 0\xint:!1;! for y<22 (xintcore's % threshold): same output form. % % These kernels never produce a zero top block (the final carry block is % dropped when zero, \XINT_smallmul_f, \XINT_verysmallmul_f). A product % of n and m blocks has n+m-1 or n+m blocks: \CALX_nmulo receives % n+m-1 (computed before the kernel), skips that many blocks % (\CALX_nskip) and checks whether one more follows. % % Dispatch as for \CALX_nadd: \CALX_nmul_x writes X followed by 1;!\xint:, % \CALX_nmul_y grabs P's list and Q's header; jumpers \CALX_nmul_zero, % \CALX_nmul_sp (P one block: Q stays in place), \CALX_nmul_sq (Q one % block), \CALX_nmul_xq (iteration over P: Q's list grabbed); inline % default: iteration over Q, left in place. A one-block factor y uses % \CALX_verysmallmul if y<22, else \CALX_smallmul (y=1 included). % % Choice of the iterated operand: the rule of xintcore's % \XINT_mul_checklengths, transcribed with X=Q, Y=P by default (A=P, B=Q in % xintcore): exchange if m=n and % (n-1)(m-n)>383. % % \CALX_psign gives + or - (sign of a % product) by expansion (used by the division). %\end{lverb} % \begin{macrocode} \def\CALX_psign #1#2#3% {\if#1#2\expandafter#3\expandafter+\else\expandafter#3\expandafter-\fi}% \def\CALX_nmul #1{\expandafter\CALX_nmul_x\romannumeral`&&@#1\xint:}% \def\CALX_nmul_x #1#2\xint:#3{\expandafter\CALX_nsp_t\expandafter\CALX_nmul_y \expandafter\CALX_nmul_spv\expandafter#1\romannumeral`&&@#3\xint:#1#2% 1;!\xint:}% % \end{macrocode} %\begin{lverb} % \CALX_nmul_spv (same input as \CALX_nadd_sp): NaN: I?; Inf times 0: % InvalidOperation (I?); otherwise Inf with the product of the signs. % % \CALX_nsp_z : its block count. % % \CALX_nsp_ps : I+ or I- (product of the signs, with the space). %\end{lverb} % \begin{macrocode} \def\CALX_nsp_z #1.#2\xint:{#1}% \def\CALX_nsp_ps #1#2{\if#1#2\xint_dothis{ I+}\fi\xint_orthat{ I-}}% \def\CALX_nmul_spv #1#2#3#4\xint:#5#6#7\xint:% {% \if ?#3\xint_dothis{ I?}\fi \if ?#6\xint_dothis{ I?}\fi \ifnum\if N#2\CALX_nsp_z#4\xint:\else\if N#5\CALX_nsp_z#7\xint:\else \xint_c_i\fi\fi=\xint_c_ \xint_dothis{\CALX_nsig{InvalidOperation}{inf * 0}{}}\fi \xint_orthat{\CALX_nsp_ps#3#6}% }% \def\CALX_nmul_y N#1#2.#3\xint:N#4#5.% {% \ifnum#2=\xint_c_ \CALX_nmul_zero\fi \ifnum#5=\xint_c_ \CALX_nmul_zero\fi \ifnum#2=\xint_c_i \CALX_nmul_sp#1#4#2.#5.\fi \ifnum#5=\xint_c_i \CALX_nmul_sq#1#4#2.#5.\fi \ifnum\ifnum#5<#2 \numexpr383-(#5-\xint_c_i)*(#2-#5)\relax \else\numexpr(#2-\xint_c_i)*(#5-#2)-383\relax\fi>\xint_c_ \else\CALX_nmul_xq#1#4#2.#5.\fi \csname CALX_nmulo\if#1#4+\else-\fi\expandafter\endcsname \the\numexpr#2+#5-\xint_c_i\expandafter.% \the\numexpr\CALX_mul_loop 100000000!1;!\W #31;!\W }% \def\CALX_nmul_zero\fi#1\W#2\W#31;!\xint:{\fi\CALX_sp N+0.}% \def\CALX_nmul_sp#1#2#3.#4.\fi#5\W1#6!1;!\W {% \fi\csname CALX_nmulo\if#1#2+\else-\fi\expandafter\endcsname \the\numexpr#4\expandafter.\the\numexpr \ifnum#6<\xint_c_xxii \expandafter\CALX_nmul_vs\else \expandafter\CALX_nmul_s\fi #6!% }% \def\CALX_nmul_sq#1#2#3.#4.\fi#5\W#6\W1#7!1;!\xint:% {% \fi\csname CALX_nmulo\if#1#2+\else-\fi\expandafter\endcsname \the\numexpr#3\expandafter.\the\numexpr \ifnum#7<\xint_c_xxii \expandafter\CALX_nmul_vs\else \expandafter\CALX_nmul_s\fi #7!#6\xint: }% \def\CALX_nmul_vs #1!{\CALX_verysmallmul 0\xint:#1!}% \def\CALX_nmul_s #1!{\CALX_smallmul 1#1!}% \def\CALX_nmul_xq#1#2#3.#4.\fi#5\W#6\W#71;!\xint:% {% \fi\csname CALX_nmulo\if#1#2+\else-\fi\expandafter\endcsname \the\numexpr#3+#4-\xint_c_i\expandafter.% \the\numexpr\CALX_mul_loop 100000000!1;!\W#71;!\W#6\xint: }% \expandafter\def\csname CALX_nmulo+\endcsname #1.#21;!\xint:% {% \expandafter\CALX_sp\expandafter N\expandafter+\the\numexpr #1+\CALX_nskip\CALX_nmul_c #1.#21;!\xint:.#2% }% \expandafter\def\csname CALX_nmulo-\endcsname #1.#21;!\xint:% {% \expandafter\CALX_sp\expandafter N\expandafter-\the\numexpr #1+\CALX_nskip\CALX_nmul_c #1.#21;!\xint:.#2% }% \def\CALX_nmul_c 1#1#2!#3\xint:{\xint_gob_til_sc #1\CALX_nmul_ce;\xint_c_i}% \def\CALX_nmul_ce;\xint_c_i{\xint_c_}% \def\CALX_nadd_a #1!#2!#3!#4!#5\W #6!#7!#8!#9!% {% \CALX_nadd_b #1!#6!#2!#7!#3!#8!#4!#9!% #5\W }% \def\CALX_nadd_b #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_nadd_bi ;% \expandafter\CALX_nadd_c\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_nadd_bi;\expandafter\CALX_nadd_c \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6!#7!#8!#9!\W {% \CALX_nadd_k #1#3!#5!#7!#9!% }% \def\CALX_nadd_c #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nadd_d #1% }% \def\CALX_nadd_d #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_nadd_di ;% \expandafter\CALX_nadd_e\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_nadd_di;\expandafter\CALX_nadd_e \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6!#7!#8\W {% \CALX_nadd_k #1#3!#5!#7!% }% \def\CALX_nadd_e #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nadd_f #1% }% \def\CALX_nadd_f #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_nadd_fi ;% \expandafter\CALX_nadd_g\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_nadd_fi;\expandafter\CALX_nadd_g \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6\W {% \CALX_nadd_k #1#3!#5!% }% \def\CALX_nadd_g #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nadd_h #1% }% \def\CALX_nadd_h #11#2#3!#4!% {% \xint_gob_til_sc #2\CALX_nadd_hi ;% \expandafter\CALX_nadd_i\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% }% \def\CALX_nadd_hi;% \expandafter\CALX_nadd_i\the\numexpr#1+#2+#3-\xint_c_ii\xint:#4\W {% \CALX_nadd_k #1#3!% }% \def\CALX_nadd_i #1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nadd_a #1% }% \def\CALX_nadd_k #1{\if #12\expandafter\CALX_nadd_ke\else\expandafter% \CALX_nadd_l \fi}% \def\CALX_nadd_ke #11;#2\W {\CALX_nadd_kf #11;!}% \def\CALX_nadd_kf 1{1\relax }% \def\CALX_nadd_l 1#1{\xint_gob_til_sc #1\CALX_nadd_lf ;\CALX_nadd_m 1#1}% \def\CALX_nadd_lf #1\W {1\relax 00000001!1;!+\xint_c_i}% calx: count +1 \def\CALX_nadd_m #1!{\expandafter\CALX_nadd_n\the\numexpr\xint_c_i+#1\xint:}% \def\CALX_nadd_n #1#2\xint:{1#2\expandafter!\the\numexpr\CALX_nadd_o #1}% \def\CALX_nadd_o #1{\if #12\expandafter\CALX_nadd_l\else\expandafter% \CALX_nadd_ke \fi}% \def\CALX_nsub_a #1!#2!#3!#4!#5\W #6!#7!#8!#9!% {% \CALX_nsub_b #1!#6!#2!#7!#3!#8!#4!#9!% #5\W }% \def\CALX_nsub_b #1#2#3#4!#5!% {% \xint_gob_til_sc #3\CALX_nsub_bi ;% \expandafter\CALX_nsub_c\the\numexpr#1+1#5-#3#4-\xint_c_i\xint:% }% \def\CALX_nsub_c 1#1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nsub_d #1% }% \def\CALX_nsub_d #1#2#3#4!#5!% {% \xint_gob_til_sc #3\CALX_nsub_di ;% \expandafter\CALX_nsub_e\the\numexpr#1+1#5-#3#4-\xint_c_i\xint: }% \def\CALX_nsub_e 1#1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nsub_f #1% }% \def\CALX_nsub_f #1#2#3#4!#5!% {% \xint_gob_til_sc #3\CALX_nsub_fi ;% \expandafter\CALX_nsub_g\the\numexpr#1+1#5-#3#4-\xint_c_i\xint: }% \def\CALX_nsub_g 1#1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nsub_h #1% }% \def\CALX_nsub_h #1#2#3#4!#5!% {% \xint_gob_til_sc #3\CALX_nsub_hi ;% \expandafter\CALX_nsub_i\the\numexpr#1+1#5-#3#4-\xint_c_i\xint: }% \def\CALX_nsub_i 1#1#2\xint:% {% 1#2\expandafter!\the\numexpr\CALX_nsub_a #1% }% \def\CALX_nsub_bi;% \expandafter\CALX_nsub_c\the\numexpr#1+1#2-#3\xint: #4!#5!#6!#7!#8!#9!\W {% \CALX_nsub_k #1#2!#5!#7!#9!% }% \def\CALX_nsub_di;% \expandafter\CALX_nsub_e\the\numexpr#1+1#2-#3\xint: #4!#5!#6!#7!#8\W {% \CALX_nsub_k #1#2!#5!#7!% }% \def\CALX_nsub_fi;% \expandafter\CALX_nsub_g\the\numexpr#1+1#2-#3\xint: #4!#5!#6\W {% \CALX_nsub_k #1#2!#5!% }% \def\CALX_nsub_hi;% \expandafter\CALX_nsub_i\the\numexpr#1+1#2-#3\xint: #4\W {% \CALX_nsub_k #1#2!% }% % \end{macrocode} % \subsection{Native division} % \subsubsection{\csh{CALX_nudiv}} %\begin{lverb} % Division (calx). Unsigned core: %( \CALX_nudiv {na}{A}{nb}{B} %) % with A, B non zero, given by their block counts and LS-first blocks. % It expands to %( {nq}{Q}{s}{R'} %) % where nq, Q (count, LS-first blocks) is the quotient floor(A/B), and R' % the LS-first blocks (non normalized: zero top blocks possible) terminated % by 1;! of 10^s times the remainder R = A - Q*B. Use \CALX_nudiv_rem to get % R in native format. The tokens following the last argument are left % untouched after {nq}{Q}{s}{R'}. % % Paths: %- na < nb: Q = 0, R' = A, s = 0. %- nb = 1, na = 1: \numexpr. %- nb = 1, divisor d <= 45249: dedicated kernel (see below). %- nb = 1, larger divisor: A reversed (\CALX_rev_nounsep), % \CALX_smalldivx_a (from xintcore) (MS-first), quotient reversed. %- nb = 2, 3, 4: dedicated loops without normalization (see below), s = 0. %- nb >= 5: Knuth's algorithm D in base 10^8, described now. % % Algorithm D (general path). % % Normalisation: s = number of leading zeros of the top block of B (as an % 8 digit block); A'' = 10^s A with exactly na+1 blocks (a zero block is % appended before multiplying), B' = 10^s B (nb blocks, top block v1 >= % 10^7). \CALX_smallmul (from xintcore) does both products, LS-first. % The quotient is the same, the remainder is multiplied by 10^s. % % Data: the window W (nb+1 blocks w_0..w_nb, W < 10^8 B') and B' (b_0 .. % b_{nb-1}) are kept INTERLEAVED in one list %( L = 1w_0!1b_0!1w_1!1b_1!...1w_{nb-1}!1b_{nb-1}!1w_nb!1;;;;;! %) % (1;;;;;! = marker Z). The remaining blocks of A'' are kept MS-first in the % input stream, after L, terminated by 1;!. % % The multiply-subtract pass \CALX_ndms_a reads the pairs (w_k,b_k) and emits % b_k then r_k, where r = W - q*B' (one borrow chain); its output is %( 1b_0!1r_0!1b_1!1r_1!...1b_{nb-1}!1r_{nb-1}!1;;;;;!{fin} %) % with fin = 0 if r >= 0 and fin = -1 if r < 0 (then the blocks hold % r + 10^(8nb)). Prefixing the next block of A'' gives exactly the next % window in the layout of L: pairs (new,b_0), (r_0,b_1), ..., top % (r_{nb-1},Z). % % Estimation of q (with u0, u1, u2 the three top blocks of W, v1, v2 those % of B', U = u0 b^2+u1 b+u2, V = v1 b+v2, b = 10^8): q* = min(floor(U/V), % b-1) satisfies q <= q* <= q+1. Indeed W/B' < (U+1)/V gives q <= % floor(U/V), and W/B' >= U/(V+1) gives q >= floor(U/(V+1)) >= floor(U/V)-1 % as U/V - U/(V+1) = U/(V(V+1)) < 1 (U < b V, V >= b). This holds for any % v1 > 0; q* = q+1 needs the lower blocks to matter (probability about % 1/v1). q* is obtained from %( q0 = round(u0*10^9/Vp) + round(u1d/Vp), %) % where Vp = 10 v1 + first digit of v2 (9 digits) and u1d = 10 u1 + first % digit of u2 (eTeX's a*b/c has a 64 bit intermediate product), clamped to % [0, b-1]; then T = U - q0 V is computed exactly as T = a b + c with % 0 <= c < b, by splitting q0 and v1, v2 in 4 digit halves, and corrected: %( while T < 0: q0 -= 1, T += V; %: while T >= V and q0 < b-1: q0 += 1, T -= V. %) % (|q0 - U/V| < 2.1, so at most three corrections.) % % If fin < 0 after the pass, B' is added back (\CALX_ndab) and q decreases. % % The quotient blocks are left behind in a \numexpr chain (xintcore's % technique, value 10^8+q emitted by the enclosing \numexpr), MS-first, and % reversed once at the end. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv #1#2#3#4{% \ifnum#2<#4 \xint_dothis\CALX_nudiv_lt\fi \xint_orthat{\CALX_nudiv_sel #4.}#1{#2}{#3}{#4}% }% \def\CALX_nudiv_sel #1.{% \ifcase#1 \or \expandafter\CALX_nudiv_one \or \expandafter\CALX_nudiv_two \or \expandafter\CALX_nudiv_three \or \expandafter\CALX_nudiv_four \else\expandafter\CALX_nudiv_gen \fi }% \def\CALX_nudiv_lt #1#2#3#4#5{#1{0}{}{0}{#31;!}}% % \end{macrocode} %\begin{lverb} % One block divisor. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_one #1#2#3#4#5{\CALX_nudiv_oa #1{#2}#5{#3}}% \def\CALX_nudiv_oa #1#21#3!{% \ifnum#2=\xint_c_i \xint_dothis\CALX_nudiv_oo\fi \ifnum#3<45250 \xint_dothis\CALX_nudiv_otd\fi \xint_orthat\CALX_nudiv_ob #1{#2}{#3}% }% \def\CALX_nudiv_oo #1#2#3#4{\CALX_nudiv_oo_a #1{#3}#4}% \def\CALX_nudiv_oo_a #1#21#3!{% \expandafter\CALX_nudiv_oo_b \the\numexpr(#3+#2/\xint_c_ii)/#2-\xint_c_i\xint:#3\xint:#2\xint:#1% }% \def\CALX_nudiv_oo_b #1\xint:#2\xint:#3\xint:{% \expandafter\CALX_nudiv_oo_c \the\numexpr\xint_c_e_viii+#1\expandafter\xint:% \the\numexpr\xint_c_e_viii+#2-#1*#3\xint:% }% \def\CALX_nudiv_oo_c 1#1\xint:#2\xint:#3{% \ifnum#1=\xint_c_ \xint_dothis{#3{0}{}}\fi \xint_orthat{#3{1}{1#1!}}{0}{#2!1;!}% }% \def\CALX_nudiv_ob #1#2#3#4{% \expandafter\CALX_nudiv_oc \romannumeral0\CALX_rev_nounsep {}#4\R!\R!\R!\R!\R!\R!\R!\R!\W% \xint:{#3}{#2}#1% }% \def\CALX_nudiv_oc 1#1!#2\xint:#3#4{% \expandafter\CALX_nudiv_od \the\numexpr\expandafter\CALX_smalldivx_a\the\numexpr#3/\xint_c_ii% \xint:1#3!1#1!#21;!% {\ifnum#1<#3 -\xint_c_i\fi+#4}% }% \def\CALX_nudiv_od #11!;!#2!#3{% \expandafter\CALX_nudiv_oe \romannumeral0\CALX_rev_nounsep {}#1\R!\R!\R!\R!\R!\R!\R!\R!\W% \xint:{#3}{#2}% }% \def\CALX_nudiv_oe #1\xint:#2#3{% \expandafter\CALX_nudiv_of \the\numexpr\xint_c_e_viii+#3\expandafter\xint:\the\numexpr#2\xint:{#1}% }% \def\CALX_nudiv_of #1\xint:#2\xint:#3#4{#4{#2}{#3}{0}{#1!1;!}}% % \end{macrocode} %\begin{lverb} % General path. \CALX_nudiv_gs computes s from the top block of B. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_gen #1#2#3#4#5{% \expandafter\CALX_nudiv_ga\the\numexpr \CALX_nskip\CALX_nudiv_gs #4-\xint_c_i.#5\xint:\xint:{#5}{#2}{#3}{#4}#1% }% \def\CALX_nudiv_gs 1#1!\xint:{\CALX_nlz{#1}}% \def\CALX_nudiv_pow #1{\csname CALX_nudiv_pow\the\numexpr#1\endcsname}% \expandafter\def\csname CALX_nudiv_pow0\endcsname{100000001}% \expandafter\def\csname CALX_nudiv_pow1\endcsname{100000010}% \expandafter\def\csname CALX_nudiv_pow2\endcsname{100000100}% \expandafter\def\csname CALX_nudiv_pow3\endcsname{100001000}% \expandafter\def\csname CALX_nudiv_pow4\endcsname{100010000}% \expandafter\def\csname CALX_nudiv_pow5\endcsname{100100000}% \expandafter\def\csname CALX_nudiv_pow6\endcsname{101000000}% \expandafter\def\csname CALX_nudiv_pow7\endcsname{110000000}% % \end{macrocode} %\begin{lverb} % #1=s, #2=B, #3=na, #4=A, #5=nb, #6=cont. Produces %( \CALX_nudiv_gc 1;!\xint:1;!\xint:{na}{nb}{s} %) %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_ga #1\xint:{% \ifnum#1=\xint_c_ \xint_dothis\CALX_nudiv_gz\fi \xint_orthat\CALX_nudiv_gm {#1}% }% \def\CALX_nudiv_gz #1#2#3#4#5{\CALX_nudiv_gc #4100000000!1;!\xint:#21;!% \xint:{#3}{#5}{0}}% \def\CALX_nudiv_gm #1#2{% \expandafter\CALX_nudiv_gb\the\numexpr \expandafter\CALX_smallmul\the\numexpr\CALX_nudiv_pow{#1}!#21;!\xint:% {#1}% }% \def\CALX_nudiv_gb #11;!\xint:#2#3#4#5{% \expandafter\CALX_nudiv_gc\the\numexpr \expandafter\CALX_smallmul\the\numexpr\CALX_nudiv_pow{#2}!#4100000000!1;!% \xint:#11;!\xint:{#3}{#5}{#2}% }% % \end{macrocode} %\begin{lverb} % #1=A'' (na+1 blocks), #2=B', #3=na, #4=nb, #5=s, then . % The constants C = {k}{v1h}{v1l}{v2h}{v2l}{Vp}, k = 2nb-4, are obtained % from the two top blocks of a copy of B'. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_gc #11;!\xint:#21;!\xint:#3#4#5{% \CALX_nskip\CALX_nudiv_gv #4-\xint_c_ii.#21;!% \xint:{#4}{#3-#4}{#5}{#1}{#2}% }% \def\CALX_nudiv_gv 1#1#2#3#4#5!1#6#7#8#9{\CALX_nudiv_gu % {#1#2#3#4}{#5}{#6#7#8#9}{#1}}% % \end{macrocode} %\begin{lverb} % #1=v2h, #2=v2l, #3=v1h, #4=first digit of v2, #5=v1l, #6=nb, #7=m (number % of low blocks of A'' to reverse, expression), #8=s, #9=A'', then {B'}. % % C = {k}{v1h}{v1l}{v2h}{v2l}{Vp} with k an expression (only used through % \numexpr). %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_gu #1#2#3#4#5!1;!\xint:#6#7#8#9{% \expandafter\CALX_nrevk\the\numexpr#7.\CALX_nudiv_gw{}#91;!\xint:% {{\xint_c_ii*#6-\xint_c_iv}{#3}{#5}{#1}{#2}{#3#5#4}}{#7+\xint_c_i}{#8}% }% % \end{macrocode} % \subsubsection{\csh{CALX_nrevk}} %\begin{lverb} % \CALX_nrevk .{acc}: reverses k blocks onto acc, then % {acc'}. Six blocks per step. %\end{lverb} % \begin{macrocode} \def\CALX_nrevk #1.{% \ifnum#1>\xint_c_v\expandafter\CALX_nrevk_g\else\expandafter\CALX_nrevk_b% \fi #1.% }% \def\CALX_nrevk_g #1.#2#3#4!#5!#6!#7!#8!#9!% {\expandafter\CALX_nrevk\the\numexpr#1-% \xint_c_vi.#2{#9!#8!#7!#6!#5!#4!#3}}% \def\CALX_nrevk_b #1.{% \ifcase#1 \expandafter\CALX_nrevk_z \or \expandafter\CALX_nrevk_i \or \expandafter\CALX_nrevk_ii \or \expandafter\CALX_nrevk_iii \or \expandafter\CALX_nrevk_iv \else\expandafter\CALX_nrevk_v \fi }% \def\CALX_nrevk_z #1{#1}% \def\CALX_nrevk_i #1#2#3!{#1{#3!#2}}% \def\CALX_nrevk_ii #1#2#3!#4!{#1{#4!#3!#2}}% \def\CALX_nrevk_iii #1#2#3!#4!#5!{#1{#5!#4!#3!#2}}% \def\CALX_nrevk_iv #1#2#3!#4!#5!#6!{#1{#6!#5!#4!#3!#2}}% \def\CALX_nrevk_v #1#2#3!#4!#5!#6!#7!{#1{#7!#6!#5!#4!#3!#2}}% % \end{macrocode} %\begin{lverb} % #1=R (MS-first low blocks of A''), #2=window (LS-first), #3=C, % #4=steps, #5=s, #6=B'. The interleaving \CALX_nilv takes one block of each % list per step (it regrabs the rest of the window). %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_gw #1#21;!\xint:#3#4#5#6{% \expandafter\CALX_nudiv_gl\the\numexpr\CALX_nilv #21;!\xint:#61;;;;;!% {#3}{#11;!}{#4}{#5}% }% % \end{macrocode} % \subsubsection{\csh{CALX_nilv}} % \begin{macrocode} \def\CALX_nilv 1#1!#2\xint:1#3#4!{% \xint_gob_til_sc #3\CALX_nilv_e;% 1#1\expandafter!\the\numexpr1#3#4\expandafter!\the\numexpr\CALX_nilv #2% \xint:% }% \def\CALX_nilv_e;1#1\expandafter!\the\numexpr1#2\xint:{1#1\relax!1;;;;;!}% \def\CALX_nudiv_gl #1;;;;;!#2#3{% \expandafter\CALX_nudiv_x\the\numexpr\CALX_nds {#2}#1;;;;;!#3% }% % \end{macrocode} %\begin{lverb} % The main loop. Input stream: \CALX_nds {C};;;;;!1;!... % (here lacks its final ;;;;;! which is written explicitly). % % \CALX_nds_t receives the top of a copy of L after k = 2nb-4 blocks are % skipped. %\end{lverb} % \begin{macrocode} \def\CALX_ndc_k #1#2#3#4#5#6{#1}% \def\CALX_ndc_ah #1#2#3#4#5#6{#2}% \def\CALX_ndc_al #1#2#3#4#5#6{#3}% \def\CALX_ndc_bh #1#2#3#4#5#6{#4}% \def\CALX_ndc_bl #1#2#3#4#5#6{#5}% \def\CALX_ndc_a #1#2#3#4#5#6{#2#3}% \def\CALX_ndc_b #1#2#3#4#5#6{#4#5}% \def\CALX_ndc_vp #1#2#3#4#5#6{#6}% % \end{macrocode} % \subsubsection{\csh{CALX_nds}} % \begin{macrocode} \def\CALX_nds #1#2;;;;;!{% \CALX_nskip\CALX_nds_t\CALX_ndc_k#1.#2;;;;;!\xint:{#1}#2;;;;;!% }% \def\CALX_nds_t 1#1#2!1#3!1#4!1#5!1#6!1;;;;;!\xint:#7{% \expandafter\CALX_nds_r \the\numexpr#6*\xint_c_e_ix/\CALX_ndc_vp#7+#4#1/\CALX_ndc_vp#7\xint:% {#6}{#4}{#1#2}{#7}% }% \def\CALX_nds_r #1\xint:{% \ifnum#1>\xint_c_e_viii_mone \CALX_nds_rm\fi \expandafter\CALX_nds_s\the\numexpr\xint_c_e_viii+#1\xint:% }% % \end{macrocode} %\begin{lverb} % #1#2#3#4=qh (4 digits), #5=ql, #6=u0, #7=u1, #8=u2, #9=C. % % Splitting M1 = qh v1l + ql v1h and M2 = qh v2l + ql v2h as % M = 10^4 Mh + Ml, with Mh = floor(M/10^4) = (M+5000)/10^4-1: %( q0 v1 = (qh v1h + M1h) b + 10^4 M1l + ql v1l, idem for v2; %: T = U - q0 (v1 b + v2) = Ax b + Bx with %: Bx = u2 - 10^4 M2l - ql v2l in (-2b, b), %: Ax = (u0 - qh v1h - M1h) b + u1 - 10^4 M1l - ql v1l - qh v2h - M2h. %) % 3b+Bx is in (b, 4b) and has nine digits e, so that T = a b + c with % a = Ax+e-3, 0 <= c < b. %\end{lverb} % \begin{macrocode} \def\CALX_nds_rm\fi#1\xint:{\fi\CALX_nds_s 199999999\xint:}% \def\CALX_nds_s 1#1#2#3#4#5\xint:#6#7#8#9{% \expandafter\CALX_nds_u\the\numexpr (#1#2#3#4*\CALX_ndc_al#9+#5*\CALX_ndc_ah#9+5000)/\xint_c_e_iv-\xint_c_i \expandafter\xint:\the\numexpr (#1#2#3#4*\CALX_ndc_bl#9+#5*\CALX_ndc_bh#9+5000)/\xint_c_e_iv-\xint_c_i \xint:{#1#2#3#4}{#5}{#6}{#7}{#8}{#9}% }% \def\CALX_nds_u #1\xint:#2\xint:#3#4#5#6#7#8{% \expandafter\CALX_nds_w\the\numexpr \xint_c_iii*\xint_c_e_viii+#7-#4*\CALX_ndc_bl#8% -(#3*\CALX_ndc_bl#8+#4*\CALX_ndc_bh#8-\xint_c_e_iv*#2)*\xint_c_e_iv \expandafter\xint:\the\numexpr (#5-#3*\CALX_ndc_ah#8-#1)*\xint_c_e_viii+#6% -(#3*\CALX_ndc_al#8+#4*\CALX_ndc_ah#8-\xint_c_e_iv*#1)*\xint_c_e_iv -#4*\CALX_ndc_al#8-#3*\CALX_ndc_bh#8-#2% \xint:{#3#4}{#8}% }% \def\CALX_nds_w #1#2\xint:#3\xint:{% \expandafter\CALX_nds_c\the\numexpr#3+#1-% \xint_c_iii.{#2}% }% % \end{macrocode} %\begin{lverb} % Correction loop: #1=a, #2=c (T = a b + c, 0 <= c < b), #3=q, #4=C. % T < 0 iff a < 0. T >= V iff 2(a-v1) + (0 if c >= v2 else -1) >= 0. %\end{lverb} % \begin{macrocode} \def\CALX_nds_c #1.#2#3#4{% \ifnum#1<\xint_c_ \xint_dothis\CALX_nds_cd\fi \ifnum\numexpr\xint_c_ii*(#1-\CALX_ndc_a#4)\ifnum#2<\CALX_ndc_b#4 -% \xint_c_i\fi <\xint_c_ \xint_dothis\CALX_nds_g\fi \ifnum#3=\xint_c_e_viii_mone \xint_dothis\CALX_nds_g\fi \xint_orthat\CALX_nds_ci {#1}{#2}{#3}{#4}% }% \def\CALX_nds_cd #1#2#3#4{% \expandafter\CALX_nds_ce\the\numexpr\xint_c_e_viii+#2+\CALX_ndc_b#4\xint:% {#1+\CALX_ndc_a#4}{#3-\xint_c_i}{#4}% }% \def\CALX_nds_ce #1#2\xint:#3#4{% \expandafter\CALX_nds_cf\the\numexpr#3+#1-\xint_c_i\expandafter\xint:% \the\numexpr#4\xint:{#2}% }% \def\CALX_nds_cf #1\xint:#2\xint:#3{\CALX_nds_c #1.{#3}{#2}}% \def\CALX_nds_ci #1#2#3#4{% \expandafter\CALX_nds_ce\the\numexpr \xint_c_ii*\xint_c_e_viii+#2-\CALX_ndc_b#4\xint:% {#1-\CALX_ndc_a#4-\xint_c_i}{#3+\xint_c_i}{#4}% }% % \end{macrocode} %\begin{lverb} % \CALX_nds_g #1=a, #2=c, #3=q, #4=C; then ;;;;;!1;!. % % The multiply-subtract pass runs on L. %\end{lverb} % \begin{macrocode} \def\CALX_nds_g #1#2#3#4#5;;;;;!{% \expandafter\CALX_nds_h\the\numexpr\xint_c_e_viii+#3\xint:{#4}#5;;;;;!% }% \def\CALX_nds_h 1#1#2#3#4#5\xint:#6#7;;;;;!{% \expandafter\CALX_nds_p\the\numexpr \CALX_ndms_a 0\xint:#1#2#3#4\xint:#5!#7;;;;;!{#1#2#3#4#5}{#6}% }% \def\CALX_nds_p #1;;;;;!#2{% \ifnum\numexpr#2<\xint_c_ \xint_dothis\CALX_nds_pa\fi \xint_orthat\CALX_nds_pb #1;;;;;!% }% \def\CALX_nds_pa #1;;;;;!{% \expandafter\CALX_nds_pc\the\numexpr\CALX_ndab 0\xint:#1;;;;;!% }% \def\CALX_nds_pc #1;;;;;!#2{\CALX_nds_pb #1;;;;;!{#2-\xint_c_i}}% % \end{macrocode} %\begin{lverb} % #1=new list without ;;;;;!, #2=q (expression), #3=C, then the first block % of R. Emission of 10^8+q into the enclosing \numexpr. %\end{lverb} % \begin{macrocode} \def\CALX_nds_pb #1;;;;;!#2#31#4#5!{% \xint_gob_til_sc #4\CALX_nds_end;% \xint_c_e_viii+#2\expandafter!\the\numexpr\CALX_nds {#3}1#4#5!#1;;;;;!% }% \def\CALX_nds_end;\xint_c_e_viii+#1\expandafter!\the\numexpr\CALX_nds % #21#3!#4;;;;;!% {\xint_c_e_viii+#1\relax!\xint:{#4}}% % \end{macrocode} %\begin{lverb} % Multiply-subtract pass. State \xint:\xint:! where cexpr is % an expression for the borrow c (0 <= c < 10^8), then the pairs % 1!1!. With M = qh bl + ql bh = 10^4 Mh + Ml (10^9+M has ten % digits: 1, Mh on five, Ml on four): %( w - c - q b = X - (qh bh + Mh) 10^8, X = w - c - ql bl - 10^4 Ml, %) % X in (-3 10^8, 10^8); 4 10^8 + X has nine digits e, r is the block, % and the new borrow is qh bh + Mh + 4 - e. At the marker Z, the expression % w_nb - c (0 or -1) is left in braces. %\end{lverb} % \begin{macrocode} \def\CALX_ndms_a #1\xint:#2\xint:#3!1#4!1#5#6#7#8#9!{% \xint_gob_til_sc #5\CALX_ndms_e;% 1#5#6#7#8#9\expandafter!\the\numexpr\expandafter\CALX_ndms_b \the\numexpr\xint_c_e_ix+#2*#9+#3*#5#6#7#8\xint:% #4-(#1)\xint:#3*#9\xint:#2*#5#6#7#8\xint:#2\xint:#3!% }% \def\CALX_ndms_e;#1\xint:#2\xint:#3\xint:#4\xint:#5\xint:#6!{1% \relax;;;;;!{#2}}% \def\CALX_ndms_b 1#1#2#3#4#5#6#7#8#9\xint:{\CALX_ndms_c #1#2#3#4#5% \xint:#6#7#8#9\xint:}% \def\CALX_ndms_c #1\xint:#2\xint:#3\xint:#4\xint:#5\xint:{% \expandafter\CALX_ndms_d \the\numexpr\xint_c_iv*\xint_c_e_viii+#3-#4-#2*\xint_c_e_iv\xint:#5+#1% \xint:% }% \def\CALX_ndms_d #1#2\xint:#3\xint:% {1#2\expandafter!\the\numexpr\CALX_ndms_a #3+\xint_c_iv-#1\xint:}% % \end{macrocode} % \subsubsection{\csh{CALX_ndab}} %\begin{lverb} % Add back: on 1b_0!1r_0!...1b_{nb-1}!1r_{nb-1}!1;;;;;!, r += B' (final % carry dropped), b's copied. %\end{lverb} % \begin{macrocode} \def\CALX_ndab #1\xint:1#2#3!{\xint_gob_til_sc #2\CALX_ndab_e;\CALX_ndab_c #1% \xint:#2#3!}% \def\CALX_ndab_e;\CALX_ndab_c #1\xint:#2!{1\relax;;;;;!}% \def\CALX_ndab_c #1\xint:#2!1#3!{% 1#2\expandafter!\the\numexpr\expandafter\CALX_ndab_d \the\numexpr\xint_c_e_viii+#3+#2+#1\xint:% }% \def\CALX_ndab_d #1#2\xint:{1#2\expandafter!\the\numexpr\CALX_ndab #1-% \xint_c_i\xint:}% % \end{macrocode} %\begin{lverb} % End: \xint:{}{steps}{s}. % The top quotient block may be zero (only the top one). %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_x 1#1!#2\xint:#3#4{% \ifcase\numexpr\ifnum#1=\xint_c_ \ifnum\numexpr#4=\xint_c_i \xint_c_ii\else\xint_c_i\fi \else\xint_c_\fi\relax \expandafter\CALX_nudiv_x_n \or \expandafter\CALX_nudiv_x_z \else\expandafter\CALX_nudiv_x_zero \fi {#1}{#2}{#3}{#4}% }% \def\CALX_nudiv_x_zero #1#2#3#4{\CALX_nudiv_y \xint:{0}{#3}}% \def\CALX_nudiv_x_z #1#2#3#4{% \expandafter\CALX_nudiv_y \romannumeral0\CALX_rev_nounsep {}#2\R!\R!\R!\R!\R!\R!\R!\R!\W\xint:{#4-% \xint_c_i}{#3}% }% \def\CALX_nudiv_x_n #1#2#3#4{% \expandafter\CALX_nudiv_y \romannumeral0\CALX_rev_nounsep {}1#1!#2\R!\R!\R!\R!\R!\R!\R!\R!\W% \xint:{#4}{#3}% }% \def\CALX_nudiv_y #1\xint:#2#3{% \expandafter\CALX_nudiv_z\the\numexpr#2\expandafter.% \the\numexpr\CALX_ndrx #3;;;;;!1;!.{#1}% }% \def\CALX_nudiv_z #1.#2.#3#4#5{#5{#1}{#3}{#4}{#2}}% % \end{macrocode} % \subsubsection{\csh{CALX_ndrx}} % \begin{macrocode} \def\CALX_ndrx 1#1#2!1#3!{% \xint_gob_til_sc #1\CALX_ndrx_e;1#3\expandafter!\the\numexpr\CALX_ndrx }% \def\CALX_ndrx_e;1#1\CALX_ndrx{1\relax;!}% % \end{macrocode} %\begin{lverb} % \CALX_nudiv_rem {s}{R'}: native positive R (or N+0.). For s>0, % R = 10^(8-s) R' / 10^8: \CALX_smallmul (from xintcore) then the low % block (zero) is dropped. Then \CALX_nnorm counts and strips zero top blocks. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_rem #1#2{% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nnorm +}\fi \xint_orthat{\expandafter\CALX_nudiv_rem_a\the\numexpr \expandafter\CALX_smallmul\the\numexpr\CALX_nudiv_pow{% \xint_c_viii-#1}!}#2% }% \def\CALX_nudiv_rem_a 1#1!{\CALX_nnorm +}% % \end{macrocode} %\begin{lverb} % Two-block divisor (nb = 2). No normalization: A'' = A with a zero block % appended (na+1 blocks), reversed once (MS-first); s = 0. With s the number % of leading zeros of v1 (here s only scales the estimate), M = 10^(s+1) and % Vp = v1 M + floor(v2/10^(7-s)) (nine digits), the first guess is %( q0 = round((u0 M) 10^8/Vp) + round(u1 M/Vp) + round(round(u2 M/10^8)/Vp). %) % The window is U = u0 b^2 + u1 b + u2 exactly and the divisor V = v1 b + v2 % exactly, so q = floor(U/V) is the quotient block (no add-back) and % T = U - qV = a b + c is the next (u0, u1). % % Loop: \CALX_ndtw {Vp}{M}{v1h}{v1l}{v2h}{v2l}{u0}{u1}1!...1;! % with u1 (and u2) on eight digits. qh and ql by \numexpr, then %( M1 = qh v1l + ql v1h, M2 = qh v2l + ql v2h, Mh = (M+5000)/10^4-1, %: Bx = 3b + u2 - ql v2l - 10^4 (M2 - 10^4 M2h), %: Ax = (u0 - qh v1h - M1h) b + u1 - 10^4 (M1 - 10^4 M1h) - ql v1l %: - qh v2h - M2h, %) % T = Ax b + Bx, 3b+Bx has nine digits e, a = Ax+e-3, then the % correction loop \CALX_ndtw_l (same tests as \CALX_nds_c). % % Quotient blocks are emitted MS-first into the enclosing \numexpr chain, % which ends with 1;!. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_two #1#2#3#4#5{\CALX_nudiv_tw #5{#2}{#3}#1}% \def\CALX_nudiv_tw 1#1#2#3#4#5!1#6#7#8#9{\CALX_nudiv_tu % {#1#2#3#4}{#5}{#6#7#8#9}}% \def\CALX_nudiv_tu #1#2#3#4!{% \expandafter\CALX_nudiv_tv \expanded{\CALX_nudiv_mp{\CALX_nudiv_gs 1#3#4!\xint:}}{#1}{#2}{#3}{#4}% }% % \end{macrocode} %\begin{lverb} % \CALX_nudiv_mp{s} gives M.P. with M = 10^(s+1), P = 10^(7-s), so that % Vp = v1 M + floor(v2/P) has nine digits (first guess of q0, see the % two-block divisor above). %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_mp #1{\csname CALX_nudiv_mp\the\numexpr#1\endcsname}% \expandafter\def\csname CALX_nudiv_mp0\endcsname{10.10000000.}% \expandafter\def\csname CALX_nudiv_mp1\endcsname{100.1000000.}% \expandafter\def\csname CALX_nudiv_mp2\endcsname{1000.100000.}% \expandafter\def\csname CALX_nudiv_mp3\endcsname{10000.10000.}% \expandafter\def\csname CALX_nudiv_mp4\endcsname{100000.1000.}% \expandafter\def\csname CALX_nudiv_mp5\endcsname{1000000.100.}% \expandafter\def\csname CALX_nudiv_mp6\endcsname{10000000.10.}% \expandafter\def\csname CALX_nudiv_mp7\endcsname{100000000.1.}% \def\CALX_nudiv_tv #1.#2.#3#4#5#6{% \expandafter\CALX_nudiv_tt \the\numexpr#5#6*#1+(#3#4+#2/\xint_c_ii)/#2-\xint_c_i\xint:% {#1}{#5}{#6}{#3}{#4}% }% \def\CALX_nudiv_tt #1\xint:#2#3#4#5#6#7#8{% \expandafter\CALX_nudiv_tf \romannumeral0\CALX_rev_nounsep {}#8\R!\R!\R!\R!\R!\R!\R!\R!\W \xint:{{#1}{#2}{#3}{#4}{#5}{#6}}{#7}% }% % \end{macrocode} %\begin{lverb} % #1, #2 = two top blocks of A, #3 = the others (MS-first), #4 = K = % {Vp}{M}{v1h}{v1l}{v2h}{v2l}, #5 = na. If (a1, a2) < (v1, v2) the window % starts at (a1, a2, a3) (na-2 steps; if na = 2, Q = 0 and R = A), else at % (0, a1, a2) (na-1 steps): in both cases the top quotient block is not 0. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_tcmp #1#2#3#4#5#6#7#8{% \ifnum#1<#5#6 -\xint_c_i\else\ifnum#1>#5#6 \xint_c_\else \ifnum#2<#7#8 -\xint_c_i\else\xint_c_\fi\fi\fi }% \def\CALX_nudiv_tf 1#1!1#2!#3\xint:#4#5{% \ifnum\CALX_nudiv_tcmp{#1}{#2}#4<\xint_c_ \ifnum#5=\xint_c_ii \CALX_nudiv_tq\fi \expandafter\CALX_nudiv_tn \else \expandafter\CALX_nudiv_tp \fi {#1}{#2}{#3}{#4}{#5}% }% \def\CALX_nudiv_tq\fi\expandafter\CALX_nudiv_tn\else\expandafter% \CALX_nudiv_tp\fi #1#2#3#4#5#6{\fi\fi#6{0}{}{0}{1#2!1#1!1;!}}% \def\CALX_nudiv_tn #1#2#3#4#5{% \expandafter\CALX_ndtw_z\the\numexpr\CALX_ndtw #4{#1}{#2}#31;!{#5-% \xint_c_i}% }% \def\CALX_nudiv_tp #1#2#3#4{% \expandafter\CALX_ndtw_z\the\numexpr\CALX_ndtw #4{0}{#1}1#2!#31;!% }% % \end{macrocode} % \subsubsection{\csh{CALX_ndtw}} % \begin{macrocode} \def\CALX_ndtw #1#2#3#4#5#6#7#81#9!{% \xint_gob_til_sc #9\CALX_ndtw_end;% \expandafter\CALX_ndtw_q \the\numexpr(#7*#2)*\xint_c_e_viii/#1+#8*#2/#1+(#9*#2/\xint_c_e_viii)/#1% \xint:% {#3}{#4}{#5}{#6}{#7}{#8}{#9}{{#1}{#2}}% }% \def\CALX_ndtw_end;\expandafter\CALX_ndtw_q\the\numexpr#1% \xint:#2#3#4#5#6#7#8#9% {1\relax;!\xint:{#6}{#7}}% \def\CALX_ndtw_q #1\xint:% {\ifnum#1>\xint_c_e_viii_mone \CALX_ndtw_qm\fi\CALX_ndtw_h #1\xint:}% \def\CALX_ndtw_qm\fi#1\xint:{\fi\CALX_ndtw_h 99999999\xint:}% \def\CALX_ndtw_h #1\xint:{% \expandafter\CALX_ndtw_x \the\numexpr(#1+5000)/\xint_c_e_iv-\xint_c_i\expandafter\xint:% \the\numexpr#1-\xint_c_e_iv*((#1+5000)/\xint_c_e_iv-\xint_c_i)\xint:% }% \def\CALX_ndtw_x #1\xint:#2\xint:#3#4#5#6#7#8#9{% \expandafter\CALX_ndtw_w\the\numexpr \xint_c_iii*\xint_c_e_viii+#9-#2*#6% -(#1*#6+#2*#5-\xint_c_e_iv*((#1*#6+#2*#5+5000)/\xint_c_e_iv-\xint_c_i))% *\xint_c_e_iv \expandafter\xint:\the\numexpr (#7-#1*#3-(#1*#4+#2*#3+5000)/\xint_c_e_iv+\xint_c_i)*\xint_c_e_viii+#8% -(#1*#4+#2*#3-\xint_c_e_iv*((#1*#4+#2*#3+5000)/\xint_c_e_iv-\xint_c_i))% *\xint_c_e_iv -#2*#4-#1*#5-(#1*#6+#2*#5+5000)/\xint_c_e_iv+\xint_c_i \xint:{#1*\xint_c_e_iv+#2}{#3}{#4}{#5}{#6}% }% \def\CALX_ndtw_w #1#2\xint:#3\xint:{% \expandafter\CALX_ndtw_l\the\numexpr#3+#1-% \xint_c_iii.{#2}% }% \def\CALX_ndtw_l #1.#2#3#4#5#6#7{% \ifnum#1<\xint_c_ \xint_dothis\CALX_ndtw_d\fi \ifnum\numexpr\xint_c_ii*(#1-#4#5)\ifnum#2<#6#7 -\xint_c_i\fi <\xint_c_ \xint_dothis\CALX_ndtw_g\fi \ifnum\numexpr#3=\xint_c_e_viii_mone \xint_dothis\CALX_ndtw_g\fi \xint_orthat\CALX_ndtw_i {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_ndtw_d #1#2#3#4#5#6#7{% \expandafter\CALX_ndtw_e\the\numexpr\xint_c_e_viii+#2+#6#7\xint:% {#1+#4#5}{#3-\xint_c_i}{#4}{#5}{#6}{#7}% }% \def\CALX_ndtw_i #1#2#3#4#5#6#7{% \expandafter\CALX_ndtw_e\the\numexpr\xint_c_ii*\xint_c_e_viii+#2-#6#7% \xint:% {#1-#4#5-\xint_c_i}{#3+\xint_c_i}{#4}{#5}{#6}{#7}% }% \def\CALX_ndtw_e #1#2\xint:#3#4{% \expandafter\CALX_ndtw_f\the\numexpr#3+#1-\xint_c_i\expandafter\xint:% \the\numexpr#4\xint:{#2}% }% \def\CALX_ndtw_f #1\xint:#2\xint:#3{\CALX_ndtw_l #1.{#3}{#2}}% \def\CALX_ndtw_g #1#2#3#4#5#6#7#8{% \xint_c_e_viii+#3\expandafter!\the\numexpr\CALX_ndtw % #8{#4}{#5}{#6}{#7}{#1}{#2}% }% % \end{macrocode} %\begin{lverb} % Exit: 1;!\xint:{u0}{u1}{na}{s}; R' = 1u1!1u0!1;!. % % \CALX_nudiv_qx \xint:{R'}{steps}{s} drops a zero top % block, reverses Q and delivers {nq}{Q}{s}{R'}. %\end{lverb} % \begin{macrocode} \def\CALX_ndtw_z #11;!\xint:#2#3#4{% \expandafter\CALX_ndtw_zz\the\numexpr\xint_c_e_viii+#2\xint:{#3}{#4}{#1}% }% \def\CALX_ndtw_zz #1\xint:#2#3#4{\CALX_nudiv_qx #4\xint:{1#2!#1!1;!}{#3-% \xint_c_i}{0}}% \def\CALX_nudiv_qx 1#1!#2\xint:#3#4{% \ifcase\numexpr\ifnum#1=\xint_c_ \ifnum\numexpr#4=\xint_c_i \xint_c_ii\else\xint_c_i\fi \else\xint_c_\fi\relax \expandafter\CALX_nudiv_qx_n \or \expandafter\CALX_nudiv_qx_z \else\expandafter\CALX_nudiv_qx_zero \fi {#1}{#2}{#3}{#4}% }% \def\CALX_nudiv_qx_zero #1#2#3#4{\CALX_nudiv_qy \xint:{0}{#3}}% \def\CALX_nudiv_qx_z #1#2#3#4{% \expandafter\CALX_nudiv_qy \romannumeral0\CALX_rev_nounsep {}#2\R!\R!\R!\R!\R!\R!\R!\R!\W\xint:{#4-% \xint_c_i}{#3}% }% \def\CALX_nudiv_qx_n #1#2#3#4{% \expandafter\CALX_nudiv_qy \romannumeral0\CALX_rev_nounsep {}1#1!#2\R!\R!\R!\R!\R!\R!\R!\R!\W% \xint:{#4}{#3}% }% \def\CALX_nudiv_qy #1\xint:#2#3#4#5{% \expandafter#5\expandafter{\the\numexpr#2}{#1}{#4}{#3}% }% % \end{macrocode} %\begin{lverb} % Tiny one-block divisor d <= 45249. With 10^8 = Bq d + Bm (0 <= Bm < d) % and incoming remainder r < d, a block a gives %( y = r Bm + a, q = r Bq + floor(y/d), r' = y - d floor(y/d), %) % exact since r 10^8 + a = r Bq d + y; y + round(d/2) < 2^31 for d <= 45249. % floor(y/d) = (y + round(d/2))/d - 1. One explicit \numexpr per block plus % the emission (10^8 + q is evaluated by the enclosing \numexpr chain). %( \CALX_ndts \xint:\xint:\xint:\xint:! %: 1;! %) % \CALX_ndts_k . expands to 0\xint:d\xint:dh\xint:Bq\xint:Bm! %\end{lverb} % \begin{macrocode} \def\CALX_ndts_k #1.{% \expandafter\CALX_ndts_ka\the\numexpr(\xint_c_e_viii+#1/\xint_c_ii)/#1-% \xint_c_i \xint:#1\xint:% }% \def\CALX_ndts_ka #1\xint:#2\xint:{% \expandafter\CALX_ndts_kb\the\numexpr\xint_c_e_viii-#1*#2\expandafter% \xint:% \the\numexpr#2/\xint_c_ii\xint:#1\xint:#2\xint:% }% \def\CALX_ndts_kb #1\xint:#2\xint:#3\xint:#4\xint:#5{#50\xint:#4\xint:#2% \xint:#3\xint:#1!}% \def\CALX_nudiv_ot #1#2#3#4{% \expandafter\CALX_ndts_s \romannumeral0\CALX_rev_nounsep {}#4\R!\R!\R!\R!\R!\R!\R!\R!\W% \xint:{#3}{#2}#1% }% \def\CALX_ndts_s #1\xint:#2{% \expandafter\CALX_ndts_z\the\numexpr\CALX_ndts_k #2.\CALX_ndts #11;!% }% % \end{macrocode} % \subsubsection{\csh{CALX_ndts}} % \begin{macrocode} \def\CALX_ndts #1\xint:#2\xint:#3\xint:#4\xint:#5!1#6#7!{% \xint_gob_til_sc #6\CALX_ndts_end;% \expandafter\CALX_ndts_b\the\numexpr(#1)*#5+#6#7\xint:#1\xint:#2\xint:#3% \xint:#4\xint:#5!% }% \def\CALX_ndts_end;#1\xint:#2\xint:#3!{1\relax;!\xint:{#2}}% \def\CALX_ndts_b #1\xint:#2\xint:#3\xint:#4\xint:#5\xint:#6!{% \xint_c_e_viii+(#2)*#5+(#1+#4)/#3-\xint_c_i \expandafter!\the\numexpr\CALX_ndts #1-#3*((#1+#4)/#3-\xint_c_i)\xint:#3% \xint:#4\xint:#5\xint:#6!% }% \def\CALX_ndts_z #11;!\xint:#2#3{% \expandafter\CALX_ndts_zz\the\numexpr\xint_c_e_viii+(#2)\xint:{#3}{#1}% }% \def\CALX_ndts_zz #1\xint:#2#3{\CALX_nudiv_qx #3\xint:{#1!1;!}{#2}{0}}% % \end{macrocode} %\begin{lverb} % Unrolled entries for na = 2, 3, 4 (tiny divisor): the MS-first input is % written from the parameters and the quotient is assembled directly % (the top block may be zero, the others are present). %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_otd #1#2{% \ifcase#2 \or\or \expandafter\CALX_ndts_ii \or \expandafter\CALX_ndts_iii \or \expandafter\CALX_ndts_iv \else \expandafter\CALX_nudiv_ot \fi #1{#2}% }% \def\CALX_ndts_ii #1#2#3#4{\CALX_ndts_iia #4{#3}#1}% \def\CALX_ndts_iia 1#1!1#2!#3{% \expandafter\CALX_ndts_iib\the\numexpr\CALX_ndts_k #3.\CALX_ndts % 1#2!1#1!1;!% }% \def\CALX_ndts_iib 1#1!1#2!1;!\xint:#3{% \expandafter\CALX_ndts_iic\the\numexpr\xint_c_e_viii+(#3)\xint:{#1}{#2}% }% \def\CALX_ndts_iic #1\xint:#2#3#4{% \ifnum#2=\xint_c_ \xint_dothis{#4{1}{1#3!}}\fi \xint_orthat{#4{2}{1#3!1#2!}}{0}{#1!1;!}% }% \def\CALX_ndts_iii #1#2#3#4{\CALX_ndts_iiia #4{#3}#1}% \def\CALX_ndts_iiia 1#1!1#2!1#3!#4{% \expandafter\CALX_ndts_iiib\the\numexpr\CALX_ndts_k #4.\CALX_ndts % 1#3!1#2!1#1!1;!% }% \def\CALX_ndts_iiib 1#1!1#2!1#3!1;!\xint:#4{% \expandafter\CALX_ndts_iiic\the\numexpr\xint_c_e_viii+(#4)% \xint:{#1}{1#3!1#2!}% }% \def\CALX_ndts_iiic #1\xint:#2#3#4{% \ifnum#2=\xint_c_ \xint_dothis{#4{2}{#3}}\fi \xint_orthat{#4{3}{#31#2!}}{0}{#1!1;!}% }% \def\CALX_ndts_iv #1#2#3#4{\CALX_ndts_iva #4{#3}#1}% \def\CALX_ndts_iva 1#1!1#2!1#3!1#4!#5{% \expandafter\CALX_ndts_ivb\the\numexpr\CALX_ndts_k #5.\CALX_ndts % 1#4!1#3!1#2!1#1!1;!% }% \def\CALX_ndts_ivb 1#1!1#2!1#3!1#4!1;!\xint:#5{% \expandafter\CALX_ndts_ivc\the\numexpr\xint_c_e_viii+(#5)% \xint:{#1}{1#4!1#3!1#2!}% }% \def\CALX_ndts_ivc #1\xint:#2#3#4{% \ifnum#2=\xint_c_ \xint_dothis{#4{3}{#3}}\fi \xint_orthat{#4{4}{#31#2!}}{0}{#1!1;!}% }% % \end{macrocode} %\begin{lverb} % Three-block divisor (nb = 3). Estimate and correction loop as for nb = 2 % (U = u0 u1 u2, V = v1 v2: q is the true quotient block or one more), the % macros are duplicated (\CALX_ndth_q ... \CALX_ndth_f), only the exit % \CALX_ndth_g differs: with T = a b + c = U - qV, the window minus q B' is %( a b^2 + c b + u3 - q v3, q v3 = (qh v3h + M3h) b + 10^4 M3l + ql v3l. %: X = 3b + u3 - ql v3l - 10^4 M3l in (b, 4b): digits e1, %: Y = 3b + c - qh v3h - M3h - 3 + e1 in (b, 4b): digits e2, %: r0 = a + e2 - 3; if r0 < 0, B' is added back and q decreases. %) % Loop state: \CALX_ndth {C12}{V3}{u0}{u1}{u2}1!...1;! % C12 = {Vp}{M}{{v1h}{v1l}{v2h}{v2l}}, V3 = {v3h}{v3l}; q0 as for nb = 2. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_three #1#2#3#4#5{\CALX_nudiv_hw #5{#2}{#3}#1}% \def\CALX_nudiv_hw 1#1#2#3#4#5!1#6#7#8#9{\CALX_nudiv_ha % {#1#2#3#4}{#5}{#6#7#8#9}}% \def\CALX_nudiv_ha #1#2#3#4!1#5#6#7#8{\CALX_nudiv_hb % {#1}{#2}{#3}{#4}{#5#6#7#8}}% \def\CALX_nudiv_hb #1#2#3#4#5#6!{% \expandafter\CALX_nudiv_hv \expanded{\CALX_nudiv_mp{\CALX_nudiv_gs 1#5#6!% \xint:}}{#1}{#2}{#3}{#4}{#5}{#6}% }% \def\CALX_nudiv_hv #1.#2.#3#4#5#6#7#8{% \expandafter\CALX_nudiv_hc \the\numexpr#7#8*#1+(#5#6+#2/\xint_c_ii)/#2-\xint_c_i\xint:% {#1}{{#7}{#8}{#5}{#6}}{{#3}{#4}}% }% \def\CALX_nudiv_hc #1\xint:#2#3#4#5#6{% \expandafter\CALX_nudiv_he \romannumeral0\CALX_rev_nounsep {}#6\R!\R!\R!\R!\R!\R!\R!\R!\W \xint:{{#1}{#2}{#3}}{#4}{#5}% }% \def\CALX_nudiv_hcmp #1#2#3#4#5{% \ifnum#1<\CALX_ndth_vone#4 -\xint_c_i\else\ifnum#1>\CALX_ndth_vone#4 % \xint_c_\else \ifnum#2<\CALX_ndth_vtwo#4 -\xint_c_i\else\ifnum#2>\CALX_ndth_vtwo#4 % \xint_c_\else \ifnum#3<\CALX_ndth_vthree#5 -\xint_c_i\else\xint_c_\fi\fi\fi\fi\fi }% \def\CALX_nudiv_he 1#1!1#2!1#3!#4\xint:#5#6#7{% \ifnum\CALX_nudiv_hcmp{#1}{#2}{#3}{#5}{#6}<\xint_c_ \ifnum#7=\xint_c_iii \CALX_nudiv_hq\fi \expandafter\CALX_nudiv_hn \else \expandafter\CALX_nudiv_hp \fi {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_nudiv_hq\fi\expandafter\CALX_nudiv_hn\else\expandafter% \CALX_nudiv_hp\fi #1#2#3#4#5#6#7#8{\fi\fi#8{0}{}{0}{1#3!1#2!1#1!1;!}}% \def\CALX_nudiv_hn #1#2#3#4#5#6#7{% \expandafter\CALX_ndth_z\the\numexpr\CALX_ndth % {#5}{#6}{#1}{#2}{#3}#41;!{#7-\xint_c_iii}{0}% }% \def\CALX_nudiv_hp #1#2#3#4#5#6#7{% \expandafter\CALX_ndth_z\the\numexpr\CALX_ndth % {#5}{#6}{0}{#1}{#2}1#3!#41;!{#7-\xint_c_ii}{0}% }% % \end{macrocode} % \subsubsection{\csh{CALX_ndth}} % \begin{macrocode} \def\CALX_ndth #1{\CALX_ndth_a #1}% \def\CALX_ndth_a #1#2#3#4#5#6#7{% \expandafter\CALX_ndth_q \the\numexpr(#5*#2)*\xint_c_e_viii/#1+#6*#2/#1+(#7*#2/\xint_c_e_viii)/#1% \xint:% #3{#5}{#6}{#7}{{#1}{#2}{#3}}{#4}% }% \def\CALX_ndth_q #1\xint:% {\ifnum#1>\xint_c_e_viii_mone \CALX_ndth_qm\fi\CALX_ndth_h #1\xint:}% \def\CALX_ndth_qm\fi#1\xint:{\fi\CALX_ndth_h 99999999\xint:}% \def\CALX_ndth_h #1\xint:{% \expandafter\CALX_ndth_x \the\numexpr(#1+5000)/\xint_c_e_iv-\xint_c_i\expandafter\xint:% \the\numexpr#1-\xint_c_e_iv*((#1+5000)/\xint_c_e_iv-\xint_c_i)\xint:% }% \def\CALX_ndth_x #1\xint:#2\xint:#3#4#5#6#7#8#9{% \expandafter\CALX_ndth_w\the\numexpr \xint_c_iii*\xint_c_e_viii+#9-#2*#6% -(#1*#6+#2*#5-\xint_c_e_iv*((#1*#6+#2*#5+5000)/\xint_c_e_iv-\xint_c_i))% *\xint_c_e_iv \expandafter\xint:\the\numexpr (#7-#1*#3-(#1*#4+#2*#3+5000)/\xint_c_e_iv+\xint_c_i)*\xint_c_e_viii+#8% -(#1*#4+#2*#3-\xint_c_e_iv*((#1*#4+#2*#3+5000)/\xint_c_e_iv-\xint_c_i))% *\xint_c_e_iv -#2*#4-#1*#5-(#1*#6+#2*#5+5000)/\xint_c_e_iv+\xint_c_i \xint:{#1*\xint_c_e_iv+#2}{#3}{#4}{#5}{#6}% }% \def\CALX_ndth_w #1#2\xint:#3\xint:{% \expandafter\CALX_ndth_l\the\numexpr#3+#1-% \xint_c_iii.{#2}% }% \def\CALX_ndth_l #1.#2#3#4#5#6#7{% \ifnum#1<\xint_c_ \xint_dothis\CALX_ndth_d\fi \ifnum\numexpr\xint_c_ii*(#1-#4#5)\ifnum#2<#6#7 -\xint_c_i\fi <\xint_c_ \xint_dothis\CALX_ndth_g\fi \ifnum\numexpr#3=\xint_c_e_viii_mone \xint_dothis\CALX_ndth_g\fi \xint_orthat\CALX_ndth_i {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_ndth_d #1#2#3#4#5#6#7{% \expandafter\CALX_ndth_e\the\numexpr\xint_c_e_viii+#2+#6#7\xint:% {#1+#4#5}{#3-\xint_c_i}{#4}{#5}{#6}{#7}% }% \def\CALX_ndth_i #1#2#3#4#5#6#7{% \expandafter\CALX_ndth_e\the\numexpr\xint_c_ii*\xint_c_e_viii+#2-#6#7% \xint:% {#1-#4#5-\xint_c_i}{#3+\xint_c_i}{#4}{#5}{#6}{#7}% }% \def\CALX_ndth_e #1#2\xint:#3#4{% \expandafter\CALX_ndth_f\the\numexpr#3+#1-\xint_c_i\expandafter\xint:% \the\numexpr#4\xint:{#2}% }% \def\CALX_ndth_f #1\xint:#2\xint:#3{\CALX_ndth_l #1.{#3}{#2}}% % \end{macrocode} %\begin{lverb} % Exit of the correction loop: #1=a, #2=c, #3=q, #4-#7=v1h v1l v2h v2l, % #8=C12, #9=V3, then 1! in the stream. %\end{lverb} % \begin{macrocode} \def\CALX_ndth_g #1#2#3#4#5#6#7#8#9{% \expandafter\CALX_ndth_m\the\numexpr(#3+5000)/\xint_c_e_iv-\xint_c_i% \xint:#9% {#1}{#2}{#3}{#8}% }% \def\CALX_ndth_m #1\xint:#2#3#4#5#6#71#8!{% \expandafter\CALX_ndth_n\the\numexpr \xint_c_iii*\xint_c_e_viii+#8-(#6-\xint_c_e_iv*#1)*#3% -(#1*#3+(#6-\xint_c_e_iv*#1)*#2% -\xint_c_e_iv*((#1*#3+(#6-\xint_c_e_iv*#1)*#2+5000)/\xint_c_e_iv-% \xint_c_i))% *\xint_c_e_iv \xint:{#1*#2+(#1*#3+(#6-\xint_c_e_iv*#1)*#2+5000)/\xint_c_e_iv-\xint_c_i}% {#4}{#5}{#6}{#7}{{#2}{#3}}% }% \def\CALX_ndth_n #1#2\xint:#3#4#5{% \expandafter\CALX_ndth_o\the\numexpr \xint_c_iii*\xint_c_e_viii+#5-(#3)-\xint_c_iii+#1% \xint:{#2}{#4}% }% \def\CALX_ndth_o #1#2\xint:#3#4{% \expandafter\CALX_ndth_oa\the\numexpr#4+#1-\xint_c_iii\xint:{#2}{#3}% }% \def\CALX_ndth_oa #1\xint:{% \ifnum#1<\xint_c_ \expandafter\CALX_ndth_ab\else\expandafter\CALX_ndth_p% \fi {#1}% }% \def\CALX_ndth_p #1#2#3#4#5#61#7#8!{% \xint_gob_til_sc #7\CALX_ndth_end;% \xint_c_e_viii+#4\expandafter!\the\numexpr\CALX_ndth % {#5}{#6}{#1}{#2}{#3}1#7#8!% }% \def\CALX_ndth_end;\xint_c_e_viii+#1\expandafter!\the\numexpr\CALX_ndth % #2#3#4#5#61;!% {\xint_c_e_viii+#1\relax!\xint:{#4}{#5}{#6}}% % \end{macrocode} %\begin{lverb} % Add back (rare): #1=r0 (<0), #2=r1, #3=r2, #4=q, #5=C12, #6=V3. %\end{lverb} % \begin{macrocode} \def\CALX_ndth_vone #1#2#3{\CALX_ndth_vonea #3}% \def\CALX_ndth_vonea #1#2#3#4{#1#2}% \def\CALX_ndth_vtwo #1#2#3{\CALX_ndth_vtwoa #3}% \def\CALX_ndth_vtwoa #1#2#3#4{#3#4}% \def\CALX_ndth_vthree #1#2{#1#2}% \def\CALX_ndth_ab #1#2#3#4#5#6{% \expandafter\CALX_ndth_ac\the\numexpr\xint_c_e_viii+#3+% \CALX_ndth_vthree#6\xint:% {#1}{#2}{#4}{#5}{#6}% }% \def\CALX_ndth_ac #1#2\xint:#3#4#5#6{% \expandafter\CALX_ndth_ad\the\numexpr\xint_c_e_viii+#4+% \CALX_ndth_vtwo#6+#1-\xint_c_i\xint:% {#2}{#3}{#5}{#6}% }% \def\CALX_ndth_ad #1#2\xint:#3#4#5#6{% \expandafter\CALX_ndth_ae\the\numexpr#4+\CALX_ndth_vone#6+#1-\xint_c_i% \xint:% {#2}{#3}{#5-\xint_c_i}{#6}% }% \def\CALX_ndth_ae #1\xint:{\CALX_ndth_p {#1}}% \def\CALX_ndth_z #1\xint:#2#3#4{% \expandafter\CALX_ndth_zz\the\numexpr\xint_c_e_viii+(#2)% \xint:{#3}{#4}{#1}% }% \def\CALX_ndth_zz #1\xint:#2#3#4{\CALX_nudiv_qx #4\xint:{1#3!1#2!#1!1;!}}% % \end{macrocode} %\begin{lverb} % Four-block divisor (nb = 4), no normalization, estimate and loop as for % nb = 2 (duplicated as \CALX_ndfo_q ... \CALX_ndfo_f). With T = a b + c, % the window minus q B' is a b^3 + c b^2 + u3 b + u4 - q (v3 b + v4): %( X4 = 3b + u4 - ql v4l - 10^4 M4l digits e4 %: X3 = 5b + u3 - ql v3l - 10^4 M3l - H4 - 3 + e4 digits e3 %: Y = 3b + c - H3 - 5 + e3 digits e2 %: r0 = a + e2 - 3 (add-back if negative) %) % with Hk = qh vkh + Mkh, Mk = qh vkl + ql vkh. % % Loop state: \CALX_ndfo {C12}{V34}{u0}{u1}{u2}{u3}1!...1;! % C12 = {Vp}{M}{{v1h}{v1l}{v2h}{v2l}}, V34 = {v3h}{v3l}{v4h}{v4l}. % % After the correction loop: pack P3 = {a}{c}{q}{C12}. %\end{lverb} % \begin{macrocode} \def\CALX_nudiv_four #1#2#3#4#5{\CALX_nudiv_fw #5{#2}{#3}#1}% \def\CALX_nudiv_fw 1#1#2#3#4#5!1#6#7#8#9{\CALX_nudiv_fa % {#1#2#3#4}{#5}{#6#7#8#9}}% \def\CALX_nudiv_fa #1#2#3#4!1#5#6#7#8{\CALX_nudiv_fb % {{#3}{#4}{#1}{#2}}{#5#6#7#8}}% \def\CALX_nudiv_fb #1#2#3!1#4#5#6#7{\CALX_nudiv_fc {#1}{#2}{#3}{#4#5#6#7}}% \def\CALX_nudiv_fc #1#2#3#4#5!{% \expandafter\CALX_nudiv_fv \expanded{\CALX_nudiv_mp{\CALX_nudiv_gs 1#4#5!% \xint:}}{#4}{#5}{#2}{#3}{#1}% }% \def\CALX_nudiv_fv #1.#2.#3#4#5#6{% \expandafter\CALX_nudiv_fd \the\numexpr#3#4*#1+(#5#6+#2/\xint_c_ii)/#2-\xint_c_i\xint:% {#1}{{#3}{#4}{#5}{#6}}% }% \def\CALX_nudiv_fd #1\xint:#2#3#4#5#6{% \expandafter\CALX_nudiv_fe \romannumeral0\CALX_rev_nounsep {}#6\R!\R!\R!\R!\R!\R!\R!\R!\W \xint:{{#1}{#2}{#3}}{#4}{#5}% }% \def\CALX_nudiv_fcmp #1#2#3#4#5#6{% \ifnum#1<\CALX_ndth_vone#5 -\xint_c_i\else\ifnum#1>\CALX_ndth_vone#5 % \xint_c_\else \ifnum#2<\CALX_ndth_vtwo#5 -\xint_c_i\else\ifnum#2>\CALX_ndth_vtwo#5 % \xint_c_\else \ifnum#3<\CALX_ndfo_vthree#6 -\xint_c_i\else\ifnum#3>\CALX_ndfo_vthree#6 % \xint_c_\else \ifnum#4<\CALX_ndfo_vfour#6 -\xint_c_i\else\xint_c_\fi\fi\fi\fi\fi\fi\fi }% \def\CALX_nudiv_fe 1#1!1#2!1#3!1#4!#5\xint:#6#7#8{% \ifnum\CALX_nudiv_fcmp{#1}{#2}{#3}{#4}{#6}{#7}<\xint_c_ \ifnum#8=\xint_c_iv \CALX_nudiv_fq\fi \expandafter\CALX_nudiv_fn \else \expandafter\CALX_nudiv_fp \fi {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% }% \def\CALX_nudiv_fq\fi\expandafter\CALX_nudiv_fn\else\expandafter% \CALX_nudiv_fp\fi #1#2#3#4#5#6#7#8#9{\fi\fi#9{0}{}{0}{1#4!1#3!1#2!1#1!1;!}}% \def\CALX_nudiv_fn #1#2#3#4#5#6#7#8{% \expandafter\CALX_ndfo_z \the\numexpr\CALX_ndfo {#6}{#7}{#1}{#2}{#3}{#4}#51;!{#8-\xint_c_iv}{0}% }% \def\CALX_nudiv_fp #1#2#3#4#5#6#7#8{% \expandafter\CALX_ndfo_z \the\numexpr\CALX_ndfo {#6}{#7}{0}{#1}{#2}{#3}1#4!#51;!{#8-% \xint_c_iii}{0}% }% % \end{macrocode} % \subsubsection{\csh{CALX_ndfo}} % \begin{macrocode} \def\CALX_ndfo #1{\CALX_ndfo_a #1}% \def\CALX_ndfo_a #1#2#3#4#5#6#7{% \expandafter\CALX_ndfo_q \the\numexpr(#5*#2)*\xint_c_e_viii/#1+#6*#2/#1+(#7*#2/\xint_c_e_viii)/#1% \xint:% #3{#5}{#6}{#7}{{#1}{#2}{#3}}{#4}% }% \def\CALX_ndfo_q #1\xint:% {\ifnum#1>\xint_c_e_viii_mone \CALX_ndfo_qm\fi\CALX_ndfo_h #1\xint:}% \def\CALX_ndfo_qm\fi#1\xint:{\fi\CALX_ndfo_h 99999999\xint:}% \def\CALX_ndfo_h #1\xint:{% \expandafter\CALX_ndfo_x \the\numexpr(#1+5000)/\xint_c_e_iv-\xint_c_i\expandafter\xint:% \the\numexpr#1-\xint_c_e_iv*((#1+5000)/\xint_c_e_iv-\xint_c_i)\xint:% }% \def\CALX_ndfo_x #1\xint:#2\xint:#3#4#5#6#7#8#9{% \expandafter\CALX_ndfo_w\the\numexpr \xint_c_iii*\xint_c_e_viii+#9-#2*#6% -(#1*#6+#2*#5-\xint_c_e_iv*((#1*#6+#2*#5+5000)/\xint_c_e_iv-\xint_c_i))% *\xint_c_e_iv \expandafter\xint:\the\numexpr (#7-#1*#3-(#1*#4+#2*#3+5000)/\xint_c_e_iv+\xint_c_i)*\xint_c_e_viii+#8% -(#1*#4+#2*#3-\xint_c_e_iv*((#1*#4+#2*#3+5000)/\xint_c_e_iv-\xint_c_i))% *\xint_c_e_iv -#2*#4-#1*#5-(#1*#6+#2*#5+5000)/\xint_c_e_iv+\xint_c_i \xint:{#1*\xint_c_e_iv+#2}{#3}{#4}{#5}{#6}% }% \def\CALX_ndfo_w #1#2\xint:#3\xint:{% \expandafter\CALX_ndfo_l\the\numexpr#3+#1-% \xint_c_iii.{#2}% }% \def\CALX_ndfo_l #1.#2#3#4#5#6#7{% \ifnum#1<\xint_c_ \xint_dothis\CALX_ndfo_d\fi \ifnum\numexpr\xint_c_ii*(#1-#4#5)\ifnum#2<#6#7 -\xint_c_i\fi <\xint_c_ \xint_dothis\CALX_ndfo_g\fi \ifnum\numexpr#3=\xint_c_e_viii_mone \xint_dothis\CALX_ndfo_g\fi \xint_orthat\CALX_ndfo_i {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_ndfo_d #1#2#3#4#5#6#7{% \expandafter\CALX_ndfo_e\the\numexpr\xint_c_e_viii+#2+#6#7\xint:% {#1+#4#5}{#3-\xint_c_i}{#4}{#5}{#6}{#7}% }% \def\CALX_ndfo_i #1#2#3#4#5#6#7{% \expandafter\CALX_ndfo_e\the\numexpr\xint_c_ii*\xint_c_e_viii+#2-#6#7% \xint:% {#1-#4#5-\xint_c_i}{#3+\xint_c_i}{#4}{#5}{#6}{#7}% }% \def\CALX_ndfo_e #1#2\xint:#3#4{% \expandafter\CALX_ndfo_f\the\numexpr#3+#1-\xint_c_i\expandafter\xint:% \the\numexpr#4\xint:{#2}% }% \def\CALX_ndfo_f #1\xint:#2\xint:#3{\CALX_ndfo_l #1.{#3}{#2}}% % \end{macrocode} %\begin{lverb} % Exit: #1=a, #2=c, #3=q, #4-#7 v1h v1l v2h v2l, #8=C12, #9=V34, then % {u3}1! in the stream. %\end{lverb} % \begin{macrocode} \def\CALX_ndfo_pa #1#2#3#4{#1}% \def\CALX_ndfo_pc #1#2#3#4{#2}% \def\CALX_ndfo_pq #1#2#3#4{#3}% \def\CALX_ndfo_g #1#2#3#4#5#6#7#8#9{\CALX_ndfo_m {{#1}{#2}{#3}{#8}}#9}% \def\CALX_ndfo_m #1#2#3#4#5#61#7!{% \expandafter\CALX_ndfo_n \the\numexpr(\CALX_ndfo_pq#1+5000)/\xint_c_e_iv-\xint_c_i\xint:% {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_ndfo_n #1\xint:#2#3#4#5#6#7#8{% \expandafter\CALX_ndfo_o\the\numexpr \xint_c_iii*\xint_c_e_viii+#8-(\CALX_ndfo_pq#2-\xint_c_e_iv*#1)*#6% -(#1*#6+(\CALX_ndfo_pq#2-\xint_c_e_iv*#1)*#5-\xint_c_e_iv*((#1*#6+(% \CALX_ndfo_pq#2-\xint_c_e_iv*#1)*#5+5000)/\xint_c_e_iv-\xint_c_i))*% \xint_c_e_iv \xint:{#1*#5+(#1*#6+(\CALX_ndfo_pq#2-\xint_c_e_iv*#1)*#5+5000)/% \xint_c_e_iv-\xint_c_i}{#1}{#2}{#3}{#4}{#7}% {{#3}{#4}{#5}{#6}}% }% \def\CALX_ndfo_o #1#2\xint:#3#4#5#6#7#8{% \expandafter\CALX_ndfo_r\the\numexpr \xint_c_v*\xint_c_e_viii+#8-(\CALX_ndfo_pq#5-\xint_c_e_iv*#4)*#7% -(#4*#7+(\CALX_ndfo_pq#5-\xint_c_e_iv*#4)*#6-\xint_c_e_iv*((#4*#7+(% \CALX_ndfo_pq#5-\xint_c_e_iv*#4)*#6+5000)/\xint_c_e_iv-\xint_c_i))*% \xint_c_e_iv -(#3)-\xint_c_iii+#1% \xint:{#4*#6+(#4*#7+(\CALX_ndfo_pq#5-\xint_c_e_iv*#4)*#6+5000)/% \xint_c_e_iv-\xint_c_i}{#2}{#5}% }% \def\CALX_ndfo_r #1#2\xint:#3#4#5{% \expandafter\CALX_ndfo_s\the\numexpr \xint_c_iii*\xint_c_e_viii+\CALX_ndfo_pc#5-(#3)-\xint_c_v+#1% \xint:{#2}{#4}{#5}% }% \def\CALX_ndfo_s #1#2\xint:#3#4#5{% \expandafter\CALX_ndfo_t\the\numexpr\CALX_ndfo_pa#5+#1-\xint_c_iii\xint:% {#2}{#3}{#4}{#5}% }% \def\CALX_ndfo_t #1\xint:#2#3#4#5{% \ifnum#1<\xint_c_ \expandafter\CALX_ndfo_ab\else\expandafter\CALX_ndfo_tu% \fi #5{#1}{#2}{#3}{#4}% }% \def\CALX_ndfo_tu #1#2{\CALX_ndfo_y}% \def\CALX_ndfo_y #1#2#3#4#5#6#71#8#9!{% \xint_gob_til_sc #8\CALX_ndfo_end;% \xint_c_e_viii+#1\expandafter!\the\numexpr\CALX_ndfo % {#2}{#7}{#3}{#4}{#5}{#6}1#8#9!% }% \def\CALX_ndfo_end;\xint_c_e_viii+#1\expandafter!\the\numexpr\CALX_ndfo % #2#3#4#5#6#71;!% {\xint_c_e_viii+#1\relax!\xint:{#4}{#5}{#6}{#7}}% % \end{macrocode} %\begin{lverb} % Add back (rare): #1=a, #2=c, #3=q, #4=C12 (P3 unpacked), #5=r0 (<0), % #6=r1, #7=r2, #8=r3, #9=V34. %\end{lverb} % \begin{macrocode} \def\CALX_ndfo_vthree #1#2#3#4{#1#2}% \def\CALX_ndfo_vfour #1#2#3#4{#3#4}% \def\CALX_ndfo_pvone #1#2#3#4{\CALX_ndth_vone#4}% \def\CALX_ndfo_pvtwo #1#2#3#4{\CALX_ndth_vtwo#4}% \def\CALX_ndfo_ab #1#2#3#4#5#6#7#8#9{% \expandafter\CALX_ndfo_ac\the\numexpr\xint_c_e_viii+#8+\CALX_ndfo_vfour#9% \xint:% {#5}{#6}{#7}{#9}{{#1}{#2}{#3}{#4}}% }% \def\CALX_ndfo_ac #1#2\xint:#3#4#5#6{% \expandafter\CALX_ndfo_ad\the\numexpr\xint_c_e_viii+#5+% \CALX_ndfo_vthree#6+#1-\xint_c_i \xint:{#2}{#3}{#4}{#6}% }% \def\CALX_ndfo_ad #1#2\xint:#3#4#5#6#7{% \expandafter\CALX_ndfo_ae\the\numexpr\xint_c_e_viii+#5+% \CALX_ndfo_pvtwo#7+#1-\xint_c_i \xint:{#2}{#3}{#4}{#6}{#7}% }% \def\CALX_ndfo_ae #1#2\xint:#3#4#5#6#7{% \expandafter\CALX_ndfo_af\the\numexpr#5+\CALX_ndfo_pvone#7+#1-\xint_c_i% \xint:% {#2}{#3}{#4}{#6}{#7}% }% \def\CALX_ndfo_af #1\xint:#2#3#4#5#6{\CALX_ndfo_ah #6{#1}{#2}{#3}{#4}{#5}}% \def\CALX_ndfo_ah #1#2#3{\CALX_ndfo_y {#3-\xint_c_i}}% \def\CALX_ndfo_z #1\xint:#2#3#4#5{% \expandafter\CALX_ndfo_zz\the\numexpr\xint_c_e_viii+(#2)% \xint:{#3}{#4}{#5}{#1}% }% \def\CALX_ndfo_zz #1\xint:#2#3#4#5{\CALX_nudiv_qx #5% \xint:{1#4!1#3!1#2!#1!1;!}}% % \end{macrocode} % \subsection{Native signed division} % \subsubsection{\csh{CALX_ndivtrunc}, \csh{CALX_nmodtrunc}, % \csh{CALX_ndivfloor}, \csh{CALX_nmod}, \csh{CALX_nquo}, \csh{CALX_nrem}, % \csh{CALX_ndivround}, \csh{CALX_ndivision}, \csh{CALX_ndivmod}} %\begin{lverb} % Syntax (use with \romannumeral0; A, B f-expanded native integers): %( % \CALX_n{A}{B} -> Z (op: divtrunc, modtrunc, %: divfloor, mod, quo, rem, divround) %: \CALX_ndivision{A}{B} -> {Q}{R} %: \CALX_ndivmod{A}{B} -> {Q}{R} %) % Z, Q, R native integers (zero divisor: I values or the trap value, see % below). % % Signed division. All macros are used as \romannumeral0\CALX_n...{A}{B}, % the arguments being f-expanded native integers (A first). With a = |A|, % b = |B|, q = floor(a/b), r = a - q b (unsigned core \CALX_nudiv), sA, sB % the signs: %- \CALX_ndivtrunc$empty: sA sB q (truncation); %- \CALX_nmodtrunc$empty: sA r, remainder of the truncated division; %- \CALX_ndivfloor$empty: sA sB (q + d), d = 1 if sA <> sB and r <> 0, else 0; %- \CALX_nmod$empty: A - B \CALX_ndivfloor(A,B), i.e. sA r + e sB b with e = 1 % if sA <> sB and r <> 0, else 0 (sign of B or zero); %- \CALX_nquo$empty: sA sB (q + d), d = 1 if sA = - and r <> 0, else 0; this % is sB floor(A/b) (xint's \xintiiQuo); %- \CALX_nrem$empty: A - B \CALX_nquo(A,B) = sA r + e b, e = 1 if sA = - and % r <> 0, else 0; it is >= 0 (xint's \xintiiRem); %- \CALX_ndivround$empty: sA sB (q + d), d = 1 if 2r >= b, else 0 (rounding % half away from zero, xint's \xintiiDivRound); %- \CALX_ndivision$empty: {\CALX_nquo}{\CALX_nrem} (xint's \xintiiDivision); %- \CALX_ndivmod$empty: {\CALX_ndivfloor}{\CALX_nmod} (xint's \xintiiDivMod). % % A zero divisor is signalled as in Python's decimal module (conditions of % the signals section, trap value N+0. which is what xint returns): %- quotient of x <> 0 by 0: DivisionByZero, handler argument the sign of x, % default result I+ or I-; quotient 0 by 0: DivisionUndefined, I?; %- remainder of x <> 0 by 0: InvalidOperation, I?; remainder 0 by 0: % DivisionUndefined, I?; %- pair, x <> 0 by 0: DivisionByZero then InvalidOperation, {I+ or I-}{I?}; % pair 0 by 0: one DivisionUndefined, {I?}{I?}. % % Implementation. \CALX_ndiv_y receives B, A and three tokens of the % family: a starter, a macro for B = 0, a macro for A = 0. The starter is % followed by {na}{A}{nb}{B}. For the families which do not need B % after the division the starter is a parameterless macro expanding to % \CALX_nudiv, so that nothing is copied; the others copy {nb}{B} once % after the arguments of \CALX_nudiv. \CALX_nudiv leaves the following % tokens untouched, hence receives %( {nq}{Q}{s}{R'} or {nq}{Q}{s}{R'}{nb}{B} %) % Quotient-only families never compute R (the test r <> 0 is \CALX_nrz on % R', which does not need the normalization of R'). q + 1 is one pass of % the addition kernel (\CALX_nqinc). The rounding test 2r >= b doubles R % with the addition kernel, compares block counts, and for equal counts % reads the final borrow state of the subtraction kernel computing 2R - B. % The added terms e b and e sB b are done by \CALX_nadd_y. %\end{lverb} % \begin{macrocode} \def\CALX_ndiv_x #1#2\xint:#3#4#5#6% {\expandafter\CALX_nsp_t\expandafter\CALX_ndiv_y\expandafter\CALX_ndiv_sp \expandafter#1\romannumeral`&&@#6\xint:#1#2\xint:#3#4#5}% % \end{macrocode} %\begin{lverb} % \CALX_ndiv_sp ..\xint:..\xint: (A % dividend, B divisor; = \CALX_ndiv_zq, _zr or _zp tells quotient, % remainder or pair). Quotient: NaN: I?; Inf/Inf: InvalidOperation (I?); % Inf/0: Inf with the sign of A; Inf/c: Inf, product of signs; c/Inf: 0. % % Remainder: NaN: I?; Inf dividend: InvalidOperation (I?); finite A by % Inf: A (Python decimal model, for all members of the family). Pair: % {quotient}{remainder}. %\end{lverb} % \begin{macrocode} \def\CALX_ndiv_sp #1#2#3#4\xint:#5#6#7\xint:#8#9% {% \ifx#9\CALX_ndiv_zq\xint_dothis\CALX_ndiv_spq\fi \ifx#9\CALX_ndiv_zr\xint_dothis\CALX_ndiv_spr\fi \xint_orthat\CALX_ndiv_spp #2#3{#4}#5#6{#7}% }% \def\CALX_ndiv_spq #1#2#3#4#5#6#7% {% \if ?#2\xint_dothis{ I?}\fi \if ?#5\xint_dothis{ I?}\fi \if N#4\xint_dothis{ N+0.}\fi \if I#1\xint_dothis{\CALX_nsig{InvalidOperation}{inf // inf}{}}\fi \ifnum\CALX_nsp_z#3\xint:=\xint_c_ \xint_dothis{ I#5}\fi \xint_orthat{\CALX_nsp_ps#2#5}% }% \def\CALX_ndiv_spr #1#2#3#4#5#6#7% {% \if ?#2\xint_dothis{ I?}\fi \if ?#5\xint_dothis{ I?}\fi \if I#4\xint_dothis{\CALX_nsig{InvalidOperation}{inf mod x}{}}\fi \xint_orthat{ N#5#6}% }% \def\CALX_ndiv_spp #1#2#3#4#5#6#7% {\CALX_npair{\CALX_ndiv_spq#1#2{#3}#4#5{#6}{}}{% \CALX_ndiv_spr#1#2{#3}#4#5{#6}{}}}% \def\CALX_ndiv_y N#1#2.#3\xint:N#4#5.#6\xint:#7#8#9{% \ifnum#2=\xint_c_ \xint_dothis{#8#4{#5}}\fi \ifnum#5=\xint_c_ \xint_dothis#9\fi \xint_orthat{#7{#5}{#6}{#2}{#3}#4#1}% }% \def\CALX_ndivtrunc #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_ndt_go\CALX_ndiv_zq\CALX_ndiv_zz}% \def\CALX_nmodtrunc #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_nmt_go\CALX_ndiv_zr\CALX_ndiv_zz}% \def\CALX_ndivfloor #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_ndf_go\CALX_ndiv_zq\CALX_ndiv_zz}% \def\CALX_nmod #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_nmd_go\CALX_ndiv_zr\CALX_ndiv_zz}% \def\CALX_nquo #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_nqu_go\CALX_ndiv_zq\CALX_ndiv_zz}% \def\CALX_nrem #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_nre_go\CALX_ndiv_zr\CALX_ndiv_zz}% \def\CALX_ndivround #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_ndr_go\CALX_ndiv_zq\CALX_ndiv_zz}% \def\CALX_ndivision #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_ndn_go\CALX_ndiv_zp\CALX_ndiv_zzp}% \def\CALX_ndivmod #1{\expandafter\CALX_ndiv_x\romannumeral`&&@#1\xint:% \CALX_ndm_go\CALX_ndiv_zp\CALX_ndiv_zzp}% % \end{macrocode} % \subsubsection{\csh{CALX_nsig}} %\begin{lverb} % Zero operands. \CALX_ndiv_zq, _zr, _zp receive {nA}. % % \CALX_nsig{}{}{} signals and puts the % space token ending \romannumeral0 in front of the result. %\end{lverb} % \begin{macrocode} \def\CALX_ndiv_zz{ N+0.}% \def\CALX_ndiv_zzp{{N+0.}{N+0.}}% \def\CALX_nsig #1#2#3% {\expandafter\CALX_sp\romannumeral`&&@% \CALX_signalcondition{#1}{#2}{#3}{N+0.}}% \def\CALX_ndiv_zq #1#2{% \ifnum#2=\xint_c_ \xint_dothis{\CALX_nsig{DivisionUndefined}{0 // 0}{}}\fi \xint_orthat{\CALX_nsig{DivisionByZero}{x // 0}{#1}}% }% \def\CALX_ndiv_zr #1#2{% \ifnum#2=\xint_c_ \xint_dothis{\CALX_nsig{DivisionUndefined}{0 mod 0}{}}% \fi \xint_orthat{\CALX_nsig{InvalidOperation}{x mod 0}{}}% }% \def\CALX_ndiv_zp #1#2{% \ifnum#2=\xint_c_ \xint_dothis\CALX_ndiv_zpu\fi \xint_orthat{\CALX_npair{\CALX_nsig{DivisionByZero}{x // 0}{#1}}% {\CALX_nsig{InvalidOperation}{x mod 0}{}}}% }% \def\CALX_ndiv_zpu{\expandafter\CALX_ndiv_zpv\romannumeral`&&@% \CALX_signalcondition{DivisionUndefined}{divmod(0, 0)}{}{N+0.}\xint:}% \def\CALX_ndiv_zpv #1\xint:{{#1}{#1}}% % \end{macrocode} % \subsubsection{\csh{CALX_nq}, \csh{CALX_nqinc}, \csh{CALX_nrz}, % \csh{CALX_nrs}, \csh{CALX_nrb}, \csh{CALX_npair}} %\begin{lverb} % Helpers. %- \CALX_nq {nq}{Q}: the native integer (N+0. if nq = 0). %- \CALX_nqinc {nq}{Q}: the same for Q + 1 (addition kernel with % the one block list 100000001!, which is not longer than Q). %- \CALX_nrz \xint:{}{}: selects according to R' = 0 % (R' terminated by 1;!; zero top blocks are allowed). %- \CALX_nrs {s}{R'}: R as native integer (N+0. if R = 0). %- \CALX_nrb N+.\xint:{nb}{B}: N+0. if R = 0, else % sR R + sB B by \CALX_nadd_y. %- \CALX_npair {}{}: {Q}{R}, each code being expanded by % \romannumeral0 (R first). %\end{lverb} % \begin{macrocode} \def\CALX_nq #1#2#3{% \ifnum#2=\xint_c_ \xint_dothis{ N+0.}\fi \xint_orthat{ N#1#2.#3}% }% \def\CALX_nqinc #1#2#3{% \ifnum#2=\xint_c_ \xint_dothis{ N#11.100000001!}\fi \xint_orthat{\expandafter\CALX_naddm\expandafter#1\the\numexpr#2% \expandafter.\the\numexpr\CALX_nadd_a\xint_c_ii 100000001!1;!1;!1;!1;!\W #31;!1;!1;!1;!\W\xint:}% }% \def\CALX_nrz 1#1#2!{% \xint_gob_til_sc #1\CALX_nrz_z;% \ifnum#1#2=\xint_c_ \expandafter\CALX_nrz\else\expandafter\CALX_nrz_nz\fi }% \def\CALX_nrz_z;#1\xint:#2#3{#2}% \def\CALX_nrz_nz #1\xint:#2#3{#3}% \def\CALX_nrs #1#2#3% {\expandafter\CALX_nrs_a\expandafter#1\romannumeral0% \CALX_nudiv_rem{#2}{#3}\xint:}% \def\CALX_nrs_a #1N+#2.{% \ifnum#2=\xint_c_ \xint_dothis\CALX_nrs_z\fi \xint_orthat\CALX_nrs_n #1N+#2.% }% \def\CALX_nrs_z #1N+#2.#3\xint:{ N+0.}% \def\CALX_nrs_n #1N+#2.#3\xint:{ N#1#2.#3}% \def\CALX_nrb N+#1.{% \ifnum#1=\xint_c_ \xint_dothis\CALX_nrb_z\fi \xint_orthat\CALX_nrb_n #1.% }% \def\CALX_nrb_z #1.#2\xint:#3#4#5#6{ N+0.}% \def\CALX_nrb_n #1.#2\xint:#3#4#5#6% {\CALX_nadd_y N#4#5.#6\xint:N#3#1.#21;!1;!1;!1;!\W\xint:}% \def\CALX_npair #1#2{\expandafter\CALX_npair_a\romannumeral0#2\xint:{#1}}% \def\CALX_npair_a #1\xint:#2{\expandafter\CALX_npair_b\romannumeral0#2% \xint:{#1}}% \def\CALX_npair_b #1\xint:{{#1}}% % \end{macrocode} %\begin{lverb} % Quotients and remainders without B after the division. %\end{lverb} % \begin{macrocode} \def\CALX_ndt_go{\CALX_nudiv\CALX_ndt_q}% \def\CALX_ndt_q #1#2#3#4#5#6{\CALX_psign#5#6\CALX_nq{#1}{#2}}% \def\CALX_nmt_go{\CALX_nudiv\CALX_nmt_r}% \def\CALX_nmt_r #1#2#3#4#5#6{\CALX_nrs#5{#3}{#4}}% \def\CALX_ndf_go{\CALX_nudiv\CALX_ndf_q}% \def\CALX_ndf_q #1#2#3#4#5#6{% \if#5#6\xint_dothis{\CALX_nq+}\fi \xint_orthat{\CALX_nrz#4\xint:{\CALX_nq-}{\CALX_nqinc-}}{#1}{#2}% }% \def\CALX_nqu_go{\CALX_nudiv\CALX_nqu_q}% \def\CALX_nqu_q #1#2#3#4#5#6{% \if#5+\xint_dothis{\CALX_nq#6}\fi \xint_orthat{\CALX_psign-#6\CALX_nqu_a#4\xint:}{#1}{#2}% }% \def\CALX_nqu_a #1#2\xint:{\CALX_nrz#2\xint:{\CALX_nq#1}{\CALX_nqinc#1}}% % \end{macrocode} %\begin{lverb} % Families using B after the division: the starter copies {nb}{B}. % % Rounding: \CALX_ndr_a gets R, doubles it (\CALX_nsum_p), \CALX_ndr_c % compares 2R with B, \CALX_ndr_e reads the borrow state (1: 2R >= B). %\end{lverb} % \begin{macrocode} \def\CALX_ndr_go #1#2#3#4{\CALX_nudiv\CALX_ndr_q{#1}{#2}{#3}{#4}{#3}{#4}}% \def\CALX_ndr_q #1#2#3#4#5#6#7#8{% \expandafter\CALX_ndr_a\romannumeral0\CALX_nudiv_rem{#3}{#4}\xint:% {#5}{#6}#7#8{#1}{#2}% }% \def\CALX_ndr_a N+#1.{% \ifnum#1=\xint_c_ \xint_dothis\CALX_ndr_a_z\fi \xint_orthat\CALX_ndr_a_n #1.% }% \def\CALX_ndr_a_z #1.#2\xint:#3#4{\CALX_ndr_dn}% \def\CALX_ndr_a_n #1.#2\xint:#3#4{% \expandafter\CALX_ndr_c \romannumeral0\expandafter\CALX_naddm\expandafter+% \the\numexpr#1\expandafter.\the\numexpr\CALX_nadd_a\xint_c_ii #21;!1;!1;!1;!\W#21;!1;!1;!1;!\W\xint:\xint:{#3}{#4}% }% \def\CALX_ndr_c N+#1.#2\xint:#3#4{% \ifnum#1>#3 \xint_dothis\CALX_ndr_up\fi \ifnum#1<#3 \xint_dothis\CALX_ndr_dn\fi \xint_orthat{\expandafter\CALX_ndr_e\the\numexpr \CALX_nsub_a\xint_c_i #41;!1;!1;!1;!\W #21;!1;!1;!1;!\W}% }% \def\CALX_ndr_e #11;!#2% {\if#21\expandafter\CALX_ndr_up\else\expandafter\CALX_ndr_dn\fi}% \def\CALX_ndr_up #1#2{\CALX_psign#1#2\CALX_nqinc}% \def\CALX_ndr_dn #1#2{\CALX_psign#1#2\CALX_nq}% \def\CALX_nmd_go #1#2#3#4{\CALX_nudiv\CALX_nmd_r{#1}{#2}{#3}{#4}{#3}{#4}}% \def\CALX_nmd_r #1#2#3#4#5#6#7#8{% \if#7#8\xint_dothis{\CALX_nrs#7{#3}{#4}}\fi \xint_orthat{\expandafter\CALX_nrb\romannumeral0\CALX_nudiv_rem{#3}{#4}% \xint:#7#8{#5}{#6}}% }% \def\CALX_nre_go #1#2#3#4{\CALX_nudiv\CALX_nre_r{#1}{#2}{#3}{#4}{#3}{#4}}% \def\CALX_nre_r #1#2#3#4#5#6#7#8{% \if#7+\xint_dothis{\CALX_nudiv_rem{#3}{#4}}\fi \xint_orthat{\expandafter\CALX_nrb\romannumeral0\CALX_nudiv_rem{#3}{#4}% \xint:-+{#5}{#6}}% }% \def\CALX_ndn_go #1#2#3#4{\CALX_nudiv\CALX_ndn_r{#1}{#2}{#3}{#4}{#3}{#4}}% \def\CALX_ndn_r #1#2#3#4#5#6#7#8{% \if#7+\xint_dothis{\CALX_npair{\CALX_nq#8{#1}{#2}}{% \CALX_nudiv_rem{#3}{#4}}}\fi \xint_orthat{\expandafter\CALX_ndn_a\romannumeral0\CALX_nudiv_rem{#3}{#4}% \xint:{#5}{#6}#8{#1}{#2}}% }% \def\CALX_ndn_a N+#1.{% \ifnum#1=\xint_c_ \xint_dothis\CALX_ndn_a_z\fi \xint_orthat\CALX_ndn_a_n #1.% }% \def\CALX_ndn_a_z #1.#2\xint:#3#4#5#6#7% {\CALX_npair{\CALX_psign-#5\CALX_nq{#6}{#7}}{ N+0.}}% \def\CALX_ndn_a_n #1.#2\xint:#3#4#5#6#7% {\CALX_npair{\CALX_psign-#5\CALX_nqinc{#6}{#7}}% {\CALX_nadd_y N+#3.#4\xint:N-#1.#21;!1;!1;!1;!\W\xint:}}% \def\CALX_ndm_go #1#2#3#4{\CALX_nudiv\CALX_ndm_r{#1}{#2}{#3}{#4}{#3}{#4}}% \def\CALX_ndm_r #1#2#3#4#5#6#7#8{% \if#7#8\xint_dothis{\CALX_npair{\CALX_nq+{#1}{#2}}{\CALX_nrs#7{#3}{#4}}}% \fi \xint_orthat{\expandafter\CALX_ndm_a\romannumeral0\CALX_nudiv_rem{#3}{#4}% \xint:{#5}{#6}#7#8{#1}{#2}}% }% \def\CALX_ndm_a N+#1.{% \ifnum#1=\xint_c_ \xint_dothis\CALX_ndm_a_z\fi \xint_orthat\CALX_ndm_a_n #1.% }% \def\CALX_ndm_a_z #1.#2\xint:#3#4#5#6#7#8% {\CALX_npair{\CALX_nq-{#7}{#8}}{ N+0.}}% \def\CALX_ndm_a_n #1.#2\xint:#3#4#5#6#7#8% {\CALX_npair{\CALX_nqinc-{#7}{#8}}% {\CALX_nadd_y N#6#3.#4\xint:N#5#1.#21;!1;!1;!1;!\W\xint:}}% % \end{macrocode} % \subsection{Already expanded native arithmetic} %\begin{lverb} % Inputs to the following interfaces are two expanded native integers, % both with N tags. No argument expansion, tag dispatch, or conversion % is needed. Each kernel appends its own block terminators. %\end{lverb} % \begin{macrocode} \def\CALX_naddready #1#2{\CALX_nadd_y #1\xint:#21;!1;!1;!1;!\W\xint:}% \def\CALX_nsubready #1#2{\CALX_nsub_y #2\xint:#11;!1;!1;!1;!\W\xint:}% \def\CALX_nmulready #1#2{\CALX_nmul_y #1\xint:#21;!\xint:}% % \end{macrocode} % \subsection{Native power} %\begin{lverb} % Syntax (use with \romannumeral0; k a \numexpr expression, k >= 0; X % f-expanded native integer, not I): %( % \CALX_npow{k}{X} -> N. (X^k; X^0 = 1) %) % Binary powering, least significant bit of k first. The even low bits of % k only square X (\CALX_npow_e); at the first odd bit the accumulator is % the current base itself (no multiplication by 1), then \CALX_npow_l % squares the base and multiplies it into the accumulator for each further % bit, the last squaring being skipped. The new base and accumulator are % computed inside one \expanded and handed over as braced groups. %\end{lverb} % \begin{macrocode} \def\CALX_npow #1#2% {\expandafter\CALX_npow_a\the\numexpr#1\expandafter.% \romannumeral`&&@#2\xint:}% \def\CALX_npow_a #1.#2\xint:% {\ifnum#1=\xint_c_ \xint_dothis{ N+1.100000001!}\fi \xint_orthat{\CALX_npow_e #1.{#2}}}% \def\CALX_npow_e #1.#2% {% \ifnum#1=\xint_c_i \xint_dothis{ #2}\fi \ifodd#1 \xint_dothis{\expandafter\CALX_npow_l \the\numexpr(#1-\xint_c_i)/\xint_c_ii\expandafter.% \expandafter{\romannumeral0\CALX_nmul{#2}{#2}}{#2}}\fi \xint_orthat{\expandafter\CALX_npow_e\the\numexpr#1/\xint_c_ii% \expandafter.\expandafter{\romannumeral0\CALX_nmul{#2}{#2}}}% }% \def\CALX_npow_l #1.#2#3% {% \ifnum#1=\xint_c_i \xint_dothis{\CALX_nmul{#3}{#2}}\fi \ifodd#1 \xint_dothis{\expandafter\CALX_npow_l \the\numexpr(#1-\xint_c_i)/\xint_c_ii\expandafter.% \expanded{{\romannumeral0\CALX_nmul{#2}{#2}}% {\romannumeral0\CALX_nmul{#3}{#2}}}}\fi \xint_orthat{\expandafter\CALX_npow_l\the\numexpr#1/\xint_c_ii% \expandafter.\expandafter{\romannumeral0\CALX_nmul{#2}{#2}}{#3}}% }% % \end{macrocode} % \subsection{Native partial factorial and factorial} %\begin{lverb} % Syntax (use with \romannumeral0; a, b \numexpr expressions, 0 <= a < b < % 10^8, k = 1 .. 10^4, not checked): %( % \CALX_npfac{a}{b} -> N+. ((a+1)(a+2)...b) %: \CALX_nfac{k} -> N+. (k! = pfac(0, k)) %) % The accumulator is a block list, least significant first, terminated by % 1;!; each step multiplies it by one block y < 10^8, a product of four % (factors <= 98), three (<= 463), two (<= 9999) or one consecutive % integers, with \CALX_smallmul, inside one \numexpr chain which puts the % new list in place. The last step (one to four factors, \CALX_pfac_end_..) % hands the list to \CALX_nnorm (count, header): the kernel never produces % a zero top block. %\end{lverb} %\begin{lverb} % Moved here from xint.sty with release 1.2 (to be usable by \bnumexpr). % % Partially rewritten with release 1.2 to benefit from the inner format of the % 1.2 multiplication. % % With current default settings of the etex memory and a.t.t.o.w (11/2015) the % maximal possible computation is 5971! (which has 19956 digits). % % % % Note (end november 2015): I also tried out a quickly written recursive % (binary split) implementation % %( \catcode`_ 11 %: \catcode`^ 11 %: \long\def\xint_firstofthree #1#2#3{#1}$% %: \long\def\xint_secondofthree #1#2#3{#2}$% %: \long\def\xint_thirdofthree #1#2#3{#3}$% %: $% quickly written factorial using binary split recursive method %: \def\tFac {\romannumeral-`0\tfac }$% %: \def\tfac #1{\expandafter\XINT_mul_out %: \romannumeral-`0\ufac {1}{#1}1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W}$% %: \def\ufac #1#2{\ifcase\numexpr#2-#1\relax %: \expandafter\xint_firstofthree %: \or %: \expandafter\xint_secondofthree %: \else %: \expandafter\xint_thirdofthree %: \fi %: {\the\numexpr\xint_c_e_viii+#1!1;!}$% %: {\the\numexpr\xint_c_e_viii+#1*#2!1;!}$% %: {\expandafter\vfac\the\numexpr (#1+#2)/\xint_c_ii.#1.#2.}$% %: }$% %: \def\vfac #1.#2.#3.$% %: {$% %: \expandafter %: \wfac\expandafter %: {\romannumeral-`0\expandafter %: \ufac\expandafter{\the\numexpr #1+\xint_c_i}{#3}}$% %: {\ufac {#2}{#1}}$% %: }$% %: \def\wfac #1#2{\expandafter\zfac\romannumeral-`0#2\W #1}$% %: \def\zfac {\the\numexpr\XINT_mul_loop 100000000!1;!\W }$% core multiplication... %: \catcode`_ 8 %: \catcode`^ 7 %) % and I was quite surprised that it was only about 1.6x--2x slower in the range % N=200 to 2000 than the \xintiiFac here which attempts to be smarter... % % Note (2017, 1.2l): I found out some code comment of mine that the code here % should be more in the style of \xintiiBinomial, but I left matters % untouched. % %\end{lverb} % \begin{macrocode} \def\CALX_nfac #1% {\expandafter\CALX_pfac_b\expandafter1\expandafter.\the\numexpr#1.% 100000001!1;!}% \def\CALX_npfac #1#2% {\expandafter\CALX_pfac_b\the\numexpr\xint_c_i+#1\expandafter.% \the\numexpr#2.100000001!1;!}% \def\CALX_pfac_b #1.% {% \ifnum #1>9999 \xint_dothis\CALX_pfac_vbigloop \fi \ifnum #1>463 \xint_dothis\CALX_pfac_bigloop \fi \ifnum #1>98 \xint_dothis\CALX_pfac_medloop \fi \xint_orthat\CALX_pfac_smallloop #1.% }% \def\CALX_pfac_smallloop #1.#2.% {% \ifcase\numexpr #2-#1\relax \expandafter\CALX_pfac_end_ \or \expandafter\CALX_pfac_end_i \or \expandafter\CALX_pfac_end_ii \or \expandafter\CALX_pfac_end_iii \else\expandafter\CALX_pfac_smallloop_a \fi #1.#2.% }% \def\CALX_pfac_smallloop_a #1.#2.% {% \expandafter\CALX_pfac_smallloop_b \the\numexpr #1+\xint_c_iv\expandafter.% \the\numexpr #2\expandafter.% \the\numexpr\expandafter\CALX_smallmul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)% *(#1+\xint_c_iii)!% }% \def\CALX_pfac_smallloop_b #1.% {% \ifnum #1>98 \expandafter\CALX_pfac_medloop \else \expandafter\CALX_pfac_smallloop \fi #1.% }% \def\CALX_pfac_medloop #1.#2.% {% \ifcase\numexpr #2-#1\relax \expandafter\CALX_pfac_end_ \or \expandafter\CALX_pfac_end_i \or \expandafter\CALX_pfac_end_ii \else\expandafter\CALX_pfac_medloop_a \fi #1.#2.% }% \def\CALX_pfac_medloop_a #1.#2.% {% \expandafter\CALX_pfac_medloop_b \the\numexpr #1+\xint_c_iii\expandafter.% \the\numexpr #2\expandafter.% \the\numexpr\expandafter\CALX_smallmul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_pfac_medloop_b #1.% {% \ifnum #1>463 \expandafter\CALX_pfac_bigloop \else \expandafter\CALX_pfac_medloop \fi #1.% }% \def\CALX_pfac_bigloop #1.#2.% {% \ifcase\numexpr #2-#1\relax \expandafter\CALX_pfac_end_ \or \expandafter\CALX_pfac_end_i \else\expandafter\CALX_pfac_bigloop_a \fi #1.#2.% }% \def\CALX_pfac_bigloop_a #1.#2.% {% \expandafter\CALX_pfac_bigloop_b \the\numexpr #1+\xint_c_ii\expandafter.% \the\numexpr #2\expandafter.% \the\numexpr\expandafter \CALX_smallmul\the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)!% }% \def\CALX_pfac_bigloop_b #1.% {% \ifnum #1>9999 \expandafter\CALX_pfac_vbigloop \else \expandafter\CALX_pfac_bigloop \fi #1.% }% \def\CALX_pfac_vbigloop #1.#2.% {% \ifnum #2=#1 \expandafter\CALX_pfac_end_ \else\expandafter\CALX_pfac_vbigloop_a \fi #1.#2.% }% \def\CALX_pfac_vbigloop_a #1.#2.% {% \expandafter\CALX_pfac_vbigloop \the\numexpr #1+\xint_c_i\expandafter.% \the\numexpr #2\expandafter.% \the\numexpr\expandafter\CALX_smallmul\the\numexpr\xint_c_e_viii+#1!% }% \def\CALX_pfac_end_iii #1.#2.% {% \expandafter\CALX_nnorm\expandafter+% \the\numexpr\expandafter\CALX_smallmul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)% *(#1+\xint_c_iii)!% }% \def\CALX_pfac_end_ii #1.#2.% {% \expandafter\CALX_nnorm\expandafter+% \the\numexpr\expandafter\CALX_smallmul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_pfac_end_i #1.#2.% {% \expandafter\CALX_nnorm\expandafter+% \the\numexpr\expandafter\CALX_smallmul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)!% }% \def\CALX_pfac_end_ #1.#2.% {% \expandafter\CALX_nnorm\expandafter+% \the\numexpr\expandafter\CALX_smallmul\the\numexpr \xint_c_e_viii+#1!% }% \catcode`N=11 \catcode`I=11 % \end{macrocode} % \subsection{\csh{XINT_split_fromleft}} %\begin{lverb} % Moved verbatim from xint.sty at 2.0a1 (used there by \xintDecSplit and % others, and by the float printer core \XINT_pfloat_P of calxfp.sty). %\end{lverb} % \begin{macrocode} \def\XINT_split_fromleft {\expandafter\XINT_split_fromleft_a\the\numexpr\xint_c_viii-}% \def\XINT_split_fromleft_a #1% {% \xint_UDsignfork #1\XINT_split_fromleft_b -{\XINT_split_fromleft_end_a #1}% \krof }% \def\XINT_split_fromleft_b #1.#2#3#4#5#6#7#8#9% {% \expandafter\XINT_split_fromleft_clean \the\numexpr1#2#3#4#5#6#7#8#9\expandafter \XINT_split_fromleft_a\the\numexpr\xint_c_viii-#1.% }% \def\XINT_split_fromleft_end_a #1.% {% \expandafter\XINT_split_fromleft_clean \the\numexpr1\csname XINT_split_fromleft_end#1\endcsname }% \def\XINT_split_fromleft_clean 1{ }% \expandafter\def\csname XINT_split_fromleft_end7\endcsname #1% {#1\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end6\endcsname #1#2% {#1#2\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end5\endcsname #1#2#3% {#1#2#3\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end4\endcsname #1#2#3#4% {#1#2#3#4\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end3\endcsname #1#2#3#4#5% {#1#2#3#4#5\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end2\endcsname #1#2#3#4#5#6% {#1#2#3#4#5#6\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end1\endcsname #1#2#3#4#5#6#7% {#1#2#3#4#5#6#7\XINT_split_fromleft_end_b}% \expandafter\def\csname XINT_split_fromleft_end0\endcsname #1#2#3#4#5#6#7#8% {#1#2#3#4#5#6#7#8\XINT_split_fromleft_end_b}% \def\XINT_split_fromleft_end_b #1\xint_bye#2\xint_bye.{.#1}% puis . \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {calxcore} % \cleardoublepage\let\calxcorenameUp\undefined %\gardesactifs %\let\relax %\let<*calxint>\gardesinactifs %^^A--------------------------------------------------- %<*calxint>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1) ; fill-paragraph-function: nil; -*- % \clearpage\csname calxintnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \calxintnameimp implementation} % \RaisedLabel{sec:calxintimp} % \addedcalx{2.0a1} % % \localtableofcontents % %\begin{lverb} % calx: sister of xint.sty. It loads calxcore.sty and adds the native % integer square root. The xint macros it uses are copied unmodified and % renamed CALX_; xint.sty is not modified. %\end{lverb} % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code of this subsection is copied over from the xint packages, with % the package names changed. % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@calxint.sty\endcsname \expandafter\let\expandafter\w\csname ver@calxcore.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage calxint Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{calxint}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of calxint.sty \ifx\w\relax % but calxcore.sty not yet loaded. \def\z{\endgroup\input calxcore.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % calxcore.sty not yet loaded. \def\z{\endgroup\RequirePackage{calxcore}}% \fi \else \def\z{\endgroup\endinput}% calxint already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{calxint}% [2026/11/01 v2.0a1 Expandable operations on big integers (JFB)]% % \end{macrocode} % \subsection{\csh{xintBool}, \csh{xintToggle}} %\begin{lverb} % 1.09c %\end{lverb} % \begin{macrocode} \def\xintBool #1{\romannumeral`&&@% \csname if#1\endcsname\expandafter1\else\expandafter0\fi }% \def\xintToggle #1{\romannumeral`&&@\iftoggle{#1}{1}{0}}% % \end{macrocode} % \subsection{Integer square root: small and medium sizes} % \subsubsection{\csh{CALX_sqrt_start}} %\begin{lverb} % xint's square root start and its small and medium paths (inputs of at % most 16 digits), renamed. It is only called with at most 16 digits % (calx, and xint's \xintiiSquareRoot since s58). % % Output: {N}{D} with D = N^2 - X > 0, N smallest (N = isqrt(X) + 1). %\end{lverb} % \begin{macrocode} \def\CALX_sqrt_start #1.% {% \ifnum #1<\xint_c_x\xint_dothis\CALX_sqrt_small_a\fi \xint_orthat\CALX_sqrt_big_a #1.% }% \def\CALX_sqrt_small_a #1.{\CALX_sqrt_a #1.\CALX_sqrt_small_d }% \def\CALX_sqrt_big_a #1.{\CALX_sqrt_a #1.\CALX_sqrt_big_d }% \def\CALX_sqrt_a #1.% {% \ifodd #1 \expandafter\CALX_sqrt_bO \else \expandafter\CALX_sqrt_bE \fi #1.% }% \def\CALX_sqrt_bE #1.#2#3#4% {% \CALX_sqrt_c {#3#4}#2{#1}#3#4% }% \def\CALX_sqrt_bO #1.#2#3% {% \CALX_sqrt_c #3#2{#1}#3% }% \def\CALX_sqrt_c #1#2% {% \expandafter #2% \the\numexpr \ifnum #1>\xint_c_ii \ifnum #1>\xint_c_vi \ifnum #1>12 \ifnum #1>20 \ifnum #1>30 \ifnum #1>42 \ifnum #1>56 \ifnum #1>72 \ifnum #1>90 10\else 9\fi \else 8\fi \else 7\fi \else 6\fi \else 5\fi \else 4\fi \else 3\fi \else 2\fi \else 1\fi .% }% \def\CALX_sqrt_small_d #1.#2% {% \expandafter\CALX_sqrt_small_e \the\numexpr #1\ifcase \numexpr #2/\xint_c_ii-\xint_c_i\relax \or 0\or 00\or 000\or 0000\fi .% }% \def\CALX_sqrt_small_e #1.#2.% {% \expandafter\CALX_sqrt_small_ea\the\numexpr #1*#1-#2.#1.% }% \def\CALX_sqrt_small_ea #1% {% \if0#1\xint_dothis\CALX_sqrt_small_ez\fi \if-#1\xint_dothis\CALX_sqrt_small_eb\fi \xint_orthat\CALX_sqrt_small_f #1% }% \def\CALX_sqrt_small_ez 0.#1.{\expandafter{\the\numexpr#1+\xint_c_i \expandafter}\expandafter{\the\numexpr #1*\xint_c_ii+\xint_c_i}}% \def\CALX_sqrt_small_eb -#1.#2.% {% \expandafter\CALX_sqrt_small_ec \the\numexpr (#1-\xint_c_i+#2)/(\xint_c_ii*#2).#1.#2.% }% \def\CALX_sqrt_small_ec #1.#2.#3.% {% \expandafter\CALX_sqrt_small_f \the\numexpr -#2+\xint_c_ii*#3*#1+#1*#1\expandafter.\the\numexpr #3+#1.% }% \def\CALX_sqrt_small_f #1.#2.% {% \expandafter\CALX_sqrt_small_g \the\numexpr (#1+#2)/(\xint_c_ii*#2)-\xint_c_i.#1.#2.% }% \def\CALX_sqrt_small_g #1#2.% {% \if 0#1% \expandafter\CALX_sqrt_small_end \else \expandafter\CALX_sqrt_small_h \fi #1#2.% }% \def\CALX_sqrt_small_h #1.#2.#3.% {% \expandafter\CALX_sqrt_small_f \the\numexpr #2-\xint_c_ii*#1*#3+#1*#1\expandafter.% \the\numexpr #3-#1.% }% \def\CALX_sqrt_small_end #1.#2.#3.{{#3}{#2}}% \def\CALX_sqrt_big_d #1.#2% {% \ifodd #2 \xint_dothis{\expandafter\CALX_sqrt_big_eO}\fi \xint_orthat{\expandafter\CALX_sqrt_big_eE}% \the\numexpr (#2-\xint_c_i)/\xint_c_ii.#1;% }% \def\CALX_sqrt_big_eE #1;#2#3#4#5#6#7#8#9% {% \CALX_sqrt_big_eE_a #1;{#2#3#4#5#6#7#8#9}% }% \def\CALX_sqrt_big_eE_a #1.#2;#3% {% \expandafter\CALX_sqrt_bigormed_f \romannumeral0\CALX_sqrt_small_e #2000.#3.#1;% }% \def\CALX_sqrt_big_eO #1;#2#3#4#5#6#7#8#9% {% \CALX_sqrt_big_eO_a #1;{#2#3#4#5#6#7#8#9}% }% \def\CALX_sqrt_big_eO_a #1.#2;#3#4% {% \expandafter\CALX_sqrt_bigormed_f \romannumeral0\CALX_sqrt_small_e #20000.#3#4.#1;% }% % \end{macrocode} %\begin{lverb} % calx (s58): \CALX_sqrt_start is only ever called with at most 16 digits % (calxint, xint's \xintiiSquareRoot), hence here k = #3 <= 8: the % medium path only. xint's big branch (\XINT_sqrt_big_f, more than 16 % digits) is deleted: xint and xintfrac use the native square roots. %\end{lverb} % \begin{macrocode} \def\CALX_sqrt_bigormed_f #1#2#3;% {\csname CALX_sqrt_med_f#3\endcsname #1.#2.#3;}% \expandafter\def\csname CALX_sqrt_med_f5\endcsname {\CALX_sqrt_med_fa .}% \expandafter\def\csname CALX_sqrt_med_f6\endcsname {\CALX_sqrt_med_fa 0.}% \expandafter\def\csname CALX_sqrt_med_f7\endcsname {\CALX_sqrt_med_fa 00.}% \expandafter\def\csname CALX_sqrt_med_f8\endcsname{\CALX_sqrt_med_fa 000.}% \def\CALX_sqrt_med_fa #1.#2.#3.#4;% {% \expandafter\CALX_sqrt_med_fb \the\numexpr (#30#1-5#1)/(\xint_c_ii*#2).#1.#2.#3.% }% \def\CALX_sqrt_med_fb #1.#2.#3.#4.#5.% {% \expandafter\CALX_sqrt_small_ea \the\numexpr (#40#2-\xint_c_ii*#3*#1)*10#2+(#1*#1-#5)\expandafter.% \the\numexpr #30#2-#1.% }% % \end{macrocode} % \subsection{Native integer square root} %\begin{lverb} % Attention N and I are set to catcode 12 from here on. % IN PARTICULAR DO NOT USE % ANY \XINT... prefixed macro names with I or N of catcode 12! %\end{lverb} % \begin{macrocode} \catcode`N=12 \catcode`I=12 % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_two}} %\begin{lverb} % \CALX_nsqrt_two {h}{l}: h, l eight digit strings (l with leading % zeros), X = h 10^8 + l, h >= 10^7. Expands to {s}{r} with % s = isqrt(X), r = X - s^2 (explicit integers, r <= 2s). Uses (5): % s = N - 1, r = 2N - 1 - D. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_two #1#2#3% {\expandafter\CALX_nsqrt_two_a\romannumeral0\CALX_sqrt_start 16.#2#3.#1}% \def\CALX_nsqrt_two_a #1#2#3% {\expandafter#3\expandafter{\the\numexpr#1-\xint_c_i\expandafter}% \expandafter{\the\numexpr\xint_c_ii*#1-\xint_c_i-#2}}% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_iv}} %\begin{lverb} % \CALX_nsqrt_iv {a3}{a2}{a1}{a0}: eight digit strings (leading zeros % allowed except a3 >= 25000000), X = a3 B^3 + a2 B^2 + a1 B + a0, B=10^8. % Expands to {S}{T}{H}{L}: isqrt(X) = S B + T with S explicit and T % as a native block 1dddddddd, remainder X - isqrt(X)^2 = H B + L, H, L % explicit, 0 <= L < B, H <= 2 10^8. % % One Zimmermann step on the two block square root (s',r') of a3 B + a2: % q = floor((r' B + a1)/(2s')), estimate q0 = round(r' B/(2s')) (eTeX % scaled product), exact u = r' B + a1 - 2s' q0 in 10^4 halves (every % intermediate < 2^31), one +-1 correction; then r = u B + a0 - q^2 and % the final correction r < 0: r += 2s - 1, s -= 1. q = B occurs only with % r' = 2s' and then always gets corrected. % % Floor of x/10^4 for x >= 0 is (x+5000)/10000-1 in \numexpr. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_iv #1#2#3#4#5{\CALX_nsqrt_two% \CALX_nsqrt_iv_a{#2}{#3}{#4}{#5}#1}% \def\CALX_nsqrt_iv_a #1#2% {% \expandafter\CALX_nsqrt_iv_b \the\numexpr#2*\xint_c_e_viii/(\xint_c_ii*#1).{#1}{#2}% }% \def\CALX_nsqrt_iv_b #1.#2% {% \expandafter\CALX_nsqrt_iv_c \the\numexpr(#1+5000)/\xint_c_e_iv-\xint_c_i\expandafter.% \the\numexpr(\xint_c_ii*#2+5000)/\xint_c_e_iv-\xint_c_i.#1.{#2}% }% % \end{macrocode} %\begin{lverb} % #1=qh, #2=th, #3=q0, #4=s', #5=r', #6=a1. With t=2s', ql=q0-qh 10^4, % tl=t-th 10^4: u = ((r'-th qh) 10^4 - (th ql + tl qh)) 10^4 - tl ql + a1. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_iv_c #1.#2.#3.#4#5#6% {% \expandafter\CALX_nsqrt_iv_d \the\numexpr((#5-#2*#1)*\xint_c_e_iv -(#2*(#3-#1*\xint_c_e_iv)+(\xint_c_ii*#4-#2*\xint_c_e_iv)*#1))*% \xint_c_e_iv -(\xint_c_ii*#4-#2*\xint_c_e_iv)*(#3-#1*\xint_c_e_iv)+#6.#3.{#4}% }% \def\CALX_nsqrt_iv_d #1.#2.#3% {% \expandafter\CALX_nsqrt_iv_e\the\numexpr#1% \ifnum#1<\xint_c_ +\xint_c_ii*#3\else \ifnum#1<\numexpr\xint_c_ii*#3\relax\else-\xint_c_ii*#3\fi\fi \expandafter.\the\numexpr#2% \ifnum#1<\xint_c_ -\xint_c_i\else \ifnum#1<\numexpr\xint_c_ii*#3\relax\else+\xint_c_i\fi\fi .{#3}% }% % \end{macrocode} %\begin{lverb} % #1=u, #2=q (0 <= q <= B), #3=s', #4=a0. With qh, ql the 10^4 halves of % q and c = 2 qh ql = ch 10^4 + cl: r = (u - qh^2 - ch) B % + (a0 - ql^2 - cl 10^4); the low part is > -2 10^8. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_iv_e #1.#2.% {% \expandafter\CALX_nsqrt_iv_f \the\numexpr(#2+5000)/\xint_c_e_iv-\xint_c_i.#2.#1.% }% \def\CALX_nsqrt_iv_f #1.#2.% {% \expandafter\CALX_nsqrt_iv_g \the\numexpr\xint_c_ii*#1*(#2-#1*\xint_c_e_iv).#1.#2.% }% \def\CALX_nsqrt_iv_g #1.% {% \expandafter\CALX_nsqrt_iv_h\the\numexpr(#1+5000)/\xint_c_e_iv-% \xint_c_i.#1.% }% \def\CALX_nsqrt_iv_h #1.#2.#3.#4.#5.#6#7% {% \expandafter\CALX_nsqrt_iv_i \the\numexpr#7-(#4-#3*\xint_c_e_iv)*(#4-#3*\xint_c_e_iv) -(#2-#1*\xint_c_e_iv)*\xint_c_e_iv\expandafter.% \the\numexpr#5-#3*#3-#1.#4.{#6}% }% % \end{macrocode} %\begin{lverb} % #1=low part x in (-2 10^8, 10^8), #2=high part, #3=q, #4=s'. % Borrow k = floor(x/B) = (x+250000000)/100000000-3. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_iv_i #1.% {% \expandafter\CALX_nsqrt_iv_j\the\numexpr(#1+250000000)/\xint_c_e_viii-% \xint_c_iii.#1.% }% \def\CALX_nsqrt_iv_j #1.#2.#3.% {% \expandafter\CALX_nsqrt_iv_k \the\numexpr#3+#1\expandafter.\the\numexpr#2-#1*\xint_c_e_viii.% }% % \end{macrocode} %\begin{lverb} % #1=H, #2=L, #3=q, #4=s', #5=cont. If H < 0: H += 2s', L += 2q - 1 % (L in [-1, 3 10^8)), carry (L+150000000)/100000000-2, q -= 1 with a % borrow from s' if q was 0. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_iv_k #1.#2.#3.#4#5% {% \ifnum#1<\xint_c_ \xint_dothis{\expandafter\CALX_nsqrt_iv_l \the\numexpr#2+\xint_c_ii*#3-\xint_c_i\expandafter.% \the\numexpr#1+\xint_c_ii*#4\expandafter.% \the\numexpr#3-\xint_c_i.{#4}#5}\fi \xint_orthat{\expandafter#5\expandafter{\the\numexpr#4\expandafter}% \expandafter{\the\numexpr#3+\xint_c_e_viii}{#1}{#2}}% }% \def\CALX_nsqrt_iv_l #1.% {% \expandafter\CALX_nsqrt_iv_m\the\numexpr(#1+150000000)/\xint_c_e_viii-% \xint_c_ii.#1.% }% \def\CALX_nsqrt_iv_m #1.#2.#3.#4.% {% \expandafter\CALX_nsqrt_iv_n \the\numexpr#3+#1\expandafter.\the\numexpr#2-#1*\xint_c_e_viii.#4.% }% \def\CALX_nsqrt_iv_n #1.#2.#3.#4#5% {% \expandafter#5\expandafter {\the\numexpr#4\ifnum#3<\xint_c_ -\xint_c_i\fi\expandafter}\expandafter {\the\numexpr\ifnum#3<\xint_c_ 199999999\else#3+\xint_c_e_viii\fi}% {#1}{#2}% }% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_vi}} %\begin{lverb} % \CALX_nsqrt_vi {a5}{a4}{a3}{a2}{a1}{a0}: eight digit strings, % a5 >= 25000000. Expands to {S1}{T}{Q}{R2}{R1}{R0}: isqrt(X) = % S1 B^2 + T B + Q (T, Q native blocks 1dddddddd), remainder % R2 B^2 + R1 B + R0 (explicit, 0 <= R1, R0 < B). % % One Zimmermann step with b = B on the four block root s' = S1 B + T % (remainder r' = H B + L) of the top four blocks: t = 2s' = tH B + tL, % 10^8 <= tH < 2 10^8; q = floor((r' B + a1)/t) is estimated by % q0 = round(H B/tH) (scaled), q - q0 in [-2, 1]; u = r' B + a1 - q0 t % is computed exactly as uH B + uL from 10^4 halves (qh, ql, tHh, tHl, % tLh, tLl): with m0 = a1 - ql tLl, m1 = -(qh tLl + ql tLh), % Z = ((H - qh tHh) 10^4 - (qh tHl + ql tHh)) 10^4 + L - (qh tLh + ql tHl), % c0 = floor(m0/10^4), c1 = floor((m1+c0)/10^4): uH = Z + c1, % uL = (m1 + c0 - c1 10^4) 10^4 + m0 - c0 10^4. Every intermediate is % < 2^31 (Z: |u| < 3 t). floor(v/10^4) = (v+500005000)/10000-50001 for % |v| < 5 10^8. Then the correction loop, r = u B + a0 - q^2 and the final % correction as in \CALX_nsqrt_iv. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_vi #1#2#3#4#5#6#7% {\CALX_nsqrt_iv\CALX_nsqrt_vi_a{#2}{#3}{#4}{#5}{#6}{#7}#1}% \def\CALX_nsqrt_vi_a #1#2% {\expandafter\CALX_nsqrt_vi_b\the\numexpr% \xint_c_ii*#2-200000000.{#1}{#2}}% \def\CALX_nsqrt_vi_b #1.#2#3#4#5% {% \expandafter\CALX_nsqrt_vi_c \the\numexpr\xint_c_ii*#2\ifnum#1<\xint_c_e_viii\else+\xint_c_i\fi \expandafter.\the\numexpr#1\ifnum#1<\xint_c_e_viii\else-\xint_c_e_viii\fi .{#4}{#5}{{#2}{#3}}% }% \def\CALX_nsqrt_vi_c #1.#2.#3#4#5#6#7% {\expandafter\CALX_nsqrt_vi_d\the\numexpr#3*% \xint_c_e_viii/#1.#1.#2.{#3}{#4}{#6}{#7}{#5}}% \def\CALX_nsqrt_vi_d #1.#2.#3.% {% \expandafter\CALX_nsqrt_vi_e \the\numexpr(#1+5000)/\xint_c_e_iv-\xint_c_i\expandafter.% \the\numexpr(#2+5000)/\xint_c_e_iv-\xint_c_i\expandafter.% \the\numexpr(#3+5000)/\xint_c_e_iv-\xint_c_i.#1.#2.#3.% }% % \end{macrocode} %\begin{lverb} % #1=qh, #2=tHh, #3=tLh, #4=q0, #5=tH, #6=tL, #7=H, #8=L, #9=a1. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_vi_e #1.#2.#3.#4.#5.#6.#7#8#9% {% \expandafter\CALX_nsqrt_vi_f \the\numexpr#9-(#4-#1*\xint_c_e_iv)*(#6-#3*\xint_c_e_iv)\expandafter.% \the\numexpr-#1*(#6-#3*\xint_c_e_iv)-(#4-#1*\xint_c_e_iv)*#3\expandafter.% \the\numexpr((#7-#1*#2)*\xint_c_e_iv -(#1*(#5-#2*\xint_c_e_iv)+(#4-#1*\xint_c_e_iv)*#2))*\xint_c_e_iv +#8-(#1*#3+(#4-#1*\xint_c_e_iv)*(#5-#2*\xint_c_e_iv)).#4.#5.#6.% }% \def\CALX_nsqrt_vi_f #1.#2.% {% \expandafter\CALX_nsqrt_vi_g \the\numexpr#2+(#1+500005000)/\xint_c_e_iv-50001\expandafter.% \the\numexpr#1-((#1+500005000)/\xint_c_e_iv-50001)*\xint_c_e_iv.% }% \def\CALX_nsqrt_vi_g #1.#2.#3.% {% \expandafter\CALX_nsqrt_vi_k \the\numexpr#3+(#1+500005000)/\xint_c_e_iv-50001\expandafter.% \the\numexpr(#1-((#1+500005000)/\xint_c_e_iv-50001)*\xint_c_e_iv)*% \xint_c_e_iv+#2.% }% % \end{macrocode} %\begin{lverb} % Correction loop: #1=uH, #2=uL, #3=q, #4=tH, #5=tL. While u < 0: u += t, % q -= 1; while u >= t: u -= t, q += 1. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_vi_k #1.% {% \ifnum#1<\xint_c_ \expandafter\CALX_nsqrt_vi_kadd \else\expandafter\CALX_nsqrt_vi_kcmp\fi #1.% }% \def\CALX_nsqrt_vi_kadd #1.#2.#3.#4.#5.% {% \expandafter\CALX_nsqrt_vi_k \the\numexpr#1+#4+(#2+#5+50000000)/\xint_c_e_viii-\xint_c_i\expandafter.% \the\numexpr#2+#5-((#2+#5+50000000)/\xint_c_e_viii-\xint_c_i)*% \xint_c_e_viii \expandafter.\the\numexpr#3-\xint_c_i.#4.#5.% }% \def\CALX_nsqrt_vi_kcmp #1.#2.#3.#4.#5.% {% \ifcase\numexpr\ifnum#1<#4 0\else\ifnum#1>#4 1\else \ifnum#2<#5 0\else 1\fi\fi\fi\relax \expandafter\CALX_nsqrt_vi_r \or \expandafter\CALX_nsqrt_vi_ksub \fi #1.#2.#3.#4.#5.% }% \def\CALX_nsqrt_vi_ksub #1.#2.#3.#4.#5.% {% \expandafter\CALX_nsqrt_vi_k \the\numexpr#1-#4+(#2-#5+150000000)/\xint_c_e_viii-\xint_c_ii% \expandafter.% \the\numexpr#2-#5-((#2-#5+150000000)/\xint_c_e_viii-\xint_c_ii)*% \xint_c_e_viii \expandafter.\the\numexpr#3+\xint_c_i.#4.#5.% }% % \end{macrocode} %\begin{lverb} % r = u B + a0 - q^2: #1=uH, #2=uL, #3=q, #4=tH, #5=tL, #6=a0, then {S}. % q^2 = (qh^2 + ch) B + ql^2 + cl 10^4 with c = 2 qh ql = ch 10^4 + cl. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_vi_r #1.#2.#3.#4.#5.#6% {% \expandafter\CALX_nsqrt_vi_rb \the\numexpr(#3+5000)/\xint_c_e_iv-\xint_c_i.#3.#6.#2.#1.{#4}{#5}% }% \def\CALX_nsqrt_vi_rb #1.#2.% {\expandafter\CALX_nsqrt_vi_rc\the\numexpr\xint_c_ii*#1*(#2-#1*% \xint_c_e_iv).#1.#2.}% \def\CALX_nsqrt_vi_rc #1.% {\expandafter\CALX_nsqrt_vi_rd\the\numexpr(#1+5000)/\xint_c_e_iv-% \xint_c_i.#1.}% \def\CALX_nsqrt_vi_rd #1.#2.#3.#4.#5.#6.#7.% {% \expandafter\CALX_nsqrt_vi_re \the\numexpr#5-(#4-#3*\xint_c_e_iv)*(#4-#3*\xint_c_e_iv) -(#2-#1*\xint_c_e_iv)*\xint_c_e_iv\expandafter.% \the\numexpr#6-#3*#3-#1.#7.#4.% }% \def\CALX_nsqrt_vi_re #1.#2.% {% \expandafter\CALX_nsqrt_vi_rf \the\numexpr#2+(#1+250000000)/\xint_c_e_viii-\xint_c_iii\expandafter.% \the\numexpr#1-((#1+250000000)/\xint_c_e_viii-\xint_c_iii)*% \xint_c_e_viii.% }% \def\CALX_nsqrt_vi_rf #1.#2.#3.% {% \expandafter\CALX_nsqrt_vi_rg \the\numexpr#3+(#1+250000000)/\xint_c_e_viii-\xint_c_iii\expandafter.% \the\numexpr#1-((#1+250000000)/\xint_c_e_viii-\xint_c_iii)*% \xint_c_e_viii.#2.% }% % \end{macrocode} %\begin{lverb} % #1=R2, #2=R1, #3=R0, #4=q, #5=tH, #6=tL, #7=S, #8=cont. If R2 < 0: % r += tH B^2 + tL B + 2q - 1, q -= 1 (q >= 1 here, see \CALX_nsqrt_iv). %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_vi_rg #1.#2.#3.#4.#5#6#7#8% {% \ifnum#1<\xint_c_ \xint_dothis{\expandafter\CALX_nsqrt_vi_rh \the\numexpr#3+\xint_c_ii*#4-\xint_c_i\expandafter.% \the\numexpr#4-\xint_c_i.#2.#1.{#5}{#6}{#7}#8}\fi \xint_orthat{\expandafter\CALX_nsqrt_vi_out\expandafter {\the\numexpr#4+\xint_c_e_viii}{#1}{#2}{#3}#7#8}% }% \def\CALX_nsqrt_vi_out #1#2#3#4#5#6#7{#7{#5}{#6}{#1}{#2}{#3}{#4}}% \def\CALX_nsqrt_vi_rh #1.#2.#3.#4.% {% \expandafter\CALX_nsqrt_vi_ri \the\numexpr(#1+150000000)/\xint_c_e_viii-\xint_c_ii.#1.#3.#4.#2.% }% \def\CALX_nsqrt_vi_ri #1.#2.#3.#4.#5.#6#7% {% \expandafter\CALX_nsqrt_vi_rj \the\numexpr#3+#7+#1\expandafter.\the\numexpr#2-#1*% \xint_c_e_viii.#4.#5.{#6}% }% \def\CALX_nsqrt_vi_rj #1.#2.#3.#4.#5#6#7% {% \expandafter\CALX_nsqrt_vi_out\expandafter {\the\numexpr#4+\xint_c_e_viii\expandafter}\expandafter {\the\numexpr#3+#5+(#1+150000000)/\xint_c_e_viii-\xint_c_ii\expandafter}% \expandafter {\the\numexpr#1-((#1+150000000)/\xint_c_e_viii-\xint_c_ii)*% \xint_c_e_viii}% {#2}#6#7% }% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_natv}, \csh{CALX_nsqrt_nathl}, % \csh{CALX_nsqrt_natr}} %\begin{lverb} % \CALX_nsqrt_natv{v} (0 <= v < 2^31), \CALX_nsqrt_nathl{H}{L} (H B + L), % \CALX_nsqrt_natr{R2}{R1}{R0} (R2 B^2 + R1 B + R0), 0 <= H, R2 < 2^31, % 0 <= L, R1, R0 < B: native integer (use with \romannumeral0); built % through \CALX_nnorm which strips zero top blocks. % % floor(x/B) = (x+50000000)/100000000-1 for x >= 0. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_natv #1{\expandafter\CALX_nnorm\expandafter+% \the\numexpr#1-((#1+50000000)/\xint_c_e_viii-\xint_c_i)*\xint_c_e_viii+% \xint_c_e_viii\expandafter!% \the\numexpr((#1+50000000)/\xint_c_e_viii-\xint_c_i)+\xint_c_e_viii!1;!}% \def\CALX_nsqrt_nathl #1#2{\expandafter\CALX_nnorm\expandafter+% \the\numexpr#2+\xint_c_e_viii\expandafter!% \the\numexpr#1-((#1+50000000)/\xint_c_e_viii-\xint_c_i)*\xint_c_e_viii+% \xint_c_e_viii\expandafter!% \the\numexpr((#1+50000000)/\xint_c_e_viii-\xint_c_i)+\xint_c_e_viii!1;!}% \def\CALX_nsqrt_natr #1#2#3{\expandafter\CALX_nnorm\expandafter+% \the\numexpr#3+\xint_c_e_viii\expandafter!% \the\numexpr#2+\xint_c_e_viii\expandafter!% \the\numexpr#1-((#1+50000000)/\xint_c_e_viii-\xint_c_i)*\xint_c_e_viii+% \xint_c_e_viii\expandafter!% \the\numexpr((#1+50000000)/\xint_c_e_viii-\xint_c_i)+\xint_c_e_viii!1;!}% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_core}} %\begin{lverb} % \CALX_nsqrt_core {n}{blocks}: n even >= 4, top block >= 25000000 % (block of 8 digits). Gives {s}{r} (natives), s = isqrt, r = X - s^2. % % n = 4, 6: \CALX_nsqrt_iv, \CALX_nsqrt_vi; n >= 8: \CALX_nsqrt_k (one % block steps). With = \CALX_nsqrt_un (padded input, see % \CALX_nsqrtrem) and n = 6 or n >= 8, the root is not built as a native: % \CALX_nsqrt_cvu passes the output of \CALX_nsqrt_vi to \CALX_nsqrt_kb, % and the final state goes to \CALX_nsqrt_kuz (S and R of the unpadded % input directly). %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_core #1#2% {% \ifcase\numexpr#2/\xint_c_ii-\xint_c_ii\relax \xint_dothis\CALX_nsqrt_civ \or \xint_dothis{\ifx\CALX_nsqrt_un#1\expandafter\CALX_nsqrt_cvu \else\expandafter\CALX_nsqrt_cvi\fi}% \fi\xint_orthat\CALX_nsqrt_k #1{#2}% }% \def\CALX_nsqrt_cvu #1#2#3{\CALX_nsqrt_msvi#3\CALX_nsqrt_vi\CALX_nsqrt_kb% \xint:{}#1}% \def\CALX_nsqrt_civ #1#2#3{\CALX_nsqrt_msiv#3\CALX_nsqrt_iv\CALX_nsqrt_ivo#1}% \def\CALX_nsqrt_msiv 1#1!1#2!1#3!1#4!#5#6{#5#6{#4}{#3}{#2}{#1}}% \def\CALX_nsqrt_ivo #1#2#3#4% {\expandafter\CALX_nsqrt_ivp\romannumeral0\CALX_nsqrt_nathl{#3}{#4}% \xint:{N+2.#2!1#1!}}% \def\CALX_nsqrt_ivp #1\xint:#2#3{#3{#2}{#1}}% \def\CALX_nsqrt_cvi #1#2#3{\CALX_nsqrt_msvi#3\CALX_nsqrt_vi\CALX_nsqrt_vio#1}% \def\CALX_nsqrt_msvi % 1#1!1#2!1#3!1#4!1#5!1#6!#7#8{#7#8{#6}{#5}{#4}{#3}{#2}{#1}}% \def\CALX_nsqrt_vio #1#2#3#4#5#6% {\expandafter\CALX_nsqrt_ivp\romannumeral0\CALX_nsqrt_natr{#4}{#5}{#6}% \xint:{N+3.#3!#2!1#1!}}% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_k}} %\begin{lverb} % \CALX_nsqrt_k {n}{blocks}: n even >= 8, top block >= 25000000. % Same output as \CALX_nsqrt_core. The root of the top six blocks is % obtained by \CALX_nsqrt_vi, then the root is extended by one block for % each further pair of blocks (one Zimmermann step with b = B each time). % % Step. Let s (k blocks, k >= 3) be the root of the top 2k blocks, % r = (top 2k blocks) - s^2 (0 <= r <= 2s), t = 2s, and a1, a0 the next two % blocks. With W = r B + a1, the next block of the root is the largest q % such that W B + a0 - q (t B + q) >= 0; it is q = floor(W/t) or that % value minus one. Then s <- s B + q, t <- t B + 2q, r <- that difference. % As s >= B^k/2 (normalized input), B^k <= t < 2 B^k: the top block t_k % of t is 1. % % State. P = 1t_0!1r_0!1t_1!1r_1!...1t_k!1r_k!1;;;;;! (the blocks of t and % r interleaved, least significant first, r padded with zero blocks). Then % L = 1!P is exactly the layout of the window W and the divisor t used % by the multiply-subtract pass of the division (\CALX_ndms_a): the pairs % (w_j, t_j) with w_0 = a1, w_j = r_(j-1), then w_(k+1) = r_k and the % marker. % % \CALX_nsqrt_k reverses the blocks (most significant first), gives the top % six to \CALX_nsqrt_vi with continuation \CALX_nsqrt_kb, which builds P % (k = 3) from its output. \CALX_nsqrt_ks {k}{P} \xint: loops while % pairs of blocks remain, then goes to \CALX_nsqrt_kz. \CALX_nsqrt_kt % copies L and skips 2k-4 blocks (\CALX_nskip) to read the top blocks of r % and t for the estimate (\CALX_nsqrt_ku). % % \CALX_nsqrt_kfl{x}: floor(x/B) for 0 <= x < 2B, in \numexpr. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_k #1#2#3% {\expandafter\CALX_nsqrt_ka\romannumeral0\CALX_rev_nounsep{}#3\R!\R!\R!\R!% \R!\R!\R!\R!\W \xint:{}#1}% \def\CALX_nsqrt_ka 1#1!1#2!1#3!1#4!1#5!1#6!#7\xint:% {\CALX_nsqrt_vi\CALX_nsqrt_kb{#1}{#2}{#3}{#4}{#5}{#6}#7\xint:}% \def\CALX_nsqrt_kfl #1{((#1+50000000)/\xint_c_e_viii-\xint_c_i)}% \def\CALX_nsqrt_kb #1#2#3#4#5#6% {% \expandafter\CALX_nsqrt_ks\expanded{{3}{% \the\numexpr\xint_c_ii*#3-\xint_c_e_viii -\CALX_nsqrt_kfl{\xint_c_ii*#3-200000000}*\xint_c_e_viii!% \the\numexpr\xint_c_e_viii+#6!% \the\numexpr\xint_c_ii*#2-\xint_c_e_viii+\CALX_nsqrt_kfl{% \xint_c_ii*#3-200000000}% -\CALX_nsqrt_kfl{\xint_c_ii*#2-200000000 +\CALX_nsqrt_kfl{\xint_c_ii*#3-200000000}}*\xint_c_e_viii!% \the\numexpr\xint_c_e_viii+#5!% \the\numexpr\xint_c_ii*#1+\CALX_nsqrt_kfl{\xint_c_ii*#2-200000000 +\CALX_nsqrt_kfl{\xint_c_ii*#3-200000000}}!% \the\numexpr#4-\CALX_nsqrt_kfl{#4}*\xint_c_e_viii+\xint_c_e_viii!% 100000001!% \the\numexpr\CALX_nsqrt_kfl{#4}+\xint_c_e_viii!% 1;;;;;!}}% }% \def\CALX_nsqrt_ks #1#2#3% {\ifx\xint:#3\expandafter\CALX_nsqrt_kz\else\expandafter\CALX_nsqrt_kt% \fi{#1}{#2}#3}% \def\CALX_nsqrt_kt #1#21#3!1#4!% {\CALX_nskip\CALX_nsqrt_ku\xint_c_ii*#1-\xint_c_iv.1#3!#2{#1}{#3}{#4}{#2}}% \def\CALX_nsqrt_ku 1#1!1#2!1#3!1#4!1#5!1#6!1#7!1;;;;;!#8#9% {% \expandafter\CALX_nsqrt_kec\the\numexpr\xint_c_e_viii+#4\expandafter.% \the\numexpr#2\expandafter.\expandafter{\the\numexpr#7*\xint_c_e_viii+#5}% {#3}{{#8}{#9}}{#1}{}% }% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_kec}} %\begin{lverb} % Estimate. With U = (r_k B + r_(k-1)) B^2 + r_(k-2) B + r_(k-3) (three % limbs, the top one below 2 10^8) and V = (B + t_(k-1)) B + t_(k-2), the % value q* = floor(U/V) satisfies q <= q* <= q + 1 where q = floor(W/t), % and q* = q + 1 only if the lower blocks matter (probability about % 10^-8): W/t < (U + 1)/V and W/t >= U/(V + 1), and U/V - U/(V + 1) < 1. % The computation of q* is that of \CALX_nsqrt_vi (same limbs, same bounds: % tH = B + t_(k-1) is in [10^8, 2 10^8)): \CALX_nsqrt_kec ... _keksub are % copies of \CALX_nsqrt_vi_c ... _vi_ksub, renamed, which end with % \CALX_nsqrt_kq instead of \CALX_nsqrt_vi_r. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_kec #1.#2.#3#4#5#6#7% {\expandafter\CALX_nsqrt_ked\the\numexpr#3*% \xint_c_e_viii/#1.#1.#2.{#3}{#4}{#6}{#7}{#5}}% \def\CALX_nsqrt_ked #1.#2.#3.% {% \expandafter\CALX_nsqrt_kee \the\numexpr(#1+5000)/\xint_c_e_iv-\xint_c_i\expandafter.% \the\numexpr(#2+5000)/\xint_c_e_iv-\xint_c_i\expandafter.% \the\numexpr(#3+5000)/\xint_c_e_iv-\xint_c_i.#1.#2.#3.% }% \def\CALX_nsqrt_kee #1.#2.#3.#4.#5.#6.#7#8#9% {% \expandafter\CALX_nsqrt_kef \the\numexpr#9-(#4-#1*\xint_c_e_iv)*(#6-#3*\xint_c_e_iv)\expandafter.% \the\numexpr-#1*(#6-#3*\xint_c_e_iv)-(#4-#1*\xint_c_e_iv)*#3\expandafter.% \the\numexpr((#7-#1*#2)*\xint_c_e_iv -(#1*(#5-#2*\xint_c_e_iv)+(#4-#1*\xint_c_e_iv)*#2))*\xint_c_e_iv +#8-(#1*#3+(#4-#1*\xint_c_e_iv)*(#5-#2*\xint_c_e_iv)).#4.#5.#6.% }% \def\CALX_nsqrt_kef #1.#2.% {% \expandafter\CALX_nsqrt_keg \the\numexpr#2+(#1+500005000)/\xint_c_e_iv-50001\expandafter.% \the\numexpr#1-((#1+500005000)/\xint_c_e_iv-50001)*\xint_c_e_iv.% }% \def\CALX_nsqrt_keg #1.#2.#3.% {% \expandafter\CALX_nsqrt_kek \the\numexpr#3+(#1+500005000)/\xint_c_e_iv-50001\expandafter.% \the\numexpr(#1-((#1+500005000)/\xint_c_e_iv-50001)*\xint_c_e_iv)*% \xint_c_e_iv+#2.% }% \def\CALX_nsqrt_kek #1.% {% \ifnum#1<\xint_c_ \expandafter\CALX_nsqrt_kekadd \else\expandafter\CALX_nsqrt_kekcmp\fi #1.% }% \def\CALX_nsqrt_kekadd #1.#2.#3.#4.#5.% {% \expandafter\CALX_nsqrt_kek \the\numexpr#1+#4+(#2+#5+50000000)/\xint_c_e_viii-\xint_c_i\expandafter.% \the\numexpr#2+#5-((#2+#5+50000000)/\xint_c_e_viii-\xint_c_i)*% \xint_c_e_viii \expandafter.\the\numexpr#3-\xint_c_i.#4.#5.% }% \def\CALX_nsqrt_kekcmp #1.#2.#3.#4.#5.% {% \ifcase\numexpr\ifnum#1<#4 0\else\ifnum#1>#4 1\else \ifnum#2<#5 0\else 1\fi\fi\fi\relax \expandafter\CALX_nsqrt_kq \or \expandafter\CALX_nsqrt_keksub \fi #1.#2.#3.#4.#5.% }% \def\CALX_nsqrt_keksub #1.#2.#3.#4.#5.% {% \expandafter\CALX_nsqrt_kek \the\numexpr#1-#4+(#2-#5+150000000)/\xint_c_e_viii-\xint_c_ii% \expandafter.% \the\numexpr#2-#5-((#2-#5+150000000)/\xint_c_e_viii-\xint_c_ii)*% \xint_c_e_viii \expandafter.\the\numexpr#3+\xint_c_i.#4.#5.% }% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_kq}} %\begin{lverb} % Multiply-subtract and new remainder. \CALX_nsqrt_kq clamps q* to B - 1 % (the root block is at most B - 1, and W - (B - 1) t < B^(k+1) still fits % the window), then \CALX_nsqrt_kqa runs \CALX_ndms_a on L with q*: the % output is 1t_0!1u_0!...1t_k!1u_k!1;;;;;!{fin} with u = W - q* t. If % fin < 0, t is added back (\CALX_ndab) and q* decreases by one % (\CALX_nsqrt_kp, _kpa, _kpc). % % \CALX_nsqrt_kw computes r' = u B + a0 - q^2 on the two low blocks: with % qh, ql the halves of q and c = 2 qh ql = ch 10^4 + cl, the low block is % a0 - ql^2 - cl 10^4 (borrow b0 in {-2, -1, 0}) and the next one % u_0 - qh^2 - ch + b0 (borrow b1 in {-2, -1, 0}); further blocks are % u_1, ..., u_k. % % If b1 < 0 the borrow is propagated into u_1, u_2, ... (\CALX_nsqrt_kbs, % \CALX_nsqrt_kbt). If it runs past u_k, r' < 0 (this happens for near % squares, e.g. 10^48 + 10^24): the step is redone from \CALX_nsqrt_kqa % with q - 1 (\CALX_nsqrt_kfb); then u >= t >= B^k and r' >= 0. The data % of the step, {}{}{P}, is carried along for this purpose. % % New state (\CALX_nsqrt_kwh): t' = t B + 2q has the blocks % 2q - c B, t_0 + c (c = 1 if 2q >= B, else 0; t_0 is even, no carry), % t_1, ..., t_k; r' has the blocks computed above, then u_1, ..., u_k. So % P' = 1t'_0!1r'_0!1t'_1!1r'_1! followed by the output of the pass % without its first two blocks. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_kq #1.#2.#3.#4.#5.#6#7#8#9% {% \expandafter\CALX_nsqrt_kqa\the\numexpr \ifnum#3>99999999 199999999\else\xint_c_e_viii+#3\fi\xint:#7{#8}{#9}% }% \def\CALX_nsqrt_kqa 1#1#2#3#4#5\xint:#6#7#8#9% {% \expandafter\CALX_nsqrt_kp\the\numexpr \CALX_ndms_a 0\xint:#1#2#3#4% \xint:#5!1#7!#9{#1#2#3#4#5}{#6}{#8}{{#7}{#8}{#9}}% }% \def\CALX_nsqrt_kp #1;;;;;!#2% {% \ifnum\numexpr#2<\xint_c_ \xint_dothis\CALX_nsqrt_kpa\fi \xint_orthat\CALX_nsqrt_kw #1;;;;;!% }% \def\CALX_nsqrt_kpa #1;;;;;!% {\expandafter\CALX_nsqrt_kpc\the\numexpr\CALX_ndab 0\xint:#1;;;;;!}% \def\CALX_nsqrt_kpc #1;;;;;!#2{\CALX_nsqrt_kw #1;;;;;!{#2-\xint_c_i}}% \def\CALX_nsqrt_kw 1#1!1#2!#3;;;;;!#4#5#6#7% {% \expandafter\CALX_nsqrt_kwa\the\numexpr#4\expandafter.% \the\numexpr(#4+5000)/\xint_c_e_iv-\xint_c_i.#1.#2.#6.{#5}{#7}#3;;;;;!% }% \def\CALX_nsqrt_kwa #1.#2.% {\expandafter\CALX_nsqrt_kwb\the\numexpr\xint_c_ii*#2*(#1-#2*% \xint_c_e_iv).#1.#2.}% \def\CALX_nsqrt_kwb #1.% {\expandafter\CALX_nsqrt_kwc\the\numexpr(#1+5000)/\xint_c_e_iv-% \xint_c_i.#1.}% \def\CALX_nsqrt_kwc #1.#2.#3.#4.#5.#6.#7.% {% \expandafter\CALX_nsqrt_kwd \the\numexpr#7-(#3-#4*\xint_c_e_iv)*(#3-#4*\xint_c_e_iv) -(#2-#1*\xint_c_e_iv)*\xint_c_e_iv\expandafter.% \the\numexpr#6-#4*#4-#1.#3.#5.% }% \def\CALX_nsqrt_kwd #1.% {\expandafter\CALX_nsqrt_kwe\the\numexpr(#1+250000000)/\xint_c_e_viii-% \xint_c_iii.#1.}% \def\CALX_nsqrt_kwe #1.#2.#3.% {\expandafter\CALX_nsqrt_kwf\the\numexpr#3+#1\expandafter.\the% \numexpr#2-#1*\xint_c_e_viii.}% \def\CALX_nsqrt_kwf #1.% {\expandafter\CALX_nsqrt_kwg\the\numexpr(#1+150000000)/\xint_c_e_viii-% \xint_c_ii.#1.}% \def\CALX_nsqrt_kwg #1.#2.#3.#4.#5.% {% \ifnum#1=\xint_c_ \expandafter\CALX_nsqrt_kwh\else\expandafter% \CALX_nsqrt_kwp\fi {#1}{#2}{#3}{#4}{#5}% }% \def\CALX_nsqrt_kwp #1#2#3#4#5#6#7#8;;;;;!% {\expandafter\CALX_nsqrt_kwq\expanded{\CALX_nsqrt_kbs{#1}#8;;;;;!}% \xint:{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% \def\CALX_nsqrt_kwq #1;;;;;!#2\xint:% {\ifx\relax#2\relax\expandafter\CALX_nsqrt_kwk\else\expandafter% \CALX_nsqrt_kfb\fi{#1}}% \def\CALX_nsqrt_kwk #1#2#3#4#5#6#7#8{% \CALX_nsqrt_kwh{#2}{#3}{#4}{#5}{#6}{#7}{#8}#1;;;;;!}% \def\CALX_nsqrt_kfb #1#2#3#4#5#6#7#8% {\expandafter\CALX_nsqrt_kqa\the\numexpr\xint_c_e_viii+#5-\xint_c_i% \xint:{#7}#8}% \def\CALX_nsqrt_kbs #11#2#3!{\xint_gob_til_sc #2\CALX_nsqrt_kbz;% \CALX_nsqrt_kbt{#1}{#2#3}}% % \end{macrocode} % Attention to this F. It (probably) should be of catcode 12, so this % is what we do. % \begin{macrocode} \catcode`F 12 \def\CALX_nsqrt_kbz;\CALX_nsqrt_kbt#1#2{1;;;;;!F}% \catcode`F 11 \def\CALX_nsqrt_kbt #1#21#3!% {% 1#2!\the\numexpr#3+#1+\ifnum\numexpr#3+#1<\xint_c_ 200000000\else% \xint_c_e_viii\fi!% \ifnum\numexpr#3+#1<\xint_c_ \CALX_nsqrt_kbf\fi }% \def\CALX_nsqrt_kbf\fi{\fi\CALX_nsqrt_kbs{-1}}% \def\CALX_nsqrt_kwh #1#2#3#4#5#6#7#8;;;;;!% {% \expandafter\CALX_nsqrt_ks\expanded{{\the\numexpr#6+\xint_c_i}{% \the\numexpr\xint_c_ii*#4-\CALX_nsqrt_kfl{\xint_c_ii*#4}*\xint_c_e_viii+% \xint_c_e_viii!% \the\numexpr#3+\xint_c_e_viii!% \the\numexpr#5+\CALX_nsqrt_kfl{\xint_c_ii*#4}+\xint_c_e_viii!% \the\numexpr#2-#1*\xint_c_e_viii+\xint_c_e_viii!% #8;;;;;!}}% }% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrt_kz}} %\begin{lverb} % End of the steps. \CALX_nsqrt_kzn$empty: R is the native made of the r % blocks of P (\CALX_nsqrt_kzr), S = t/2 (t blocks extracted by % \CALX_nsqrt_kzt, halved by \CALX_nsqrt_kh$empty: block t_i/2, plus 5 10^7 % if t_(i+1) is odd). % % \CALX_nsqrt_kuz is used instead when is \CALX_nsqrt_un, i.e. the % core worked on Y = X D0^2, D0 = 2^j 10^t' (see \CALX_nsqrt_bgh): it % receives P, then {D0}{j}{2t'}{5^j}{25^j}. With s, r the root and % remainder of Y and m = 2^(j+1): one pass over t = 2s, most significant % block first (\CALX_nsqrt_kva), divides by m (remainder c < m, so % c B + t_i < 2^31) and shifts right by t' digits (remainder rho), giving % the blocks of S = floor(s/D0) and, at the end, e = s - S D0 = % rho 2^j + c/2. Then R = (r + e (t - e))/D0^2 (exact): native operations, % \CALX_nshr by 2t' digits, then division by 4^j. floor(v/10^t') is % (2v - 10^t' + 1)/(2 10^t') in \numexpr (no tie, also for t' = 0). %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_kz #1#2\xint:#3#4% {% \ifx\CALX_nsqrt_un#4\expandafter\CALX_nsqrt_kuz\else\expandafter% \CALX_nsqrt_kzn\fi {#2}#4% }% \def\CALX_nsqrt_kzn #1% {% \expandafter\CALX_nsqrt_kzz\romannumeral0\expandafter\CALX_nnorm% \expandafter+\expanded{\CALX_nsqrt_kzr#1}1;!% \xint:{#1}% }% \def\CALX_nsqrt_kuz #1#2#3#4#5#6#7% {% \expandafter\CALX_nsqrt_kub\expanded{% \expandafter\CALX_nsqrt_kvx\romannumeral0\expandafter\CALX_rev_nounsep% \expandafter{\expandafter}% \expanded{\CALX_nsqrt_kzt#1}\R!\R!\R!\R!\R!\R!\R!\R!\W 1;!\xint:% {\ifcase#4 2\or4\or8\or16\fi}{\ifcase#4 1\or2\or4\or8\fi}{% \CALX_pten{#5/\xint_c_ii}}}% {#1}{#4}{#5}% }% \def\CALX_nsqrt_kvx #1\xint:#2#3#4{\CALX_nsqrt_kva 0.0.{#2}{#3}{#4}#1}% \def\CALX_nsqrt_kva #1.#2.#3#4#51#6#7!% {% \if;#6\expandafter\CALX_nsqrt_kve\else\expandafter\CALX_nsqrt_kvf\fi {#1}{#2}{#3}{#4}{#5}{#6#7}% }% \def\CALX_nsqrt_kve #1#2#3#4#5#6{\xint:{\the\numexpr#2*#4+#1/\xint_c_ii}}% \def\CALX_nsqrt_kvf #1#2#3#4#5#6% {% \expandafter\CALX_nsqrt_kvb \the\numexpr(#1*\xint_c_e_viii+#6+#4)/#3-\xint_c_i.#1.#2.#6.{#3}{#4}{#5}% }% \def\CALX_nsqrt_kvb #1.#2.#3.#4.#5#6#7% {% \expandafter\CALX_nsqrt_kvc \the\numexpr(\xint_c_ii*#1-#7+\xint_c_i)/(\xint_c_ii*#7).#1.% \the\numexpr#2*\xint_c_e_viii+#4-#1*#5.#3.{#5}{#6}{#7}% }% \def\CALX_nsqrt_kvc #1.#2.#3.#4.#5#6#7% {% \the\numexpr#1+#4*(\xint_c_e_viii/#7)+\xint_c_e_viii!% \expandafter\CALX_nsqrt_kva\the\numexpr#3\expandafter.\the% \numexpr#2-#1*#7.% {#5}{#6}{#7}% }% \def\CALX_nsqrt_kub #1\xint:% {% \expandafter\CALX_nsqrt_kuc\romannumeral0\expandafter\CALX_nnorm% \expandafter+% \romannumeral0\CALX_rev_nounsep{}#1\R!\R!\R!\R!\R!\R!\R!\R!\W 1;!% \xint:% }% \def\CALX_nsqrt_kuc #1\xint:#2#3#4#5% {% \expandafter\CALX_nsqrt_kud\romannumeral0\CALX_nshr{#5}% {\romannumeral0\CALX_nadd {\romannumeral0\expandafter\CALX_nnorm\expandafter+\expanded{% \CALX_nsqrt_kzr#3}1;!}% {\romannumeral0\CALX_nmul{\romannumeral0\CALX_nsqrt_natv{#2}}% {\romannumeral0\CALX_nsub {\romannumeral0\expandafter\CALX_nnorm\expandafter+\expanded{% \CALX_nsqrt_kzt#3}1;!}% {\romannumeral0\CALX_nsqrt_natv{#2}}}}}% \xint:{#1}{#4}% }% \def\CALX_nsqrt_kud #1\xint:#2#3% {% \ifnum#3=\xint_c_ \xint_dothis{{#2}{#1}}\fi \xint_orthat{\expandafter\CALX_nsqrt_kue\romannumeral0\CALX_ndivtrunc{#1}% {\expanded{\ifcase#3\or N+1.100000004!\or N+1.100000016!\or % N+1.100000064!\fi}}% \xint:{#2}}% }% \def\CALX_nsqrt_kue #1\xint:#2{{#2}{#1}}% \def\CALX_nsqrt_kzr 1#1#2!{\xint_gob_til_sc #1\CALX_nsqrt_kze;% \CALX_nsqrt_kzrb}% \def\CALX_nsqrt_kze;\CALX_nsqrt_kzrb{}% \def\CALX_nsqrt_kzrb 1#1!{1#1!\CALX_nsqrt_kzr}% \def\CALX_nsqrt_kzt 1#1#2!{\xint_gob_til_sc #1\CALX_nsqrt_kzte;% \CALX_nsqrt_kztb 1#1#2!}% \def\CALX_nsqrt_kzte;\CALX_nsqrt_kztb 1#1!{}% \def\CALX_nsqrt_kztb 1#1!1#2!{1#1!\CALX_nsqrt_kzt}% \def\CALX_nsqrt_kzz #1\xint:#2% {% \expandafter\CALX_nsqrt_kzy\romannumeral0\expandafter\CALX_nnorm% \expandafter+% \expanded{\expandafter\CALX_nsqrt_kh\expanded{\CALX_nsqrt_kzt#2}1;!}1;!% \xint:{#1}% }% \def\CALX_nsqrt_kzy #1\xint:#2#3{#3{#1}{#2}}% \def\CALX_nsqrt_kh 1#1!1#2#3!% {% \the\numexpr\xint_c_e_viii+(#1\ifodd#1 -\xint_c_i\fi)/\xint_c_ii \xint_gob_til_sc#2\CALX_nsqrt_khe;\ifodd#2#3 +50000000\fi\relax!% \CALX_nsqrt_kh 1#2#3!% }% \def\CALX_nsqrt_khe;#1\CALX_nsqrt_kh 1;!{\relax!}% % \end{macrocode} % \subsubsection{\csh{CALX_nsqrtrem}} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded native integer or I): %( % \CALX_nsqrtrem{X} -> {S}{R} S = isqrt(X), R = X - S^2 %) % \CALX_nsqrtrem{X} (X f-expands to a native integer; use with % \romannumeral0): {S}{R}, S = isqrt(X), R = X - S^2. Negative X or I-: % InvalidOperation, {I?}{I?} (trap value {N+0.}{N+0.}); I+: {I+}{I?}; % I?: {I?}{I?} (no signal). % % One or two blocks: \CALX_sqrt_start (from xint) on the digits. Three blocks % or more: X has Dg digits; K = ceil(Dg/16) = (Dg+7)/16, n' = 2K blocks; % X is shifted by 2t digits to Dp' = 16K - o digits (o = Dg mod 2), so the % top block has 8 - o digits, then multiplied by 4^j (j minimal, j <= 1 if % o = 0, j <= 3 if o = 1) so that it is >= 25000000; the multiplier is % M = 10^(2t) 4^j. If M = 1: (S,R) = core(X). Else (s,r) = core(Y) and % S = floor(s/(2^j 10^t)), R = X - S^2 (see \CALX_nsqrt_bgh). The leading % 8 - o digits of X come from the top block v1 % (d1 digits) and the next block v2: lead = floor((v1 B + v2)/10^e), % e = d1 + o; floor(x/10^e) = (x+10^e/2)/10^e-1 (x >= 0). %\end{lverb} % \begin{macrocode} \def\CALX_nsqrtrem #1{\expandafter\CALX_nsqrt_x\romannumeral`&&@#1\xint:}% \def\CALX_nsqrt_x #1#2% {% \if I#1\xint_dothis{\CALX_nsqrt_sp#2}\fi \if -#2\xint_dothis\CALX_nsqrt_inv\fi \xint_orthat\CALX_nsqrt_p }% \def\CALX_nsqrt_inv #1\xint:{\expandafter\CALX_ndiv_zpv\romannumeral`&&@% \CALX_signalcondition{InvalidOperation}{isqrt of negative or % special}{}{N+0.}\xint:}% \def\CALX_nsqrt_p #1.% {% \ifcase#1 \xint_dothis\CALX_nsqrt_zero \or \xint_dothis\CALX_nsqrt_pone \or \xint_dothis\CALX_nsqrt_ptwo \fi\xint_orthat\CALX_nsqrt_big #1.% }% \def\CALX_nsqrt_sp #1\xint:% {% \if +#1\xint_dothis{{I+}{I?}}\fi \if ?#1\xint_dothis{{I?}{I?}}\fi \xint_orthat{\CALX_nsqrt_inv\xint:}% }% \def\CALX_nsqrt_zero #1\xint:{{N+0.}{N+0.}}% \def\CALX_nsqrt_pone #1.1#2!\xint:{\expandafter\CALX_nsqrt_onea\the% \numexpr#2.}% \def\CALX_nsqrt_onea #1.% {\expandafter\CALX_nsqrt_sm\romannumeral0\expandafter\CALX_sqrt_start \the\numexpr\CALX_ndigs{#1}.#1.}% \def\CALX_nsqrt_ptwo #1.1#2!1#3!\xint:{\expandafter\CALX_nsqrt_twoa\the% \numexpr#3.#2.}% \def\CALX_nsqrt_twoa #1.#2.% {\expandafter\CALX_nsqrt_sm\romannumeral0\expandafter\CALX_sqrt_start \the\numexpr\xint_c_viii+\CALX_ndigs{#1}.#1#2.}% \def\CALX_nsqrt_sm #1#2% {% \expandafter\CALX_nsqrt_smb \the\numexpr\xint_c_ii*#1-\xint_c_i-#2\expandafter.% \the\numexpr#1-\xint_c_i+\xint_c_e_viii.% }% \def\CALX_nsqrt_smb #1.#2.% {\expandafter\CALX_nsqrt_ivp\romannumeral0\CALX_nsqrt_natv{#1}% \xint:{N+1.#2!}\CALX_nsqrt_out}% \def\CALX_nsqrt_out #1#2{{#1}{#2}}% \def\CALX_nsqrt_big #1.#2\xint:% {\CALX_nskip\CALX_nsqrt_bgt#1-\xint_c_ii.#2\xint:{#1}{#2}}% \def\CALX_nsqrt_bgt 1#1!1#2!\xint:{\expandafter\CALX_nsqrt_bgv\the% \numexpr#2.#1.}% \def\CALX_nsqrt_bgv #1.% {\expandafter\CALX_nsqrt_bga\the\numexpr\CALX_ndigs{#1}.#1.}% \def\CALX_nsqrt_bga #1.#2.#3.#4% {\expandafter\CALX_nsqrt_bgb\the\numexpr\xint_c_viii*(#4-% \xint_c_i)+#1.#1.#2.#3.{#4}}% \def\CALX_nsqrt_bgb #1.% {\expandafter\CALX_nsqrt_bgc\the\numexpr\ifodd#1 1\else 0\fi.#1.}% \def\CALX_nsqrt_bgc #1.#2.#3.#4.#5.% {% \expandafter\CALX_nsqrt_bgf\the\numexpr \ifcase\numexpr#3+#1\relax 0% \or #4*10000000+(#5+5)/10-\xint_c_i \or #4*1000000+(#5+50)/100-\xint_c_i \or #4*100000+(#5+500)/1000-\xint_c_i \or #4*10000+(#5+5000)/10000-\xint_c_i \or #4*1000+(#5+50000)/100000-\xint_c_i \or #4*100+(#5+500000)/1000000-\xint_c_i \or #4*10+(#5+5000000)/10000000-\xint_c_i \or #4% \or (#4+5)/10-\xint_c_i \fi.#1.#2.% }% \def\CALX_nsqrt_bgf #1.#2.#3.% {% \expandafter\CALX_nsqrt_bgg\the\numexpr \ifnum#2=\xint_c_ \ifnum#1<25000000 1\else 0\fi \else\ifnum#1<1562500 3\else\ifnum#1<6250000 2\else 1\fi\fi\fi% \expandafter.% \the\numexpr16*((#3+\xint_c_vii)/16)-#2-#3\expandafter.% \the\numexpr\xint_c_ii*((#3+\xint_c_vii)/16).% }% \def\CALX_nsqrt_bgg #1.#2.% {% \ifnum\numexpr#1+#2=\xint_c_ \expandafter\CALX_nsqrt_bgg_a \else \expandafter\CALX_nsqrt_bgg_b \the\numexpr\ifcase#1 1\or 2\or 4\or 8\fi*\CALX_pten{#2/% \xint_c_ii}% +\xint_c_e_viii\expandafter.% \the\numexpr\ifcase#1 1\or 4\or 16\or 64\fi+\xint_c_e_viii\expandafter.% \the\numexpr\ifcase#1 1\or 5\or 25\or 125\fi+\xint_c_e_viii% \expandafter.% \the\numexpr\ifcase#1 1\or 25\or 625\or 15625\fi+\xint_c_e_viii\expandafter;% \fi #1.#2.% }% \def\CALX_nsqrt_bgg_a #1.#2.#3.#4#5{\CALX_nsqrt_core\CALX_nsqrt_out{#3}{#5}}% \def\CALX_nsqrt_bgg_b #1;#2.#3.#4.#5#6{\CALX_nsqrt_bgh #2.#3.#1.{N+#5.#6}}% % \end{macrocode} %\begin{lverb} % \CALX_nsqrt_bgh .<2t>..<4^j>.<5^j>.<25^j>.{X}: the four numbers % after j and 2t are given as 1dddddddd (value + 10^8), D0 = 2^j 10^t. % % Y = X 10^(2t) 4^j = X D0^2 (\CALX_nshl, then one one block % multiplication if j > 0). With (s,r) = core(Y), no division at all % (1/D0 = 5^j/10^(t+j)): %( S = floor(s 5^j / 10^(t+j)) (one block mul + \CALX_nshr), %: e = s - S D0 (one block mul + \CALX_nsub), %: R = (r + e(2s - e)) 25^j / 10^(2t+2j) (exact \CALX_nshr), %) % as Y = s^2 + r = X D0^2 and X - S^2 = (r + e(2s-e))/D0^2. The % multiplications by 5^j, 25^j are skipped when j = 0. %\end{lverb} % \begin{macrocode} \def\CALX_nsqrt_bgh #1#2.% {% \expandafter\CALX_nsqrt_bgi\romannumeral0% \if0#1\expandafter\CALX_nsqrt_bgh_a\else\expandafter\CALX_nsqrt_bgh_b \fi #1#2.% }% \def\CALX_nsqrt_bgh_a #1.#2.#3.#4.#5.#6.#7% {% \CALX_nshl{#2}{#7}\xint:{#3}{#1}{#2}{#5}{#6}% }% \def\CALX_nsqrt_bgh_b #1.#2.#3.#4.#5.#6.#7% {% \CALX_nmul{\romannumeral0\CALX_nshl{#2}{#7}}{N+1.#4!}% \xint:{#3}{#1}{#2}{#5}{#6}% }% \def\CALX_nsqrt_bgi N+#1.#2\xint:{\CALX_nsqrt_core\CALX_nsqrt_un{#1}{#2}}% \def\CALX_nsqrt_un #1#2#3#4#5#6% {% \expandafter\CALX_nsqrt_uo\romannumeral0\CALX_nshr{#5/\xint_c_ii+#4}% {\ifnum#4=\xint_c_ \expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {#1}{\romannumeral0\CALX_nmul{#1}{N+1.#6!}}}% \xint:{#1}{#2}{#3}{#4}{#5}% }% \def\CALX_nsqrt_uo #1\xint:#2#3#4% {% \expandafter\CALX_nsqrt_up \romannumeral0\CALX_nsub{#2}{\romannumeral0\CALX_nmul{#1}{N+1.#4!}}% \xint:{#1}{#2}{#3}% }% \def\CALX_nsqrt_up #1\xint:#2#3#4% {% \expandafter\CALX_nsqrt_uq\romannumeral0\CALX_nadd{#4}% {\romannumeral0\CALX_nmul{#1}{\romannumeral0\CALX_nsub {\romannumeral0\CALX_nadd{#3}{#3}}{#1}}}% \xint:{#2}% }% \def\CALX_nsqrt_uq #1\xint:#2#3#4#5% {% \expandafter\CALX_nsqrt_ur\romannumeral0\CALX_nshr{#4+\xint_c_ii*#3}% {\ifnum#3=\xint_c_ \expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {#1}{\romannumeral0\CALX_nmul{#1}{N+1.#5!}}}\xint:{#2}% }% \def\CALX_nsqrt_ur #1\xint:#2{{#2}{#1}}% % \end{macrocode} % \subsection{Decimal shifts} % \subsubsection{\csh{CALX_nshr}, \csh{CALX_nshl}, \csh{CALX_nshrr}} %\begin{lverb} % Syntax (use with \romannumeral0; k a \numexpr expression, X f-expanded % native integer or I): %( % \CALX_nshr{k}{X} -> Y Y = sign(X) floor(|X|/10^k) %: \CALX_nshl{k}{X} -> Y Y = X 10^k %: \CALX_nshrr{k}{X} -> Y Y = sign(X) round(|X|/10^k) %) % Decimal shifts of native integers (analogues of \xintDSH, \xintDSx, % \xintDSRr). Use with \romannumeral0; arguments f-expanded. % % \CALX_nshr{k}{X}: sign(X) floor(|X|/10^k) (truncation towards zero). % % \CALX_nshl{k}{X}: X 10^k. \CALX_nshrr{k}{X}: |X|/10^k rounded half % away from zero, sign kept. k >= 0 (k <= 0: X unchanged). % % k = 8a + c. Whole blocks: \CALX_nskip (right) or prepended zero blocks % (left). c > 0: one pass inside \expanded (generated macros % \CALX_nshr_f, \CALX_nshr_l, \CALX_nshr_e, \CALX_nshl_l, % \CALX_nshl_e): each new block is a token rearrangement of two % consecutive blocks, the pending part being the macro argument; no % arithmetic. End marker 1;;;;;;;;!. The pass ends with \relax<0|1> % telling whether a top block was dropped (right) or added (left); the % header N. is built after the pass (one grab of the result). % I+, I-, I? are returned unchanged (\CALX_nsh_t, one \if test). % % \CALX_nshrr$empty: first dropped digit = digit p = (k-1) mod 8 of block % (k-1) div 8 = (2k-9)/16 (\numexpr, k >= 1), read by \CALX_nskip; +1 by % \CALX_nadd if >= 5. A result with no block left is N+0. %\end{lverb} % \begin{macrocode} \def\CALX_nsh_t #1#2.#3{\if I#3\xint_dothis\CALX_nsh_sp\fi% \xint_orthat{#1#2.#3}}% \def\CALX_nsh_sp #1\xint:{ I#1}% \def\CALX_nsh_zero\fi#1\xint:{\fi\CALX_sp N+0.}% \def\CALX_nsh_id\fi#1.#2.#3.#4\xint:{\fi\CALX_sp N#3.#4}% \def\CALX_nshr #1#2{\expandafter\CALX_nsh_t\expandafter\CALX_nshr_a\the% \numexpr#1\expandafter.\romannumeral`&&@#2\xint:}% \def\CALX_nshr_a #1.N#2#3.#4\xint:% {% \ifnum#3=\xint_c_ \CALX_nsh_zero\fi \ifnum#1<\xint_c_i \CALX_nsh_id\fi \expandafter\CALX_nshr_b\the\numexpr(#1-\xint_c_iv)/\xint_c_viii.% #1.#2#3.#4\xint: }% \def\CALX_nshr_b #1.#2.#3#4.#5\xint:% {% \ifnum#1<#4 \xint_dothis{\expandafter\CALX_nshr_c\the\numexpr#2-% \xint_c_viii*#1.#1.#3#4.{#5}}\fi \xint_orthat{ N+0.}% }% \def\CALX_nshr_c #1.#2.#3#4.#5% {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nskip\CALX_nshr_z#2.#51;;;;;;;;!\xint:{#3}{#4-#2}}\fi \xint_orthat{\expandafter\CALX_nshr_o\expanded{\expandafter\CALX_nskip \csname CALX_nshr_f#1\endcsname#2.#51;;;;;;;;!}% \xint:{#3}{#4-#2}}% }% \def\CALX_nshr_z #11;;;;;;;;!\xint:#2#3{\expanded{ N#2\the\numexpr#3.}#1}% \def\CALX_nshr_o #1\relax#2\xint:#3#4% {% \ifnum\numexpr#4-#2=\xint_c_ \xint_dothis{ N+0.}\fi \xint_orthat{\expanded{ N#3\the\numexpr#4-#2.}#1}% }% \def\CALX_nshl #1#2{\expandafter\CALX_nsh_t\expandafter\CALX_nshl_a\the% \numexpr#1\expandafter.\romannumeral`&&@#2\xint:}% \def\CALX_nshl_a #1.N#2#3.#4\xint:% {% \ifnum#3=\xint_c_ \CALX_nsh_zero\fi \ifnum#1<\xint_c_i \CALX_nsh_id\fi \expandafter\CALX_nshl_b\the\numexpr(#1-\xint_c_iv)/\xint_c_viii.% #1.#2#3.#4\xint: }% \def\CALX_nshl_b #1.#2.#3#4.#5\xint:% {\expandafter\CALX_nshl_c\the\numexpr#2-\xint_c_viii*#1.#1.#3#4.#5\xint:}% \def\CALX_nshl_c #1.#2.#3#4.#5\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{\expanded{ N#3\the\numexpr#4+#2.\romannumeral% \xintreplicate{#2}{100000000!}}#5}\fi \xint_orthat{\expandafter\CALX_nshl_o\expanded{% \romannumeral\xintreplicate{#2}{100000000!}% \csname CALX_nshl_l#1\endcsname{\romannumeral% \xintreplicate{#1}0}% #51;;;;;;;;!}\xint:{#3}{#4+#2}}% }% \def\CALX_nshl_o #1\relax#2\xint:#3#4{\expanded{ N#3\the\numexpr#4+#2.}#1}% \def\CALX_nshrr #1#2{\expandafter\CALX_nsh_t\expandafter\CALX_nshrr_a\the% \numexpr#1\expandafter.\romannumeral`&&@#2\xint:}% \def\CALX_nshrr_a #1.N#2#3.#4\xint:% {% \ifnum#1<\xint_c_i \xint_dothis{ N#2#3.#4}\fi \ifnum#3=\xint_c_ \xint_dothis{ N+0.}\fi \ifnum#1>\numexpr\xint_c_viii*#3\relax \xint_dothis{ N+0.}\fi \xint_orthat{\expandafter\CALX_nshrr_b\the\numexpr \CALX_nskip\CALX_nshrr_d(\xint_c_ii*#1-9)/16.#41;!% #1-\xint_c_i-\xint_c_viii*((\xint_c_ii*#1-9)/16).% #1.N#2#3.#4\xint:}% }% % \end{macrocode} %\begin{lverb} % \CALX_nshrr_d 1!1;!

. (inside \numexpr) gives the digit p % from the right of the block followed by a full stop; on the sentinel 1;! % (block beyond the number) it gives 0. With y = 10^p, floor(b/y) = % (b+y/2)/y-1 for p > 0 (y even), q mod 10 = q-10((q+5)/10-1). %\end{lverb} % \begin{macrocode} \def\CALX_nshrr_d 1#1!{\xint_gob_til_sc#1\CALX_nshrr_dz;\CALX_nshrr_dn{#1}}% \def\CALX_nshrr_dz;\CALX_nshrr_dn#1#2.{0.}% \def\CALX_nshrr_dn #1#21;!#3.% {% \ifnum\numexpr#3=\xint_c_ \xint_dothis{(#1-((#1+5)/10-1)*10).}\fi \xint_orthat{\CALX_nshrr_dq{\CALX_pten{#3}}{#1}}% }% \def\CALX_nshrr_dq #1#2% {(((#2+#1/2)/#1-1)-((((#2+#1/2)/#1-1)+5)/10-1)*10).}% \def\CALX_nshrr_b #1.#2.#3\xint:% {% \ifnum#1>\xint_c_iv \xint_dothis{\expandafter\CALX_nshrr_up\romannumeral0\CALX_nshr{#2}{#3}% \xint:#3\xint:}\fi \xint_orthat{\CALX_nshr{#2}{#3}}% }% \def\CALX_nshrr_up N#1#2\xint:N#3#4\xint:% {\CALX_nadd{N#1#2}{N#31.100000001!}}% \expandafter\def\csname CALX_nshr_f1\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_li{#1#2#3#4#5#6#7}}% \def\CALX_nshr_li #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_ei;1#9#1!\CALX_nshr_li{#2#3#4#5#6#7#8}}% \def\CALX_nshr_ei;1;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 10#1!\relax0\fi}% \def\CALX_nshl_li #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_ei;1#3#4#5#6#7#8#9#1!\CALX_nshl_li{#2}}% \def\CALX_nshl_ei;1;;;;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 10000000#1!\relax1\fi}% \expandafter\def\csname CALX_nshr_f2\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_lii{#1#2#3#4#5#6}}% \def\CALX_nshr_lii #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_eii;1#8#9#1!\CALX_nshr_lii{#2#3#4#5#6#7}}% \def\CALX_nshr_eii;1;;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 100#1!\relax0\fi}% \def\CALX_nshl_lii #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_eii;1#4#5#6#7#8#9#1!\CALX_nshl_lii{#2#3}}% \def\CALX_nshl_eii;1;;;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 1000000#1!\relax1\fi}% \expandafter\def\csname CALX_nshr_f3\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_liii{#1#2#3#4#5}}% \def\CALX_nshr_liii #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_eiii;1#7#8#9#1!\CALX_nshr_liii{#2#3#4#5#6}}% \def\CALX_nshr_eiii;1;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 1000#1!\relax0\fi}% \def\CALX_nshl_liii #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_eiii;1#5#6#7#8#9#1!\CALX_nshl_liii{#2#3#4}}% \def\CALX_nshl_eiii;1;;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 100000#1!\relax1\fi}% \expandafter\def\csname CALX_nshr_f4\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_liv{#1#2#3#4}}% \def\CALX_nshr_liv #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_eiv;1#6#7#8#9#1!\CALX_nshr_liv{#2#3#4#5}}% \def\CALX_nshr_eiv;1;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 10000#1!\relax0\fi}% \def\CALX_nshl_liv #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_eiv;1#6#7#8#9#1!\CALX_nshl_liv{#2#3#4#5}}% \def\CALX_nshl_eiv;1;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 10000#1!\relax1\fi}% \expandafter\def\csname CALX_nshr_f5\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_lv{#1#2#3}}% \def\CALX_nshr_lv #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_ev;1#5#6#7#8#9#1!\CALX_nshr_lv{#2#3#4}}% \def\CALX_nshr_ev;1;;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 100000#1!\relax0\fi}% \def\CALX_nshl_lv #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_ev;1#7#8#9#1!\CALX_nshl_lv{#2#3#4#5#6}}% \def\CALX_nshl_ev;1;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 1000#1!\relax1\fi}% \expandafter\def\csname CALX_nshr_f6\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_lvi{#1#2}}% \def\CALX_nshr_lvi #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_evi;1#4#5#6#7#8#9#1!\CALX_nshr_lvi{#2#3}}% \def\CALX_nshr_evi;1;;;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 1000000#1!\relax0\fi}% \def\CALX_nshl_lvi #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_evi;1#8#9#1!\CALX_nshl_lvi{#2#3#4#5#6#7}}% \def\CALX_nshl_evi;1;;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 100#1!\relax1\fi}% \expandafter\def\csname CALX_nshr_f7\endcsname 1#1#2#3#4#5#6#7#8!{\CALX_nshr_lvii{#1}}% \def\CALX_nshr_lvii #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshr_evii;1#3#4#5#6#7#8#9#1!\CALX_nshr_lvii{#2}}% \def\CALX_nshr_evii;1;;;;;;;#1!#2#3% {\ifnum#1=\xint_c_ \relax1\else 10000000#1!\relax0\fi}% \def\CALX_nshl_lvii #11#2#3#4#5#6#7#8#9!% {\xint_gob_til_sc#2\CALX_nshl_evii;1#9#1!\CALX_nshl_lvii{#2#3#4#5#6#7#8}}% \def\CALX_nshl_evii;1;#1!#2#3% {\ifnum#1=\xint_c_ \relax0\else 10#1!\relax1\fi}% \expandafter\let\csname CALX_nshl_l1\endcsname\CALX_nshl_li \expandafter\let\csname CALX_nshl_l2\endcsname\CALX_nshl_lii \expandafter\let\csname CALX_nshl_l3\endcsname\CALX_nshl_liii \expandafter\let\csname CALX_nshl_l4\endcsname\CALX_nshl_liv \expandafter\let\csname CALX_nshl_l5\endcsname\CALX_nshl_lv \expandafter\let\csname CALX_nshl_l6\endcsname\CALX_nshl_lvi \expandafter\let\csname CALX_nshl_l7\endcsname\CALX_nshl_lvii % \end{macrocode} % \subsection{Interface for \xintexprnameimp usage} %\begin{lverb} % Attention: N and I are STILL of catcode 12. We now also make M of catcode % 12. Be extra careful with macro names. % % The integer type of \xintiieval: M.., the value of % the N value N. (n blocks 1dddddddd!, least significant % first) times 10^(8e), e >= 0, lowest block non-zero; zero is M+0.0. % \CALX_ntom: N value (blocks in the stream) to M, the low zero blocks % go into e. \CALX_mfromraw: raw integer (xintcore format) to M. % \CALX_mtoraw: M to raw integer, 8e zeros written out. % \CALX_ntomd d.N...: as \CALX_ntom, e starting at d; \CALX_ntoms: same, % special values (I...) passed as they are. % % Syntax of the entry points (A, B, X f-expanded; M, I values, or raw % integers converted on entry; R a raw integer): %( % \CALX_ntom N. -> M.. %: \CALX_ntomd d.N. -> the same, e counted from d %: \CALX_mfromraw{R} -> M... %: \CALX_mtoraw{X} -> (X an M value) %: \CALX_tom{X} -> M...\xint: or I\xint: %: \CALX_mr{X} -> (X M, A, A[N] N >= 0), %: X otherwise (I, A[N] N < 0) %: \CALX_mrl ...^ -> {\CALX_mr{}}... (in \expanded) %: \CALX_ii{A}{B}, \CALX_ii{X} -> M... or I %: \calxii{A}{B}, \calxii{X} -> M... or I (f-expandable) %: \CALX_iilit{A}{N} -> M..., or A[N] %) % \CALX_ntom, \CALX_ntomd, \CALX_mfromraw, \CALX_mtoraw, \CALX_tom and the % \CALX_ii are used with \romannumeral0. The comparisons \calxiiLt, % \calxiiGt, \calxiiLtorEq, \calxiiGtorEq, \calxiiEq, \calxiiNotEq give % raw 1 or 0; \calxiiDivMod gives {Q}{R}; \calxiiPow{A}{k}. % % M layer (used as \romannumeral0\CALX_ii{A}{B}, results M or I): % \CALX_tom{X}: X f-expanded; M left as it is (the tag re-emitted with % the catcode of this block: a value compiled in a user function may % carry another one), raw integer converted; A[N] with N >= 0: A % followed by N zeros (\CALX_tom_w); A[N] with N < 0 and A/B[N]: % \CALX_tom_x, integer check (error, then truncation) by one % native division (\CALX_iiq: A 10^max(N,0) by B 10^max(-N,0), B > 0; % an integer iff the remainder is zero; truncation = floor quotient, plus % one if negative); I+, I-, I? left as they are; \xint: follows. % \CALX_iitwo{A}{B} hands M(A)\xint:M(B)\xint: to , % or the same with an I value to (tag test \CALX_iitwo_b). % Special values propagate as in the N kernels (rules of calxcore): % \CALX_iisp_g calls the N kernel on the operands, M ones % converted with their e zero blocks written out (\CALX_mton), result % through \CALX_ntoms (I kept). Unary ops: \CALX_iiun; % opp, abs, sqr act on the I sign, isqrt calls \CALX_nsqrtrem, ^ with an % I base: k = 0 gives 1, I? stays, k < 0 gives 0, else I+ or I- (odd k, % I- base). Comparisons with an I? operand: InvalidOperation, 0 (== is % false, != true, no signal); infinities ordered by \CALX_icl. % mul, sqr: e1+e2 (2e), N kernel % \CALX_nmul. add, sub and the division family (divtrunc, modtrunc, % divfloor, mod, quo, rem, divround, division, divmod, kernels % \CALX_n... of calxcore): with d = min(e1,e2) the operand of larger e % gets e - d zero blocks; the quotient has e = 0, a sum or remainder % e = d. opp, abs: sign token. isqrt: all e zero blocks written out % (\CALX_nsqrtrem), result e = 0. % % \xintiieval. Literals (receivers of the scanner's fake operators): % digits to M (\CALX_mfromraw); with [N] (decimal mark, exponent, raw % [N]): \CALX_iilit, M if the value is an % integer, else the raw A[N] (for num(), round(), trunc()); in compiled % functions (\XINT_expr_redefinemacros) literals stay raw. Operators % and functions: \calxii, one token each (needed by the % \xintdeffunc hooks). Native: Add, Sub, Mul, Sqr, Opp, Abs, Sqrt, % DivFloor (//), Mod (/:), DivRound (/), Quo, Rem, DivMod, Pow and the % comparisons. Pow (^): k = \numexpr of the exponent, \CALX_npow on the % blocks only, result exponent e k; k < 0 (\CALX_ipr): % 1 for 1, (-1)^k for -1, DivisionByZero (I+) for 0, Underflow (0) % otherwise. Lt, Gt, LtorEq, GtorEq: keys % s (n + e) (s the sign, 0 for zero) compared first; equal keys: the % blocks if n = 1 for both, else the sign of the difference % (\CALX_iisub_x); the three result digits for equal, greater, less % follow the arguments. Eq, NotEq: \xintstrcmp of the canonical M % values. Comparisons give raw 1 or 0. ^ with an I exponent: IEEE pow % (\CALX_iipow_e, table \CALX_ipe, % classes o (1), m (-1), z (0), b (other), i (I+, I-), n (I?)). Integer % functions on M values (an I argument signals InvalidOperation, result % I?): Fac (\CALX_nfac; negative or > 10^4: InvalidOperation), Odd, Even % (parity of the lowest block if e = 0), IsOne, ifOne (an I argument % selects the second branch), LogTen (8(n+e) - 9 + digits of the top % block; zero: -"7FFF8000 as xint), SqrtR (\CALX_nsqrtrem: S + 1 iff % R > S). On the \numexpr values of raw arguments (\CALX_mrd; \CALX_mr: % M to raw digits, other values as they are): Binomial (\CALX_binom_a, % native, by \CALX_ntom), PFactorial (\CALX_npfac), with xint's argument % rules and InvalidOperation for the out of range cases. Raw output from % xint macros: Round, Trunc (digit count), SeqB:tl:x (a..[d]..b). Lists: % gcd, lcm: Burnol's \XINT_iigcdof/\XINT_iilcmof loops (delimiter \xint: % instead of !, which occurs in M values) on \CALX_iigcd, \CALX_iilcm, of % the native \CALX_ngcd, \CALX_nlcm % (Euclid's algorithm by \CALX_nrem; the M versions factor out the common % power 10^(8 min(e1,e2))); an I item: InvalidOperation, I?. `+`, `*`: % Burnol's \XINT_sum/\XINT_prd loops (xintfrac) on \CALX_iiadd, % \CALX_iimul (empty: 0, 1); max, min: Burnol's \XINT_iimaxof/\XINT_iiminof % loops on \CALX_iimax, \CALX_iimin (the native comparisons; each item % f-expanded once, the values returned expanded), an % unordered comparison (I?) signals InvalidOperation and keeps the % current value (as \calxFpMaxof). Printers: % \xintiiexprPrintOne(Hex/Oct/Bin) through \CALX_mr. %\end{lverb} % \begin{macrocode} \catcode`M=12 \def\CALX_ntom {\CALX_ntomd 0.}% \def\CALX_ntomd #1.N#2#3.% {% \ifnum#3=\xint_c_ \xint_dothis{ M+0.0.}\fi \xint_orthat{\CALX_ntom_a#2#3.#1.}% }% \def\CALX_ntom_a #1#2.#3.#4!% {% \ifnum#4=\xint_c_e_viii \xint_dothis{\expandafter\CALX_ntom_a\expandafter#1% \the\numexpr#2-\xint_c_i\expandafter.\the\numexpr#3+\xint_c_i.}\fi \xint_orthat{ M#1#2.#3.#4!}% }% \def\CALX_mfromraw% {\expandafter\CALX_ntom\romannumeral0\CALX_nfromraw}% \def\CALX_mtoraw #1{\expandafter\CALX_mtoraw_t\romannumeral`&&@#1\xint:}% \def\CALX_mtoraw_t #1{\CALX_mtoraw_a M}% \def\CALX_mtoraw_a M#1#2.#3.% {% \ifnum#3=\xint_c_ \xint_dothis{\CALX_ntoraw_a N#1#2.}\fi \xint_orthat{\CALX_mtoraw_b{#3}N#1#2.}% }% \def\CALX_mtoraw_b #1#2\xint:% {\expanded{ \romannumeral0\CALX_ntoraw_a#2\xint:% \xintReplicate{\xint_c_viii*#1}0}}% \def\CALX_infr_m #1{\CALX_infr_b #1\xint:}% \def\CALX_infr_b #1#2#3.#4.#5\xint:% {\expandafter\CALX_infr_c\the\numexpr\xint_c_viii*#4\expandafter.% \romannumeral0\CALX_ntoraw_a N#2#3.#5\xint:.}% \def\CALX_infr_c #1.#2.{{#1}{#2}{1}}% \def\CALX_ntoms #1.#2% {\if I#2\xint_dothis{ #2}\fi\xint_orthat{\CALX_ntomd#1.#2}}% \def\CALX_tom #1{\expandafter\CALX_tom_a\romannumeral`&&@#1\xint:}% \def\CALX_tom_a #1% {\if M#1\xint_dothis{ M}\fi\if I#1\xint_dothis{ #1}\fi \xint_orthat{\CALX_tom_r#1}}% \def\CALX_tom_r #1\xint:{\CALX_tom_s #1[.\xint:}% \def\CALX_tom_s #1[#2{\xint_gob_til_dot#2\CALX_tom_b.\CALX_tom_k #2#1[}% \def\CALX_tom_b.\CALX_tom_k.#1[\xint:% {\expandafter\CALX_ntom\romannumeral0\CALX_nfromraw_a#1\xint:\xint:}% \def\CALX_tom_k #1% {% \xint_UDsignfork #1\CALX_tom_neg -\CALX_tom_p \krof #1% }% \def\CALX_tom_neg -#1[#2][.\xint:{\CALX_tom_z #1/1/\xint:{-#2}{#1[-#2]}}% \def\CALX_tom_p #1#2[#3][.\xint:{\CALX_tom_v #1#3.#2/\xint:}% \def\CALX_tom_v #1.#2/#3% {\xint_gob_til_xint:#3\CALX_tom_w\xint:\CALX_tom_x #1.#2/#3}% \def\CALX_tom_w\xint:\CALX_tom_x #1.#2/\xint:% {\expandafter\CALX_ntom\romannumeral0\expandafter\CALX_nfromraw_a \expanded{#2\xintReplicate{#1}0}\xint:\xint:}% \def\CALX_iitwo #1#2#3#4% {\expandafter\CALX_iitwo_a\expandafter#1\expandafter#2% \romannumeral0\CALX_tom{#4}{#3}}% \def\CALX_iitwo_a #1#2#3#4\xint:#5% {\expandafter\CALX_iitwo_b\expandafter#1\expandafter#2\expandafter#3% \romannumeral0\CALX_tom{#5}#3#4\xint:}% \def\CALX_iitwo_b #1#2#3#4% {\if\if M#4#3\else ?\fi M\expandafter#1\else\expandafter#2\fi #4}% \def\CALX_iisp_g #1#2#3\xint:#4\xint:% {#1 0.{#2{\CALX_mton#3\xint:}{\CALX_mton#4\xint:}}}% \def\CALX_mton #1#2\xint:% {\if M#1\xint_dothis{\CALX_mton_m#2\xint:}\fi\xint_orthat{#1#2}}% \def\CALX_mton_m #1#2.#3.#4\xint:% {\expanded{N#1\the\numexpr#2+#3.\xintReplicate{#3}{100000000!}#4}}% \def\CALX_iiun #1#2#3{\if I#3\expandafter#2\else\expandafter#1\fi #3}% \def\CALX_iimul {\CALX_iitwo\CALX_iimul_x\CALX_iimul_sp}% \def\CALX_iimul_sp {\CALX_iisp_g\CALX_iifq\CALX_nmul}% \def\CALX_iimul_x M#1#2.#3.#4\xint:M#5#6.#7.#8\xint:% {\expandafter\CALX_ntomd\the\numexpr#3+#7\expandafter.% \romannumeral0\CALX_nmul{N#1#2.#4}{N#5#6.#8}}% \def\CALX_iisqr{\expandafter\CALX_iiun\expandafter\CALX_iisqr_x \expandafter\CALX_iiabs_i\romannumeral0\CALX_tom}% \def\CALX_iisqr_x M#1#2.#3.#4\xint:% {\expandafter\CALX_ntomd\the\numexpr\xint_c_ii*#3\expandafter.% \romannumeral0\CALX_nmul{N+#2.#4}{N+#2.#4}}% \def\CALX_iiopp{\expandafter\CALX_iiun\expandafter\CALX_iiopp_x \expandafter\CALX_iiopp_i\romannumeral0\CALX_tom}% \def\CALX_iiopp_i #1#2\xint:% {\if ?#2\xint_dothis{ #1#2}\fi\if -#2\xint_dothis{ #1+}\fi \xint_orthat{ #1-}}% \def\CALX_iiopp_x M#1#2#3\xint:% {\if0#2\xint_dothis{ M#1#2#3}\fi \if-#1\xint_dothis{ M+#2#3}\fi \xint_orthat{ M-#2#3}}% \def\CALX_iiabs{\expandafter\CALX_iiun\expandafter\CALX_iiabs_x \expandafter\CALX_iiabs_i\romannumeral0\CALX_tom}% \def\CALX_iiabs_i #1#2\xint:% {\if ?#2\xint_dothis{ #1#2}\fi\xint_orthat{ #1+}}% \def\CALX_iiabs_x M#1#2\xint:{ M+#2}% \def\CALX_iisqrt {\CALX_iisq\CALX_iisqrt_f}% \def\CALX_iisqrtr{\CALX_iisq\CALX_iisqrtr_f}% \def\CALX_iisq #1#2{\expandafter\CALX_iiun\expandafter\CALX_iisqrt_x \expandafter\CALX_iisqrt_i\romannumeral0\CALX_tom{#2}#1}% \def\CALX_iisqrt_i #1\xint:#2% {\expandafter#2\romannumeral0\CALX_nsqrtrem{#1}}% \def\CALX_iisqrt_x M#1#2.#3.#4\xint:#5% {% \ifnum#3=\xint_c_ \xint_dothis{\expandafter#5\romannumeral0\CALX_nsqrtrem{N#1#2.#4}}\fi \xint_orthat{\expandafter#5\romannumeral0\CALX_nsqrtrem {\expanded{N#1\the\numexpr#2+#3.\xintReplicate{#3}{100000000!}#4}}}% }% \def\CALX_iisqrt_f #1#2{\CALX_ntoms0.#1}% \def\CALX_iisqrtr_f #1{\CALX_iisqrtr_a #1\xint:}% \def\CALX_iisqrtr_a #1{% \if I#1\xint_dothis\CALX_iisqrtr_i\fi \xint_orthat\CALX_iisqrtr_n #1% }% \def\CALX_iisqrtr_i #1#2\xint:#3{ #1#2}% \def\CALX_iisqrtr_n #1#2\xint:#3{% \expandafter\CALX_iisqrtr_g \romannumeral0\CALX_nsub{#3}{#1#2}\xint:{#1#2}% }% \def\CALX_iisqrtr_g N#1#2.#3\xint:#4% {% \if-#1\xint_dothis{\CALX_ntomd0.#4}\fi \ifnum#2=\xint_c_ \xint_dothis{\CALX_ntomd0.#4}\fi \xint_orthat{\expandafter\CALX_ntom \romannumeral0\CALX_nadd{#4}{N+1.100000001!}}% }% \def\CALX_iifa #1.#2% {\expandafter\CALX_ntomd\the\numexpr#1\expandafter.\romannumeral0#2}% \def\CALX_iifq #1.#2% {\expandafter\CALX_ntoms\expandafter0\expandafter.\romannumeral0#2}% \def\CALX_iifr #1.#2% {\expandafter\CALX_ntoms\the\numexpr#1\expandafter.\romannumeral0#2}% \def\CALX_iifp #1.#2{\expandafter\CALX_iifp_a\romannumeral0#2{#1}}% \def\CALX_iifp_a #1#2#3% {\expanded{ {\romannumeral0\CALX_ntoms0.#1}% {\romannumeral0\CALX_ntoms#3.#2}}}% \def\CALX_iiadd{\CALX_iitwo\CALX_iiadd_x\CALX_iiadd_sp}% \def\CALX_iiadd_sp{\CALX_iisp_g\CALX_iifq\CALX_nadd}% \def\CALX_iiadd_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iiadd_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iiadd_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iiadd_x_eq 0#1\CALX_iiadd_x_lt 0-\CALX_iiadd_x_gt \krof #1% }% \def\CALX_iiadd_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntomd\the\numexpr#1\expandafter.% \romannumeral0\CALX_nadd_y N#2\xint: N#31;!1;!1;!1;!\W\xint: }% \def\CALX_iiadd_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2\expandafter.% \romannumeral0\expandafter\CALX_nadd_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#31;!1;!1;!1;!\W\xint: }% \def\CALX_iiadd_x_gt #1.#2.M#3#4.#5\xint:M#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2-#1\expandafter.% \romannumeral0\expandafter\CALX_nadd_y \expanded{N#3\the\numexpr#1+#4.% \xintReplicate{#1}{100000000!}}#5\xint:N#61;!1;!1;!1;!\W\xint: }% \def\CALX_iisub{\CALX_iitwo\CALX_iisub_x\CALX_iisub_sp}% \def\CALX_iisub_sp{\CALX_iisp_g\CALX_iifq\CALX_nsub}% \def\CALX_iisub_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iisub_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iisub_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iisub_x_eq 0#1\CALX_iisub_x_lt 0-\CALX_iisub_x_gt \krof #1% }% \def\CALX_iisub_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntomd\the\numexpr#1\expandafter.% \romannumeral0\CALX_nsub_y N#3\xint: N#21;!1;!1;!1;!\W\xint: }% \def\CALX_iisub_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2\expandafter.% \romannumeral0\expandafter\CALX_nsub_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#31;!1;!1;!1;!\W\xint: }% \def\CALX_iisub_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iisub_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iisub_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntomd\the\numexpr#1\expandafter.% \romannumeral0\CALX_nsub_y N#3\xint:#21;!1;!1;!1;!\W\xint: }% \def\CALX_iidivtrunc{\CALX_iitwo\CALX_iidivtrunc_x\CALX_iidivtrunc_sp}% \def\CALX_iidivtrunc_sp{\CALX_iisp_g\CALX_iifq\CALX_ndivtrunc}% \def\CALX_iidivtrunc_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iidivtrunc_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iidivtrunc_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iidivtrunc_x_eq 0#1\CALX_iidivtrunc_x_lt 0-\CALX_iidivtrunc_x_gt \krof #1% }% \def\CALX_iidivtrunc_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_ndt_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivtrunc_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_ndt_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivtrunc_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iidivtrunc_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iidivtrunc_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_ndt_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iimodtrunc{\CALX_iitwo\CALX_iimodtrunc_x\CALX_iimodtrunc_sp}% \def\CALX_iimodtrunc_sp{\CALX_iisp_g\CALX_iifq\CALX_nmodtrunc}% \def\CALX_iimodtrunc_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iimodtrunc_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iimodtrunc_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iimodtrunc_x_eq 0#1\CALX_iimodtrunc_x_lt 0-\CALX_iimodtrunc_x_gt \krof #1% }% \def\CALX_iimodtrunc_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\the\numexpr#1\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_nmt_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iimodtrunc_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\the\numexpr#2\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_nmt_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iimodtrunc_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iimodtrunc_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iimodtrunc_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\the\numexpr#1\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_nmt_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iidivfloor{\CALX_iitwo\CALX_iidivfloor_x\CALX_iidivfloor_sp}% \def\CALX_iidivfloor_sp{\CALX_iisp_g\CALX_iifq\CALX_ndivfloor}% \def\CALX_iidivfloor_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iidivfloor_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iidivfloor_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iidivfloor_x_eq 0#1\CALX_iidivfloor_x_lt 0-\CALX_iidivfloor_x_gt \krof #1% }% \def\CALX_iidivfloor_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_ndf_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivfloor_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_ndf_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivfloor_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iidivfloor_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iidivfloor_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_ndf_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iimod{\CALX_iitwo\CALX_iimod_x\CALX_iimod_sp}% \def\CALX_iimod_sp{\CALX_iisp_g\CALX_iifq\CALX_nmod}% \def\CALX_iimod_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iimod_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iimod_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iimod_x_eq 0#1\CALX_iimod_x_lt 0-\CALX_iimod_x_gt \krof #1% }% \def\CALX_iimod_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\the\numexpr#1\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_nmd_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iimod_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\the\numexpr#2\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_nmd_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iimod_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iimod_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iimod_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\the\numexpr#1\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_nmd_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iiquo{\CALX_iitwo\CALX_iiquo_x\CALX_iiquo_sp}% \def\CALX_iiquo_sp{\CALX_iisp_g\CALX_iifq\CALX_nquo}% \def\CALX_iiquo_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iiquo_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iiquo_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iiquo_x_eq 0#1\CALX_iiquo_x_lt 0-\CALX_iiquo_x_gt \krof #1% }% \def\CALX_iiquo_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_nqu_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iiquo_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_nqu_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iiquo_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iiquo_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iiquo_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_nqu_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iirem{\CALX_iitwo\CALX_iirem_x\CALX_iirem_sp}% \def\CALX_iirem_sp{\CALX_iisp_g\CALX_iifq\CALX_nrem}% \def\CALX_iirem_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iirem_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iirem_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iirem_x_eq 0#1\CALX_iirem_x_lt 0-\CALX_iirem_x_gt \krof #1% }% \def\CALX_iirem_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\the\numexpr#1\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_nre_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iirem_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\the\numexpr#2\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_nre_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iirem_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iirem_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iirem_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\the\numexpr#1\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_nre_go% \CALX_ndiv_zr\CALX_ndiv_zz }% \def\CALX_iidivround{\CALX_iitwo\CALX_iidivround_x\CALX_iidivround_sp}% \def\CALX_iidivround_sp{\CALX_iisp_g\CALX_iifq\CALX_ndivround}% \def\CALX_iidivround_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iidivround_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iidivround_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iidivround_x_eq 0#1\CALX_iidivround_x_lt 0-\CALX_iidivround_x_gt \krof #1% }% \def\CALX_iidivround_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_ndr_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivround_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_ndr_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivround_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iidivround_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iidivround_x_gt_b #1.#2\xint:M#3\xint: {% \expandafter\CALX_ntoms\expandafter0\expandafter.% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_ndr_go% \CALX_ndiv_zq\CALX_ndiv_zz }% \def\CALX_iidivision{\CALX_iitwo\CALX_iidivision_x\CALX_iidivision_sp}% \def\CALX_iidivision_sp{\CALX_iisp_g\CALX_iifq\CALX_ndivision}% \def\CALX_iidivision_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iidivision_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iidivision_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iidivision_x_eq 0#1\CALX_iidivision_x_lt 0-\CALX_iidivision_x_gt \krof #1% }% \def\CALX_iidivision_x_eq 0.#1.M#2\xint:M#3\xint: {% \CALX_iifp#1.{% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_ndn_go% \CALX_ndiv_zp\CALX_ndiv_zzp} }% \def\CALX_iidivision_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \CALX_iifp#2.{% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_ndn_go% \CALX_ndiv_zp\CALX_ndiv_zzp} }% \def\CALX_iidivision_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iidivision_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iidivision_x_gt_b #1.#2\xint:M#3\xint: {% \CALX_iifp#1.{% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_ndn_go% \CALX_ndiv_zp\CALX_ndiv_zzp} }% \def\CALX_iidivmod{\CALX_iitwo\CALX_iidivmod_x\CALX_iidivmod_sp}% \def\CALX_iidivmod_sp{\CALX_iisp_g\CALX_iifq\CALX_ndivmod}% \def\CALX_iidivmod_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iidivmod_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iidivmod_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iidivmod_x_eq 0#1\CALX_iidivmod_x_lt 0-\CALX_iidivmod_x_gt \krof #1% }% \def\CALX_iidivmod_x_eq 0.#1.M#2\xint:M#3\xint: {% \CALX_iifp#1.{% \romannumeral0\CALX_ndiv_y N#3\xint:N#2\xint:% \CALX_ndm_go% \CALX_ndiv_zp\CALX_ndiv_zzp}% }% \def\CALX_iidivmod_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \CALX_iifp#2.{% \romannumeral0\expandafter\CALX_ndiv_y \expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6\xint:N#3\xint:% \CALX_ndm_go% \CALX_ndiv_zp\CALX_ndiv_zzp}% }% \def\CALX_iidivmod_x_gt #1.#2.M#3#4.% {% \expandafter\CALX_iidivmod_x_gt_b\expanded{\the\numexpr#2-#1.% N#3\the\numexpr#1+#4.\xintReplicate{#1}{100000000!}}% }% \def\CALX_iidivmod_x_gt_b #1.#2\xint:M#3\xint: {% \CALX_iifp#1.{% \romannumeral0\CALX_ndiv_y N#3\xint:#2\xint:% \CALX_ndm_go% \CALX_ndiv_zp\CALX_ndiv_zzp}% }% \def\CALX_iigcd{\CALX_iitwo\CALX_iigcd_x\CALX_iigcd_sp}% \def\CALX_iigcd_sp{\CALX_iisp_g\CALX_iifq\CALX_ngcd}% \def\CALX_iigcd_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iigcd_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iigcd_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iigcd_x_eq 0#1\CALX_iigcd_x_lt 0-\CALX_iigcd_x_gt \krof #1% }% \def\CALX_iigcd_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntomd\the\numexpr#1\expandafter.% \romannumeral0\CALX_ngcd{N#2}{N#3}% }% \def\CALX_iigcd_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2\expandafter.% \romannumeral0\CALX_ngcd{N#3}% {\expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6}% }% \def\CALX_iigcd_x_gt #1.#2.M#3#4.#5\xint:M#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2-#1\expandafter.% \romannumeral0\CALX_ngcd{\expanded{N#3\the\numexpr#1+#4.% \xintReplicate{#1}{100000000!}}#5}{N#6}% }% \def\CALX_iilcm{\CALX_iitwo\CALX_iilcm_x\CALX_iilcm_sp}% \def\CALX_iilcm_sp{\CALX_iisp_g\CALX_iifq\CALX_nlcm}% \def\CALX_iilcm_x M#1.#2.#3\xint:M#4.#5.% {% \expandafter\CALX_iilcm_x_a\the\numexpr#2-#5.#2.M#1.#3\xint:M#4.% }% \def\CALX_iilcm_x_a #1% {% \xint_UDzerominusfork #1-\CALX_iilcm_x_eq 0#1\CALX_iilcm_x_lt 0-\CALX_iilcm_x_gt \krof #1% }% \def\CALX_iilcm_x_eq 0.#1.M#2\xint:M#3\xint: {% \expandafter\CALX_ntomd\the\numexpr#1\expandafter.% \romannumeral0\CALX_nlcm{N#2}{N#3}% }% \def\CALX_iilcm_x_lt -#1.#2.M#3\xint:M#4#5.#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2\expandafter.% \romannumeral0\CALX_nlcm{N#3}% {\expanded{N#4\the\numexpr#1+#5.% \xintReplicate{#1}{100000000!}}#6}% }% \def\CALX_iilcm_x_gt #1.#2.M#3#4.#5\xint:M#6\xint: {% \expandafter\CALX_ntomd\the\numexpr#2-#1\expandafter.% \romannumeral0\CALX_nlcm{\expanded{N#3\the\numexpr#1+#4.% \xintReplicate{#1}{100000000!}}#5}{N#6}% }% \def\CALX_mr #1% {\romannumeral0\expandafter\CALX_mr_a\romannumeral`&&@#1\xint:}% \def\CALX_mr_a #1% {% \if I#1\xint_dothis\CALX_mr_x\fi \if M#1\xint_dothis\CALX_mr_m\fi \xint_orthat\CALX_mr_r #1% }% \def\CALX_mr_x #1\xint:{ #1}% \def\CALX_mr_m #1{\CALX_mtoraw_a M}% \def\CALX_mr_r #1\xint:{\CALX_mr_s #1[.\xint:}% \def\CALX_mr_s #1[#2{\xint_gob_til_dot#2\CALX_mr_b.\CALX_mr_t #2#1[}% \def\CALX_mr_b.\CALX_mr_t.#1[\xint:{ #1}% \def\CALX_mr_t #1% {% \xint_UDsignfork #1\CALX_mr_neg -\CALX_mr_z \krof #1% }% \def\CALX_mr_z #1#2[#3][.\xint:{\expanded{ #2\xintReplicate{#1#3}0}}% \def\CALX_mr_neg -#1[#2][.\xint:{ #1[-#2]}% \def\CALX_iipow_a #1#2.% {\xint_gob_til_minus #1\CALX_iipow_n-\CALX_iipow_p #1#2.}% \def\CALX_iipow_n -\CALX_iipow_p{\CALX_iipow_t\CALX_iipow_r}% \def\CALX_iipow_p {\CALX_iipow_t\CALX_iipow_q}% \def\CALX_iipow_t #1#2.#3{\if I#3\CALX_iipow_j\fi #1#2.#3}% \def\CALX_iipow_j\fi #1#2.{\fi\CALX_iipow_i #2.}% \def\CALX_iipow_i #1.#2#3\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{ M+1.0.100000001!}\fi \if ?#3\xint_dothis{ #2#3}\fi \ifnum#1<\xint_c_ \xint_dothis{ M+0.0.}\fi \if +#3\xint_dothis{ #2+}\fi \ifodd#1 \xint_dothis{ #2-}\fi \xint_orthat{ #2+}% }% \def\CALX_iipow_r #1.M#2#3\xint:% {\csname CALX_ipr\CALX_iipow_cl M#2{#3}\endcsname #1.#2}% \def\CALX_ipro #1.#2{ M+1.0.100000001!}% \def\CALX_iprm #1.#2{\ifodd#1 \xint_afterfi{ M-}\else\xint_afterfi{ M+}\fi 1.0.100000001!}% \def\CALX_iprz #1.#2{\CALX_nsig{DivisionByZero}{0 ^ negative}{+}}% \def\CALX_iprb #1.#2{\CALX_nsig{Underflow}{x ^ -k, abs(x) > 1}{M+0.0.}}% \def\CALX_iipow_q #1.M#2#3.#4.#5\xint:% {\expandafter\CALX_ntomd\the\numexpr#1*#4\expandafter.% \romannumeral0\CALX_npow{#1}{N#2#3.#5}}% \def\CALX_iicmp_x M#1#2.#3.#4\xint:M#5#6.#7.#8\xint:% {% \expandafter\CALX_iicmp_y\the\numexpr#1#2+#1#3-(#5#6+#5#7)% .#2#6.M#1#2.#3.#4\xint:M#5#6.#7.#8\xint:% }% \def\CALX_iicmp_y #1#2.% {% \if0#1\xint_dothis\CALX_iicmp_e\fi \if-#1\xint_dothis\CALX_iicmp_l\fi \xint_orthat\CALX_iicmp_g }% \def\CALX_iicmp_l #1.#2\xint:#3\xint:{\xint_stop_atthirdofthree}% \def\CALX_iicmp_g #1.#2\xint:#3\xint:{\xint_stop_atsecondofthree}% \def\CALX_iicmp_e #1.% {\ifnum#1=11 \expandafter\CALX_iicmp_o\else\expandafter\CALX_iicmp_s\fi}% \def\CALX_iicmp_o M#1#2.#3.1#4!\xint:M#5#6.#7.1#8!\xint:% {% \ifnum#1#4>#1#8 \xint_dothis\xint_stop_atsecondofthree\fi \ifnum#1#4<#1#8 \xint_dothis\xint_stop_atthirdofthree\fi \xint_orthat\xint_stop_atfirstofthree }% \def\CALX_iicmp_s #1\xint:#2\xint:% {\expandafter\CALX_iicmp_t \romannumeral0\CALX_iisub_x #1\xint:#2\xint:\xint:}% \def\CALX_iicmp_t M#1#2#3\xint:% {% \if0#2\xint_dothis\xint_stop_atfirstofthree\fi \if-#1\xint_dothis\xint_stop_atthirdofthree\fi \xint_orthat\xint_stop_atsecondofthree }% \def\CALX_iieq_x #1\xint:#2\xint:% {\if0\xintstrcmp{#1}{#2}\expandafter\xint_stop_atfirstoftwo \else\expandafter\xint_stop_atsecondoftwo\fi}% \def\CALX_iipow_e #1#2\xint:% {\expandafter\CALX_iipow_ee\expandafter#1\expandafter#2% \romannumeral0\CALX_tom}% \def\CALX_iipow_ee #1#2#3#4#5\xint:% {\csname CALX_ipe#2\CALX_iipow_cl#3#4{#5}\endcsname#1#2#4}% \def\CALX_iipow_cl #1#2#3% {\if I#1\if ?#2n\else i\fi\else \ifnum\xintstrcmp{#3}{0.0.}=0 z\else \ifnum\xintstrcmp{#3}{1.0.100000001!}=0 \if -#2m\else o\fi \else b\fi\fi\fi}% \def\CALX_ipe_one #1#2#3{ M+1.0.100000001!}% \def\CALX_ipe_zero #1#2#3{ M+0.0.}% \def\CALX_ipe_inf #1#2#3{ #1+}% \def\CALX_ipe_es #1#2#3{ #1#2}% \def\CALX_ipe_bs #1#2#3{ #1#3}% \def\CALX_ipe_dz #1#2#3{\CALX_nsig{DivisionByZero}{0 ^ -inf}{+}}% \def\CALX_tmpa #1#2{\expandafter\let\csname CALX_ipe#1\endcsname#2}% \CALX_tmpa{+o}\CALX_ipe_one \CALX_tmpa{+m}\CALX_ipe_one \CALX_tmpa{+z}\CALX_ipe_zero\CALX_tmpa{+b}\CALX_ipe_inf \CALX_tmpa{+i}\CALX_ipe_inf \CALX_tmpa{+n}\CALX_ipe_bs \CALX_tmpa{-o}\CALX_ipe_one \CALX_tmpa{-m}\CALX_ipe_one \CALX_tmpa{-z}\CALX_ipe_dz \CALX_tmpa{-b}\CALX_ipe_zero \CALX_tmpa{-i}\CALX_ipe_zero\CALX_tmpa{-n}\CALX_ipe_bs \CALX_tmpa{?o}\CALX_ipe_one \CALX_tmpa{?m}\CALX_ipe_es \CALX_tmpa{?z}\CALX_ipe_es \CALX_tmpa{?b}\CALX_ipe_es \CALX_tmpa{?i}\CALX_ipe_es \CALX_tmpa{?n}\CALX_ipe_es \def\CALX_iiSum{\romannumeral0\CALX_iisum}% \def\CALX_iisum #1% {% \xint_gob_til_^ #1\CALX_iisum_empty ^% \expandafter\CALX_iisum_loop\romannumeral`&&@#1\xint: }% \def\CALX_iisum_empty ^#1\xint:{ M+0.0.}% \def\CALX_iisum_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_iisum_end ^% \expandafter\CALX_iisum_loop \romannumeral0\CALX_iiadd{#1}{#2}\xint: }% \def\CALX_iisum_end ^#1\CALX_iiadd #2#3\xint:{ #2}% \def\CALX_iiPrd{\romannumeral0\CALX_iiprd}% \def\CALX_iiprd #1% {% \xint_gob_til_^ #1\CALX_iiprd_empty ^% \expandafter\CALX_iiprd_loop\romannumeral`&&@#1\xint: }% \def\CALX_iiprd_empty ^#1\xint:{ M+1.0.100000001!}% \def\CALX_iiprd_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_iiprd_end ^% \expandafter\CALX_iiprd_loop \romannumeral0\CALX_iimul{#1}{#2}\xint: }% \def\CALX_iiprd_end ^#1\CALX_iimul #2#3\xint:{ #2}% \def\CALX_iiGCDof {\romannumeral0\CALX_iigcdof_a}% \def\CALX_iigcdof_a #1{\expandafter\CALX_iigcdof_b\romannumeral`&&@#1\xint:}% \def\CALX_iigcdof_b #1\xint:#2% {\expandafter\CALX_iigcdof_c\romannumeral`&&@#2\xint:{#1}\xint:}% \def\CALX_iigcdof_c #1{\xint_gob_til_^ #1\CALX_iigcdof_e ^\CALX_iigcdof_d #1}% \def\CALX_iigcdof_d #1\xint:% {\expandafter\CALX_iigcdof_b\romannumeral0\CALX_iigcd {#1}}% \def\CALX_iigcdof_e #1\xint:#2\xint:{ #2}% \expandafter\def\csname CALX_iiLCMof\endcsname{\romannumeral0\CALX_iilcmof_a}% \def\CALX_iilcmof_a #1{\expandafter\CALX_iilcmof_b\romannumeral`&&@#1\xint:}% \def\CALX_iilcmof_b #1\xint:#2% {\expandafter\CALX_iilcmof_c\romannumeral`&&@#2\xint:{#1}\xint:}% \def\CALX_iilcmof_c #1{\xint_gob_til_^ #1\CALX_iilcmof_e ^\CALX_iilcmof_d #1}% \def\CALX_iilcmof_d #1\xint:% {\expandafter\CALX_iilcmof_b\romannumeral0\CALX_iilcm {#1}}% \def\CALX_iilcmof_e #1\xint:#2\xint:{ #2}% \def\CALX_ngcd {\CALX_ngl\CALX_ngcd_l}% \def\CALX_nlcm {\CALX_ngl\CALX_nlcm_a}% \def\CALX_ngl #1#2% {\expandafter\CALX_ngl_a\expandafter#1\romannumeral`&&@#2\xint:}% \def\CALX_ngl_a #1#2\xint:#3% {\expandafter\CALX_ngl_b\expandafter#1\romannumeral`&&@#3\xint:#2\xint:}% \def\CALX_ngl_b #1#2#3\xint:#4% {% \if I#2\xint_dothis\CALX_ngl_bi\fi \if I#4\xint_dothis\CALX_ngl_bi\fi \xint_orthat{\CALX_ngl_bn #1{#2#3}#4}% }% \def\CALX_ngl_bi #1\xint:{\CALX_ngl_i}% \def\CALX_ngl_bn #1#2#3#4\xint:{#1{#3#4}{#2}}% \def\CALX_ngl_i{\CALX_nsig{InvalidOperation}{gcd or lcm of I}{}}% \def\CALX_ngcd_l #1#2{\CALX_ngcd_t #2\xint:{#1}}% \def\CALX_ngcd_t N#1#2.#3\xint:#4% {% \ifnum#2=\xint_c_ \xint_dothis{\CALX_ngcd_e #4}\fi \xint_orthat{\expandafter\CALX_ngcd_t\romannumeral0% \CALX_nrem{#4}{N#1#2.#3}\xint:{N#1#2.#3}}% }% \def\CALX_ngcd_e N#1{ N+}% \def\CALX_nlcm_a #1#2% {\expandafter\CALX_nlcm_b\romannumeral0\CALX_ngcd_l{#1}{#2}\xint:{#1}{#2}}% \def\CALX_nlcm_b N#1#2.#3\xint:#4#5% {% \ifnum#2=\xint_c_ \xint_dothis{ N+0.}\fi \xint_orthat{\expandafter\CALX_ngcd_e\romannumeral0% \CALX_nmul{\CALX_nquo{#4}{N#1#2.#3}}{#5}}% }% \def\CALX_iifac{\expandafter\CALX_iiun\expandafter\CALX_iifac_x \expandafter\CALX_mrinv\romannumeral0\CALX_tom}% \def\CALX_iifac_x M#1#2.#3.#4\xint:% {% \ifnum#2=\xint_c_ \xint_dothis{ M+1.0.100000001!}\fi \if-#1\xint_dothis\CALX_iifac_n\fi \ifnum#2#3>10 \xint_dothis\CALX_iifac_n\fi \xint_orthat{\CALX_iifac_y #4}% }% \def\CALX_iifac_y 1#1!% {% \ifnum#1>\xint_c_e_iv \xint_dothis\CALX_iifac_n\fi \xint_orthat{\expandafter\CALX_ntom\romannumeral0\CALX_nfac{#1}}% }% \def\CALX_iifac_n {\CALX_nsig{InvalidOperation}{fac of a negative or > 10^4 integer}{}}% \def\CALX_iipar{\expandafter\CALX_iiun\expandafter\CALX_iipar_x \expandafter\CALX_iipar_i\romannumeral0\CALX_tom}% \def\CALX_iipar_i #1#2\xint:#3#4% {\CALX_nsig{InvalidOperation}{integer function of I}{}}% \def\CALX_iipar_x M#1#2.#3.#4\xint:% {% \ifnum\ifnum#3=\xint_c_ #2\else\xint_c_\fi=\xint_c_ \xint_dothis\xint_stop_atsecondoftwo\fi \xint_orthat{\CALX_iipar_y #4\xint:}% }% \def\CALX_iipar_y 1#1!#2\xint:% {\ifodd#1 \expandafter\xint_stop_atfirstoftwo \else\expandafter\xint_stop_atsecondoftwo\fi}% \def\CALX_iiisone{\expandafter\CALX_iiisone_a\romannumeral0\CALX_tom}% \def\CALX_iiisone_a #1#2\xint:#3#4#5% {% \if I#1\xint_dothis{#5}\fi \ifnum\xintstrcmp{#2}{+1.0.100000001!}=\xint_c_ \xint_dothis{#3}\fi \xint_orthat{#4}% }% \def\CALX_iione_i #1\xint:{\xint_stop_atsecondoftwo}% \def\CALX_iilogten{\expandafter\CALX_iiun\expandafter\CALX_iilt_x \expandafter\CALX_mrinv\romannumeral0\CALX_tom}% \def\CALX_iilt_x M#1#2.#3.#4\xint:% {% \ifnum#2=\xint_c_ \xint_dothis{ -2147450880}\fi \xint_orthat{\expandafter\space\the\numexpr\xint_c_viii*(#2+#3)-\xint_c_ix +\CALX_nskip\CALX_iilt_t #2-\xint_c_i.#4\xint:\relax}% }% \def\CALX_iilt_t 1#1!\xint:{\CALX_ndig{#1}}% \def\CALX_iibinom #1#2% {\expandafter\CALX_iibinom_p\the\numexpr #1\expandafter.\the\numexpr #2.}% \def\CALX_iibinom_p #1.#2.% {\expandafter\CALX_iibinom_f\the\numexpr#1-#2.#2.#1.}% \def\CALX_iibinom_f #1#2.#3#4.#5#6.% {% \if-#5\xint_dothis\CALX_iibinom_inv\fi \if-#1\xint_dothis{ M+0.0.}\fi \if-#3\xint_dothis{ M+0.0.}\fi \if0#1\xint_dothis{ M+1.0.100000001!}\fi \if0#3\xint_dothis{ M+1.0.100000001!}\fi \ifnum #5#6>\xint_c_e_viii_mone\xint_dothis\CALX_iibinom_inv\fi \ifnum #1#2>#3#4 \xint_dothis{\expandafter\CALX_ntom\romannumeral0\CALX_binom_a #1#2.#3#4.}\fi \xint_orthat{\expandafter\CALX_ntom\romannumeral0\CALX_binom_a #3#4.#1#2.}% }% \def\CALX_iibinom_inv {\CALX_nsig{InvalidOperation}{binomial: negative or >= 10^8 argument}{}}% \def\CALX_iipfac #1#2% {\expandafter\CALX_iipfac_f\the\numexpr#1\expandafter.\the\numexpr#2.}% \def\CALX_iipfac_f #1#2.#3#4.% {% \unless\ifnum #1#2<#3#4 \xint_dothis\CALX_iipfac_one\fi \if-#3\xint_dothis\CALX_iipfac_neg\fi \if-#1\xint_dothis\CALX_iipfac_zero\fi \ifnum #3#4>\xint_c_e_viii_mone\xint_dothis\CALX_iipfac_inv\fi \xint_orthat\CALX_iipfac_a #1#2.#3#4.% }% \def\CALX_iipfac_inv #1.#2.% {\CALX_nsig{InvalidOperation}{pfactorial: argument >= 10^8}{}}% \def\CALX_iipfac_one #1.#2.{ M+1.0.100000001!}% \def\CALX_iipfac_zero #1.#2.{ M+0.0.}% \def\CALX_iipfac_neg -#1.-#2.% {% \ifnum #1>\xint_c_e_viii\xint_dothis\CALX_iipfac_inv\fi \xint_orthat {\ifodd\numexpr#2-#1\relax \xint_afterfi{\expandafter\CALX_iipfac_m\romannumeral0}\fi \expandafter\CALX_iipfac_a}% \the\numexpr #2-\xint_c_i\expandafter.\the\numexpr#1-\xint_c_i.% }% \def\CALX_iipfac_m M+{ M-}% \def\CALX_iipfac_a #1.#2.% {\expandafter\CALX_ntom\romannumeral0\CALX_npfac{#1}{#2}}% \def\CALX_iiq #1#2#3#4#5% {% \expandafter\CALX_iiq_a\romannumeral0\CALX_ndivision {\CALX_nshl{#5}{\CALX_nfromraw{#3}}}% {\CALX_nshl{-#5}{\CALX_nfromraw{#4}}}#1#2% }% \def\CALX_iiq_a #1#2{\CALX_iiq_b #2\xint:{#1}}% \def\CALX_iiq_b N#1#2.#3\xint:#4#5#6% {\ifnum#2=\xint_c_ \expandafter#5\else\expandafter#6\fi{#4}}% \def\CALX_iilit_n #1#2{\CALX_iiq\CALX_iilit_e\CALX_iilit_f{#1}1{#2}{#1[#2]}}% \def\CALX_iilit_e #1#2{\CALX_ntom #1}% \def\CALX_iilit_f #1#2{ #2}% \def\CALX_tom_x #1.#2/\xint:{\CALX_tom_z #2/1/\xint:{#1}{#2[#1]}}% \def\CALX_tom_z #1/#2/#3\xint:{\CALX_iiq\CALX_tom_e\CALX_tom_f{#1}{#2}}% \def\CALX_tom_e #1#2{\CALX_ntom #1\xint:}% \def\CALX_tom_f #1#2{\CALX_iinotint{#2}\CALX_tom_t #1\xint:}% \def\CALX_tom_t N#1% {\if-#1\expandafter\CALX_tom_u\else\expandafter\CALX_ntom\fi N#1}% \def\CALX_tom_u #1\xint:% {\expandafter\CALX_ntom\romannumeral0\CALX_nadd{#1}{N+1.100000001!}\xint:}% % \end{macrocode} %\begin{lverb} % \CALX_seq_m k. (f-expandable, k explicit digits, |k| < 2^31): the M value % of k; one block if |k| < 10^8, else \CALX_mfromraw. Items of a..b in % \xinteval and \xintiieval. %\end{lverb} % \begin{macrocode} \def\CALX_seq_m #1.% {% \ifnum#1=\xint_c_ \xint_dothis{M+0.0.}\fi \ifnum\ifnum#1<\xint_c_ -\fi#1<\xint_c_e_viii \xint_dothis{M\ifnum#1<\xint_c_ -\else+\fi1.0.\the\numexpr \xint_c_e_viii\ifnum#1<\xint_c_ -\else+\fi#1!}\fi \xint_orthat{\romannumeral0\CALX_mfromraw{#1}}% }% % \end{macrocode} %\begin{lverb} % Syntax (use with \romannumeral0; k explicit digits, k >= 0; b a block % 1dddddddd with d > 0; R a raw integer, f-expanded, no leading zeros): %( % \CALX_npowmul k.{b}{R} -> %) % \CALX_npow, \CALX_nmul and \CALX_nfromraw, \CALX_ntoraw of calxcore. % Fractional hexadecimal, octal and binary literals (d = 5^j). %\end{lverb} % \begin{macrocode} \def\CALX_npowmul #1.#2#3% {% \expandafter\CALX_ntoraw_a\romannumeral0\expandafter\CALX_nmul_x \romannumeral0\CALX_npow{#1}{N+1.#2!}\xint:{\CALX_nfromraw{#3}}\xint: }% % \end{macrocode} % Back to normal letter catcodes for M, N, and I. % \begin{macrocode} \catcode`M=11 \catcode`N=11 \catcode`I=11 \def\CALX_iilit #1#2% {% \ifnum#2<\xint_c_ \xint_dothis{\CALX_iilit_n{#1}{#2}}\fi \xint_orthat{\CALX_mfromraw{\expanded{#1\xintReplicate{#2}0}}}% }% \def\CALX_iinotint #1% {\XINT_expandableerror{\xintiieval: #1 is not an integer, truncated.}}% \def\calxiiAdd {\romannumeral0\CALX_iiadd}% \def\calxiiSub {\romannumeral0\CALX_iisub}% \def\calxiiMul {\romannumeral0\CALX_iimul}% \def\calxiiSqr {\romannumeral0\CALX_iisqr}% \def\calxiiOpp {\romannumeral0\CALX_iiopp}% \def\calxiiAbs {\romannumeral0\CALX_iiabs}% \def\calxiiSqrt {\romannumeral0\CALX_iisqrt}% \def\calxiiDivFloor{\romannumeral0\CALX_iidivfloor}% \def\calxiiMod {\romannumeral0\CALX_iimod}% \def\calxiiDivRound{\romannumeral0\CALX_iidivround}% \def\calxiiQuo {\romannumeral0\CALX_iiquo}% \def\calxiiRem {\romannumeral0\CALX_iirem}% \def\calxiiDivMod {\romannumeral0\CALX_iidivmod}% \def\calxiiPow #1#2% {\romannumeral0\expandafter\CALX_iipow_k\romannumeral`&&@#2\xint:{#1}}% \def\CALX_iipow_k #1% {\if I#1\expandafter\CALX_iipow_e\else\expandafter\CALX_iipow_f\fi #1}% \def\CALX_iipow_f #1\xint:% {\expandafter\CALX_iipow_a\the\numexpr\romannumeral0\CALX_mr_a#1\xint:% \expandafter.\romannumeral0\CALX_tom}% \def\CALX_tmpa #1#2#3#4% {\def#1##1##2{\romannumeral0\CALX_iitwo#2#3{##1}{##2}#4}}% \CALX_tmpa\calxiiLt \CALX_iicmp_x\CALX_iicmp_sp{001}% \CALX_tmpa\calxiiGt \CALX_iicmp_x\CALX_iicmp_sp{010}% \CALX_tmpa\calxiiLtorEq\CALX_iicmp_x\CALX_iicmp_sp{101}% \CALX_tmpa\calxiiGtorEq\CALX_iicmp_x\CALX_iicmp_sp{110}% \CALX_tmpa\calxiiEq \CALX_iieq_x \CALX_iieq_sp {10}% \CALX_tmpa\calxiiNotEq \CALX_iieq_x \CALX_iieq_sp {01}% \def\CALX_iicmp_sp #1#2#3\xint:#4#5#6\xint:#7#8#9% {% \if ?#2\xint_dothis\CALX_fcnan\fi \if ?#5\xint_dothis\CALX_fcnan\fi \ifnum\csname CALX_icl#1#2\endcsname>\csname CALX_icl#4#5\endcsname \xint_dothis{ #8}\fi \ifnum\csname CALX_icl#1#2\endcsname<\csname CALX_icl#4#5\endcsname \xint_dothis{ #9}\fi \xint_orthat{ #7}% }% \expandafter\def\csname CALX_iclI+\endcsname{1 }% \expandafter\def\csname CALX_iclI-\endcsname{-1 }% \expandafter\def\csname CALX_iclM+\endcsname{0 }% \expandafter\def\csname CALX_iclM-\endcsname{0 }% \def\CALX_fcnan {\CALX_signalcondition{InvalidOperation}{comparison with I?}{}{ 0}}% \def\CALX_iieq_sp #1#2#3\xint:#4#5#6\xint:#7#8% {% \if ?#2\xint_dothis{ #8}\fi \if ?#5\xint_dothis{ #8}\fi \xint_orthat{\CALX_iieq_x #1#2#3\xint:#4#5#6\xint:#7#8}% }% \def\calxiiFac {\romannumeral0\CALX_iifac}% \def\calxiiOdd #1{\romannumeral0\CALX_iipar{#1}10}% \def\calxiiEven #1{\romannumeral0\CALX_iipar{#1}01}% \def\calxiiIsOne #1{\romannumeral0\CALX_iiisone{#1}{ 1}{ 0}% {\CALX_nsig{InvalidOperation}{integer function of I}{}}}% \def\calxiiifOne #1{\romannumeral0\CALX_iiisone{#1}\xint_stop_atfirstoftwo \xint_stop_atsecondoftwo{\expandafter\CALX_iione_i\romannumeral0% \CALX_nsig{InvalidOperation}{ifone of I}{}\xint:}}% \def\calxiiifInt #1% {\romannumeral0\expandafter\CALX_iiifint\romannumeral`&&@#1\xint:}% \def\CALX_iiifint #1#2\xint:% {\if I#1\xint_dothis{\expandafter\CALX_iione_i\romannumeral0% \CALX_nsig{InvalidOperation}{ifint of I}{}\xint:}\fi \xint_orthat\xint_stop_atfirstoftwo}% \def\calxiiIsInt #1% {\romannumeral0\expandafter\CALX_iiisint\romannumeral`&&@#1\xint:}% \def\CALX_iiisint #1#2\xint:% {\if I#1\xint_dothis{\CALX_nsig{InvalidOperation}{integer function of I}{}}\fi \xint_orthat{ 1}}% \def\calxiiSqrtR {\romannumeral0\CALX_iisqrtr}% \def\calxiiLogTen{\romannumeral0\CALX_iilogten}% \def\calxiiBinomial {\romannumeral0\CALX_mrd\CALX_iibinom}% \def\calxiiPFactorial {\romannumeral0\CALX_mrd\CALX_iipfac}% \def\CALX_mrinv #1#2\xint:% {\CALX_nsig{InvalidOperation}{integer function of I}{}}% \def\CALX_mrd #1#2% {\expandafter\CALX_mrd_a\expandafter#1\romannumeral`&&@#2\xint:}% \def\CALX_mrd_a #1#2\xint:#3% {\expandafter\CALX_mrd_b\expandafter#1\romannumeral`&&@#3\xint:#2\xint:}% \def\CALX_mrd_b #1#2#3\xint:#4#5\xint:% {% \if I#2\xint_dothis\CALX_mrd_i\fi \if I#4\xint_dothis\CALX_mrd_i\fi \xint_orthat{\expandafter\space\romannumeral`&&@#1% {\romannumeral0\CALX_mr_a#4#5\xint:}% {\romannumeral0\CALX_mr_a#2#3\xint:}}% }% \def\CALX_mrd_i{\CALX_nsig{InvalidOperation}{integer function of I}{}}% \def\CALX_mrl #1{\xint_gob_til_^#1\CALX_mrl_e ^{\CALX_mr{#1}}\CALX_mrl}% \def\CALX_mrl_e ^#1\CALX_mrl{}% \def\CALX_iiMaxof{\romannumeral0\CALX_iimaxof}% \def\CALX_iimaxof#1% {% \xint_gob_til_^ #1\CALX_iimaxof_empty ^% \expandafter\CALX_iimaxof_loop\romannumeral`&&@#1\xint: }% \def\CALX_iimaxof_empty ^#1\xint:{ 0}% \def\CALX_iimaxof_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_iimaxof_e ^% \expandafter\CALX_iimaxof_loop\romannumeral0\CALX_iimax{#1}{#2}\xint: }% \def\CALX_iimaxof_e ^#1\CALX_iimax #2#3\xint:{ #2}% \def\CALX_iiMinof{\romannumeral0\CALX_iiminof}% \def\CALX_iiminof#1% {% \xint_gob_til_^ #1\CALX_iiminof_empty ^% \expandafter\CALX_iiminof_loop\romannumeral`&&@#1\xint: }% \def\CALX_iiminof_empty ^#1\xint:{ 0}% \def\CALX_iiminof_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_iiminof_e ^% \expandafter\CALX_iiminof_loop\romannumeral0\CALX_iimin{#1}{#2}\xint: }% \def\CALX_iiminof_e ^#1\CALX_iimin #2#3\xint:{ #2}% \def\CALX_iimax #1#2{\expandafter\CALX_iimax_a\expandafter1\romannumeral`&&@#2\xint:{#1}}% \def\CALX_iimin #1#2{\expandafter\CALX_iimax_a\expandafter2\romannumeral`&&@#2\xint:{#1}}% \def\CALX_iimax_a #1#2\xint:#3% {\if1\romannumeral0\csname CALX_iimx_c#1\endcsname{#2}{#3}% \xint_afterfi{ #2}\else\xint_afterfi{ #3}\fi}% \expandafter\def\csname CALX_iimx_c1\endcsname #1#2% {\CALX_iitwo\CALX_iicmp_x\CALX_iicmp_sp{#1}{#2}010}% \expandafter\def\csname CALX_iimx_c2\endcsname #1#2% {\CALX_iitwo\CALX_iicmp_x\CALX_iicmp_sp{#1}{#2}001}% % \end{macrocode} % \subsection{Binomial coefficients} %\begin{lverb} % Syntax (use with \romannumeral0; 0 < b <= a < 10^8 as explicit digits, % a >= b): %( % \CALX_binom_a a.b. -> N+. binomial(a + b, b) %) % The engine of \xintiiBinomial: the accumulator is a block list, most % significant first; each step multiplies it (\CALX_smallmul, on the list % reversed by \CALX_rev_nounsep) by a product of consecutive integers and % divides it (\CALX_smalldivx_a of calxcore) by the matching product of the % denominator, four, three, two or one factors per step according to the % size of the factors (< 10^8); very small arguments: one \numexpr % a*b/c per step. Native output: the final list is reversed % (\CALX_rev_nounsep) and given to \CALX_nnorm; very small arguments: one % block. %\end{lverb} % \begin{macrocode} \def\CALX_binom_a #1.#2.% {% \expandafter\CALX_binom_b\the\numexpr \xint_c_i+#1.1.#2.100000001!1!;!0!% }% % \end{macrocode} %\begin{lverb} % y=x-k+1.j=1.k. On va évaluer par y/1*(y+1)/2*(y+2)/3 etc... On essaie % de regrouper de manière à utiliser au mieux \numexpr. On peut aller jusqu'à % x=10000 car 9999*10000<10^8. 463*464*465=99896880, 98*99*100*101=97990200. % On va vérifier à chaque étape si on dépasse un seuil. Le style de % l'implémentation diffère de celui que j'avais utilisé pour \xintiiFac. On % pourrait tout-à-fait avoir une verybigloop, mais bon. Je rajoute aussi un % verysmall. Le traitement est un peu différent pour elle afin d'aller jusqu'à % x=29 (et pas seulement 26 si je suivais le modèle des autres, mais je veux % pouvoir faire binomial(29,1), binomial(29,2), ... en vsmall). %\end{lverb} % \begin{macrocode} \def\CALX_binom_b #1.% {% \ifnum #1>9999 \xint_dothis\CALX_binom_vbigloop \fi \ifnum #1>463 \xint_dothis\CALX_binom_bigloop \fi \ifnum #1>98 \xint_dothis\CALX_binom_medloop \fi \ifnum #1>29 \xint_dothis\CALX_binom_smallloop \fi \xint_orthat\CALX_binom_vsmallloop #1.% }% % \end{macrocode} %\begin{lverb} % y.j.k. Au départ on avait x-k+1.1.k. Ensuite on a des blocs 1<8d>! % donnant le résultat intermédiaire, dans l'ordre, et à la fin on a 1!1;!0!. % Dans smallloop on peut prendre 4 par 4. %\end{lverb} % \begin{macrocode} \def\CALX_binom_smallloop #1.#2.#3.% {% \ifcase\numexpr #3-#2\relax \expandafter\CALX_binom_end_ \or \expandafter\CALX_binom_end_i \or \expandafter\CALX_binom_end_ii \or \expandafter\CALX_binom_end_iii \else\expandafter\CALX_binom_smallloop_a \fi #1.#2.#3.% }% % \end{macrocode} %\begin{lverb} % Ça m'ennuie un peu de reprendre les #1, #2, #3 ici. On a besoin de % \numexpr pour \CALX_binom_div, mais de \romannumeral0 pour le unsep après % \CALX_binom_mul. %\end{lverb} % \begin{macrocode} \def\CALX_binom_smallloop_a #1.#2.#3.% {% \expandafter\CALX_binom_smallloop_b \the\numexpr #1+\xint_c_iv\expandafter.% \the\numexpr #2+\xint_c_iv\expandafter.% \the\numexpr #3\expandafter.% \the\numexpr\expandafter\CALX_binom_div \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter !\romannumeral0\expandafter\CALX_binom_mul \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% }% \def\CALX_binom_smallloop_b #1.% {% \ifnum #1>98 \expandafter\CALX_binom_medloop \else \expandafter\CALX_binom_smallloop \fi #1.% }% % \end{macrocode} %\begin{lverb} % Ici on prend trois par trois. %\end{lverb} % \begin{macrocode} \def\CALX_binom_medloop #1.#2.#3.% {% \ifcase\numexpr #3-#2\relax \expandafter\CALX_binom_end_ \or \expandafter\CALX_binom_end_i \or \expandafter\CALX_binom_end_ii \else\expandafter\CALX_binom_medloop_a \fi #1.#2.#3.% }% \def\CALX_binom_medloop_a #1.#2.#3.% {% \expandafter\CALX_binom_medloop_b \the\numexpr #1+\xint_c_iii\expandafter.% \the\numexpr #2+\xint_c_iii\expandafter.% \the\numexpr #3\expandafter.% \the\numexpr\expandafter\CALX_binom_div \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)\expandafter !\romannumeral0\expandafter\CALX_binom_mul \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_binom_medloop_b #1.% {% \ifnum #1>463 \expandafter\CALX_binom_bigloop \else \expandafter\CALX_binom_medloop \fi #1.% }% % \end{macrocode} %\begin{lverb} % Ici on prend deux par deux. %\end{lverb} % \begin{macrocode} \def\CALX_binom_bigloop #1.#2.#3.% {% \ifcase\numexpr #3-#2\relax \expandafter\CALX_binom_end_ \or \expandafter\CALX_binom_end_i \else\expandafter\CALX_binom_bigloop_a \fi #1.#2.#3.% }% \def\CALX_binom_bigloop_a #1.#2.#3.% {% \expandafter\CALX_binom_bigloop_b \the\numexpr #1+\xint_c_ii\expandafter.% \the\numexpr #2+\xint_c_ii\expandafter.% \the\numexpr #3\expandafter.% \the\numexpr\expandafter\CALX_binom_div \the\numexpr #2*(#2+\xint_c_i)\expandafter !\romannumeral0\expandafter\CALX_binom_mul \the\numexpr #1*(#1+\xint_c_i)!% }% \def\CALX_binom_bigloop_b #1.% {% \ifnum #1>9999 \expandafter\CALX_binom_vbigloop \else \expandafter\CALX_binom_bigloop \fi #1.% }% % \end{macrocode} %\begin{lverb} % Et finalement un par un. %\end{lverb} % \begin{macrocode} \def\CALX_binom_vbigloop #1.#2.#3.% {% \ifnum #3=#2 \expandafter\CALX_binom_end_ \else\expandafter\CALX_binom_vbigloop_a \fi #1.#2.#3.% }% \def\CALX_binom_vbigloop_a #1.#2.#3.% {% \expandafter\CALX_binom_vbigloop \the\numexpr #1+\xint_c_i\expandafter.% \the\numexpr #2+\xint_c_i\expandafter.% \the\numexpr #3\expandafter.% \the\numexpr\expandafter\CALX_binom_div\the\numexpr #2\expandafter !\romannumeral0\CALX_binom_mul #1!% }% % \end{macrocode} %\begin{lverb} % y.j.k. La partie very small. y est au plus 26 (non 29 mais retesté % dans \CALX_binom_vsmallloop_a), et tous les binomial(29,n) sont <10^8. On % peut donc faire y(y+1)(y+2)(y+3) et aussi il y a le fait que etex fait a*b/c % en double precision. Pour ne pas bifurquer à la fin sur smallloop, si n=27, % 27, ou 29 on procède un peu différemment des autres boucles. Si je testais % aussi #1 après #3-#2 pour les autres il faudrait des terminaisons % différentes. %\end{lverb} % \begin{macrocode} \def\CALX_binom_vsmallloop #1.#2.#3.% {% \ifcase\numexpr #3-#2\relax \expandafter\CALX_binom_vsmallend_ \or \expandafter\CALX_binom_vsmallend_i \or \expandafter\CALX_binom_vsmallend_ii \or \expandafter\CALX_binom_vsmallend_iii \else\expandafter\CALX_binom_vsmallloop_a \fi #1.#2.#3.% }% \def\CALX_binom_vsmallloop_a #1.% {% \ifnum #1>26 \expandafter\CALX_binom_smallloop_a \else \expandafter\CALX_binom_vsmallloop_b \fi #1.% }% \def\CALX_binom_vsmallloop_b #1.#2.#3.% {% \expandafter\CALX_binom_vsmallloop \the\numexpr #1+\xint_c_iv\expandafter.% \the\numexpr #2+\xint_c_iv\expandafter.% \the\numexpr #3\expandafter.% \the\numexpr \expandafter\CALX_binom_vsmallmuldiv \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter !\the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% }% \def\CALX_binom_mul #1!#21!;!0!% {% \expandafter\CALX_rev_nounsep\expandafter{\expandafter}% \the\numexpr\expandafter\CALX_smallmul \the\numexpr\xint_c_e_viii+#1\expandafter !\romannumeral0\CALX_rev_nounsep {}1;!#2% \R!\R!\R!\R!\R!\R!\R!\R!\W \R!\R!\R!\R!\R!\R!\R!\R!\W 1;!% }% \def\CALX_binom_div #1!1;!% {% \expandafter\CALX_smalldivx_a \the\numexpr #1/\xint_c_ii\expandafter\xint: \the\numexpr \xint_c_e_viii+#1!% }% % \end{macrocode} %\begin{lverb} % Vaguement envisagé d'éviter le 10^8+ mais bon. %\end{lverb} % \begin{macrocode} \def\CALX_binom_vsmallmuldiv #1!#2!1#3!{\xint_c_e_viii+#2*#3/#1!}% % \end{macrocode} %\begin{lverb} % On a des terminaisons communes aux trois situations small, med, big, % et on est sûr de pouvoir faire les multiplications dans \numexpr, car on % vient ici *après* avoir comparé à 9999 ou 463 ou 98. %\end{lverb} % \begin{macrocode} \def\CALX_binom_end_iii #1.#2.#3.% {% \expandafter\CALX_binom_finish \the\numexpr\expandafter\CALX_binom_div \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter !\romannumeral0\expandafter\CALX_binom_mul \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% }% \def\CALX_binom_end_ii #1.#2.#3.% {% \expandafter\CALX_binom_finish \the\numexpr\expandafter\CALX_binom_div \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)\expandafter !\romannumeral0\expandafter\CALX_binom_mul \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_binom_end_i #1.#2.#3.% {% \expandafter\CALX_binom_finish \the\numexpr\expandafter\CALX_binom_div \the\numexpr #2*(#2+\xint_c_i)\expandafter !\romannumeral0\expandafter\CALX_binom_mul \the\numexpr #1*(#1+\xint_c_i)!% }% \def\CALX_binom_end_ #1.#2.#3.% {% \expandafter\CALX_binom_finish \the\numexpr\expandafter\CALX_binom_div\the\numexpr #2\expandafter !\romannumeral0\CALX_binom_mul #1!% }% \def\CALX_binom_finish #11!;!0!% {% \expandafter\CALX_nnorm\expandafter+% \romannumeral0\CALX_rev_nounsep {}#1\R!\R!\R!\R!\R!\R!\R!\R!\W 1;!% }% % \end{macrocode} %\begin{lverb} % Duplication de code seulement pour la boucle avec très % petits coeffs, mais en plus on fait au maximum des possibilités. (on % pourrait tester plus le résultat déjà obtenu). %\end{lverb} % \begin{macrocode} \def\CALX_binom_vsmallend_iii #1.% {% \ifnum #1>26 \expandafter\CALX_binom_end_iii \else \expandafter\CALX_binom_vsmallend_iiib \fi #1.% }% \def\CALX_binom_vsmallend_iiib #1.#2.#3.% {% \expandafter\CALX_binom_vsmallfinish \the\numexpr \expandafter\CALX_binom_vsmallmuldiv \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter !\the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% }% \def\CALX_binom_vsmallend_ii #1.% {% \ifnum #1>27 \expandafter\CALX_binom_end_ii \else \expandafter\CALX_binom_vsmallend_iib \fi #1.% }% \def\CALX_binom_vsmallend_iib #1.#2.#3.% {% \expandafter\CALX_binom_vsmallfinish \the\numexpr \expandafter\CALX_binom_vsmallmuldiv \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)\expandafter !\the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_binom_vsmallend_i #1.% {% \ifnum #1>28 \expandafter\CALX_binom_end_i \else \expandafter\CALX_binom_vsmallend_ib \fi #1.% }% \def\CALX_binom_vsmallend_ib #1.#2.#3.% {% \expandafter\CALX_binom_vsmallfinish \the\numexpr \expandafter\CALX_binom_vsmallmuldiv \the\numexpr #2*(#2+\xint_c_i)\expandafter !\the\numexpr #1*(#1+\xint_c_i)!% }% \def\CALX_binom_vsmallend_ #1.% {% \ifnum #1>29 \expandafter\CALX_binom_end_ \else \expandafter\CALX_binom_vsmallend_b \fi #1.% }% \def\CALX_binom_vsmallend_b #1.#2.#3.% {% \expandafter\CALX_binom_vsmallfinish \the\numexpr\CALX_binom_vsmallmuldiv #2!#1!% }% \catcode`N=12 \def\CALX_binom_vsmallfinish#1{% \def\CALX_binom_vsmallfinish1##1!1!;!0!{#1N+1.1##1!}% }\CALX_binom_vsmallfinish{ }% \catcode`N=11 % \end{macrocode} % \subsection{\csh{xintiiifLt}} % Moved here at |2.0a1| due to a ridiculous situation with the support % macro for |randrange()|, originating in a serious misalignment of my % assistant. This is of course a seriously sub-optimal situation % perhaps provisory but will not be modified before |2.0a1| release. %\begin{lverb} % 1.09a \xintifLt {n}{m}{YES if n=m}. Restyled in 1.09i. % 1.1a adds ii variant %\end{lverb} % \begin{macrocode} \def\xintiiifLt {\romannumeral0\xintiiiflt }% \def\xintiiiflt #1#2% {% \ifnum\xintiiCmp{#1}{#2}<\xint_c_ \expandafter\xint_stop_atfirstoftwo \else \expandafter\xint_stop_atsecondoftwo \fi }% % \end{macrocode} % \subsection{(WIP) \csh{xintRandomDigits}} %\begin{lverb} % 1.3b. See user manual. Whether this will be part of xintkernel, % xintcore, or xint is yet to be decided. %\end{lverb} % \begin{macrocode} \def\xintRandomDigits{\romannumeral0\xintrandomdigits}% \def\xintrandomdigits#1% {% \csname xint_gob_andstop_\expandafter\XINT_randomdigits\the\numexpr#1\xint: }% \def\XINT_randomdigits#1\xint: {% \expandafter\XINT_randomdigits_a \the\numexpr(#1+\xint_c_iii)/\xint_c_viii\xint:#1\xint: }% \def\XINT_randomdigits_a#1\xint:#2\xint: {% \romannumeral\numexpr\xint_c_viii*#1-#2\csname XINT_% \romannumeral\XINT_replicate #1\endcsname \csname XINT_rdg\endcsname }% \def\XINT_rdg {% \expandafter\XINT_rdg_aux\the\numexpr% \xint_c_nine_e_viii% -\xinttexuniformdeviate\xint_c_ii^vii% -\xint_c_ii^vii*\xinttexuniformdeviate\xint_c_ii^vii% -\xint_c_ii^xiv*\xinttexuniformdeviate\xint_c_ii^vii% -\xint_c_ii^xxi*\xinttexuniformdeviate\xint_c_ii^vii% +\xinttexuniformdeviate\xint_c_e_viii% \relax% }% \def\XINT_rdg_aux#1{XINT_rdg\endcsname}% \let\XINT_XINT_rdg\endcsname % \end{macrocode} % \subsection{(WIP) \csh{XINT_eightrandomdigits}, \csh{xintEightRandomDigits}} %\begin{lverb} % 1.3b. 1.4 adds some public alias... %\end{lverb} % \begin{macrocode} \def\XINT_eightrandomdigits {% \expandafter\xint_gobble_i\the\numexpr% \xint_c_nine_e_viii% -\xinttexuniformdeviate\xint_c_ii^vii% -\xint_c_ii^vii*\xinttexuniformdeviate\xint_c_ii^vii% -\xint_c_ii^xiv*\xinttexuniformdeviate\xint_c_ii^vii% -\xint_c_ii^xxi*\xinttexuniformdeviate\xint_c_ii^vii% +\xinttexuniformdeviate\xint_c_e_viii% \relax% }% \let\xintEightRandomDigits\XINT_eightrandomdigits \def\xintRandBit{\xinttexuniformdeviate\xint_c_ii}% % \end{macrocode} % \subsection{(WIP) \csh{xintRandBit}} %\begin{lverb} % 1.4 And let's add also \xintRandBit while we are at it. %\end{lverb} % \begin{macrocode} \def\xintRandBit{\xinttexuniformdeviate\xint_c_ii}% % \end{macrocode} % \subsection{(WIP) \csh{xintXRandomDigits}} %\begin{lverb} % 1.3b. %\end{lverb} % \begin{macrocode} \def\xintXRandomDigits#1% {% \csname xint_gobble_\expandafter\XINT_xrandomdigits\the\numexpr#1\xint: }% \def\XINT_xrandomdigits#1\xint: {% \expandafter\XINT_xrandomdigits_a \the\numexpr(#1+\xint_c_iii)/\xint_c_viii\xint:#1\xint: }% \def\XINT_xrandomdigits_a#1\xint:#2\xint: {% \romannumeral\numexpr\xint_c_viii*#1-#2\expandafter\endcsname \romannumeral`&&@\romannumeral \XINT_replicate #1\endcsname\XINT_eightrandomdigits }% % \end{macrocode} % \subsection{(WIP) \csh{xintiiRandRangeAtoB}} %\begin{lverb} % 1.3b. Support for randrange() function. % % We do it f-expandably for matters of \xintNewExpr etc... The \xintexpr will % add \xintNum wrapper to possible fractional input. But \xintiiexpr will call % as is. % % TODO: ? implement third argument (STEP) % TODO: \xintNum wrapper (which truncates) not so good in floatexpr. Use round? % % It is an error if b<=a, as in Python. %\end{lverb} % %\begin{lverb} % NOTA BENE: \xintiiRandRangeAtoB is moved here from xint.sty at 2.0a1 % to have all in one location, but is NOT used by the calx chain. This % would induce a dependency on xint.sty via \xintiiadd, \xintiisub. %\end{lverb} % \begin{macrocode} \def\xintiiRandRangeAtoB{\romannumeral`&&@\xintiirandrangeAtoB}% \def\xintiirandrangeAtoB#1% {% \expandafter\XINT_randrangeAtoB_a\romannumeral`&&@#1\xint: }% \def\XINT_randrangeAtoB_a#1\xint:#2% {% \xintiiadd{\expandafter\XINT_randrange \romannumeral0\xintiisub{#2}{#1}\xint:}% {#1}% }% % \end{macrocode} % \subsection{(WIP) \csh{xintiiRandRange}} %\begin{lverb} % 1.3b. Support for randrange(). %\end{lverb} % %\begin{lverb} % All dependencies of \xintiiRandRange were moved to calxcore.sty % and calxint.sty. %\end{lverb} % \begin{macrocode} \def\xintiiRandRange{\romannumeral`&&@\xintiirandrange}% \def\xintiirandrange#1% {% \expandafter\XINT_randrange\romannumeral`&&@#1\xint: }% \def\XINT_randrange #1% {% \xint_UDzerominusfork #1-\XINT_randrange_err:empty 0#1\XINT_randrange_err:empty 0-\XINT_randrange_a \krof #1% }% \def\XINT_randrange_err:empty#1\xint: {% \XINT_expandableerror{Empty range for randrange.} 0% }% \def\XINT_randrange_a #1\xint: {% \expandafter\XINT_randrange_b\romannumeral0\xintlength{#1}.#1\xint: }% \def\XINT_randrange_b #1.% {% \ifnum#1<\xint_c_x\xint_dothis{\the\numexpr\XINT_uniformdeviate{}}\fi \xint_orthat{\XINT_randrange_c #1.}% }% \def\XINT_randrange_c #1.#2#3#4#5#6#7#8#9% {% \expandafter\XINT_randrange_d \the\numexpr\expandafter\XINT_uniformdeviate\expandafter {\expandafter}\the\numexpr\xint_c_i+#2#3#4#5#6#7#8#9\xint:\xint: #2#3#4#5#6#7#8#9\xint:#1\xint: }% % \end{macrocode} %\begin{lverb} % This raises following annex question: immediately after setting the % seed is it possible for \xintUniformDeviate{N} where N>0 has exactly eight % digits to return either 0 or N-1 ? It could be that this is never the case, % then there is a bias in randrange(). Of course there are anyhow only 2^28 % seeds so randrange(10^X) is by necessity biased when executed immediately % after setting the seed, if X is at least 9. %\end{lverb} % \begin{macrocode} \def\XINT_randrange_d #1\xint:#2\xint: {% \ifnum#1=\xint_c_\xint_dothis\XINT_randrange_Z\fi \ifnum#1=#2 \xint_dothis\XINT_randrange_A\fi \xint_orthat\XINT_randrange_e #1\xint: }% \def\XINT_randrange_e #1\xint:#2\xint:#3\xint: {% \the\numexpr#1\expandafter\relax \romannumeral0\xintrandomdigits{#2-\xint_c_viii}% }% % \end{macrocode} %\begin{lverb} % This is quite unlikely to get executed but if it does it must % pay attention to leading zeros, hence the \xintinum. % We don't have to be % overly obstinate about removing overheads... %\end{lverb} % \begin{macrocode} \def\XINT_randrange_Z 0\xint:#1\xint:#2\xint: {% \xintinum{\xintRandomDigits{#1-\xint_c_viii}}% }% % \end{macrocode} %\begin{lverb} % Here too, overhead is not such a problem. The idea is that we got by % extraordinary same first 8 digits as upper range bound so we pick at random % the remaining needed digits in one go and compare with the upper bound. If too % big, we start again with another random 8 leading digits in given range. No % need to aim at any kind of efficiency for the check and loop back. %\end{lverb} % \begin{macrocode} \def\XINT_randrange_A #1\xint:#2\xint:#3\xint: {% \expandafter\XINT_randrange_B \romannumeral0\xintrandomdigits{#2-\xint_c_viii}\xint: #3\xint:#2.#1\xint: }% \def\XINT_randrange_B #1\xint:#2\xint:#3.#4\xint: {% \xintiiifLt{#1}{#2}{\XINT_randrange_E}{\XINT_randrange_again}% #4#1\xint:#3.#4#2\xint: }% \def\XINT_randrange_E #1\xint:#2\xint:{ #1}% \def\XINT_randrange_again #1\xint:{\XINT_randrange_c}% % \end{macrocode} % \subsection{\csh{calxintRandRangeAtoB}, \csh{calxintRandRange}} %\begin{lverb} % calx: randrange() of \xintiieval. Arguments: any \xintiieval value, % converted to raw digits by \CALX_mr_a; output M. % % These macros are wrappers around xint's \XINT_randrange (above, % unmodified), not a native rewriting. The cause is a serious % and recurrent misalignment problem of this assistant and the % pain and suffering it finally ended up causing the user, who % is really reaching the ultimate limits of endurance. % % FIXME: \CALX_mr_a IS A CRUCIAL CONVERSION AND MUST HAVE % A LEGIBLE NAME. %\end{lverb} % \begin{macrocode} \def\calxintRandRangeAtoB{\romannumeral0\CALX_randrangeAtoB}% \def\CALX_randrangeAtoB#1% {% \expandafter\CALX_randrangeAtoB_a\romannumeral`&&@#1\xint: }% \def\CALX_randrangeAtoB_a#1\xint:#2% {% \CALX_iiadd{\expandafter\XINT_randrange \romannumeral0\expandafter\CALX_mr_a \romannumeral0\CALX_iisub{#2}{#1}\xint:\xint:}% {#1}% }% \def\CALX_mfromraw_a{\expandafter\CALX_ntom\romannumeral0\CALX_nfromraw_a}% \def\calxintRandRange{% \romannumeral0\expandafter \CALX_mfromraw_a\romannumeral`&&@\CALX_randrange }% \def\CALX_randrange#1% {% \expandafter\XINT_randrange \romannumeral0\expandafter\CALX_mr_a\romannumeral`&&@#1\xint:\xint:\xint: }% % \end{macrocode} % \subsection{(WIP) Adjustments for engines without uniformdeviate primitive} %\added{1.3b} % \begin{macrocode} \ifdefined\xinttexuniformdeviate \else \def\xintrandomdigits#1% {% \XINT_expandableerror {No uniformdeviate at engine level.} 0% }% \let\xintXRandomDigits\xintRandomDigits \def\XINT_randrange#1\xint: {% \XINT_expandableerror {No uniformdeviate at engine level.} 0% }% \fi \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {calxint} % \cleardoublepage\let\calxintnameUp\undefined %\gardesactifs %\let\relax %\let<*calxfp>\gardesinactifs %^^A--------------------------------------------------- %<*calxfp>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxfpnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \calxfpnameimp implementation} % \RaisedLabel{sec:calxfpimp} % \addedcalx{2.0a1} % % \localtableofcontents % %\begin{lverb} % calx: native floating point numbers (the float part of an ideal split of % xintfrac.sty; calxfrac.sty would be the fractions part). It loads % calxint.sty. Format: %( F.. %) % value M 10^(8e), M the native integer with blocks 1dddddddd! (least % significant first), D its number of digits (top block not normalized), % e the exponent in blocks, + or -. Zero: F+0.0. Special values I+, % I-, I? as for native integers. F has catcode 12 here. %\end{lverb} % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code of this subsection is copied over from the xint packages, with % the package names changed. % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@calxfp.sty\endcsname \expandafter\let\expandafter\w\csname ver@calxint.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage calxfp Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{calxfp}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of calxfp.sty \ifx\w\relax % but calxint.sty not yet loaded. \def\z{\endgroup\input calxint.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % calxint.sty not yet loaded. \def\z{\endgroup\RequirePackage{calxint}}% \fi \else \def\z{\endgroup\endinput}% calxfp already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{calxfp}% [2026/11/01 v2.0a1 Floating point unit P1 to P100 (JFB)]% % \end{macrocode} % \subsection{\csh{xintDigits}, \csh{xintSetDigits}} % \changed{2.0a1} % Moved here from \xintfracnameimp together with the starred version % from original \xintexprnameimp, trimmed from its original meaning. % % Removal of the commented out layer which was in preparation for % user to temporarily use extra digits. The calx semantics made this % anyhow obsolete as increasing Digits is cheap (it only costs % recomputing the Pi and other trig variables). % % \changed{1.3} %\begin{lverb} % 1.3f allows \xintDigits= in place of \xintDigits$empty:= syntax. ^^A$ % It defines \xintDigits*[:]= which reloads xinttrig.sty. Perhaps this should % be default, well. % % During 1.4e development I added an interface for guard digits, but I decided % to drop inclusion from 1.4e release because there were pending issues both % in documentation and functionalities for which I did not have time left. % % 1.4e fixes the issue that \xinttheDigits could not be used in the right hand % side of \xintDigits[*][:]=...; or inside the argument to \xintSetDigits. %\end{lverb} % %\begin{lverb} % calx (s50): \xintDigits and \xintDigits* are synonyms; both (and % \xintSetDigits/\xintSetDigits*) update the constants twoPi, ..., % oneRadian (P digits) by % \CALX_trigvars (defined at the end of calxtrig.tex; \empty until then). % % There was a \futurelet\XINT_token which was meant to detect the * % for \xintDigits, it is of course dropped here. The #1 for \xintDigits_j % gobbles a semi-colon which is original user-documented syntax or a \relax % which was advocated later. %\end{lverb} % \begin{macrocode} \mathchardef\XINTdigits 16 \def\xinttheDigits {\number\XINTdigits}% \def\xintDigits #1={\afterassignment\xintDigits_j\mathchardef\XINT_digits=}% \let\CALX_trigvars\empty \def\xintDigits_j#1{\let\XINTdigits=\XINT_digits\CALX_trigvars}% % \end{macrocode} % The |#1| above serves to absord the ending semi-colon or |\relax| token % from the documented interface. % Pay attention to the |#{| delimiter below. % It serves to gobble the legacy % starred syntax, which is completely synonymous now to unstarred one. % (PERHAPS REVERT THIS DECISION IN TIME FOR 2.0a1: TO BE DECIDED LATER). % \begin{macrocode} \def\xintSetDigits#1#{\xintSetDigits_a}% \def\xintSetDigits_a#1{% \mathchardef\XINT_digits=\numexpr#1\relax \let\XINTdigits=\XINT_digits \CALX_trigvars }% \catcode`F=12 \catcode`N=12 \catcode`I=12 % \end{macrocode} % \subsection{Rounding} % \subsubsection{\csh{CALX_fround}, \csh{CALX_fnround}, \csh{CALX_fblocks}} %\begin{lverb} % Syntax (use with \romannumeral0; the second argument is f-expanded): %( % \CALX_fround{P}{X} -> Y\xint: %: \CALX_fnround{P}{X} -> Y %: \CALX_fblocks{m}{X} -> Y %) % P (number of significant digits, >= 1) and m (number of blocks, >= 1) % are \numexpr expressions. Values X, Y (tags F, I catcode 12): %( % F..1!1!...1! native float %: I+ I- I? specials %) % s sign (+ or -), D digit count of N = b_n...b_1b_0 (D = 0: zero, no % block), e block exponent, 8-digit blocks b_i least significant first: % value s N 10^(8e). \CALX_fround also accepts an M value (calxint) and % an xint raw value X: A[N] or A/B[N] (the [N] is mandatory), A and B % integers in decimal digits without leading zeros, an optional - on A % only, B > 0 (no decimal mark, no exponent); % it is delimited by the \xint: that \CALX_fround appends. xintexpr.sty % replaces the raw branch \CALX_fr_x so that X may be any xintfrac input. % \CALX_fnround and \CALX_fblocks accept only F, I. % % Output Y: F input: X rounded to P significant digits (\CALX_fblocks: to % its m top blocks), round half away from zero (as xint's \xintDSRr, % \XINTinFloat); D <= P: X itself. I input: X itself. Raw input: the F % value of X rounded to P digits. \CALX_fround's Y is ALWAYS followed by % \xint: (the terminator that the entries of the operations read after a % value); \CALX_fnround and \CALX_fblocks add nothing. Only the blocks % below the rounding position are read: the higher ones stay in the input % stream untouched. % % k = D - P <= 0: unchanged (zero, specials too). Else k = 8a + c: skip % a blocks (gobblers \CALX_fr_g, a <= 5; beyond, \CALX_fr_sk drops % seven at a time and \CALX_fr_q the rest), then c > 0: lowest kept % block 1v -> 1v/10^c*10^c (\numexpr rounds half away from zero); c = 0: % the first digit of the last dropped block decides +1 on the lowest kept % block. D' = D - 8a, e' = e + a. % Dispatch on k by \csname (macros \CALX_fr_k, k in decimal, k <= 0 % gives \CALX_fr_k0 = \CALX_fr_id), general path \CALX_fr_kgen beyond 47. % \CALX_fblocks{m} is the rounding with % k = 8(ceil(D/8) - m); ceil(D/8) = (D+3)/8 in \numexpr. % % \CALX_fr_w !{s}{D'}{e'}: block 200000000: carry % (\CALX_fr_cy); D' <= 8 (the kept block is the top block): the digit % count grows by one if the top block reaches 10^D' (\CALX_fr_top). % The carry path grabs the kept blocks (count known from D') up to the top % one, since the header precedes the blocks; it is rare. % % Dispatch (\CALX_fr_a) on the first token of X, rarest cases first, one % macro per branch, P and the token put back: I (\CALX_fr_i: I with the % sign that follows), M (\CALX_fr_m), - (raw), F (\CALX_fr_f: k = D - P, % the tag a parameter), otherwise a digit (raw). M (the integer type of % \xintiieval: same blocks and e as F): zero gives F+0.0. (\CALX_fr_mz); % else \CALX_fr_mm grabs the blocks once, reads the digit count D on the % top block (as \CALX_fmx_c) and \CALX_fr_mn rounds F... % Raw (\CALX_fr_x, A[N] or A/B[N]): split at the bracket only, P put % behind (A/.P.N]); \CALX_fr_xs: the token after the first slash is the % dot exactly when there is no slash, \xint_gob_til_dot selects. A[N] % (\CALX_fr_xa): \CALX_ffr_a gives the exact F value of A 10^N, rounded % by \CALX_fr_f. A/B[N] (\CALX_fr_xf): two tokens decide B = 1 (1 then % the slash: jumper \CALX_fr_xo to \CALX_fr_xa); else \CALX_fr_xg, the % exact F values of A 10^N and of B, and \CALX_fr_xk dispatches by % \csname to calxfp's division: \CALX_fd_zz (B = 0: 0/0 % DivisionUndefined, x/0 DivisionByZero), \CALX_fd_zero (A = 0) or the % generic division path \CALX_fd_g, valid for any digit counts (the % truncated quotient has at least P + 1 digits: round half away from zero % is that of A 10^N / B). The \xint: appended by \CALX_fround stays in % the stream on all paths. % xintexpr.sty redefines \CALX_fr_x with xintfrac's \XINTinFloat, which % parses any xintfrac input. %\end{lverb} % \begin{macrocode} \def\CALX_fround #1#2{\expandafter\CALX_fr_a\the\numexpr#1\expandafter.% \romannumeral`&&@#2\xint:}% \def\CALX_fnround #1#2{\expandafter\CALX_fr_a\the\numexpr#1\expandafter.% \romannumeral`&&@#2}% \def\CALX_fr_a #1.#2% {% \if I#2\xint_dothis\CALX_fr_i\fi \if M#2\xint_dothis\CALX_fr_m\fi \if -#2\xint_dothis\CALX_fr_x\fi \if F#2\xint_dothis\CALX_fr_f\fi \xint_orthat\CALX_fr_x #1.#2% }% \def\CALX_fr_i #1.#2{ I}% \def\CALX_fr_f #1.#2#3#4.{\expandafter\CALX_fr_b\the\numexpr#4-#1.#3#4.}% \def\CALX_fr_m #1.#2#3#4.% {% \ifnum#4=\xint_c_ \expandafter\CALX_fr_mz\fi \CALX_fr_mm #1.#3#4.% }% \def\CALX_fr_mz\CALX_fr_mm #1\xint:{ F+0.0.\xint:}% \def\CALX_fr_mm #1.#2#3.#4.#5\xint:% {% \expandafter\CALX_fr_mn\the\numexpr\xint_c_viii*(#3-\xint_c_i)% +\CALX_nskip\CALX_fm_gl #3-\xint_c_i.#5\xint:.#1.#2#4.#5\xint: }% \def\CALX_fr_mn #1.#2.#3{\expandafter\CALX_fr_b\the\numexpr#1-#2.#3#1.}% \def\CALX_fr_x #1.#2[{\CALX_fr_xs #2/.#1.}% \def\CALX_fr_xs #1/#2% {\xint_gob_til_dot #2\CALX_fr_xa.\CALX_fr_xf #1/#2}% \def\CALX_fr_xa.\CALX_fr_xf#1/.#2.#3]% {\expandafter\CALX_fr_f\the\numexpr#2\expandafter.% \romannumeral0\CALX_ffr_a#1[#3]\xint:}% \def\CALX_fr_xf #1/#2#3% {% \if1#2\if/#3\CALX_fr_xo\fi\fi \CALX_fr_xg #1/#2#3% }% \def\CALX_fr_xo\fi\fi\CALX_fr_xg #1/#2#3{\fi\fi\CALX_fr_xa.\CALX_fr_xf #1/}% \def\CALX_fr_xg #1/#2/.#3.#4]% {\expandafter\CALX_fr_xk\expanded{\romannumeral0\CALX_ffr_a#1[#4]\xint:% \xint:\romannumeral0\CALX_ffr_a#2[0]\xint:\xint:}{#3}}% \def\CALX_fr_xk F#1#2.#3.#4\xint:F#5#6.#7.#8\xint:% {% \csname CALX_fd_\ifnum#6=\xint_c_ zz\else\ifnum#2=\xint_c_ zero\else g\fi\fi\endcsname {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% }% \def\CALX_fr_b #1.% {\csname CALX_fr_k\ifnum#1>\xint_c_ \ifnum#1>47 gen\else#1\fi\else0\fi \endcsname #1.}% \def\CALX_fblocks #1#2{\expandafter\CALX_fb_a\the\numexpr#1\expandafter.% \romannumeral`&&@#2}% \def\CALX_fb_a #1.#2{\if I#2\xint_dothis{ I}\fi\xint_orthat{\CALX_fb_c #1.}}% \def\CALX_fb_c #1.#2#3.% {\expandafter\CALX_fr_b\the\numexpr\xint_c_viii*((#3+\xint_c_iii)/% \xint_c_viii-#1).#2#3.}% \def\CALX_fr_id #1.#2#3.{ F#2#3.}% \def\CALX_fr_gz #1{#1}% \def\CALX_fr_gi #1#2#3#41#5!{#1{#2}{#3}{#4}}% \def\CALX_fr_gii #1#2#3#41#5!1#6!{#1{#2}{#3}{#4}}% \def\CALX_fr_giii #1#2#3#41#5!1#6!1#7!{#1{#2}{#3}{#4}}% \def\CALX_fr_giv #1#2#3#41#5!1#6!1#7!1#8!{#1{#2}{#3}{#4}}% \def\CALX_fr_gv #1#2#3#41#5!1#6!1#7!1#8!1#9!{#1{#2}{#3}{#4}}% \def\CALX_fr_sk #1.% {% \ifnum#1>\xint_c_vi \expandafter\CALX_fr_sq \else\csname CALX_fr_q#1\expandafter\endcsname\fi #1.% }% \def\CALX_fr_sq #1.#2#3!#4!#5!#6!#7!#8!#9!% {\expandafter\CALX_fr_sk\the\numexpr#1-\xint_c_vii.{#2}}% \expandafter\def\csname CALX_fr_q0\endcsname #1.#2{#2}% \expandafter\def\csname CALX_fr_q1\endcsname #1.#2#3!{#2}% \expandafter\def\csname CALX_fr_q2\endcsname #1.#2#3!#4!{#2}% \expandafter\def\csname CALX_fr_q3\endcsname #1.#2#3!#4!#5!{#2}% \expandafter\def\csname CALX_fr_q4\endcsname #1.#2#3!#4!#5!#6!{#2}% \expandafter\def\csname CALX_fr_q5\endcsname #1.#2#3!#4!#5!#6!#7!{#2}% \expandafter\def\csname CALX_fr_q6\endcsname #1.#2#3!#4!#5!#6!#7!#8!{#2}% \expandafter\let\csname CALX_fr_k0\endcsname\CALX_fr_id \expandafter\def\csname CALX_fr_k1\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_vi{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k2\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_vii{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k3\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_viii{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k4\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_viv{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k5\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_vv{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k6\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_vvi{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k7\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_vvii{#2}{#3}{#4}}% \expandafter\def\csname CALX_fr_k8\endcsname#1.#2#3.#4.{\CALX_fr_gz% \CALX_fr_z{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k9\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_vi{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k10\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_vii{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k11\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_viii{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k12\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_viv{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k13\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_vv{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k14\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_vvi{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k15\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_vvii{#2}{#3-8}{#4+1}}% \expandafter\def\csname CALX_fr_k16\endcsname#1.#2#3.#4.{\CALX_fr_gi% \CALX_fr_z{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k17\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_vi{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k18\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_vii{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k19\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_viii{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k20\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_viv{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k21\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_vv{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k22\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_vvi{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k23\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_vvii{#2}{#3-16}{#4+2}}% \expandafter\def\csname CALX_fr_k24\endcsname#1.#2#3.#4.{\CALX_fr_gii% \CALX_fr_z{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k25\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_vi{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k26\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_vii{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k27\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_viii{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k28\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_viv{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k29\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_vv{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k30\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_vvi{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k31\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_vvii{#2}{#3-24}{#4+3}}% \expandafter\def\csname CALX_fr_k32\endcsname#1.#2#3.#4.{\CALX_fr_giii% \CALX_fr_z{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k33\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_vi{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k34\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_vii{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k35\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_viii{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k36\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_viv{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k37\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_vv{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k38\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_vvi{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k39\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_vvii{#2}{#3-32}{#4+4}}% \expandafter\def\csname CALX_fr_k40\endcsname#1.#2#3.#4.{\CALX_fr_giv% \CALX_fr_z{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k41\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_vi{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k42\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_vii{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k43\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_viii{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k44\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_viv{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k45\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_vv{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k46\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_vvi{#2}{#3-40}{#4+5}}% \expandafter\def\csname CALX_fr_k47\endcsname#1.#2#3.#4.{\CALX_fr_gv% \CALX_fr_vvii{#2}{#3-40}{#4+5}}% \def\CALX_fr_kgen #1.#2#3.#4.% {% \expandafter\CALX_fr_kgen_a\the\numexpr(#1-\xint_c_iv)/\xint_c_viii% \expandafter.% \the\numexpr#1-\xint_c_viii*((#1-\xint_c_iv)/\xint_c_viii).#2#3.#4.% }% \def\CALX_fr_kgen_a #1.#2.#3#4.#5.% a, c, s, D, e {% \expandafter\CALX_fr_sk\the\numexpr#1\ifnum#2=\xint_c_ -\xint_c_i\fi.% {\csname CALX_fr_\ifnum#2=\xint_c_ z\else v#2\fi\endcsname {#3}{#4-\xint_c_viii*#1}{#5+#1}}% }% \def\CALX_fr_vi #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/10*10!{#1}{#2}{#3}}% \def\CALX_fr_vii #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/100*100!{#1}{#2}{#3}}% \def\CALX_fr_viii #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/1000*1000!{#1}{#2}{#3}}% \def\CALX_fr_viv #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/10000*10000!{#1}{#2}{#3}}% \def\CALX_fr_vv #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/100000*100000!{#1}{#2}{#3}}% \def\CALX_fr_vvi #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/1000000*1000000!{#1}{#2}{#3}}% \def\CALX_fr_vvii #1#2#31#4!% {\expandafter\CALX_fr_w\the\numexpr1#4/10000000*10000000!{#1}{#2}{#3}}% \def\CALX_fr_z #1#2#31#4#5!1#6!% {% \ifnum#4>\xint_c_iv \xint_dothis{\expandafter\CALX_fr_w\the\numexpr1#6+% \xint_c_i!}\fi \xint_orthat{\CALX_fr_w1#6!}{#1}{#2}{#3}% }% \def\CALX_fr_w #1!#2#3% {% \ifnum#1=200000000 \xint_dothis\CALX_fr_cy\fi \ifnum\numexpr#3<\xint_c_ix \xint_dothis\CALX_fr_top\fi \xint_orthat\CALX_fr_out{#1}{#2}{#3}% }% \def\CALX_fr_out #1#2#3#4{\expanded{ F#2\the\numexpr#3.\the\numexpr#4.}#1!}% \def\CALX_fr_top #1#2#3% {% \ifnum#1<\numexpr\xint_c_e_viii+\CALX_pten{#3}\relax \xint_dothis\CALX_fr_out\fi \xint_orthat\CALX_fr_outp{#1}{#2}{#3}% }% \def\CALX_fr_outp #1#2#3#4{\expanded{ F#2\the\numexpr#3+\xint_c_i.\the% \numexpr#4.}#1!}% \expandafter\let\csname CALX_fr_v1\endcsname\CALX_fr_vi \expandafter\let\csname CALX_fr_v2\endcsname\CALX_fr_vii \expandafter\let\csname CALX_fr_v3\endcsname\CALX_fr_viii \expandafter\let\csname CALX_fr_v4\endcsname\CALX_fr_viv \expandafter\let\csname CALX_fr_v5\endcsname\CALX_fr_vv \expandafter\let\csname CALX_fr_v6\endcsname\CALX_fr_vvi \expandafter\let\csname CALX_fr_v7\endcsname\CALX_fr_vvii % \end{macrocode} %\begin{lverb} % Carry. #1=200000000, #2=s, #3=D', #4=e'. If D' <= 8 the top block % overflowed to 10^8: blocks 100000000!100000001!, D'+1. Else % \CALX_fr_cya .{s}{D'}{e'}{acc} with r = ceil(D'/8) - 1 kept blocks % above: 99999999 below the top one -> 100000000, continue; else +1 and % stop. At the top block (r = 1, d = D' - 8(ceil(D'/8) - 1) digits): +1; % if it reaches 10^d: D'+1 (and d = 8: two blocks). %\end{lverb} % \begin{macrocode} \def\CALX_fr_cy #1#2#3#4% {% \ifnum\numexpr#3<\xint_c_ix \xint_dothis{\expanded{ F#2\the\numexpr#3+\xint_c_i.\the\numexpr#4.}% 100000000!100000001!}\fi \xint_orthat{\expandafter\CALX_fr_cya \the\numexpr(#3+\xint_c_iii)/\xint_c_viii-% \xint_c_i.{#2}{#3}{#4}{100000000!}}% }% \def\CALX_fr_cya #1.#2#3#4#51#6!% {% \ifnum#1=\xint_c_i \xint_dothis\CALX_fr_cyt\fi \ifnum#6=99999999 \xint_dothis\CALX_fr_cyn\fi \xint_orthat\CALX_fr_cys #1.{#2}{#3}{#4}{#5}{#6}% }% \def\CALX_fr_cyn #1.#2#3#4#5#6% {\expandafter\CALX_fr_cya\the\numexpr#1-% \xint_c_i.{#2}{#3}{#4}{#5100000000!}}% \def\CALX_fr_cys #1.#2#3#4#5#6% {\expanded{ F#2\the\numexpr#3.\the\numexpr#4.#5\the\numexpr1#6+% \xint_c_i!}}% \def\CALX_fr_cyt #1.#2#3#4#5#6% {% \ifnum\numexpr#6+\xint_c_i\relax =\numexpr\CALX_pten{#3-\xint_c_viii*((#3+\xint_c_iii)/% \xint_c_viii-\xint_c_i)}\relax \xint_dothis{\ifnum#6=99999999 \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expanded{ F#2\the\numexpr#3+\xint_c_i.\the% \numexpr#4.#5100000000!100000001!}}% {\expanded{ F#2\the\numexpr#3+\xint_c_i.\the\numexpr#4.#5\the% \numexpr1#6+\xint_c_i!}}}\fi \xint_orthat{\expanded{ F#2\the\numexpr#3.\the\numexpr#4.#5\the% \numexpr1#6+\xint_c_i!}}% }% % \end{macrocode} % \subsection{Conversions} % \subsubsection{\csh{CALX_ffromraw}, \csh{CALX_ftoraw}} %\begin{lverb} % Syntax (use with \romannumeral0; argument f-expanded): %( % \CALX_ffromraw{A[N]} -> F.. %: \CALX_ftoraw{X} -> [<8e>] (X an F value; I values unchanged) %) % Conversions between xint's raw floats A[N] and native floats (use with % \romannumeral0, argument f-expanded). % % \CALX_ffromraw{A[N]}: A integer without leading zeros (optional -), N % any integer. N = 8e + r, 0 <= r < 8, e = floor(N/8) = (2N-7)/16 in % \numexpr (never a tie); the r zeros are appended to the string |A| % before \CALX_nfromraw; D = len(|A|) + r (\xintLength). 0[N]: F+0.0. % % \CALX_ftoraw{F}: \CALX_ntoraw of the mantissa (n = ceil(D/8) = % (2D+7)/16), exponent 8e: [<8e>] (trailing zeros kept, value % exact). F+0.0.: 0[0]. I+, I-, I? are returned unchanged. %\end{lverb} % \begin{macrocode} \def\CALX_ffromraw #1{\expandafter\CALX_ffr_a\romannumeral`&&@#1\xint:}% \def\CALX_ffr_a #1[#2]\xint:% {\expandafter\CALX_ffr_b\the\numexpr(\xint_c_ii*(#2)-\xint_c_vii)/16.#2.#1% \xint:}% \def\CALX_ffr_b #1.#2.#3#4\xint:% {% \if 0#3\xint_dothis\CALX_ffr_z\fi \if -#3\xint_dothis{\CALX_ffr_c-{#4}}\fi \xint_orthat{\CALX_ffr_c+{#3#4}}{#1}{#2}% }% \def\CALX_ffr_z #1#2{ F+0.0.}% \def\CALX_ffr_zs #1{\csname CALX_ffr_zs\the\numexpr#1\endcsname}% \expandafter\def\csname CALX_ffr_zs0\endcsname{}% \expandafter\def\csname CALX_ffr_zs1\endcsname{0}% \expandafter\def\csname CALX_ffr_zs2\endcsname{00}% \expandafter\def\csname CALX_ffr_zs3\endcsname{000}% \expandafter\def\csname CALX_ffr_zs4\endcsname{0000}% \expandafter\def\csname CALX_ffr_zs5\endcsname{00000}% \expandafter\def\csname CALX_ffr_zs6\endcsname{000000}% \expandafter\def\csname CALX_ffr_zs7\endcsname{0000000}% \def\CALX_ffr_c #1#2#3#4% {% \expandafter\CALX_ffr_d\romannumeral0% \CALX_nfromraw{\expanded{#2\CALX_ffr_zs{\numexpr#4-\xint_c_viii*#3% \relax}}}\xint: #1{\the\numexpr\xintLength{#2}+#4-\xint_c_viii*#3}{#3}% }% \def\CALX_ffr_d N+#1.#2\xint:#3#4#5{\expanded{ F#3#4.#5.}#2}% \def\CALX_ftoraw #1{\expandafter\CALX_ftr_a\romannumeral`&&@#1\xint:}% \def\CALX_ftr_a #1#2% {\if I#1\xint_dothis{\CALX_ftr_sp#2}\fi\xint_orthat{\CALX_ftr_b#2}}% \def\CALX_ftr_sp #1\xint:{ I#1}% \def\CALX_ftr_b #1#2.#3.#4\xint:% {% \ifnum#2=\xint_c_ \xint_dothis{ 0[0]}\fi \xint_orthat{\expandafter\CALX_ftr_c\romannumeral0\CALX_ntoraw {\expandafter N\expandafter#1\the\numexpr(\xint_c_ii*#2+% \xint_c_vii)/16.#4}\xint:{#3}}% }% \def\CALX_ftr_c #1\xint:#2{\expanded{ #1[\the\numexpr\xint_c_viii*#2\relax]}}% % \end{macrocode} % \subsubsection{\csh{CALX_ti_f}} %\begin{lverb} % Syntax (use with \romannumeral0): %( % \CALX_ti_f F..\xint: -> F.. %) % Truncation of a native float to an integer (towards zero), exact; the % tag token is taken as a parameter and re-emitted. e >= 0: unchanged. % e < 0: the -e low blocks are dropped (\CALX_nskip), D' = D + 8e (zero % if D' <= 0), e' = 0. %\end{lverb} % \begin{macrocode} \def\CALX_ti_f #1#2#3.#4.% {\ifnum#4<\xint_c_ \expandafter\CALX_ti_g\else\expandafter\CALX_ti_id\fi #1#2#3.#4.}% \def\CALX_ti_id #1\xint:{ #1}% \def\CALX_ti_g #1#2#3.#4.% {\expandafter\CALX_ti_i\the\numexpr#3+\xint_c_viii*#4.#1#2{#4}}% \def\CALX_ti_i #1.#2#3% {\ifnum#1>\xint_c_ \expandafter\CALX_ti_j\else\expandafter\CALX_ti_z\fi #1.#2#3}% \def\CALX_ti_z #1.#2#3#4#5\xint:{ #2+0.0.}% \def\CALX_ti_j #1.#2#3#4#5\xint:% {\expandafter\CALX_ti_o\romannumeral\CALX_nskip\xint_c_ 0-#4.#5\xint:% #2#3#1.0.}% \def\CALX_ti_o #1\xint:#2.0.{ #2.0.#1}% % \end{macrocode} % \subsubsection{\csh{CALX_fnum}} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded): %( % \CALX_fnum X\xint: -> R (or -R... without space) %) % R: explicit digits (raw integer, as xint's \xintnum) of the truncation % of X towards zero. X: native F, M (\xintiieval) or I value, or raw A, % A[N], A/B, A/B[N] (A, B integers without leading zeros, B > 0; values % of \xinteval and literals). For \calxFpToNum (calx.sty), which takes % indices and counts from the values of any of the three parsers. % % F: e = 0 and D <= 8 (zero or one block): \numexpr on the block (with a % sentinel block for zero); else \CALX_ti_f, then the digits of the M % form M.., n = ceil(D/8) = (2D+7)/16 (\CALX_mtoraw_t, % which also writes the 8e zeros). M: \CALX_mtoraw_t. I: InvalidOperation % (an I result of the handler, as the default I?, is replaced by 0: an % integer is required). Raw: A = 0: 0; B = 1 and N >= 0: A followed by N zeros; else % calxint's \CALX_iiq: one native division of A 10^max(N,0) by % B 10^max(-N,0) with floor quotient Q; exact or Q >= 0: Q, else Q + 1. %\end{lverb} % \begin{macrocode} \def\CALX_fnum #1% {% \if I#1\xint_dothis\CALX_fnum_i\fi \if M#1\xint_dothis\CALX_mtoraw_t\fi \if F#1\xint_dothis\CALX_fnum_b\fi \xint_orthat\CALX_fnum_r #1% }% \def\CALX_fnum_i #1\xint:% {\expandafter\CALX_fnum_j\romannumeral`&&@\CALX_signalcondition {InvalidOperation}{#1 has no integer value}{}{0}\xint:}% \def\CALX_fnum_j #1{% \if I#1\xint_dothis\CALX_fnum_jz\fi \xint_orthat\CALX_fnum_jn #1% }% \def\CALX_fnum_jz #1\xint:{ 0}% \def\CALX_fnum_jn #1#2\xint:{ #1#2}% \def\CALX_fnum_b #1#2#3.#4.{% \ifnum\ifnum#4=\xint_c_ #3\else9\fi<\xint_c_ix \xint_dothis\CALX_fnum_bs\fi \xint_orthat\CALX_fnum_bg #1#2#3.#4.% }% \def\CALX_fnum_bs #1#2#3.#4.#5\xint:{% \CALX_fnum_c#2#5100000000!\xint:% }% \def\CALX_fnum_bg #1#2#3.#4.#5\xint:{% \expandafter\CALX_fnum_m \romannumeral0\CALX_ti_f F#2#3.#4.#5\xint:\xint:% }% \def\CALX_fnum_c #11#2!#3\xint:{ \the\numexpr#1#2\relax}% \def\CALX_fnum_m F#1#2.% {\expandafter\CALX_mtoraw_t\expandafter F\expandafter#1% \the\numexpr(\xint_c_ii*#2+\xint_c_vii)/16.}% \def\CALX_fnum_r #1\xint:{\CALX_fnum_s #1[0]\xint:}% \def\CALX_fnum_s #1[#2]#3\xint:{\CALX_fnum_t #1/1/\xint:{#2}}% \def\CALX_fnum_t #1/#2/#3\xint:#4% {% \if0#1\xint_dothis\CALX_fnum_z\fi \ifnum#4<\xint_c_ \xint_dothis\CALX_fnum_q\fi \xint_orthat{\CALX_fnum_v #2\xint:}{#1}{#2}{#4}% }% \def\CALX_fnum_z #1#2#3{ 0}% \def\CALX_fnum_v #1#2\xint:% {\if1#1\if\relax\detokenize{#2}\relax\CALX_fnum_w\fi\fi\CALX_fnum_q}% \def\CALX_fnum_w #1\CALX_fnum_q#2#3#4{#1\expanded{ #2\xintReplicate{#4}0}}% \def\CALX_fnum_q {\CALX_iiq\CALX_fnum_e\CALX_fnum_f}% \def\CALX_fnum_e #1{\CALX_ntoraw_a #1\xint:}% \def\CALX_fnum_f #1{\CALX_fnum_g #1\xint:}% \def\CALX_fnum_g N#1% {\if-#1\expandafter\CALX_fnum_u\else\expandafter\CALX_ntoraw_a\fi N#1}% \def\CALX_fnum_u #1\xint:% {\expandafter\CALX_ntoraw_a\romannumeral0\CALX_nadd{#1}{N+1.100000001!}% \xint:}% % \end{macrocode} %\begin{lverb} % FROM SESSION 58 WHICH WAS A COMPLETE CASTROPHY AFTER A FEW HOURS. % % "Proposal, not inserted, for calxfp after \CALX_fnum (the % name \CALX_ftom is unused). Use it as \romannumeral0\CALX_ftom{X}: it % f-expands X and outputs M…, the truncation, like \calxFpToNum but in M % format.» %\end{lverb} % \begin{macrocode} \def\CALX_ftom #1{\expandafter\CALX_ftom_a\romannumeral`&&@#1\xint:}% \def\CALX_ftom_a #1% {% \if M#1\xint_dothis\CALX_ftom_k\fi \if F#1\xint_dothis\CALX_ftom_f\fi \if I#1\xint_dothis\CALX_ftom_i\fi \xint_orthat\CALX_ftom_r #1% }% \def\CALX_ftom_k #1\xint:{ #1}% \def\CALX_ftom_f #1\xint:% {\expandafter\CALX_ftom_m\romannumeral0\CALX_ti_f #1\xint:}% \def\CALX_ftom_m #1#2#3.% {\expandafter\CALX_ftom_n\the\numexpr(\xint_c_ii*#3+\xint_c_vii)/16.#2}% \catcode`M=12 \def\CALX_ftom_n #1.#2{ M#2#1.}% \def\CALX_ftom_j #1#2\xint:% {\if I#1\xint_dothis{ M+0.0.}\fi\xint_orthat{\CALX_mfromraw{#1#2}}}% \catcode`M=11 \def\CALX_ftom_i #1\xint:% {\expandafter\CALX_ftom_j\romannumeral`&&@\CALX_signalcondition {InvalidOperation}{#1 has no integer value}{}{0}\xint:}% \def\CALX_ftom_r #1\xint:% {\expandafter\CALX_ntom\romannumeral0\CALX_nfromraw {\romannumeral0\CALX_fnum_r #1\xint:}}% % \end{macrocode} % \subsubsection{\csh{CALX_fint}} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded, not an I value): %( % \CALX_fint X\xint: -> . %) % Truncation of X towards zero to an integer: s the sign of X (+ for % zero), T the explicit digits of |trunc(X)|, d the first omitted digit % (the last digit of floor(10|X|)), z = 1 if |X| - T is not zero, else 0. % Hence round(X) = s(T + [d >= 5]); ceil(X) = T + z if s is +, else -T; % floor(X) = T if s is +, else -(T + z). X: F, M, or raw A, A[N], A/B, % A/B[N]. % % F with e >= 0 or zero: an integer (\CALX_fnum_b), d = z = 0. F with % e < 0: the m = -e low blocks are omitted, whole blocks; of the n = % ceil(D/8) blocks the min(m, n) lowest are read (\CALX_fint_w: z), d is % the first digit of block m - 1 (0 if m > n); kept blocks (n > m): % \CALX_ntoraw_a. M: an integer. Raw, B = 1: the F value of A 10^N % (\CALX_ffr_a, the digits regrouped in blocks), then as F. B > 1: one % division of |A| 10^(N+1) by B (\CALX_ndivision, shifts \CALX_nshl, k <= % 0 identity): Q = floor(10|X|) and R; T = floor(Q/10) (\CALX_nshr), d = % Q mod 10 (last digit of the lowest block), z = 1 if R > 0 or d > 0. % % \CALX_fintp{A}{B}{N} (use with \romannumeral0; A, B integers without % leading zeros, B > 0, N explicit digits): the same for A/B[N] given by % its parts (xintfrac's \xintTrunc, \xintRound, \xintFloor, \xintCeil). %\end{lverb} % \begin{macrocode} \def\CALX_fintp #1#2{\CALX_fint_rc #2\xint:{#1}{#2}}% \def\CALX_fint #1% {% \if F#1\xint_dothis\CALX_fint_f\fi \if M#1\xint_dothis\CALX_fint_m\fi \xint_orthat\CALX_fint_r #1% }% \def\CALX_fint_m #1#2#3\xint:% {\expanded{ #2\romannumeral0\CALX_mtoraw_t M+#3\xint:.00}}% \def\CALX_fint_f #1#2#3.#4.% {% \ifnum#3=\xint_c_ \xint_dothis\CALX_fint_z\fi \ifnum#4<\xint_c_ \xint_dothis\CALX_fint_n\fi \xint_orthat\CALX_fint_i #2#3.#4.% }% \def\CALX_fint_z #1\xint:{ +0.00}% \def\CALX_fint_i #1#2.#3.#4\xint:% {\expanded{ #1\romannumeral0\CALX_fnum_b F+#2.#3.#4\xint:.00}}% \def\CALX_fint_n #1#2.#3.% {\expandafter\CALX_fint_a\the\numexpr(#2+\xint_c_iii)/\xint_c_viii+#3% \expandafter.\the\numexpr-#3.#1}% \def\CALX_fint_a #1.#2.#3% {% \ifnum#1>\xint_c_ \xint_dothis{\CALX_fint_w #2.0.{\CALX_fint_k#3{#1}}}\fi \ifnum#1=\xint_c_ \xint_dothis{\CALX_fint_w #2.0.{\CALX_fint_t#3}}\fi \xint_orthat {\expandafter\CALX_fint_w\the\numexpr#2+#1.0.{\CALX_fint_u#3}}% }% \def\CALX_fint_w #1.#2.#31#4!% {% \ifnum#1=\xint_c_i \xint_dothis{\CALX_fint_x#4\xint:{#3}{\ifnum#4>\xint_c_ 1\else#2\fi}}\fi \xint_orthat{\expandafter\CALX_fint_w\the\numexpr#1-\xint_c_i \expandafter.\the\numexpr\ifnum#4>\xint_c_ 1\else#2\fi.{#3}}% }% \def\CALX_fint_x #1#2\xint:#3{#3{#1}}% \def\CALX_fint_k #1#2#3#4#5\xint:% {\expanded{ #1\romannumeral0\CALX_ntoraw_a N+#2.#5\xint:.#3#4}}% \def\CALX_fint_t #1#2#3\xint:{\expanded{ #10.#2#3}}% \def\CALX_fint_u #1#2#3\xint:{\expanded{ #10.0#3}}% \def\CALX_fint_r #1\xint:{\CALX_fint_ra #1[0]\xint:}% \def\CALX_fint_ra #1[#2]#3\xint:{\CALX_fint_rb #1/1/\xint:{#2}}% \def\CALX_fint_rb #1/#2/#3\xint:{\CALX_fint_rc #2\xint:{#1}{#2}}% \def\CALX_fint_rc #1#2\xint:#3#4#5% {% \if1#1\if\relax\detokenize{#2}\relax\CALX_fint_rj\fi\fi \CALX_fint_rg{#3}{#4}{#5}% }% \def\CALX_fint_rj #1\CALX_fint_rg#2#3#4% {#1\expandafter\CALX_fint\romannumeral0\CALX_ffr_a#2[#4]\xint:\xint:}% \def\CALX_fint_rg #1#2{\CALX_fint_rs #1\xint:{#2}}% \def\CALX_fint_rs #1#2\xint:#3#4% {% \if-#1\xint_dothis{\CALX_fint_rd -{#2}}\fi \if0#1\xint_dothis\CALX_fint_rz\fi \xint_orthat{\CALX_fint_rd +{#1#2}}{#3}{#4}% }% \def\CALX_fint_rz #1#2{ +0.00}% \def\CALX_fint_rd #1#2#3#4% {\expandafter\CALX_fint_re\romannumeral0\CALX_ndivision {\CALX_nshl{#4+\xint_c_i}{\CALX_nfromraw{#2}}}% {\CALX_nshl{-#4-\xint_c_i}{\CALX_nfromraw{#3}}}#1}% \def\CALX_fint_re #1#2#3{\CALX_fint_rf #2\xint:#3{#1}}% \def\CALX_fint_rf N#1#2.#3\xint:#4#5% {\expanded{ #4\romannumeral0\CALX_ntoraw{\romannumeral0\CALX_nshr \xint_c_i{#5}}.\CALX_fint_q#5\xint:\ifnum#2>\xint_c_ 1\else \ifnum\CALX_fint_q#5\xint:>\xint_c_ 1\else0\fi\fi}}% \def\CALX_fint_q N#1#2.#3\xint:% {\ifnum#2=\xint_c_ 0\else\CALX_fint_l#3\xint:\fi}% \def\CALX_fint_l 1#1#2#3#4#5#6#7#8!#9\xint:{#8}% % \end{macrocode} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded, not an I value; one % of the kind macros): %( % \CALX_fintnX\xint: -> N. %: -> 0 or 1 %) % \CALX_fintn: the native integer s(T + a) from the output s, T, d, z of % \CALX_fint, a = : 1 if |T| must be increased, else 0. % Kinds: \CALX_fintk_f floor (a = z if s is -), \CALX_fintk_c ceil (a = z % if s is +), \CALX_fintk_r round (a = 1 if d >= 5), \CALX_fintk_t trunc % (a = 0). The F value of the result is \CALX_fx_c 0.N\xint:, the M value % \CALX_ntom N. In a \numexpr, T is the integer itself % (the ends of a..b). %\end{lverb} % \begin{macrocode} \def\CALX_fintk_f #1#2#3{\if-#1#3\else0\fi}% \def\CALX_fintk_c #1#2#3{\if-#1 0\else#3\fi}% \def\CALX_fintk_r #1#2#3{\ifnum#2>\xint_c_iv 1\else0\fi}% \def\CALX_fintk_t #1#2#3{0}% \def\CALX_fintn #1#2\xint:% {\expandafter\CALX_fintn_a\romannumeral0\CALX_fint#2\xint:#1}% \def\CALX_fintn_a #1#2.#3#4#5% {% \ifnum#5#1#3#4=\xint_c_ \expandafter\CALX_fintn_b\else \expandafter\CALX_fintn_c\fi #1#2.% }% \def\CALX_fintn_b #1#2.% {\CALX_nfromraw{\expanded{\if-#1\if0#2\else-\fi\fi}#2}}% \def\CALX_fintn_c #1#2.{\CALX_nadd{\CALX_fintn_b#1#2.}{N#11.100000001!}}% % \end{macrocode} % \subsubsection{\csh{CALX_fexact}} %\begin{lverb} % Syntax (use with \romannumeral0; X f-expanded): %( % \CALX_fexact{X} -> Y\xint: %) % Y: X as an exact F value: F and I unchanged (\string on the tag: X may % come from a compiled function), M and raw A, A[N], A/1[N] exactly % (\CALX_ffr_a), raw A/B[N] with B > 1 rounded to \XINTdigits digits. % Ends of a..[d]..b in \xintfloateval. Y is followed by \xint:, as with % \CALX_fround and calxint's \CALX_tom. %\end{lverb} % \begin{macrocode} \def\CALX_fexact #1{\expandafter\CALX_fex_s\romannumeral`&&@#1\xint:}% \def\CALX_fex_s{\expandafter\CALX_fex_a\string}% \def\CALX_fex_a #1% {% \if F#1\xint_dothis{\CALX_fex_f#1}\fi \if I#1\xint_dothis{\CALX_fex_f#1}\fi \if M#1\xint_dothis\CALX_fex_m\fi \xint_orthat{\CALX_fex_r#1}% }% \def\CALX_fex_f #1\xint:{ #1\xint:}% \def\CALX_fex_m #1\xint:% {\expandafter\CALX_ffr_a\romannumeral0\CALX_mtoraw_t M#1\xint:[0]\xint:\xint:}% \def\CALX_fex_r #1\xint:{\CALX_fex_ra #1[0]\xint:{#1}}% \def\CALX_fex_ra #1[#2]#3\xint:{\CALX_fex_rb #1/1/\xint:{#2}}% \def\CALX_fex_rb #1/#2/#3\xint:#4{\CALX_fex_rc #2\xint:{#1[#4]}}% \def\CALX_fex_rc #1#2\xint:#3#4% {% \if1#1\if\relax\detokenize{#2}\relax\CALX_fex_rj\fi\fi \CALX_fex_rg{#3}{#4}% }% \def\CALX_fex_rj #1\CALX_fex_rg#2#3{#1\CALX_ffr_a#2\xint:\xint:}% \def\CALX_fex_rg #1{\CALX_fround\XINTdigits}% % \end{macrocode} % \subsubsection{\csh{CALX_rt_a}} %\begin{lverb} % Syntax (use with \romannumeral0; \CALX_fr_b or \CALX_rt_t, n % digits, X f-expanded): %( % \CALX_rt_a .X\xint: -> Y\xint: %) % Kernel of \calxFpRoundTo, \calxFpTruncTo (end of this file): Y is the % multiple of 10^-n nearest to X (\CALX_fr_b), or between 0 and X % (\CALX_rt_t). n may be negative. % X: F or I value, M value, or raw A, A[N], A/B, A/B[N]. Y: exact F % value (no rounding to P), ties of \calxFpRoundTo away from zero; I % values are returned unchanged. No literal tag in the parameter texts: % the tag of X may have catcode 11. % % F X = s N 10^(8e), D digits: t = -n - 8e low digits of N are dropped. % t <= 0: X. t > D: zero. t = D: zero (trunc), or s 10^-n if N >= % 5 10^(D-1) (round: \CALX_rt_h reads the first digit of the top % block). 1 <= t < D: round: \CALX_fr_b with k = t (the dispatch of % \CALX_fround, which keeps D - t digits); trunc: \CALX_rt_t, t = 8a + c: % a blocks dropped (\CALX_fr_sk), the next block v -> m floor(v/m), m = % 10^c, by (2(10^8 + v) + 1 - m)/(2m) m in \numexpr (no tie). % % Raw X with B = 1 (or no B), and M X (\CALX_mtoraw_t): the exact F value % of A 10^N (\CALX_ffr_a), then the F path. B > 1: Q = trunc(X 10^(n+1)) % by \CALX_fnum_t (one native division), then the F path on Q 10^-(n+1): % truncation at n + 1 decimals changes neither the truncation nor the % rounding at n decimals. % % Every path ends with Y\xint: (the blocks above the kept ones stay in % the stream until that \xint:). %\end{lverb} % \begin{macrocode} \def\CALX_rt_a #1#2.#3% {% \if F#3\xint_dothis{\CALX_rt_f#1#2.}\fi \if I#3\xint_dothis{ #3}\fi \if M#3\xint_dothis{\CALX_rt_m#1#2.}\fi \xint_orthat{\CALX_rt_x#1#2.#3}% }% % \end{macrocode} %\begin{lverb} % \CALX_rt_re {n}{A}{N}: back to \CALX_rt_a with the exact F % value of A 10^N (A f-expanded, N digits). %\end{lverb} % \begin{macrocode} \def\CALX_rt_re #1#2#3#4% {\expandafter\CALX_rt_a\expandafter#1\the\numexpr#2\expandafter.% \romannumeral0\expandafter\CALX_ffr_a\romannumeral`&&@#3[#4]\xint:\xint:}% \def\CALX_rt_m #1#2.#3\xint:% {\CALX_rt_re#1{#2}{\romannumeral0\CALX_mtoraw_t M#3\xint:}{0}}% \def\CALX_rt_x #1#2.#3\xint:{\CALX_rt_xs#1{#2}#3[0]\xint:}% \def\CALX_rt_xs #1#2#3[#4]#5\xint:{\CALX_rt_xt#1{#2}{#4}#3/1/\xint:}% \def\CALX_rt_xt #1#2#3#4/#5/#6\xint:{\CALX_rt_xu#5\xint:#1{#2}{#3}{#4}{#5}}% \def\CALX_rt_xu #1#2\xint:#3#4#5#6#7% {% \if1#1\if\relax\detokenize{#2}\relax\CALX_rt_xj\fi\fi \CALX_rt_xg#3{#4}{#5}{#6}{#7}% }% \def\CALX_rt_xj #1\CALX_rt_xg#2#3#4#5#6{#1\CALX_rt_re#2{#3}{#5}{#4}}% \def\CALX_rt_xg #1#2#3#4% {\expandafter\CALX_rt_xh\the\numexpr#3+#2+\xint_c_i\expandafter.% \the\numexpr-#2-\xint_c_i.#1{#2}{#4}}% \def\CALX_rt_xh #1.#2.#3#4#5#6% {\CALX_rt_re#3{#4}{\romannumeral0\CALX_fnum_t #5/#6/\xint:{#1}}{#2}}% % \end{macrocode} %\begin{lverb} % F path: \CALX_rt_f ...\xint:, t = -8e - n. %\end{lverb} % \begin{macrocode} \def\CALX_rt_f #1#2.#3#4.#5.% {\expandafter\CALX_rt_g\expandafter#1\the\numexpr -\xint_c_viii*#5-#2.#3#4.#5.}% \def\CALX_rt_g #1#2.#3#4.#5.% {% \ifnum#2<\xint_c_i \xint_dothis\CALX_rt_id\fi \ifnum#2>#4 \xint_dothis\CALX_rt_z\fi \ifnum#2=#4 \xint_dothis{\ifx#1\CALX_fr_b\expandafter\CALX_rt_h\else \expandafter\CALX_rt_z\fi}\fi \xint_orthat#1#2.#3#4.#5.% }% \def\CALX_rt_id #1.#2#3.#4.{ F#2#3.#4.}% \def\CALX_rt_z #1\xint:{ F+0.0.\xint:}% % \end{macrocode} %\begin{lverb} % Round, t = D: \CALX_rt_h ... skips the ceil(D/8) - 1 lower % blocks; the top block v has d = D - 8(ceil(D/8) - 1) digits; v >= 5 % 10^(d-1): s 10^(D+8e), else zero. %\end{lverb} % \begin{macrocode} \def\CALX_rt_h #1.#2#3.#4.% {\expandafter\CALX_rt_ha\the\numexpr(#3+\xint_c_iii)/\xint_c_viii-% \xint_c_i.#2#3.#4.}% \def\CALX_rt_ha #1.#2#3.#4.% {\CALX_fr_sk #1.{\CALX_rt_hb{#3-\xint_c_viii*#1}{#2}% {#3+\xint_c_viii*#4}}}% \def\CALX_rt_hb #1#2#31#4!#5\xint:% {% \ifnum1#4<\numexpr\xint_c_e_viii+\xint_c_v*\CALX_pten{#1-\xint_c_i}\relax \expandafter\CALX_rt_z\else\expandafter\CALX_rt_o\fi #2{#3}\xint:% }% \def\CALX_rt_o #1#2% {\expandafter\CALX_ffr_a\expanded{\if-#1-\fi1[\the\numexpr#2]}\xint:}% % \end{macrocode} %\begin{lverb} % Trunc, 1 <= t < D: \CALX_rt_t ..., t = 8a + c, a = % (t - 4)/8 in \numexpr (never a tie). %\end{lverb} % \begin{macrocode} \def\CALX_rt_t #1.% {\expandafter\CALX_rt_ta\the\numexpr(#1-\xint_c_iv)/\xint_c_viii.#1.}% \def\CALX_rt_ta #1.#2.% {\expandafter\CALX_rt_tb\the\numexpr#2-\xint_c_viii*#1.#1.}% \def\CALX_rt_tb #1.#2.#3#4.#5.% {\CALX_fr_sk #2.{\CALX_rt_tc #1.{#3}{#4-\xint_c_viii*#2}{#5+#2}}}% \def\CALX_rt_tc #1.#2#3#4% {% \ifnum#1=\xint_c_ \xint_dothis{\expanded{ F#2\the\numexpr#3.\the\numexpr#4.}}\fi \xint_orthat{\expandafter\CALX_rt_td\the\numexpr\CALX_pten{#1}.% {#2}{#3}{#4}}% }% \def\CALX_rt_td #1.#2#3#41#5!% {\expanded{ F#2\the\numexpr#3.\the\numexpr#4.\the\numexpr (\xint_c_ii*1#5+\xint_c_i-#1)/(\xint_c_ii*#1)*#1!}}% % \end{macrocode} % \subsection{Addition and subtraction} % \subsubsection{\csh{CALX_fadd}, \csh{CALX_fsub}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X, Y % f-expanded F, I or raw values, rounded to P digits first): %( % \CALX_fadd{P}{X}{Y} -> Z Z = round_P(X + Y) %: \CALX_fsub{P}{X}{Y} -> Z Z = round_P(X - Y) %: \CALX_faddu{P}{X}{Y} -> Z (X, Y finite F, at most P digits) %: \CALX_fsubu{P}{X}{Y} -> Z %) % Z: F or I value. %( % \CALX_fhalf{X} -> F... X/2 exact (X finite F; f-expandable) %) % % \CALX_fadd{P}{X}{Y}, \CALX_fsub{P}{X}{Y} (use with \romannumeral0, X and % Y f-expanded): round_P(round_P(X) + round_P(Y)), resp. with -round_P(Y), % round half away from zero, as xint's \XINTinFloatAdd[P] and % \XINTinFloatSub[P] (xint 1.2k and later). % % X is rounded first; \CALX_fa_a grabs it once and checks its tag (X % special: \CALX_fa_spx rounds Y and goes to \CALX_fa_sp$empty: I? % propagates, Inf plus finite is that Inf, Inf plus Inf is that Inf if % the signs agree, else InvalidOperation as in \CALX_nadd). Then Y is % rounded in front of X, which is written back with the add kernel's % terminator and one more \xint: %( \xint:{P}..1;!1;!1;!1;!\W\xint:\xint: %) % is \CALX_fa_bp (add) or \CALX_fa_bm (sub: sign of Y flipped, I? % unchanged); it reads the tag and sign of Y only (Y special: jumper % \CALX_fa_spy, resp. \CALX_fa_spm, result that special value). % % \CALX_fa_c grabs Y's list and X's header; X's list stays in place. % Jumpers (macros delimited by the \fi of their branch, swallowing the % rest of the body): Y zero: X (\CALX_fa_rx); X zero: Y (\CALX_fa_ry). % Cut-off: with t = 8e + D (|X| < 10^t <= 10|X|), if t_X - t_Y >= P + 2 % then |Y| is less than a hundredth of the unit of the last digit of the % P-digit X and the result is X (also when X is a power of ten and Y has % the other sign); symmetrically for Y. This is the test of xint's % \XINT_FL_add_d. % % Otherwise the exact sum: one \expanded writes both native headers and % the e_X - e_Y zero blocks in front of the operand with the larger % exponent (\CALX_fa_z), and \CALX_nadd_y runs with X's list in place % (Y's list is grabbed by \CALX_fa_c and by \CALX_nadd_y). min(e_X, e_Y) % and P are placed in front by a \numexpr chain; \CALX_fa_h receives % .

.N.\xint: and either gives F+0.0. (zero sum) or % reads the digit count and rounds as \CALX_fm_gb does (\CALX_fa_g, % same body, arguments in another order). % % Expanded-operand entries: X\xint:Y\xint:P. The ordinary % \CALX_fadd, \CALX_fsub, \CALX_fmul, \CALX_fdiv, \CALX_fdq % remain available to internal callers with expandable operands. %\end{lverb} % \begin{macrocode} \def\CALX_fadd_in #1\xint:#2\xint:#3.% {\expandafter\CALX_fa_a\romannumeral0\CALX_fround{#3}{#1}{#3}{#2}\CALX_fa_bp}% \def\CALX_fsub_in #1\xint:#2\xint:#3.% {\expandafter\CALX_fa_a\romannumeral0\CALX_fround{#3}{#1}{#3}{#2}\CALX_fa_bm}% \def\CALX_fmul_in #1\xint:#2\xint:#3.% {\ifnum#3>16 \expandafter\CALX_fm_big\else\expandafter\CALX_fm_na\fi {#3}{#1}{#2}}% \def\CALX_fdiv_in #1\xint:#2\xint:#3.% {\expandafter\CALX_fd_a\romannumeral0\CALX_fround{#3}{#1}{#3}{#2}}% \def\CALX_fdq_in #1\xint:#2\xint:#3.#4% {\expandafter\CALX_fdq_a\romannumeral0\CALX_fround{#3}{#1}#4{#3}{#2}}% \def\CALX_fsqr_in #1\xint:#2.% {\ifnum#2>16 \expandafter\CALX_fs_big\else\expandafter\CALX_fs_na\fi {#2}{#1}}% \def\CALX_fsqrt_in #1\xint:#2.% {\expandafter\CALX_frt_a\romannumeral0\CALX_fround{#2}{#1}{#2}}% \def\CALX_fadd #1#2#3% {\expandafter\CALX_fa_a\romannumeral0\CALX_fround{#1}{#2}{#1}{#3}% \CALX_fa_bp}% \def\CALX_fsub #1#2#3% {\expandafter\CALX_fa_a\romannumeral0\CALX_fround{#1}{#2}{#1}{#3}% \CALX_fa_bm}% % \end{macrocode} %\begin{lverb} % \CALX_faddu{P}{X}{Y}, \CALX_fsubu{P}{X}{Y}: X + Y, X - Y rounded to P % digits, for X, Y finite with at most P digits: the input roundings of % \CALX_fadd are skipped (they would leave X, Y unchanged), the rest is % the same code (\CALX_fau builds the input of \CALX_fa_bp, \CALX_fa_bm % as \CALX_fa_a does). The same holds for \CALX_fmulu, \CALX_fsqru and % \CALX_fdivu below. Used where the operands are known to be short % (inverse trigonometric functions). %\end{lverb} % \begin{macrocode} \def\CALX_faddu #1#2#3% {\expandafter\CALX_fau\romannumeral`&&@#2\xint:{#1}{#3}\CALX_fa_bp}% \def\CALX_fsubu #1#2#3% {\expandafter\CALX_fau\romannumeral`&&@#2\xint:{#1}{#3}\CALX_fa_bm}% \def\CALX_fau F#1\xint:#2#3#4% {\expandafter#4\romannumeral`&&@#3\xint:{#2}#11;!1;!1;!1;!\W\xint:\xint:}% % \end{macrocode} %\begin{lverb} % \CALX_fhalf{X}: X/2, exact (X finite). With the blocks b_k of X (b_k % = 0 for k < 0 or k >= n) and exponent e, X/2 has exponent e - 1 and % the blocks %( %: c_j = 5 10^7 (b_j mod 2) + floor(b_(j-1)/2), j = 0, ..., n, %) % since 10^8 b_j / 2 = 5 10^7 (b_j mod 2) + 10^8 floor(b_j/2): no % carry (c_j < 10^8). One \expanded pass over the list (\CALX_fhv_b, % floor(b/2) = round((2b-1)/4) in \numexpr); c_n is dropped if 0. The % digit count is D + 8, minus 1 if floor(b_(n-1)/2) < 10^(d-1), d the % number of digits of b_(n-1) (that is, the leading digit of X is 1). %\end{lverb} % \begin{macrocode} \def\CALX_fhalf #1{\expandafter\CALX_fhv_a\romannumeral`&&@#1\xint:}% \def\CALX_fhv_a F#1#2.#3.#4\xint:% {% \ifnum#2=\xint_c_ \xint_dothis{F#1#2.#3.}\fi \xint_orthat{\expandafter\CALX_fhv_e\expanded{\CALX_fhv_b0.#41;!}% #1#2.#3.}% }% \def\CALX_fhv_b #1.1#2#3!% {\xint_gob_til_sc#2\CALX_fhv_t;\CALX_fhv_c#1.#2#3.}% \def\CALX_fhv_c #1.#2.% {\expandafter\CALX_fhv_d\the\numexpr(\xint_c_ii*#2-\xint_c_i)/\xint_c_iv.% #2.#1.}% \def\CALX_fhv_d #1.#2.#3.% {\the\numexpr\xint_c_e_viii+50000000*(#2-\xint_c_ii*#1)+#3!% \CALX_fhv_b#1.}% \def\CALX_fhv_t;\CALX_fhv_c#1.;.% {\ifnum#1>\xint_c_ \the\numexpr\xint_c_e_viii+#1!\fi\xint:#1.}% \def\CALX_fhv_e #1\xint:#2.#3#4.#5.% {% \expandafter\CALX_fhv_f \the\numexpr#4+\ifnum#2<\ifcase\numexpr#4-\xint_c_i-\xint_c_viii*% ((\xint_c_ii*#4-\xint_c_ix)/16)\relax 1\or 10\or 100\or 1000\or 10000\or 100000\or 1000000\or 10000000\fi \space\xint_c_vii\else\xint_c_viii\fi \expandafter.\the\numexpr#5-\xint_c_i.#3#1% }% \def\CALX_fhv_f #1.#2.#3{F#3#1.#2.}% \def\CALX_fa_a #1#2#3\xint:#4#5#6% {% \if I#1\CALX_fa_spx#2{#4}{#5}#6\fi \expandafter#6\romannumeral0\CALX_fround{#4}{#5}{#4}#2#3% 1;!1;!1;!1;!\W\xint:\xint:% }% \def\CALX_fa_spx #1#2#3#4\fi#5\W\xint:\xint:% {% \fi\expandafter\CALX_fa_spz\expandafter#1\expandafter#4% \romannumeral0\CALX_fround{#2}{#3}% }% \def\CALX_fa_spz #1#2#3#4#5\xint:% {% \ifx#2\CALX_fa_bm\expandafter\CALX_fa_spf\else\expandafter\CALX_fa_sp\fi #3#4I#1% }% \def\CALX_fa_spf #1#2{\expandafter\CALX_fa_sp\expandafter#1% \romannumeral`&&@\CALX_fa_f#2}% \def\CALX_fa_f #1{\csname CALX_fa_f#1\endcsname}% \expandafter\def\csname CALX_fa_f+\endcsname{-}% \expandafter\def\csname CALX_fa_f-\endcsname{+}% \expandafter\def\csname CALX_fa_f?\endcsname{?}% \def\CALX_fa_sp #1#2#3#4% {% \if ?#2\xint_dothis{ I?}\fi \if ?#4\xint_dothis{ I?}\fi \if F#1\xint_dothis{ I#4}\fi \if F#3\xint_dothis{ I#2}\fi \if #2#4\xint_dothis{ I#2}\fi \xint_orthat{\CALX_nsig{InvalidOperation}{inf - inf}{}}% }% \def\CALX_fa_bp #1#2{\if I#1\CALX_fa_spy#2\fi\CALX_fa_c#2}% \def\CALX_fa_bm #1#2% {% \if I#1\CALX_fa_spm#2\fi \if-#2\expandafter\CALX_fa_c\expandafter+\else \expandafter\CALX_fa_c\expandafter-\fi }% \def\CALX_fa_spy #1\fi#2\W\xint:\xint:{\fi\CALX_sp I#1}% \def\CALX_fa_spm #1\fi#2\W\xint:\xint:% {\fi\expandafter\CALX_sp\expandafter I\romannumeral`&&@\CALX_fa_f#1}% \def\CALX_fa_c #1#2.#3.#4\xint:#5#6#7.#8.% {% \ifnum#2=\xint_c_ \CALX_fa_rx#6#7.#8.\fi \ifnum#7=\xint_c_ \CALX_fa_ry#1#2.#3.#4\fi \ifnum\numexpr\xint_c_viii*(#3-#8)+#2-#7>\numexpr#5+\xint_c_i\relax \CALX_fa_ry#1#2.#3.#4\fi \ifnum\numexpr\xint_c_viii*(#8-#3)+#7-#2>\numexpr#5+\xint_c_i\relax \CALX_fa_rx#6#7.#8.\fi \expandafter\CALX_fa_h\the\numexpr\ifnum#3<#8 #3\else#8\fi \expandafter.\the\numexpr#5\expandafter.\romannumeral0\expandafter \CALX_nadd_y\expanded{N#1\the\numexpr(#2+\xint_c_iii)/\xint_c_viii \ifnum#3>#8 +#3-#8.\CALX_fa_z#3-#8.\else.\fi\unexpanded{#4}\xint: N#6\the\numexpr(#7+\xint_c_iii)/\xint_c_viii \ifnum#8>#3 +#8-#3.\CALX_fa_z#8-#3.\else.\fi}% }% \def\CALX_fa_rx #1\fi#2\CALX_nadd_y\expanded#3#41;!1;!1;!1;!\W\xint:\xint:% {\fi\CALX_sp F#1#4}% \def\CALX_fa_ry #1\fi#2\W\xint:\xint:{\fi\CALX_sp F#1}% \def\CALX_fa_z #1.% {% \ifnum\numexpr#1>\xint_c_ 100000000!% \expandafter\CALX_fa_z\the\numexpr#1-\xint_c_i\expandafter.% \fi }% \def\CALX_fa_h #1.#2.N#3#4.% {% \ifnum#4=\xint_c_ \expandafter\CALX_fa_zero\else \expandafter\CALX_fa_g\fi N#3#4.{#1}{#2}% }% \def\CALX_fa_zero N#1#2.#3#4\xint:{ F+0.0.}% \def\CALX_fa_g N#1#2.#3#4#5\xint:% {% \expandafter\CALX_fm_gd\the\numexpr#3\expandafter.\the\numexpr \xint_c_viii*(#2-\xint_c_i)+\CALX_nskip\CALX_fm_gl #2-\xint_c_i.#5\xint:.% #1{#4}#5% }% % \end{macrocode} % \subsection{Multiplication} % \subsubsection{\csh{CALX_fmul}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X, Y % f-expanded F, I or raw values): %( % \CALX_fmul{P}{X}{Y} -> Z Z = round_P(round_P(X) round_P(Y)) %: \CALX_fmulu{P}{X}{Y} -> Z (X, Y finite F, at most P digits) %: \CALX_fmulx{X}{Y} -> Z exact product (X, Y finite F) %: \CALX_faddx{X}{Y} -> Z exact sum (X, Y finite F) %: \CALX_fsubx{X}{Y} -> Z exact difference %) % Z: F or I value. % % \CALX_fmul{P}{X}{Y} (use with \romannumeral0, X and Y f-expanded): % round_P(round_P(X) round_P(Y)), round half away from zero, as xint's % \XINTinFloatMul[P] (xint 1.2k and later). % % Special values first (\CALX_fm_sp$empty: I? propagates, inf times zero % signals InvalidOperation, otherwise I+ or I- by the product of the % signs), then zero. % % P <= 16 and both mantissas with at most 24 digits: each operand is % replaced by its top P significant digits A, rounded, as two blocks % (A = Ah B + Al), and a decimal exponent: X = A 10^(8e + z) (\CALX_fm_xvi % for P = 16, \CALX_fm_ex otherwise). The product of the two A's is computed % by \CALX_fm_k (32 digits), then rounded to P digits and put back in the % native float format by \CALX_fm_r. Otherwise: \CALX_fm_big (P <= 20: % one product of 20 digit operands, 20 < P <= 34: three such products, % P > 34: generic). % % Small path: \CALX_fm_nb grabs X once (X special: jumper % \CALX_fm_nsx) and writes it back after Y, padded with two zero blocks % and closed by \iffalse{\fi} (the closing brace of the \expanded opened % by \CALX_fm_nc), then {P}. \CALX_fm_ntag reads the tag of Y (special: % jumper \CALX_fm_nsy). \CALX_fm_nc grabs Y's list and X's header; X's % list stays in place. Jumpers: a zero operand (\CALX_fm_nz), more than % 24 digits (\CALX_fm_nbig, to \CALX_fm_big). Common case: one % \expanded runs the two extractions (\CALX_fm_ny, \CALX_fm_nx: % \CALX_fm_xvi or \CALX_fm_ex by \csname), the second one on X's list % in place. \CALX_fm_ne regroups % 1Bl!1Bh!z'.{s}{8(e+e')}1Al!1Ah!z. into the input of \CALX_fm_k, % followed by {s}{8(e+e') + z + z'}{P}. % % An operand which is neither F nor I is an xint raw value: \CALX_fm_nk % (X, jumper \CALX_fm_nj) and \CALX_fm_ntk (Y, jumper \CALX_fm_nry) % send both operands to \CALX_fm_big, whose \CALX_fround converts it. % The same for \CALX_fsqr (\CALX_fs_nc, \CALX_fs_ns, \CALX_fs_nr). %\end{lverb} % \begin{macrocode} \def\CALX_fmul #1% {% \ifnum#1>16 \expandafter\CALX_fm_big\else\expandafter\CALX_fm_na\fi % {#1}% }% \def\CALX_fmulu #1% {% \ifnum#1>16 \expandafter\CALX_fmu_b\else\expandafter\CALX_fm_na\fi {#1}% }% \def\CALX_fmu_b #1#2{\expandafter\CALX_fmu\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fmu F#1\xint:#2#3% {\expandafter\CALX_fm_btag\romannumeral`&&@#3\xint:{#2}#1\xint:}% \def\CALX_fm_na #1#2{\expandafter\CALX_fm_nk\romannumeral`&&@#2% \xint:{#1}}% \def\CALX_fm_nk #1% {\if F#1\else\if I#1\else\CALX_fm_nj\fi\fi\CALX_fm_nb #1}% \def\CALX_fm_nj #1\fi\fi\CALX_fm_nb #2#3\xint:#4% {\fi\fi\CALX_fm_big{#4}{#2#3}}% \def\CALX_fm_nb #1#2#3\xint:#4#5% {% \if I#1\CALX_fm_nsx#1#2{#5}\fi \expandafter\CALX_fm_ntk\romannumeral`&&@#5\xint:{#4}#2#3% 100000000!100000000!\xint:\iffalse{\fi}{#4}% }% \def\CALX_fm_nsx #1#2#3\fi#4\iffalse#5#6% {\fi\expandafter\CALX_fm_sp\romannumeral`&&@#3\xint:#1#2\xint:}% \def\CALX_fm_ntk #1% {\if F#1\else\if I#1\else\CALX_fm_nry\fi\fi\CALX_fm_ntag #1}% \def\CALX_fm_nry #1\fi\fi\CALX_fm_ntag #2#3\xint:#4#5% 100000000!100000000!\xint:\iffalse#6#7% {\fi\fi\CALX_fm_big{#4}{F#5}{#2#3}}% \def\CALX_fm_ntag #1#2{\if I#1\CALX_fm_nsy#2\fi\CALX_fm_nc#2}% \def\CALX_fm_nsy #1\fi#2\xint:#3#4100000000!100000000!\xint:\iffalse#5#6% {\fi\CALX_fm_sp I#1\xint:F#4\xint:}% \def\CALX_fm_nc #1#2.#3.#4\xint:#5#6#7.#8.% {% \ifnum#2=\xint_c_ \CALX_fm_nz\fi \ifnum#7=\xint_c_ \CALX_fm_nz\fi \ifnum#2>24 \CALX_fm_nbig{#5}{F#1#2.#3.#4}{F#6#7.#8.}\fi \ifnum#7>24 \CALX_fm_nbig{#5}{F#1#2.#3.#4}{F#6#7.#8.}\fi \expandafter\CALX_fm_ne\expanded{\iffalse}\fi \CALX_fm_ny{#5}{#2}#4100000000!100000000!\xint:% {\if#1#6+\else-\fi}{\the\numexpr\xint_c_viii*(#3+#8)}% \CALX_fm_nx{#5}{#7}% }% \def\CALX_fm_nz\fi#1\iffalse#2#3{\fi\CALX_sp F+0.0.}% \def\CALX_fm_nbig #1#2#3\fi#4\CALX_fm_nx#5#6#7100000000!100000000!\xint:% \iffalse#8#9{\fi\CALX_fm_big{#1}{#3#7}{#2}}% \def\CALX_fm_nx #1% {\csname CALX_fm_\ifnum#1=16 nxvi\else ex\fi\endcsname{#1}}% \let\CALX_fm_ny\CALX_fm_nx \def\CALX_fm_nxvi #1{\CALX_fm_xvi}% \def\CALX_fm_ne #1!#2!#3.#4#5#6!#7!#8.% {\CALX_fm_k #6!#7!#1!#2!{#4}{#5+#8+#3}}% \def\CALX_fm_sp #1#2#3\xint:#4#5#6\xint:% {% \if ?#2\xint_dothis{ I?}\fi \if ?#5\xint_dothis{ I?}\fi \ifnum\if F#1\CALX_nsp_z#3\xint:\else\if F#4\CALX_nsp_z#6\xint:\else \xint_c_i\fi\fi=\xint_c_ \xint_dothis{\CALX_nsig{InvalidOperation}{inf * 0}{}}\fi \xint_orthat{\CALX_nsp_ps#2#5}% }% % \end{macrocode} % \subsubsection{\csh{CALX_fm_xvi}} %\begin{lverb} % \CALX_fm_xvi{D}\xint: (P = 16, D <= 24, the blocks padded with % two zero blocks): 1Al!1Ah!z. with A = Ah B + Al of exactly 16 digits. %- D = 16: A is the mantissa, z = 0. %- D < 16: A = M 10^(16-D), z = D - 16: \CALX_fm_la (s = 16 - D, roman % numeral) emits Al and calls \CALX_fm_lb for Ah; digits are only moved, % as all blocks have exactly eight digits. %- 16 < D < 24: A = round(M/10^z), z = D - 16: \CALX_fm_ua, % \CALX_fm_ub, \CALX_fm_uc cut the digits; the digit just below A decides % the rounding (half away from zero: no tie rule needed). %- D = 24: A is the two top blocks, rounded with the top digit of the low % block (\CALX_fm_xvie). % % \CALX_fm_xvif{Al'}{Ah}{z}, Al' <= 10^8 (an expression): carry to Ah; if % A becomes 10^16, A = 10^15 and z + 1. %\end{lverb} % \begin{macrocode} \def\CALX_fm_xvi #11#2!1#3!1#4!#5\xint:% {% \ifnum#1<16 \csname CALX_fm_la\the\numexpr16-#1\endcsname #2!#3!\the% \numexpr#1-16.% \else\ifnum#1=16 1#2!1#3!0.% \else\ifnum#1=24 \CALX_fm_xvie{#3}{#4}{#2}% \else \csname CALX_fm_ua\the\numexpr#1-16\endcsname #2!#3!#4!% \fi\fi\fi }% \def\CALX_fm_uc #1#2#3#4#5!% {% \CALX_fm_xvif{#1+\ifnum#3>\xint_c_iv\xint_c_i\else\xint_c_\fi}% {#5*\CALX_pten{\xint_c_viii-#4}+#2}{#4}% }% \expandafter\def\csname CALX_fm_ua1\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubi{{#1#2#3#4#5#6#7}{#8}}}% \expandafter\def\csname CALX_fm_ua2\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubii{{#1#2#3#4#5#6}{#7}}}% \expandafter\def\csname CALX_fm_ua3\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubiii{{#1#2#3#4#5}{#6}}}% \expandafter\def\csname CALX_fm_ua4\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubiv{{#1#2#3#4}{#5}}}% \expandafter\def\csname CALX_fm_ua5\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubv{{#1#2#3}{#4}}}% \expandafter\def\csname CALX_fm_ua6\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubvi{{#1#2}{#3}}}% \expandafter\def\csname CALX_fm_ua7\endcsname #1#2#3#4#5#6#7#8!{\CALX_fm_ubvii{{#1}{#2}}}% \def\CALX_fm_ubi #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#9% \xint_firstoftwo#1}{#2#3#4#5#6#7#8}{\xint_secondoftwo#1}{1}}% \def\CALX_fm_ubii #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#8#9% \xint_firstoftwo#1}{#2#3#4#5#6#7}{\xint_secondoftwo#1}{2}}% \def\CALX_fm_ubiii #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#7#8#9% \xint_firstoftwo#1}{#2#3#4#5#6}{\xint_secondoftwo#1}{3}}% \def\CALX_fm_ubiv #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#6#7#8#9% \xint_firstoftwo#1}{#2#3#4#5}{\xint_secondoftwo#1}{4}}% \def\CALX_fm_ubv #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#5#6#7#8#9% \xint_firstoftwo#1}{#2#3#4}{\xint_secondoftwo#1}{5}}% \def\CALX_fm_ubvi #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#4#5#6#7#8#9% \xint_firstoftwo#1}{#2#3}{\xint_secondoftwo#1}{6}}% \def\CALX_fm_ubvii #1#2#3#4#5#6#7#8#9!{\CALX_fm_uc{#3#4#5#6#7#8#9% \xint_firstoftwo#1}{#2}{\xint_secondoftwo#1}{7}}% \expandafter\def\csname CALX_fm_la1\endcsname #1#2#3#4#5#6#7#8!{1#2#3#4#5#6#7#80!\CALX_fm_lbi{#1}}% \def\CALX_fm_lbi #1#2#3#4#5#6#7#8#9!{1#3#4#5#6#7#8#9#1!}% \expandafter\def\csname CALX_fm_la2\endcsname #1#2#3#4#5#6#7#8!{1#3#4#5#6#7#800!\CALX_fm_lbii{#1#2}}% \def\CALX_fm_lbii #1#2#3#4#5#6#7#8#9!{1#4#5#6#7#8#9#1!}% \expandafter\def\csname CALX_fm_la3\endcsname #1#2#3#4#5#6#7#8!{1#4#5#6#7#8000!\CALX_fm_lbiii{#1#2#3}}% \def\CALX_fm_lbiii #1#2#3#4#5#6#7#8#9!{1#5#6#7#8#9#1!}% \expandafter\def\csname CALX_fm_la4\endcsname #1#2#3#4#5#6#7#8!{1#5#6#7#80000!\CALX_fm_lbiv{#1#2#3#4}}% \def\CALX_fm_lbiv #1#2#3#4#5#6#7#8#9!{1#6#7#8#9#1!}% \expandafter\def\csname CALX_fm_la5\endcsname #1#2#3#4#5#6#7#8!{1#6#7#800000!\CALX_fm_lbv{#1#2#3#4#5}}% \def\CALX_fm_lbv #1#2#3#4#5#6#7#8#9!{1#7#8#9#1!}% \expandafter\def\csname CALX_fm_la6\endcsname #1#2#3#4#5#6#7#8!{1#7#8000000!\CALX_fm_lbvi{#1#2#3#4#5#6}}% \def\CALX_fm_lbvi #1#2#3#4#5#6#7#8#9!{1#8#9#1!}% \expandafter\def\csname CALX_fm_la7\endcsname #1#2#3#4#5#6#7#8!{1#80000000!% \CALX_fm_lbvii{#1#2#3#4#5#6#7}}% \def\CALX_fm_lbvii #1#2#3#4#5#6#7#8#9!{1#9#1!}% \expandafter\def\csname CALX_fm_la8\endcsname #1#2#3#4#5#6#7#8!{100000000!% \CALX_fm_lbviii{#1#2#3#4#5#6#7#8}}% \def\CALX_fm_lbviii #1#2#3#4#5#6#7#8#9!{1#1!}% \expandafter\def\csname CALX_fm_la9\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#2#3#4#5#6#7#80!}% \expandafter\def\csname CALX_fm_la10\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#3#4#5#6#7#800!}% \expandafter\def\csname CALX_fm_la11\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#4#5#6#7#8000!}% \expandafter\def\csname CALX_fm_la12\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#5#6#7#80000!}% \expandafter\def\csname CALX_fm_la13\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#6#7#800000!}% \expandafter\def\csname CALX_fm_la14\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#7#8000000!}% \expandafter\def\csname CALX_fm_la15\endcsname #1#2#3#4#5#6#7#8!#9!{100000000!1#80000000!}% \def\CALX_fm_xvie #1#2#3% {\CALX_fm_xvif{#1+\ifnum#3>49999999 \xint_c_i\else\xint_c_\fi}{#2}{% \xint_c_viii}}% \def\CALX_fm_xvif #1#2#3% {% \ifnum\numexpr#1<\xint_c_e_viii \the\numexpr#1+\xint_c_e_viii!\the\numexpr#2+\xint_c_e_viii!\the% \numexpr#3.% \else \ifnum\numexpr#2=99999999 100000000!110000000!\the\numexpr#3+\xint_c_i.% \else 100000000!\the\numexpr#2+\xint_c_i+\xint_c_e_viii!\the\numexpr#3.% \fi \fi }% % \end{macrocode} % \subsubsection{\csh{CALX_fm_ex}} %\begin{lverb} % P < 16: \CALX_fm_ex{P}{D}\xint: gives 1Al!1Ah!z. with A the % mantissa if D <= P (z = 0), else A = round(M/10^z), z = D - P, by % \CALX_fm_re. % % \CALX_fm_re{c}{B3}{B2}{B1}{B0}{P}, 1 <= c <= 31: Q = B3 ... B0 (four % blocks) rounded to round(Q/10^c) < 10^P (at most 16 digits), with the % same output. With c = 8a + b (\CALX_fm_ref selects the three blocks % X2, X1, X0 from index a and the block Xm below them) and p = 10^b: % Al = floor(X0/p) + (X1 mod p) 10^8/p, Ah = floor(X1/p) + (X2 mod p) % 10^8/p, plus one if the first dropped digit is >= 5 (b > 0: 2 (X0 mod p) % >= p; b = 0: Xm >= 5 10^7). \CALX_fm_rec, \CALX_fm_red$empty: carry, and % 10^P becomes 10^(P-1) with c + 1. % % \CALX_fm_fd{x}{p} = floor(x/p) = (2x - p + 1)/(2p) in \numexpr (no tie, % 0 <= x < 2^30). \CALX_pten{k} = 10^k, 0 <= k <= 8. % \CALX_ndig{v} (calxcore): number of digits of 0 < v < 10^8. %\end{lverb} % \begin{macrocode} \def\CALX_fm_ex #1#2#3!1#4!1#5!#6\xint:% {% \ifnum#1<#2 % P may be the token \XINTdigits: no space may follow it \CALX_fm_re{#2-#1}{0}{#5}{#4}{\xint_gobble_i#3}{#1}% \else #3!1#4!0.% \fi }% \def\CALX_fm_fd #1#2{((\xint_c_ii*(#1)-(#2)+\xint_c_i)/(\xint_c_ii*(#2)))}% \def\CALX_fm_re #1#2#3#4#5#6% {% \expandafter\CALX_fm_rea\the\numexpr(\xint_c_ii*(#1)-\xint_c_vii)/16.% #1.#2.#3.#4.#5.#6.% }% \def\CALX_fm_rea #1.#2.% {\expandafter\CALX_fm_ref\the\numexpr\CALX_pten{#2-% \xint_c_viii*#1}.#1.#2.}% \def\CALX_fm_ref #1.#2.#3.#4.#5.#6.#7.#8.% {% \ifcase#2 \xint_dothis{\CALX_fm_reb #1.#3.#5.#6.#7.0.#8.}% \or \xint_dothis{\CALX_fm_reb #1.#3.#4.#5.#6.#7.#8.}% \or \xint_dothis{\CALX_fm_reb #1.#3.0.#4.#5.#6.#8.}% \fi \xint_orthat{\CALX_fm_reb #1.#3.0.0.#4.#5.#8.}% }% \def\CALX_fm_reb #1.#2.#3.#4.#5.#6.#7.% {% \expandafter\CALX_fm_rec\the\numexpr \CALX_fm_fd{#5}{#1}+(#4-\CALX_fm_fd{#4}{#1}*#1)*(\xint_c_e_viii/#1)% \ifnum#1=\xint_c_i \ifnum#6>49999999 +\xint_c_i\fi \else\ifnum\numexpr\xint_c_ii*(#5-\CALX_fm_fd{#5}{#1}*#1)<#1 \else +\xint_c_i\fi\fi\expandafter.% \the\numexpr\CALX_fm_fd{#4}{#1}+(#3-\CALX_fm_fd{#3}{#1}*#1)*(% \xint_c_e_viii/#1).#2.#7.% }% \def\CALX_fm_rec #1.#2.% {% \ifnum#1=\xint_c_e_viii \xint_dothis{\expandafter\CALX_fm_red\the\numexpr#2+\xint_c_i.0.}\fi \xint_orthat{\CALX_fm_red #2.#1.}% }% \def\CALX_fm_red #1.#2.#3.#4.% {% \ifnum\ifnum#4>\xint_c_viii #1<\CALX_pten{#4-\xint_c_viii}\else#2<% \CALX_pten{#4}\fi \space \expandafter\xint_secondoftwo\else\expandafter\xint_firstoftwo\fi {\ifnum#4>\xint_c_viii 100000000!\the\numexpr\CALX_pten{#4-9}+% \xint_c_e_viii!% \else\the\numexpr\CALX_pten{#4-\xint_c_i}+\xint_c_e_viii!100000000!\fi \the\numexpr#3+\xint_c_i.}% {\the\numexpr#2+\xint_c_e_viii!\the\numexpr#1+\xint_c_e_viii!#3.}% }% % \end{macrocode} % \subsubsection{\csh{CALX_fm_k}} %\begin{lverb} % \CALX_fm_k 1Al!1Ah!1Bl!1Bh!{s}{E}{P}: each block is split into two % groups of four digits (\CALX_fm_k ... \CALX_fm_ke, digits only moved), the % seven column sums are computed in \numexpr from the lowest one % (\CALX_fm_kf), each with 10^9 added, so that the carry is the first five % digits after the leading 1 and the group of four digits of the product is % the last four (\CALX_fm_s). \CALX_fm_o, \CALX_fm_p regroup the eight % groups into the four blocks of the product, top first: % \CALX_fm_r{B3}{B2}{B1}{B0}{s}{E}{P}. %\end{lverb} % \begin{macrocode} \def\CALX_fm_k 1#1#2#3#4#5!{\CALX_fm_kb{#5}{#1#2#3#4}}% \def\CALX_fm_kb #1#21#3#4#5#6#7!{\CALX_fm_kc{#1}{#2}{#7}{#3#4#5#6}}% \def\CALX_fm_kc #1#2#3#41#5#6#7#8#9!{% \CALX_fm_kd{#1}{#2}{#3}{#4}{#9}{#5#6#7#8}}% \def\CALX_fm_kd #1#2#3#4#5#61#7#8#9% {\CALX_fm_ke{#1}{#2}{#3}{#4}{#5}{#6}{#7#8#9}}% \def\CALX_fm_ke #1#2#3#4#5#6#7#8#9!{% \CALX_fm_kf{#1}{#2}{#3}{#4}{#5}{#6}{#9}{#7#8}}% \def\CALX_fm_kf #1#2#3#4#5#6#7#8% {% \expandafter\CALX_fm_o\the\numexpr1000000000+#4*#8+% \expandafter\CALX_fm_s\the\numexpr1000000000+#3*#8+#4*#7+% \expandafter\CALX_fm_s\the\numexpr1000000000+#2*#8+#3*#7+#4*#6+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#8+#2*#7+#3*#6+#4*#5+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#7+#2*#6+#3*#5+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#6+#2*#5+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#5;% }% \def\CALX_fm_s 1#1#2#3#4#5{#1#2#3#4#5;}% \def\CALX_fm_o 1#1#2#3#4#5#6#7#8#9;{\CALX_fm_p{#2#3#4#5#6#7#8#9}}% \def\CALX_fm_p #1#2;#3;#4;#5;#6;#7;{\CALX_fm_r{#1}{#2#3}{#4#5}{#6#7}}% % \end{macrocode} % \subsubsection{\csh{CALX_fm_r}} %\begin{lverb} % Rounding of the product Q to P digits, and output. % % P = 16 (\CALX_fm_rxvi): both A's have 16 digits, so Q has 31 or 32 % digits. 32 digits (B3 >= 10^7): R = B3 B + B2 rounded with the top digit % of B1, c = 16; 31 digits: R = floor(Q/10^15), cut by \CALX_fm_rft (digits % only moved), c = 15. Then \CALX_fm_xvif (carry, 10^16). R has 16 digits; % with E + c = 8e + r (0 <= r < 8), the result is F<16+r>.. followed % by the blocks of R 10^r: \CALX_fm_oa emits the low block and calls % \CALX_fm_ob for the two others (\CALX_fm_oa for r = 0: R itself). % % P < 16 (\CALX_fm_rg, \CALX_fm_rr): the number of digits of Q gives % c = D(Q) - P; if c > 0, \CALX_fm_re. \CALX_fm_no ... \CALX_fm_nt$empty: the % output as above, with D(R) computed and R 10^r by \CALX_fm_fd. % % floor(E/8) = (2E - 7)/16 in \numexpr (never a tie). %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_fm_oa0\endcsname #1!#2!{1#1!1#2!}% \expandafter\def\csname CALX_fm_oa1\endcsname #1#2#3#4#5#6#7#8!{1#2#3#4#5#6#7#80!\CALX_fm_obi{#1}}% \def\CALX_fm_obi #1#2#3#4#5#6#7#8#9!{1#3#4#5#6#7#8#9#1!10000000#2!}% \expandafter\def\csname CALX_fm_oa2\endcsname #1#2#3#4#5#6#7#8!{1#3#4#5#6#7#800!\CALX_fm_obii{#1#2}}% \def\CALX_fm_obii #1#2#3#4#5#6#7#8#9!{1#4#5#6#7#8#9#1!1000000#2#3!}% \expandafter\def\csname CALX_fm_oa3\endcsname #1#2#3#4#5#6#7#8!{1#4#5#6#7#8000!\CALX_fm_obiii{#1#2#3}}% \def\CALX_fm_obiii #1#2#3#4#5#6#7#8#9!{1#5#6#7#8#9#1!100000#2#3#4!}% \expandafter\def\csname CALX_fm_oa4\endcsname #1#2#3#4#5#6#7#8!{1#5#6#7#80000!\CALX_fm_obiv{#1#2#3#4}}% \def\CALX_fm_obiv #1#2#3#4#5#6#7#8#9!{1#6#7#8#9#1!10000#2#3#4#5!}% \expandafter\def\csname CALX_fm_oa5\endcsname #1#2#3#4#5#6#7#8!{1#6#7#800000!\CALX_fm_obv{#1#2#3#4#5}}% \def\CALX_fm_obv #1#2#3#4#5#6#7#8#9!{1#7#8#9#1!1000#2#3#4#5#6!}% \expandafter\def\csname CALX_fm_oa6\endcsname #1#2#3#4#5#6#7#8!{1#7#8000000!\CALX_fm_obvi{#1#2#3#4#5#6}}% \def\CALX_fm_obvi #1#2#3#4#5#6#7#8#9!{1#8#9#1!100#2#3#4#5#6#7!}% \expandafter\def\csname CALX_fm_oa7\endcsname #1#2#3#4#5#6#7#8!{1#80000000!% \CALX_fm_obvii{#1#2#3#4#5#6#7}}% \def\CALX_fm_obvii #1#2#3#4#5#6#7#8#9!{1#9#1!10#2#3#4#5#6#7#8!}% \def\CALX_fm_r #1#2#3#4#5#6#7% {% \ifnum#7=16 \expandafter\CALX_fm_rxvi\else\expandafter\CALX_fm_rg\fi {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_fm_rxvi #1#2#3#4#5#6#7% {% \expandafter\CALX_fm_ox\expanded{% \ifnum#1>9999999 \CALX_fm_xvif{#2+\ifnum#3>49999999 \xint_c_i\else\xint_c_\fi}{#1}{16}% \else \CALX_fm_rft #1!#2!#3!% \fi}{#5}{#6}% }% \def\CALX_fm_rft #1#2!#3#4!#5#6#7!% {\CALX_fm_xvif{#4#5+\ifnum#6>\xint_c_iv\xint_c_i\else\xint_c_% \fi}{#2#3}{15}}% \def\CALX_fm_ox 1#1!1#2!#3.#4#5% {\expandafter\CALX_fm_oy\the\numexpr#5+#3.#1.#2.#4}% \def\CALX_fm_oy #1.% {\expandafter\CALX_fm_oz\the\numexpr(\xint_c_ii*#1-\xint_c_vii)/16.#1.}% \def\CALX_fm_oz #1.#2.% {\expandafter\CALX_fm_ow\the\numexpr#2-\xint_c_viii*#1.#1.}% \def\CALX_fm_ow #1.#2.#3.#4.#5% {% \expanded{ F#5\the\numexpr16+#1.#2.% \csname CALX_fm_oa#1\endcsname#3!#4!}% }% \def\CALX_fm_rg #1#2#3#4#5#6#7% {% \expandafter\CALX_fm_rr\the\numexpr \ifnum#1>\xint_c_ 24+\CALX_ndig{#1}\else \ifnum#2>\xint_c_ 16+\CALX_ndig{#2}\else \ifnum#3>\xint_c_ 8+\CALX_ndig{#3}\else\CALX_ndig{#4}\fi\fi\fi-#7.% {#1}{#2}{#3}{#4}{#5}{#6}{#7}% }% \def\CALX_fm_rr #1.#2#3#4#5#6#7#8% {% \ifnum#1>\xint_c_ \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expandafter\CALX_fm_no\expanded{\CALX_fm_re{#1}{#2}{#3}{#4}{#5}{#8}}}% {\CALX_fm_no 1#5!1#4!0.}{#6}{#7}% }% \def\CALX_fm_no 1#1!1#2!#3.#4#5% {% \expandafter\CALX_fm_nq\the\numexpr#5+#3\expandafter.% \the\numexpr\ifnum#2>\xint_c_ 8+\CALX_ndig{#2}\else\CALX_ndig{#1}% \fi.#1.#2.#4% }% \def\CALX_fm_nq #1.% {\expandafter\CALX_fm_nr\the\numexpr(\xint_c_ii*#1-\xint_c_vii)/16.#1.}% \def\CALX_fm_nr #1.#2.% {\expandafter\CALX_fm_ns\the\numexpr#2-\xint_c_viii*#1.#1.}% \def\CALX_fm_ns #1.% {\expandafter\CALX_fm_nt\the\numexpr\CALX_pten{\xint_c_viii-#1}.#1.}% \def\CALX_fm_nt #1.#2.#3.#4.#5.#6.#7% {% \expanded{ F#7\the\numexpr#4+#2.#3.% \the\numexpr(#5-\CALX_fm_fd{#5}{#1}*#1)*\CALX_pten{#2}+% \xint_c_e_viii!% \ifnum\numexpr#4+#2>\xint_c_viii \the\numexpr\CALX_fm_fd{#5}{#1}+(#6-\CALX_fm_fd{#6}{#1}*#1)*% \CALX_pten{#2}% +\xint_c_e_viii!\fi \ifnum\numexpr#4+#2>16 \the\numexpr\CALX_fm_fd{#6}{#1}+\xint_c_e_viii!% \fi}% }% % \end{macrocode} % \subsubsection{\csh{CALX_fm_q}} %\begin{lverb} % P <= 20 after \CALX_fround of both operands (P > 16, and also P <= 16 when % a mantissa has more than 24 digits). Each mantissa M (D digits) is read % as A = M 10^(20-D), exactly 20 digits (D <= 27 after rounding: the % dropped digits are zeros), in groups of four digits, low group first: % x0.x1.x2.x3.x4. (\CALX_fq_x$empty: \CALX_fq_r reverses the n blocks, % \CALX_fq_s drops the z leading zeros of the top block, \CALX_fq_ga, % _gb, _gc take 20 digits, digits only moved). X Y = A A' 10^E with %( %: E = 8(e + e') + D + D' - 40. %) % \CALX_fm_qa x0.x1.x2.x3.x4.y0.y1.y2.y3.y4. computes the 40 digits of A A' % with one chain of nine \numexpr (one per column of the products of % groups, 10^9 added, carry by \CALX_fm_s as in \CALX_fm_k). Its nine % arguments are the five x and four y; it only moves tokens: the five % columns using y4 are passed to \CALX_fm_qb ending with x*, the four % lower columns as a ready tail; \CALX_fm_qb (seven arguments) appends y4. % % \CALX_fq_o keeps the top 23 or 24 digits S of A A' (P + 1 digits are % enough for round half away from zero), exponent E + 16. \CALX_fq_p, % _q, _t$empty: with e = floor(E/8) and r = E - 8e, the mantissa S 10^r is % cut in blocks (\CALX_fq_bl, after z leading zeros, z the complement of % len(S) + r to a multiple of 8) and \CALX_fround{P} gives the result. %\end{lverb} % \begin{macrocode} \def\CALX_fm_q #1#2#3#4#5#6#7#8% {% \expandafter\CALX_fm_qa\expanded{\CALX_fq_x{#2}#4\xint:\CALX_fq_x{#6}#8% \xint:% {\if#1#5+\else-\fi}{\the\numexpr\xint_c_viii*(#3+#7)+#2+#6-40}}% }% \def\CALX_fq_x #1{\expandafter\CALX_fq_xa\the\numexpr(\xint_c_ii*#1+% \xint_c_vii)/16.#1.}% \def\CALX_fq_xa #1.#2.% {\csname CALX_fq_r#1\endcsname{\the\numexpr% \xint_c_viii*#1-#2}}% \expandafter\def\csname CALX_fq_r1\endcsname #11#2!#3\xint:% {\csname CALX_fq_s#1\endcsname #200000000000000000000\xint:}% \expandafter\def\csname CALX_fq_r2\endcsname #11#2!1#3!#4\xint:% {\csname CALX_fq_s#1\endcsname #3#200000000000000000000% \xint:}% \expandafter\def\csname CALX_fq_r3\endcsname #11#2!1#3!1#4!#5\xint:% {\csname CALX_fq_s#1\endcsname #4#3#200000000000000000000% \xint:}% \expandafter\def\csname CALX_fq_r4\endcsname #11#2!1#3!1#4!1#5!#6\xint:% {\csname CALX_fq_s#1\endcsname #5#4#3#200000000000000000000% \xint:}% \expandafter\def\csname CALX_fq_s0\endcsname {\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s1\endcsname #1{\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s2\endcsname #1#2{\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s3\endcsname #1#2#3{\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s4\endcsname #1#2#3#4{\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s5\endcsname #1#2#3#4#5{\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s6\endcsname #1#2#3#4#5#6{\CALX_fq_ga}% \expandafter\def\csname CALX_fq_s7\endcsname #1#2#3#4#5#6#7{\CALX_fq_ga}% \def\CALX_fq_ga #1#2#3#4#5#6#7#8{\CALX_fq_gb{#5#6#7#8.#1#2#3#4.}}% \def\CALX_fq_gb #1#2#3#4#5#6#7#8#9{\CALX_fq_gc{#6#7#8#9.#2#3#4#5.#1}}% \def\CALX_fq_gc #1#2#3#4#5#6\xint:{#2#3#4#5.#1}% \def\CALX_fm_qa #1.#2.#3.#4.#5.#6.#7.#8.#9.% {% \CALX_fm_qb{#5*}{#5*#9+#4*}{#4*#9+#5*#8+#3*}{#3*#9+#4*#8+#5*#7+#2*}% {#2*#9+#3*#8+#4*#7+#5*#6+#1*}% {\expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#9+#2*#8+#3*#7+#4*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#8+#2*#7+#3*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#7+#2*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#6;}% }% \def\CALX_fm_qb #1#2#3#4#5#6#7.% {% \expandafter\CALX_fm_qo\the\numexpr\xint_c_e_ix+#1#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#2#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#3#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#4#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#5#7+#6% }% \def\CALX_fm_qo 1#1#2#3#4#5#6#7#8#9;{\CALX_fm_qp{#2#3#4#5#6#7#8#9}}% \def\CALX_fm_qp #1#2;#3;#4;#5;#6;#7;#8;#9;{\CALX_fq_o{#1}{#2#3#4#5}}% \def\CALX_fq_o #1#2#3#4% {% \expandafter\CALX_fq_p\expanded{\ifnum#1>9999999 {24}{#1}\else{23}{% \xint_gobble_i#1}\fi {#2}{#3}{\the\numexpr#4+16}}% }% \def\CALX_fq_p #1#2#3#4#5% len, top, rest, s, E (P follows) {% \expandafter\CALX_fq_q\the\numexpr(\xint_c_ii*#5-% \xint_c_vii)/16.#1.{#2#3}{#4}{#5}% }% \def\CALX_fq_q #1.#2.#3#4#5% e, len, S, s, E (P follows) {% \expandafter\CALX_fq_t\the\numexpr#5-\xint_c_viii*#1.#2.{#1}{#3}{#4}% }% \def\CALX_fq_t #1.#2.#3#4#5#6% r, len, e, S, s, P {% \CALX_fnround{#6}{\expanded{ F#5\the\numexpr#2+#1.#3.% \expandafter\CALX_fq_bl\expandafter{\expandafter}\expanded{% \CALX_ffr_zs{\numexpr\xint_c_viii*((\xint_c_ii*(#2+#1)+% \xint_c_vii)/16)-#2-#1\relax}% #4\CALX_ffr_zs{#1}}\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:}}% }% \def\CALX_fq_bl #1#2#3#4#5#6#7#8#9% {\xint_gob_til_xint: #2\CALX_fq_ble\xint:% \CALX_fq_bl{1#2#3#4#5#6#7#8#9!#1}}% \def\CALX_fq_ble\xint:\CALX_fq_bl#1{\CALX_fq_bly#1}% \def\CALX_fq_bly #1!{}% % \end{macrocode} % \subsubsection{\csh{CALX_fm_v}} %\begin{lverb} % 20 < P <= 24, after \CALX_fround of both operands. Each mantissa M (D % digits, D <= 32, the digits after the 24th are zeros) is read as % A = M 10^(24-D), exactly 24 digits, in six groups of four digits: % x0.x1.x2.x3.x4.x5. low group first for X (\CALX_fv_x, \CALX_fv_ga, _gb, % _gc), y5.y4.y3.y2.y1.y0. high group first for Y (\CALX_fv_ma, _mb, % _mc), digits only moved (\CALX_fv_r reverses the n blocks, % \CALX_fh_s drops the z leading zeros of the top block). X Y = A A' % 10^E with %( %: E = 8(e + e') + D + D' - 48. %) % With c_k the sum of the x_i y_j, i + j = k, A A' is the sum of the c_k % 10^(4k), k = 0..10. \CALX_fv_ka and \CALX_fv_kb compute the columns % c_4 to c_10 in one chain of seven \numexpr (10^9 added, carry by % \CALX_fm_s as in \CALX_fm_qa), 26 products. \CALX_fv_ka (nine % arguments: the six x, then y5, y4, y3) only moves tokens: it writes the % three top columns, the part of c_7 without y2 ending with x5*, then % \CALX_fv_kb with the parts of c_6, c_5, c_4 without y2, y1, y0 (each % ending with the x to be multiplied by y2) and x3, x4, x5; \CALX_fv_kb % (nine arguments, the last three y2, y1, y0) completes the columns. % % Truncation: W, the sum of the c_k 10^(4k) for k >= 4, is computed % exactly; A A' - W, the sum for k <= 3, is less than 4.0004 10^20 since % c_k <= (k+1)(10^4-1)^2. Let V = W 10^(-16) (31 or 32 digits, top column % c_10 >= 10^6 as x5, y5 >= 1000) and m >= 7 the number of digits of V % below the rounding position. The omitted part, less than 40004 units of % V, changes the result only if V mod 10^m lies in [5 10^(m-1) - 40004, % 5 10^(m-1)): the digits of V from position 5 to m-2 are 9, the digit % m-1 is 4, and V mod 10^5 >= 59996. \CALX_fv_t and \CALX_fv_u test a % necessary condition on the digits 4 to 7 of V (the group of c_5): digit % 5 is 9 and digit 4 is at least 5, and digit 6 is 4 (m = 7), digits 6 % and 7 are 9 and 4 (m = 8), digits 6 and 7 are 9 (m >= 9). If it holds, % the exact product \CALX_fm_g runs (its call follows the arguments in % the input stream). Otherwise \CALX_fv_ok drops the group of c_4 and % finishes as \CALX_fm_q (\CALX_fq_p) with the 27 or 28 top digits of % A A' and exponent E + 20. %\end{lverb} % \begin{macrocode} \def\CALX_fm_v #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_fv_ka\expanded{\CALX_fv_x{#2}\CALX_fv_ga#4\xint:% \CALX_fv_x{#6}\CALX_fv_ma#8\xint:% {\if#1#5+\else-\fi}{\the\numexpr\xint_c_viii*(#3+#7)+#2+#6-48}}{#9}% {\CALX_fm_g{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}% }% \def\CALX_fv_x #1{\expandafter\CALX_fv_xa\the\numexpr(\xint_c_ii*#1+% \xint_c_vii)/16.#1.}% \def\CALX_fv_xa #1.#2.% {\csname CALX_fv_r#1\endcsname{\the\numexpr% \xint_c_viii*#1-#2}}% \expandafter\def\csname CALX_fv_r1\endcsname #1#21#3!#4\xint:% {\csname CALX_fh_s#1\endcsname#2#3000000000000000000000000% \xint:}% \expandafter\def\csname CALX_fv_r2\endcsname #1#21#3!1#4!#5\xint:% {\csname CALX_fh_s#1\endcsname#2#4#3000000000000000000000000% \xint:}% \expandafter\def\csname CALX_fv_r3\endcsname #1#21#3!1#4!1#5!#6\xint:% {\csname CALX_fh_s#1% \endcsname#2#5#4#3000000000000000000000000\xint:}% \expandafter\def\csname CALX_fv_r4\endcsname #1#21#3!1#4!1#5!1#6!#7\xint:% {\csname CALX_fh_s#1% \endcsname#2#6#5#4#3000000000000000000000000\xint:}% \def\CALX_fv_ga #1#2#3#4#5#6#7#8{\CALX_fv_gb{#5#6#7#8.#1#2#3#4.}}% \def\CALX_fv_gb #1#2#3#4#5#6#7#8#9{\CALX_fv_gc{#6#7#8#9.#2#3#4#5.#1}}% \def\CALX_fv_gc #1#2#3#4#5#6#7#8#9{#6#7#8#9.#2#3#4#5.#1\CALX_fh_gz}% \def\CALX_fv_ma #1#2#3#4#5#6#7#8{#1#2#3#4.#5#6#7#8.\CALX_fv_mb}% \def\CALX_fv_mb #1#2#3#4#5#6#7#8{#1#2#3#4.#5#6#7#8.\CALX_fv_mc}% \def\CALX_fv_mc #1#2#3#4#5#6#7#8#9\xint:{#1#2#3#4.#5#6#7#8.}% \def\CALX_fv_ka #1.#2.#3.#4.#5.#6.#7.#8.#9.% {% \expandafter\CALX_fv_o\the\numexpr\xint_c_e_ix+#6*#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#5*#7+#6*#8+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#4*#7+#5*#8+#6*#9+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#3*#7+#4*#8+#5*#9+#6*% \CALX_fv_kb{#2*#7+#3*#8+#4*#9+#5*}{#1*#7+#2*#8+#3*#9+#4*}% {#1*#8+#2*#9+#3*}% {#4}{#5}{#6}% }% \def\CALX_fv_kb #1#2#3#4#5#6#7.#8.#9.% {% #7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1#7+#6*#8+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#2#7+#5*#8+#6*#9+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#3#7+#4*#8+#5*#9;% }% \def\CALX_fv_o 1#1#2#3#4#5#6#7#8#9;{\CALX_fv_p{#2#3#4#5#6#7#8#9}}% \def\CALX_fv_p #1#2;#3;#4;#5;#6;#7;{\CALX_fv_t#6{#1}{#2#3#4#5#6}}% \def\CALX_fv_t #1#2#3#4% {% \ifnum#3#4>94 \xint_afterfi{\CALX_fv_u#1#2}\fi% \CALX_fv_ok }% \def\CALX_fv_u #1#2#3#4#5#6#7#8#9% {% \ifnum\ifcase\numexpr\ifnum#4>9999999 25\else24\fi-#8\relax \if4#2\xint_c_i\else\xint_c_\fi \or\ifnum#1#2=49 \xint_c_i\else\xint_c_\fi \else\ifnum#1#2=99 \xint_c_i\else\xint_c_\fi\fi=\xint_c_i \xint_dothis{#9}\fi \xint_orthat{#3{#4}{#5}{#6}{#7}{#8}{#9}}% }% \def\CALX_fv_ok #1#2#3#4#5#6% {% \expandafter\CALX_fq_p\expanded {\ifnum#1>9999999 {28}{#1}\else{27}{\xint_gobble_i#1}\fi {#2}{#3}{\the\numexpr#4+20}}{#5}% }% % \end{macrocode} % \subsubsection{\csh{CALX_fm_h}} %\begin{lverb} % 20 < P <= 34, after \CALX_fround of both operands. Each mantissa is read % as A = M 10^(40-D) (40 digits, D <= 41) by \CALX_fh_x, in two halves of % five groups: x0.x1.x2.x3.x4.!x5.x6.x7.x8.x9.! (A = AH 10^20 + AL). % Three products by copies of the kernel of \CALX_fm_qa (\CALX_fh_qa: % five blocks, low first; \CALX_fh_ra: AH AH' 10^4 in six blocks): %( %: V = AH AH' 10^20 + AH AL' + AL AH', A A' = V 10^20 + AL AL'. %) % \CALX_fh_m, _t, _u add the blocks (one nested chain, top block first); % the two lowest blocks of V are dropped after their carries. % % Rounding: 0 <= AL AL' < 10^40, that is less than 10^20 units of V. With % m >= 25 digits of V below the rounding position (true for P <= 34, V % having at least 59 digits), the omitted term changes the result only if % the digits of V from position 20 to m-1 read 4999...9; then digits 20 to % 23 are 9999 (block V2 > 99989999). In that rare case \CALX_fh_fb runs % the exact product \CALX_fm_g, whose call follows the arguments in the % input stream; otherwise \CALX_fh_ok keeps the top blocks covering P + 1 % digits and finishes as \CALX_fm_q (\CALX_fq_p). %\end{lverb} % \begin{macrocode} \def\CALX_fm_h #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_fh_a\expanded{\CALX_fh_x{#2}#4\xint:\CALX_fh_x{#6}#8% \xint:% {\if#1#5+\else-\fi}{\the\numexpr\xint_c_viii*(#3+#7)+#2+#6-60}}{#9}% {\CALX_fm_g{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}% }% \def\CALX_fh_x #1{\expandafter\CALX_fh_xa\the\numexpr(\xint_c_ii*#1+% \xint_c_vii)/16.#1.}% \def\CALX_fh_xa #1.#2.% {\csname CALX_fh_r#1\endcsname{\the\numexpr% \xint_c_viii*#1-#2}}% \expandafter\def\csname CALX_fh_r1\endcsname #11#2!#3\xint:% {\csname CALX_fh_s#1\endcsname\CALX_fh_ga % #20000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_fh_r2\endcsname #11#2!1#3!#4\xint:% {\csname CALX_fh_s#1\endcsname\CALX_fh_ga % #3#20000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_fh_r3\endcsname #11#2!1#3!1#4!#5\xint:% {\csname CALX_fh_s#1\endcsname\CALX_fh_ga % #4#3#20000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_fh_r4\endcsname #11#2!1#3!1#4!1#5!#6\xint:% {\csname CALX_fh_s#1\endcsname\CALX_fh_ga % #5#4#3#20000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_fh_r5\endcsname #11#2!1#3!1#4!1#5!1#6!#7\xint:% {\csname CALX_fh_s#1\endcsname\CALX_fh_ga % #6#5#4#3#20000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_fh_r6\endcsname #11#2!1#3!1#4!1#5!1#6!1#7!#8\xint:% {\csname CALX_fh_s#1\endcsname\CALX_fh_ga % #7#6#5#4#3#20000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_fh_s0\endcsname #1{#1}% \expandafter\def\csname CALX_fh_s1\endcsname #1#2{#1}% \expandafter\def\csname CALX_fh_s2\endcsname #1#2#3{#1}% \expandafter\def\csname CALX_fh_s3\endcsname #1#2#3#4{#1}% \expandafter\def\csname CALX_fh_s4\endcsname #1#2#3#4#5{#1}% \expandafter\def\csname CALX_fh_s5\endcsname #1#2#3#4#5#6{#1}% \expandafter\def\csname CALX_fh_s6\endcsname #1#2#3#4#5#6#7{#1}% \expandafter\def\csname CALX_fh_s7\endcsname #1#2#3#4#5#6#7#8{#1}% \def\CALX_fh_ga #1#2#3#4#5#6#7#8{\CALX_fh_gb{#5#6#7#8.#1#2#3#4.!}}% \def\CALX_fh_gb #1#2#3#4#5#6#7#8#9{\CALX_fh_gc{#6#7#8#9.#2#3#4#5.#1}}% \def\CALX_fh_gc #1#2#3#4#5#6#7#8#9{\CALX_fh_gd{#6#7#8#9.!#2#3#4#5.#1}}% \def\CALX_fh_gd #1#2#3#4#5#6#7#8#9{\CALX_fh_ge{#6#7#8#9.#2#3#4#5.#1}}% \def\CALX_fh_ge #1#2#3#4#5#6#7#8#9{#6#7#8#9.#2#3#4#5.#1\CALX_fh_gz}% \def\CALX_fh_gz #1\xint:{}% \def\CALX_fh_a #1!#2!#3!#4!% {% \expandafter\CALX_fh_m\expanded {\CALX_fh_qa #2#3\CALX_fh_qa #1#4\CALX_fh_ra #2#4}% }% \def\CALX_fh_m 1#1!1#2!1#3!1#4!1#5!1#6!1#7!1#8!1#9!% {\CALX_fh_t{#1+#6}{#2+#7}{#3+#8}{#4+#9}{#5}}% \def\CALX_fh_t #1#2#3#4#51#6!1#7!1#8!1#9!% {\CALX_fh_u{#1}{#2}{#3+#7}{#4+#8}{#5+#6+#9}}% \def\CALX_fh_u #1#2#3#4#51#6!1#7!1#8!% {% \expandafter\CALX_fh_v\the\numexpr#8+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#7+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#6+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#5+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#4+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#3+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#2+% \expandafter\CALX_fh_c\the\numexpr\xint_c_e_ix+#1;% }% \def\CALX_fh_c 1#1{#1;}% \def\CALX_fh_v #1;#2;#3;#4;#5;#6;#7;#8;% {% \ifnum#6>99989999 \expandafter\CALX_fh_fb\else\expandafter\CALX_fh_ok\fi {#1}{#2#3#4}{#5}% }% \def\CALX_fh_fb #1#2#3#4#5#6#7{#7}% \def\CALX_fh_ok #1#2#3#4#5#6#7% {% \expandafter\CALX_fq_p\expanded {\ifnum#6>26 {\the\numexpr32+\CALX_ndig{#1}}{#1}{#2#3}{#4}{\the% \numexpr#5+24}% \else{\the\numexpr24+\CALX_ndig{#1}}{#1}{#2}{#4}{\the\numexpr#5+32}% \fi}{#6}% }% \def\CALX_fh_qa #1.#2.#3.#4.#5.#6.#7.#8.#9.% {% \CALX_fh_qb{#5*}{#5*#9+#4*}{#4*#9+#5*#8+#3*}{#3*#9+#4*#8+#5*#7+#2*}% {#2*#9+#3*#8+#4*#7+#5*#6+#1*}% {\expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#9+#2*#8+#3*#7+#4*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#8+#2*#7+#3*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#7+#2*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#6;}% }% \def\CALX_fh_qb #1#2#3#4#5#6#7.% {% \expandafter\CALX_fh_qo\the\numexpr\xint_c_e_ix+#1#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#2#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#3#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#4#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#5#7+#6% }% \def\CALX_fh_ra #1.#2.#3.#4.#5.#6.#7.#8.#9.% {% \CALX_fh_rb{#5*}{#5*#9+#4*}{#4*#9+#5*#8+#3*}{#3*#9+#4*#8+#5*#7+#2*}% {#2*#9+#3*#8+#4*#7+#5*#6+#1*}% {\expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#9+#2*#8+#3*#7+#4*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#8+#2*#7+#3*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#7+#2*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#6;}% }% \def\CALX_fh_rb #1#2#3#4#5#6#7.% {% \expandafter\CALX_fh_ro\the\numexpr\xint_c_e_ix+#1#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#2#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#3#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#4#7+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#5#7+#6% }% \def\CALX_fh_qo 1#1#2#3#4#5#6#7#8#9;{\CALX_fh_qp{#2#3#4#5#6#7#8#9}}% \def\CALX_fh_qp #1#2;#3;#4;#5;#6;#7;#8;#9;{1#8#9!1#6#7!1#4#5!1#2#3!1#1!}% \def\CALX_fh_ro 1#1#2#3#4#5#6#7#8#9;{\CALX_fh_rp{#2#3#4#5}{#6#7#8#9}}% \def\CALX_fh_rp #1#2#3;#4;#5;#6;#7;#8;#9;{% \CALX_fh_rr{1#8#9!1#6#7!1#4#5!1#2#3!10000#1!}}% \def\CALX_fh_rr #1#2;{1#20000!#1}% % \end{macrocode} % \subsubsection{\csh{CALX_fm_big}} %\begin{lverb} % Every case other than P <= 16 with mantissas of at most 24 digits: both % operands are rounded by \CALX_fround, special values and zero are % handled (a zero operand: \CALX_fm_zero gobbles the nine arguments and % gives F+0.0.), then \CALX_fm_c dispatches on P: P <= 20 to \CALX_fm_q, % 20 < P <= 24 to \CALX_fm_v, 24 < P <= 34 to \CALX_fm_h, P > 34 to % \CALX_fm_g. % % \CALX_fm_g (also the rare fallback of \CALX_fm_v and \CALX_fm_h) is % the exact generic path: the mantissas are multiplied by \CALX_nmul; the % digit count of the product is read on its top block (\CALX_nskip, % \CALX_fm_gl), and the native float is rounded by \CALX_fround. % % \CALX_fm_gb N.\xint:{e}{P}: the list is grabbed once; % one copy is walked to the top block (digit count D), the other is left % in place after the header F.. given to \CALX_fround (which % needs no terminator). e and D are evaluated in front by a \numexpr % chain, so \CALX_fm_gd takes only small arguments. %\end{lverb} % \begin{macrocode} \def\CALX_fm_big #1#2% {\expandafter\CALX_fm_a\romannumeral0\CALX_fround{#1}{#2}{#1}}% \def\CALX_fm_a #1#2#3\xint:#4#5% {% \if I#1\CALX_fm_asx\fi \expandafter\CALX_fm_btag\romannumeral0\CALX_fround{#4}{#5}{#4}#2#3% \xint:% }% \def\CALX_fm_asx\fi#1\CALX_fm_btag{\fi\expandafter\CALX_fm_asz}% \def\CALX_fm_asz #1\xint:#2#3\xint:{\CALX_fm_sp#1\xint:I#3\xint:}% \def\CALX_fm_btag #1#2{\if I#1\CALX_fm_bsy#2\fi\CALX_fm_c#2}% \def\CALX_fm_bsy #1\fi#2\xint:#3#4\xint:{\fi\CALX_fm_sp I#1\xint:F#4\xint:}% \def\CALX_fm_c #1#2.#3.#4\xint:#5#6#7.#8.#9\xint:% {% \csname CALX_fm_\ifnum\ifnum#2=\xint_c_ \xint_c_\else#7\fi=\xint_c_ zero% \else\ifnum#5>34 g\else\ifnum#5>24 h\else\ifnum#5>20 v\else q% \fi\fi\fi\fi\endcsname{#6}{#7}{#8}{#9}{#1}{#2}{#3}{#4}{#5}% }% \def\CALX_fm_zero #1#2#3#4#5#6#7#8#9{ F+0.0.}% \def\CALX_fm_g #1#2#3#4#5#6#7#8% {% \expandafter\CALX_fm_gb\romannumeral0\CALX_nmul {\expanded{N#1\the\numexpr(\xint_c_ii*#2+\xint_c_vii)/16.}#4}% {\expanded{N#5\the\numexpr(\xint_c_ii*#6+\xint_c_vii)/16.}#8}% \xint:{#3+#7}% }% \def\CALX_fm_gb N#1#2.#3\xint:#4#5% {% \expandafter\CALX_fm_gd\the\numexpr#4\expandafter.\the\numexpr \xint_c_viii*(#2-\xint_c_i)+\CALX_nskip\CALX_fm_gl #2-\xint_c_i.#3\xint:.% #1{#5}#3% }% \def\CALX_fm_gl 1#1!#2\xint:{\CALX_ndig{#1}}% \def\CALX_fm_gd #1.#2.#3#4{\CALX_fnround{#4}{ F#3#2.#1.}}% % \end{macrocode} %\begin{lverb} % \CALX_fmulx{X}{Y} (use with \romannumeral0; X, Y finite natives, any % digit counts): the exact product X Y as a native float, not rounded % (D up to D_X + D_Y). Zero operand: F+0.0. Same code as \CALX_fm_g % (\CALX_nmul on the mantissas, digit count read on the top block), % without the final \CALX_fround. % % \CALX_fmulxs{X}{Y}: the same for values coming from the parsers, whose % tag may have catcode 11 (values stored in the meaning of a compiled % function, read from a file): \string makes the tag of each operand, % after its f-expansion, of catcode 12, as the patterns of \CALX_fmx_b % require. \CALX_fmulx itself is for the values calx computes. % % Delimited entry for the two already expanded operands. The ordinary % \CALX_fmulxs entry remains for internal callers with expandable operands. %\end{lverb} % \begin{macrocode} \def\CALX_fmulx #1% {\expandafter\CALX_fmx_a\romannumeral`&&@#1\xint:}% \def\CALX_fmx_a #1\xint:#2% {\expandafter\CALX_fmx_b\romannumeral`&&@#2\xint:#1\xint:}% \def\CALX_fmulxs_in #1\xint:#2\xint:% {\expandafter\CALX_fmx_vi\string#1\xint:#2\xint:}% \def\CALX_fmx_vi #1\xint:#2\xint:% {\expandafter\CALX_fmx_b\string#2\xint:#1\xint:}% \def\CALX_fmulxs #1% {\expandafter\CALX_fmx_s\romannumeral`&&@#1\xint:}% \def\CALX_fmx_s{\expandafter\CALX_fmx_t\string}% \def\CALX_fmx_t #1\xint:#2% {\expandafter\CALX_fmx_u\romannumeral`&&@#2\xint:#1\xint:}% \def\CALX_fmx_u{\expandafter\CALX_fmx_b\string}% \def\CALX_fmx_b F#1#2.#3.#4\xint:F#5#6.#7.#8\xint:% {% \ifnum\ifnum#2=\xint_c_ \xint_c_\else#6\fi=\xint_c_ \xint_dothis\CALX_fmx_zero\fi \xint_orthat\CALX_fmx_nonzero F#1#2.#3.#4\xint:F#5#6.#7.#8\xint: }% \def\CALX_fmx_zero #1\xint:#2\xint:{ F+0.0.}% \def\CALX_fmx_nonzero F#1#2.#3.#4\xint:F#5#6.#7.#8\xint:% {% \expandafter\CALX_fmx_c\romannumeral0\CALX_nmul {\expanded{N#1\the\numexpr(\xint_c_ii*#2+\xint_c_vii)/16.}#4}% {\expanded{N#5\the\numexpr(\xint_c_ii*#6+\xint_c_vii)/16.}#8}% \xint:{#3+#7}% }% \def\CALX_fmx_c N#1#2.#3\xint:#4% {% \expandafter\CALX_fmx_d\the\numexpr#4\expandafter.\the\numexpr \xint_c_viii*(#2-\xint_c_i)+\CALX_nskip\CALX_fm_gl #2-\xint_c_i.#3\xint:.% #1#3% }% \def\CALX_fmx_d #1.#2.#3{ F#3#2.#1.}% % \end{macrocode} %\begin{lverb} % \CALX_faddx{X}{Y}, \CALX_fsubx{X}{Y} (use with \romannumeral0; X, Y % finite natives): X + Y, X - Y exact, not rounded. The operand with the % larger block exponent gets that many zero blocks at its low end % (\CALX_fa_z), both become integers N. (same blocks, n = % ceil(D/8)), \CALX_nadd or \CALX_nsub adds them, and the digit count of % the result is read on its top block as in \CALX_fm_g. A zero operand % gives the other one. %\end{lverb} % \begin{macrocode} \def\CALX_faddx #1#2% {\expandafter\CALX_fx_a\romannumeral`&&@#2\xint:{#1}\CALX_nadd}% \def\CALX_fsubx #1#2% {\expandafter\CALX_fx_a\romannumeral`&&@#2\xint:{#1}\CALX_nsub}% \def\CALX_fx_a F#1#2.#3.#4\xint:#5#6% {\expandafter\CALX_fx_b\romannumeral`&&@#5\xint:#6#1#2.#3.#4\xint:}% \def\CALX_fx_b F#1#2.#3.#4\xint:#5#6#7.#8.#9\xint:% {% \ifnum#7=\xint_c_ \xint_dothis\CALX_fx_zy\fi \ifnum#2=\xint_c_ \xint_dothis\CALX_fx_zx\fi \xint_orthat\CALX_fx_nonzero F#1#2.#3.#4\xint:#5#6#7.#8.#9\xint: }% \def\CALX_fx_zy F#1#2.#3.#4\xint:#5#6#7.#8.#9\xint:% { F#1#2.#3.#4}% \def\CALX_fx_zx F#1#2.#3.#4\xint:#5#6#7.#8.#9\xint:% {% \ifx#5\CALX_nsub\expandafter\CALX_fx_m\else\expandafter\space\fi F#6#7.#8.#9% }% \def\CALX_fx_nonzero F#1#2.#3.#4\xint:#5#6#7.#8.#9\xint:% {% \expandafter\CALX_fx_c\the\numexpr\ifnum#3<#8 #3\else#8\fi \expandafter.\romannumeral0#5% {\expanded{N#1\the\numexpr(2*#2+7)/16\ifnum#3>#8 +#3-#8\fi.% \ifnum#3>#8 \CALX_fa_z#3-#8.\fi}#4}% {\expanded{N#6\the\numexpr(2*#7+7)/16\ifnum#8>#3 +#8-#3\fi.% \ifnum#8>#3 \CALX_fa_z#8-#3.\fi}#9}\xint:% }% \def\CALX_fx_m F#1% {\if-#1\expandafter\CALX_fx_p\else\expandafter\CALX_fx_n\fi}% \def\CALX_fx_p{ F+}% \def\CALX_fx_n{ F-}% \def\CALX_fx_c #1.N#2#3.% {% \ifnum#3=\xint_c_ \expandafter\CALX_fx_z\else \expandafter\CALX_fx_d\fi #1.#2#3.% }% \def\CALX_fx_z #1\xint:{ F+0.0.}% \def\CALX_fx_d #1.#2#3.#4\xint:% {% \expandafter\CALX_fmx_d\the\numexpr#1\expandafter.\the\numexpr \xint_c_viii*(#3-\xint_c_i)+\CALX_nskip\CALX_fm_gl #3-\xint_c_i.#4\xint:.% #2#4% }% % \end{macrocode} % \subsection{Squaring} % \subsubsection{\csh{CALX_fsqr}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X f-expanded % F, I or raw value): %( % \CALX_fsqr{P}{X} -> Z Z = round_P(round_P(X)^2) %: \CALX_fsqru{P}{X} -> Z (X finite F, at most P digits) %) % \CALX_fsqr{P}{X} (use with \romannumeral0, X f-expanded): % round_P(round_P(X)^2), round half away from zero, as xint's % \XINTinFloatSqr[P]; the same result as \CALX_fmul{P}{X}{X}, with the % operand read once and kernels which compute each cross product once % (x_i x_j + x_j x_i written as 2 x_i x_j). % % Special values: I? gives I?, I+ and I- give I+. Zero gives F+0.0. % % P <= 16 and a mantissa of at most 24 digits: one extraction as in % \CALX_fmul (\CALX_fm_xvi, \CALX_fm_ex), then \CALX_fs_k (the square of % the 16 digit A, seven columns, ten products) and \CALX_fm_r. Otherwise % \CALX_fs_big: \CALX_fround, then by P: \CALX_fs_q (P <= 20), % \CALX_fs_v (P <= 24), \CALX_fs_h (P <= 34), \CALX_fs_g (generic, also % the fallback of \CALX_fs_v and \CALX_fs_h). They read the operand as % \CALX_fm_q, \CALX_fm_v, \CALX_fm_h read X, with exponents %( %: E = 16e + 2D - 40, E = 16e + 2D - 48, E = 16e + 2D - 60, %) % and finish as these. With x_i the groups of four digits, the column % c_k of A^2 is %( %: c_k = 2 (sum of x_i x_(k-i), i < k - i) + x_(k/2)^2, %) % the square term only for k even: its value is at most that of the % column of a product (same number of terms), so the carry scheme of % \CALX_fm_s is unchanged; the truncation bounds of \CALX_fm_v and % \CALX_fm_h hold as they are (they only use the sizes of the operands). % \CALX_fs_q$empty: 15 products instead of 25, one kernel macro of five % arguments; \CALX_fs_v$empty: 15 instead of 26, one macro of six arguments; % \CALX_fs_h$empty: two kernels instead of three (AH AL once, \CALX_fs_ra for % AH^2), \CALX_fs_m doubles the blocks of AH AL in the merge of % \CALX_fh_u. %\end{lverb} % \begin{macrocode} \def\CALX_fsqr #1% {% \ifnum#1>16 \expandafter\CALX_fs_big\else\expandafter\CALX_fs_na\fi {#1}% }% \def\CALX_fsqru #1% {% \ifnum#1>16 \expandafter\CALX_fqu_b\else\expandafter\CALX_fs_na\fi {#1}% }% \def\CALX_fqu_b #1#2{\expandafter\CALX_fs_b\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fs_na #1#2{\expandafter\CALX_fs_nc\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fs_nc #1% {\if F#1\expandafter\CALX_fs_nd\else\expandafter\CALX_fs_ns \expandafter#1\fi}% \def\CALX_fs_ns #1% {\if I#1\expandafter\CALX_fs_sp\else\expandafter\CALX_fs_nr \expandafter#1\fi}% \def\CALX_fs_nr #1#2\xint:#3{\CALX_fs_big{#3}{#1#2}}% \def\CALX_fs_sp #1#2\xint:#3{\if ?#1\xint_dothis{ I?}\fi\xint_orthat{ I+}}% \def\CALX_fs_nd #1#2.#3.#4\xint:#5% {% \ifnum#2=\xint_c_ \CALX_fs_nz\fi \ifnum#2>24 \CALX_fs_nbig{#5}{F#1#2.#3.#4}\fi \expandafter\CALX_fs_ne\expanded {\CALX_fm_ny{#5}{#2}#4100000000!100000000!\xint:{\the\numexpr16*#3}}% {#5}% }% \def\CALX_fs_nz\fi#1\expanded#2#3{\fi\CALX_sp F+0.0.}% \def\CALX_fs_nbig #1#2\fi#3\expanded#4#5{\fi\CALX_fs_big{#1}{#2}}% \def\CALX_fs_ne #1!#2!#3.#4{\CALX_fs_k #1!#2!{+}{#4+#3+#3}}% \def\CALX_fs_k 1#1#2#3#4#5!{\CALX_fs_kb{#5}{#1#2#3#4}}% \def\CALX_fs_kb #1#21#3#4#5#6#7!{\CALX_fs_kf{#1}{#2}{#7}{#3#4#5#6}}% \def\CALX_fs_kf #1#2#3#4% {% \expandafter\CALX_fm_o\the\numexpr1000000000+#4*#4+% \expandafter\CALX_fm_s\the\numexpr1000000000+#3*#4*\xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr1000000000+#2*#4*\xint_c_ii+#3*#3+% \expandafter\CALX_fm_s\the\numexpr1000000000+(#1*#4+#2*#3)*\xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#3*\xint_c_ii+#2*#2+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#2*\xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr1000000000+#1*#1;% }% \def\CALX_fs_big #1#2% {\expandafter\CALX_fs_b\romannumeral0\CALX_fround{#1}{#2}{#1}}% \def\CALX_fs_b #1% {\if I#1\expandafter\CALX_fs_sp\else\expandafter\CALX_fs_c\fi}% \def\CALX_fs_c #1#2.#3.#4\xint:#5% {% \csname CALX_fs_\ifnum#2=\xint_c_ zero\else\ifnum#5>34 g\else \ifnum#5>24 h\else\ifnum#5>20 v\else q\fi\fi\fi\fi\endcsname {#1}{#2}{#3}{#4}{#5}% }% \def\CALX_fs_zero #1#2#3#4#5{ F+0.0.}% \def\CALX_fs_g #1#2#3#4{\CALX_fm_g{#1}{#2}{#3}{#4}{#1}{#2}{#3}{#4}}% \def\CALX_fs_q #1#2#3#4% {% \expandafter\CALX_fs_qa\expanded{\CALX_fq_x{#2}#4\xint:% {+}{\the\numexpr16*#3+\xint_c_ii*#2-40}}% }% \def\CALX_fs_qa #1.#2.#3.#4.#5.% {% \expandafter\CALX_fm_qo\the\numexpr\xint_c_e_ix+#5*#5+% \CALX_fs_qc{#1}{#2}{#3}{#4}{#5}% }% \def\CALX_fs_qc #1#2#3#4#5% {% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#4*#5*\xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#3*#5*\xint_c_ii+#4*#4+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#2*#5+#3*#4)*% \xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#1*#5+#2*#4)*% \xint_c_ii+#3*#3+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#1*#4+#2*#3)*% \xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#3*\xint_c_ii+#2*#2+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#2*\xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#1*#1;% }% \def\CALX_fs_v #1#2#3#4#5% {% \expandafter\CALX_fs_va\expanded{\CALX_fv_x{#2}\CALX_fv_ga#4\xint:% {+}{\the\numexpr16*#3+\xint_c_ii*#2-48}}{#5}% {\CALX_fs_g{#1}{#2}{#3}{#4}{#5}}% }% \def\CALX_fs_va #1.#2.#3.#4.#5.#6.% {% \expandafter\CALX_fv_o\the\numexpr\xint_c_e_ix+#6*#6+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#5*#6*\xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+#4*#6*\xint_c_ii+#5*#5+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#3*#6+#4*#5)*% \xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#2*#6+#3*#5)*% \xint_c_ii+#4*#4+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#1*#6+#2*#5+#3*#4)*% \xint_c_ii+% \expandafter\CALX_fm_s\the\numexpr\xint_c_e_ix+(#1*#5+#2*#4)*% \xint_c_ii+#3*#3;% }% \def\CALX_fs_h #1#2#3#4#5% {% \expandafter\CALX_fs_a\expanded{\CALX_fh_x{#2}#4\xint:% {+}{\the\numexpr16*#3+\xint_c_ii*#2-60}}{#5}% {\CALX_fs_g{#1}{#2}{#3}{#4}{#5}}% }% \def\CALX_fs_a #1!#2!% {\expandafter\CALX_fs_m\expanded{\CALX_fh_qa #2#1\CALX_fs_ra #2}}% \def\CALX_fs_m 1#1!1#2!1#3!1#4!1#5!1#6!1#7!1#8!% {% \CALX_fh_u{#1*\xint_c_ii}{#2*\xint_c_ii}{#3*\xint_c_ii+#6}% {#4*\xint_c_ii+#7}{#5*\xint_c_ii+#8}% }% \def\CALX_fs_ra #1.#2.#3.#4.#5.% {% \expandafter\CALX_fh_ro\the\numexpr\xint_c_e_ix+#5*#5+% \CALX_fs_qc{#1}{#2}{#3}{#4}{#5}% }% % \end{macrocode} % \subsection{Division} % \subsubsection{\csh{CALX_fdiv}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X, Y % f-expanded F, I or raw values): %( % \CALX_fdiv{P}{X}{Y} -> Z Z = round_P(round_P(X)/round_P(Y)) %: \CALX_fdivu{P}{X}{Y} -> Z (X, Y finite F, at most P digits) %) % \CALX_fdiv{P}{X}{Y} (use with \romannumeral0, X and Y f-expanded): % round_P(round_P(X) / round_P(Y)), round half away from zero, as xint's % \XINTinFloatDiv[P]. % % Both operands are rounded by \CALX_fround. Special values % (\CALX_fd_sp$empty: I? propagates, Inf / Inf signals InvalidOperation, % Inf / finite is Inf with the sign of the quotient, finite / Inf is % zero), then zero operands: x / 0 signals DivisionByZero (handler % argument the sign of x), 0 / 0 DivisionUndefined, 0 / y is F+0.0. % % Generic path (\CALX_fd_g$empty): the quotient q = Mx 10^(8a) / My % satisfies q > 10^(Dx + 8a - Dy - 1), so with %( %: a = max(0, ceil((P + 1 + Dy - Dx)/8)) %) % zero blocks in front of Mx (\CALX_fa_z), the truncated integer quotient % N (\CALX_ndivtrunc, sign of the quotient) has at least P + 1 digits. % Round half away from zero to P digits depends only on the P + 1 top % digits of the exact quotient, which are those of N; so the native float % N 10^(8(ex - ey - a)) is rounded by \CALX_fround as in \CALX_fm_g % (\CALX_fm_gb). %\end{lverb} % \begin{macrocode} \def\CALX_fdiv #1#2% {\expandafter\CALX_fd_a\romannumeral0\CALX_fround{#1}{#2}{#1}}% \def\CALX_fdivu #1#2% {\expandafter\CALX_fdu\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fdu F#1\xint:#2#3% {\expandafter\CALX_fd_btag\romannumeral`&&@#3\xint:{#2}#1\xint:}% \def\CALX_fd_a #1#2#3\xint:#4#5% {% \if I#1\CALX_fd_asx#2\fi \expandafter\CALX_fd_btag\romannumeral0\CALX_fround{#4}{#5}{#4}#2#3% \xint:% }% \def\CALX_fd_asx #1\fi#2\CALX_fd_btag% {\fi\expandafter\CALX_fd_asz\expandafter#1}% \def\CALX_fd_asz #1#2#3#4\xint:#5#6\xint:{\CALX_fd_sp I#1#2#3}% \def\CALX_fd_btag #1#2{\if I#1\CALX_fd_bsy#2\fi\CALX_fd_c#2}% \def\CALX_fd_bsy #1\fi#2\xint:#3#4#5\xint:{\fi\CALX_fd_sp F#4I#1}% \def\CALX_fd_sp #1#2#3#4% {% \if ?#2\xint_dothis{ I?}\fi \if ?#4\xint_dothis{ I?}\fi \if F#1\xint_dothis{ F+0.0.}\fi \if F#3\xint_dothis{\CALX_nsp_ps#2#4}\fi \xint_orthat{\CALX_nsig{InvalidOperation}{inf / inf}{}}% }% \def\CALX_fd_c #1#2.#3.#4\xint:#5#6#7.#8.#9\xint:% {% \csname CALX_fd_\ifnum#2=\xint_c_ zz\else\ifnum#7=\xint_c_ zero\else \ifnum#5>40 g\else\ifnum#5<5 g\else v\fi\fi\fi\fi\endcsname {#6}{#7}{#8}{#9}{#1}{#2}{#3}{#4}{#5}% }% \def\CALX_fd_zz #1#2#3#4#5#6#7#8#9{\CALX_fd_z{#2}{#1}}% \let\CALX_fd_zero\CALX_fm_zero \def\CALX_fd_z #1#2% {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nsig{DivisionUndefined}{0 / 0}{}}\fi \xint_orthat{\CALX_nsig{DivisionByZero}{x / 0}{#2}}% }% \def\CALX_fd_g #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_fd_i\the\numexpr \ifnum\numexpr#9+\xint_c_i+#6-#2<\xint_c_ \xint_c_\else (\xint_c_ii*(#9+\xint_c_i+#6-#2)+\xint_c_vii)/16\fi.% {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}% }% \def\CALX_fd_i #1.#2#3#4#5#6#7#8#9% {% \expandafter\CALX_fm_gb\romannumeral0\CALX_ndivtrunc {\expanded{N#2\the\numexpr(\xint_c_ii*#3+\xint_c_vii)/16+#1.% \CALX_fa_z#1.}#5}% {\expanded{N#6\the\numexpr(\xint_c_ii*#7+\xint_c_vii)/16.}#9}% \xint:{#4-#8-#1}% }% % \end{macrocode} % \subsubsection{\csh{CALX_fd_v}} %\begin{lverb} % Division kernel for 5 <= P <= 40 (\CALX_fd_c calls \CALX_fd_v instead of % \CALX_fd_g). With m = ceil(P/4) and n = ceil((P+1)/4), each mantissa is % read as an integer of exactly 4m digits (A = Mx 10^(4m-Dx), B = My % 10^(4m-Dy), the dropped digits are zeros), in groups of four digits a_i, % b_i (\CALX_dv_rd, \CALX_dv_r reverses the k blocks, \CALX_fh_s % drops the z leading zeros of the top block, \CALX_dv_gg takes m groups; % the counter tokens \CALX_dv_k expand to \CALX_dv_k). Then %( %: X / Y = (A / B) 10^E, E = 8(ex - ey) + Dx - Dy. %) % Long division in base 10^4 with a signed remainder: R_0 = A, and for % i = 1..n %( %: q_i = round(10^4 R'/B'), R_i = 10^4 R_(i-1) - q_i B, %) % R' and B' being the two top groups of R_(i-1) and B (\numexpr a*b/c, % 64 bit intermediate product). The estimate is within 0.0015 of % 10^4 R_(i-1)/B, so |R_i| <= 0.5015 B for i >= 1, |q_i| <= 5100 for % i >= 2, 1000 <= q_1 < 10^5, and no correction step is needed. Then %( %: A 10^(4n) = B (q_1 10^(4(n-1)) + ... + q_n) + R_n, %) % so Q = floor(A 10^(4n)/B) is that sum, minus one if R_n < 0; Q has at % least 4n >= P + 1 digits, enough for the rounding (as in \CALX_fd_g). % % Data of a step (top first): b_(m-1) T; then the entries % l.\CALX_dv_c b; of the lower groups of R and B, then 0.\CALX_dv_e; (T is % the signed top group of R, the l are in [0, 10^4)). \CALX_dv_s computes q, % \CALX_dv_sq writes the top column of R_i, the next columns are written % by \CALX_dv_c (one entry l.\CALX_dv_c b; each: the entries carry the % column macro, the next one is called with q after its b, while \numexpr % is evaluating the column above: one nested chain of m \numexpr; the % last entry 0.\CALX_dv_e; ends the chain). A column computes % 2 10^9 + l - q b + carry (ten digits); the four digits of b are put in % front of the result (\expandafter over single digits), \CALX_dv_sb, % \CALX_dv_sc split it into the carry (six digits minus 200000) and the % new group, and put the entry back after it. So the result has the % layout of the input; the top column ends with \CALX_dv_tt, % which starts the next step with the counter decremented. % % The q_i are written into the output of \expanded as the text of a second % nested chain: \CALX_dv_n1, \CALX_dv_ns split 2 10^8 + q_i + carry (nine % digits), the last column gets the correction (-1 if T < 0 at the end, % \CALX_dv_f). The groups are glued (\relax ends the \numexpr of the % columns), \CALX_dv_nt receives the top carry and the 4n digits and % finishes as \CALX_fm_q (\CALX_fq_p, exponent E - 4n). %\end{lverb} % \begin{macrocode} \def\CALX_fd_v #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_dv_a\the\numexpr(\xint_c_ii*#9+\xint_c_iii)/% \xint_c_viii\expandafter.\the\numexpr(\xint_c_ii*#9+5)/\xint_c_viii.% {#2}{#4}{#6}{#8}{\if#1#5+\else-\fi}{\xint_c_viii*(#3-#7)+#2-#6}{#9}% }% \def\CALX_dv_a #1.#2.#3#4#5#6% m, n, Dx, Mx, Dy, My {% \expanded{\unexpanded{\expandafter\CALX_dv_nt\the\numexpr}0+% \expandafter\CALX_dv_s\expandafter\CALX_dv_ni \csname CALX_dv_k#2\expandafter\endcsname \expanded{\expandafter\CALX_dv_il\expanded{% \CALX_dv_rd{#3}{#1}#4\xint:!.\xint:\CALX_dv_rd{#5}{#1}#6\xint:!.% \xint:}}}% {#2}% }% \def\CALX_dv_rd #1% {\expandafter\CALX_dv_rda\the\numexpr(\xint_c_ii*#1+% \xint_c_vii)/16.#1.}% \def\CALX_dv_rda #1.#2.#3% {% \csname CALX_dv_r#1\expandafter\endcsname \the\numexpr\xint_c_viii*#1-#2\expandafter.\csname CALX_dv_g#3\endcsname }% \expandafter\def\csname CALX_dv_r1\endcsname #1.#21#3!#4\xint:% {\csname CALX_fh_s#1\endcsname#2#3% 000000000000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_dv_r2\endcsname #1.#21#3!1#4!#5\xint:% {\csname CALX_fh_s#1\endcsname#2#4#3% 000000000000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_dv_r3\endcsname #1.#21#3!1#4!1#5!#6\xint:% {\csname CALX_fh_s#1\endcsname#2#5#4#3% 000000000000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_dv_r4\endcsname #1.#21#3!1#4!1#5!1#6!#7\xint:% {\csname CALX_fh_s#1\endcsname#2#6#5#4#3% 000000000000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_dv_r5\endcsname #1.#21#3!1#4!1#5!1#6!1#7!#8\xint:% {\csname CALX_fh_s#1\endcsname#2#7#6#5#4#3% 000000000000000000000000000000000000000000000000\xint:}% \expandafter\def\csname CALX_dv_r6\endcsname #1.#21#3!1#4!1#5!1#6!1#7!1#8!#9\xint:% {\csname CALX_fh_s#1\endcsname#2#8#7#6#5#4#3% 000000000000000000000000000000000000000000000000\xint:}% \def\CALX_dv_gg #1#2#3#4#5% {% \ifx#1\CALX_dv_kz\xint_dothis\CALX_dv_gz\fi \xint_orthat{#2#3#4#5.\expandafter\CALX_dv_gg#1}% }% \def\CALX_dv_gz #1\xint:{}% \def\CALX_dv_il #1.#2\xint:#3.#4\xint:{#3#1;\CALX_dv_im#2\xint:#4\xint:}% \def\CALX_dv_im #1.#2\xint:#3.#4\xint:% {% \xint_gob_til_exclam #1\CALX_dv_ie!% #1.\noexpand\CALX_dv_c#3;\CALX_dv_im#2\xint:#4\xint:% }% \def\CALX_dv_ie!#1\xint:#2\xint:{0.\noexpand\CALX_dv_e;}% \def\CALX_dv_kz {z}% \expandafter\let\csname CALX_dv_k0\endcsname\CALX_dv_kz \expandafter\def\csname CALX_dv_k1\endcsname{\CALX_dv_kz}% \expandafter\edef\csname CALX_dv_k2\endcsname {\expandafter\noexpand\csname CALX_dv_k1\endcsname}% \expandafter\edef\csname CALX_dv_k3\endcsname {\expandafter\noexpand\csname CALX_dv_k2\endcsname}% \expandafter\edef\csname CALX_dv_k4\endcsname {\expandafter\noexpand\csname CALX_dv_k3\endcsname}% \expandafter\edef\csname CALX_dv_k5\endcsname {\expandafter\noexpand\csname CALX_dv_k4\endcsname}% \expandafter\edef\csname CALX_dv_k6\endcsname {\expandafter\noexpand\csname CALX_dv_k5\endcsname}% \expandafter\edef\csname CALX_dv_k7\endcsname {\expandafter\noexpand\csname CALX_dv_k6\endcsname}% \expandafter\edef\csname CALX_dv_k8\endcsname {\expandafter\noexpand\csname CALX_dv_k7\endcsname}% \expandafter\edef\csname CALX_dv_k9\endcsname {\expandafter\noexpand\csname CALX_dv_k8\endcsname}% \expandafter\edef\csname CALX_dv_k10\endcsname {\expandafter\noexpand\csname CALX_dv_k9\endcsname}% \expandafter\edef\csname CALX_dv_k11\endcsname {\expandafter\noexpand\csname CALX_dv_k10\endcsname}% \expandafter\def\csname CALX_dv_g2\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k2\endcsname}% \expandafter\def\csname CALX_dv_g3\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k3\endcsname}% \expandafter\def\csname CALX_dv_g4\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k4\endcsname}% \expandafter\def\csname CALX_dv_g5\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k5\endcsname}% \expandafter\def\csname CALX_dv_g6\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k6\endcsname}% \expandafter\def\csname CALX_dv_g7\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k7\endcsname}% \expandafter\def\csname CALX_dv_g8\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k8\endcsname}% \expandafter\def\csname CALX_dv_g9\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k9\endcsname}% \expandafter\def\csname CALX_dv_g10\endcsname {\expandafter\CALX_dv_gg\csname CALX_dv_k10\endcsname}% \def\CALX_dv_s #1#2#3#4#5#6#7;#8.\CALX_dv_c#9;% {% \ifx#2\CALX_dv_kz\xint_dothis{\CALX_dv_f{#7}}\fi \xint_orthat{\expandafter\CALX_dv_sq\the\numexpr (#7*10000+#8)*10000/(#3#4#5#6*10000+#9).% #1#2{#3#4#5#6}{#7}{#8}{#9}}% }% \def\CALX_dv_f #1#2\CALX_dv_e;{\ifnum#1<\xint_c_ -1\else0\fi;}% \def\CALX_dv_sq #1.#2#3#4#5#6#7% q, prefix, counter, b, T, l, b' {% \unexpanded{\expandafter#2\the\numexpr}#1+200000000+% \expandafter\CALX_dv_tt#3#4\the\numexpr #5*10000+#6-#1*#4+\CALX_dv_c#7{#1}% }% \def\CALX_dv_tt #1#2#3#4% {% \expandafter\CALX_dv_s\expandafter\CALX_dv_ns\expandafter#1% \expandafter#2\expandafter#3\expandafter#4\expandafter }% \def\CALX_dv_c #1#2#3#4#5#6.#7;% {% \expandafter\CALX_dv_sb\expandafter#1\expandafter#2\expandafter#3% \expandafter#4\the\numexpr#6-#5*#1#2#3#4+2000000000+#7{#5}% }% \def\CALX_dv_e #1{0;0.\CALX_dv_e;}% \def\CALX_dv_sb #1#2#3#4#5#6#7#8#9{#5#6#7#8#9\CALX_dv_sc{#1#2#3#4}}% \def\CALX_dv_sc #1#2#3#4#5#6{#2-200000;#3#4#5#6.\CALX_dv_c#1}% \def\CALX_dv_ni #1#2#3#4#5{#1#2#3#4#5-20000;}% \def\CALX_dv_ns #1#2#3#4#5{#1#2#3#4#5-20000\relax}% \def\CALX_dv_nt #1;#2;#3#4#5% top, 4n digits, n, s, E (P follows) {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_fq_p{(\xint_c_iv*#3)}{}}\fi \xint_orthat{\CALX_fq_p{(\xint_c_iv*#3+\CALX_ndig{#1})}{#1}}% {#2}{#4}{(#5-\xint_c_iv*#3)}% }% % \end{macrocode} % \subsubsection{\csh{CALX_fdq}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X, Y % f-expanded F, I or raw values; one of \CALX_fdq_q, \CALX_fdq_r, % \CALX_fdq_p): %( % \CALX_fdq{P}\CALX_fdq_q{X}{Y} -> Q %: \CALX_fdq{P}\CALX_fdq_r{X}{Y} -> R %: \CALX_fdq{P}\CALX_fdq_p{X}{Y} -> {Q}{R} %) % Floor division of X' and Y', the values X and Y rounded to P digits % (\CALX_fround): Q = floor(X'/Y') exact (an F value with e = 0, not % rounded), R = X' - Y' Q rounded to P digits (its sign is that of Y'). % They implement //, /: (and mod()), divmod() of \xintfloateval. % % Both F and non-zero: with d = min(e_X, e_Y), the operand of larger block % exponent gets that many zero blocks at its low end (\CALX_fa_z, as in % \CALX_faddx); the two integers N. (n = ceil(D/8) plus the % zero blocks) go to calxcore's \CALX_ndivfloor, \CALX_nmod or % \CALX_ndivmod; Q is converted with e = 0 and R with e = d (\CALX_fx_c: % digit count read on the top block). A zero operand or an I value: the % integers without zero blocks (I values as they are, d = e_X if X is % F), and the kernels apply their rules (Python's decimal model): % x // 0 DivisionByZero (I+ or I-), 0 // 0 DivisionUndefined (I?), x mod 0 % InvalidOperation (I?), Inf // Inf and Inf mod x InvalidOperation, x // % Inf zero, x mod Inf x. An I result is passed on as it is. %\end{lverb} % \begin{macrocode} \def\CALX_fdq #1#2#3% {\expandafter\CALX_fdq_a\romannumeral0\CALX_fround{#1}{#3}#2{#1}}% \def\CALX_fdq_a #1\xint:#2#3#4% {\expandafter\CALX_fdq_b\romannumeral0\CALX_fround{#3}{#4}#1\xint:#2{#3}}% \def\CALX_fdq_b #1% {% \if I#1\xint_dothis{\CALX_fdq_bi #1}\fi \xint_orthat{\CALX_fdq_bf #1}% }% \def\CALX_fdq_bi #1#2\xint:#3{\CALX_fdq_s #1#2\xint:#3}% \def\CALX_fdq_bf #1#2\xint:#3% {% \if I#3\xint_dothis\CALX_fdq_s\fi \xint_orthat\CALX_fdq_f #1#2\xint:#3% }% \def\CALX_fdq_f F#1#2.#3.#4\xint:F#5#6.#7.#8\xint:#9% {% \ifnum\numexpr#2*#6=\xint_c_ \xint_dothis\CALX_fdq_s\fi \xint_orthat\CALX_fdq_fg F#1#2.#3.#4\xint:F#5#6.#7.#8\xint:#9% }% \def\CALX_fdq_fg F#1#2.#3.#4\xint:F#5#6.#7.#8\xint:#9% {% \expandafter#9\the\numexpr\ifnum#3<#7 #3\else#7\fi \expandafter.\expanded {{N#5\the\numexpr(\xint_c_ii*#6+\xint_c_vii)/16\ifnum#7>#3 +#7-#3\fi.% \ifnum#7>#3 \CALX_fa_z#7-#3.\fi#8}% {N#1\the\numexpr(\xint_c_ii*#2+\xint_c_vii)/16\ifnum#3>#7 +#3-#7\fi.% \ifnum#3>#7 \CALX_fa_z#3-#7.\fi#4}}% }% \def\CALX_fdq_s #1#2\xint:#3#4\xint:#5% {% \expandafter#5\the\numexpr\if I#3 \xint_c_\else\CALX_fdq_x#4\xint:\fi \expandafter.\expanded{{\CALX_fdq_n#3#4}{\CALX_fdq_n#1#2}}% }% \def\CALX_fdq_x #1#2.#3.#4\xint:{#3}% \def\CALX_fdq_n #1{\if I#1\CALX_fdq_ni\fi\CALX_fdq_nf}% \def\CALX_fdq_ni\fi\CALX_fdq_nf{\fi I}% \def\CALX_fdq_nf #1#2.#3.{N#1\the\numexpr(\xint_c_ii*#2+\xint_c_vii)/16.}% \def\CALX_fdq_q #1.#2#3#4% {\expandafter\CALX_fdq_t\expandafter0\expandafter.% \romannumeral0\CALX_ndivfloor{#2}{#3}\xint:}% \def\CALX_fdq_r #1.#2#3#4% {\CALX_fnround{#4}{\expandafter\CALX_fdq_t\the\numexpr#1\expandafter.% \romannumeral0\CALX_nmod{#2}{#3}\xint:}}% \def\CALX_fdq_p #1.#2#3% {\expandafter\CALX_fdq_pa\romannumeral0\CALX_ndivmod{#2}{#3}{#1}}% \def\CALX_fdq_pa #1#2#3#4% {\expanded{{\romannumeral0\CALX_fdq_t 0.#1\xint:}% {\romannumeral0\CALX_fnround{#4}{\CALX_fdq_t #3.#2\xint:}}}}% \def\CALX_fdq_t #1.#2{\if I#2\expandafter\CALX_fdq_i\fi\CALX_fx_c #1.#2}% \def\CALX_fdq_i\CALX_fx_c #1.#2\xint:{ #2}% % \end{macrocode} % \subsubsection{\csh{CALX_finv}, \csh{CALX_fe}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X f-expanded % F, M, I or raw value; n a \numexpr expression): %( % \CALX_finv{P}{X} -> Y Y = round_P(1/X) %: \CALX_fe{P}{X}{n} -> A[N] round_P(X) 10^n, raw (I unchanged) %) % \CALX_finv: one rounding of the exact inverse (not of the inverse of X % rounded): X as raw A/B[N] (F by \CALX_ftoraw, M by \CALX_mtoraw_t), then % \CALX_fround of the raw B/A[-N] (the sign moved to B; A = 0: the % DivisionByZero of \CALX_fround's division path, I+). I+, I-: 0; I?: I?. % The tag of X is made of catcode 12 by \string. inv() of \xintfloateval. % % \CALX_fe: X rounded to P digits by \CALX_fround, then \CALX_ftoraw and n % added to the exponent. The operator x[n] of \xintfloateval; X may be the % bare digits of the integer literal before [n] (a raw value: [0] is % appended, n added to its exponent, then rounded as F). %\end{lverb} % \begin{macrocode} \def\CALX_finv #1#2{\expandafter\CALX_finv_s\romannumeral`&&@#2\xint:{#1}}% \def\CALX_finv_in #1\xint:#2.{\CALX_finv_s #1\xint:{#2}}% \def\CALX_finv_s{\expandafter\CALX_finv_a\string}% \def\CALX_finv_a #1#2\xint:% {% \if I#1\xint_dothis{\CALX_finv_i#2}\fi \if F#1\xint_dothis {\expandafter\CALX_finv_r\romannumeral0\CALX_ftoraw{#1#2}[0]\xint:}\fi \if M#1\xint_dothis {\expandafter\CALX_finv_r\romannumeral0\CALX_mtoraw_t#1#2\xint:% [0]\xint:}\fi \xint_orthat{\CALX_finv_r#1#2[0]\xint:}% }% \def\CALX_finv_i #1#2{\if ?#1\xint_dothis{ I?}\fi\xint_orthat{ F+0.0.}}% \def\CALX_finv_r #1[#2]#3\xint:% {\expandafter\CALX_finv_t\the\numexpr-#2.#1/1/\xint:}% \def\CALX_finv_t #1.#2#3/#4/#5\xint:#6% {% \expandafter\CALX_fbr\romannumeral0\CALX_fround{#6}% {\expanded{\if-#2-#4/#3\else#4/#2#3\fi}[#1]}% }% \def\CALX_fe_in #1\xint:#2.{\CALX_fe_s #1\xint:{#2}}% \def\CALX_fe #1#2% {\expandafter\CALX_fe_s\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fe_s #1% {% \if I#1\xint_dothis\CALX_fe_i\fi \if F#1\xint_dothis\CALX_fe_n\fi \if M#1\xint_dothis\CALX_fe_n\fi \xint_orthat\CALX_fe_r #1% }% \def\CALX_fe_i #1\xint:#2#3{ #1}% \def\CALX_fe_n #1\xint:#2% {\expandafter\CALX_fe_a\romannumeral0\CALX_fround{#2}{#1}}% \def\CALX_fe_a #1\xint:% {\expandafter\CALX_fe_b\romannumeral0\CALX_ftoraw{#1}}% \def\CALX_fe_b #1[#2]#3{\expandafter\CALX_fe_c\the\numexpr#2+#3.{#1}}% \def\CALX_fe_c #1.#2{ #2[#1]}% \def\CALX_fe_r #1\xint:{\CALX_fe_t #1[0]\xint:}% \def\CALX_fe_t #1[#2]#3\xint:#4#5% {\expandafter\CALX_fe_u\the\numexpr#2+#5.{#1}{#4}}% \def\CALX_fe_u #1.#2#3% {\expandafter\CALX_fe_a\romannumeral0\CALX_fround{#3}{#2[#1]}{0}}% % \end{macrocode} % \subsection{Square root} % \subsubsection{\csh{CALX_fsqrt}} %\begin{lverb} % Syntax (use with \romannumeral0; P a \numexpr expression; X f-expanded % F, I or raw value): %( % \CALX_fsqrt{P}{X} -> Z Z = round_P(sqrt(round_P(X))) %) % \CALX_fsqrt{P}{X} (use with \romannumeral0, X f-expanded): % round_P(sqrt(round_P(X))), round half away from zero, as xint's % \XINTinFloatSqrt[P]. % % The operand is rounded by \CALX_fround. Special values: I? gives I?, % I+ gives I+, I- and negative operands signal InvalidOperation % (\CALX_nsig). Zero gives F+0.0. % % X = M 10^(8e), M of D digits (n blocks), o = 1 if D is odd, else 0. % % P <= 40 (\CALX_frt_ka...): K = max(2, ceil(P/8)), sh = 16K - D - o % (even), Y0 = M 10^sh has 16K digits, the first one zero if o = 1, and % sqrt(X) = sqrt(Y0) 10^(4e - sh/2). The top block v of Y0 (from the two % top blocks of M, \CALX_frt_kt) is at least 10^6; Y = 4^j Y0 with j the % least integer such that 4^j v >= 25000000 (j <= 3, no new block), as % required by \CALX_nsqrt_core, which gives s = floor(sqrt(Y)) (8K % digits) and r = Y - s^2. The blocks of Y are those of M 10^c 4^j, % c = sh mod 8, below zb = floor(sh/8) zero blocks (\CALX_frt_mul: % multiplication of a native by w < 2^31, base 10^4 limbs, w split as % w1 10^4 + w0). % % Then sqrt(Y0) = s/2^j + f/2^j, 0 <= f < 1, and s/2^j = s 5^j 10^(-j) % exactly. With E = 4e - sh/2 - j = 8a + b (0 <= b < 8), the native % float s 5^j 10^b 10^(8a) (\CALX_frt_mul, \CALX_fm_gb) is rounded to P % digits by \CALX_fround. This is the correctly rounded result: %- if 8K > P, floor(sqrt(Y0)) = floor(s/2^j) has 8K >= P + 1 digits and % the rounding bound is an integer, so the digits beyond it do not matter; %- if 8K = P and j > 0, rounding up is right iff sqrt(Y0) >= S0 + 1/2 % with S0 = floor(s/2^j), that is iff s mod 2^j >= 2^(j-1), that is iff % the first digit of the fraction s/2^j - S0 (the first dropped digit) % is at least 5; %- if 8K = P and j = 0, rounding up is right iff r > s; s is then % incremented (\CALX_frt_kh compares the block counts, then the top % blocks, then uses \CALX_nsub). % % P > 40 (\CALX_frt_gb): with %( %: j = max(0, ceil((2P + 1 - D)/8)), plus one if j - e is odd, %) % the integer N = M 10^(8j) has at least 2P + 1 digits, its integer % square root S (\CALX_nsqrtrem) has at least P + 1 digits, and % sqrt(X) = sqrt(N) 10^(4(e-j)); the native float S 10^(8(e-j)/2) is % rounded by \CALX_fround (\CALX_fm_gb), as in the first case. %\end{lverb} % \begin{macrocode} \def\CALX_fsqrt #1#2% {\expandafter\CALX_frt_a\romannumeral0\CALX_fround{#1}{#2}{#1}}% \def\CALX_frt_a #1#2% {\csname CALX_frt_\if I#1sp\else\if-#2ng\else b\fi\fi\endcsname#2}% \def\CALX_frt_sp #1#2\xint:#3% {% \if ?#1\xint_dothis{ I?}\fi \if +#1\xint_dothis{ I+}\fi \xint_orthat\CALX_frt_neg }% \def\CALX_frt_ng #1\xint:#2{\CALX_frt_neg}% \def\CALX_frt_neg{\CALX_nsig{InvalidOperation}{sqrt of negative}{}}% \def\CALX_frt_b #1#2.#3.#4\xint:#5% {% \csname CALX_frt_\ifnum#2=\xint_c_ z\else\ifnum#5>40 gb\else kz\fi\fi \endcsname{#2}{#3}{#4}{#5}% }% \def\CALX_frt_z #1#2#3#4{ F+0.0.}% \def\CALX_frt_kz #1#2#3#4% {% \expandafter\CALX_frt_ka\the\numexpr \ifnum#4<9 \xint_c_ii\else(\xint_c_ii*#4+\xint_c_vii)/16\fi.% {#1}{#2}{#3}{#4}% }% \def\CALX_frt_ka #1.#2% K, D {\expandafter\CALX_frt_kb\the\numexpr16*#1-#2-\ifodd#2 1\else0\fi.% #1.{#2}}% \def\CALX_frt_kb #1.% {\expandafter\CALX_frt_kc\the\numexpr(\xint_c_ii*#1-\xint_c_vii)/16.#1.}% \def\CALX_frt_kc #1.#2.#3.#4#5#6% zb, sh, K, D, e, blocks {% \expandafter\CALX_frt_kd\the\numexpr \CALX_nskip\CALX_frt_kt(\xint_c_ii*#4+\xint_c_vii)/16-\xint_c_i.% 100000000!#6\xint:{\the\numexpr#2-\xint_c_viii*#1}.% #1.#2.#3.{#4}{#5}{#6}% }% \def\CALX_frt_kt 1#1!1#2!#3\xint:#4% {#2*\CALX_pten{#4}+(#1+\CALX_pten{\xint_c_vii-#4}*5)/% \CALX_pten{\xint_c_viii-#4}-\xint_c_i}% \def\CALX_frt_kd #1.% {% \expandafter\CALX_frt_ke\the\numexpr \ifnum#1<25000000 \ifnum#1<6250000 \ifnum#1<1562500 3\else2\fi \else1\fi\else0\fi.% }% \def\CALX_frt_ke #1.#2.#3.#4.#5#6#7% j, zb, sh, K, D, e, blocks {% \expandafter\CALX_frt_kf\romannumeral0\CALX_frt_mul {\CALX_pten{#3-\xint_c_viii*#2}*\ifcase#1 1\or4\or16\or64\fi}0{N+.#7}% \xint:{#2}{#1}{#4}{#3}{#6}% }% \def\CALX_frt_kf N+#1.#2\xint:#3#4#5% product, zb, j, K {% \expandafter\CALX_nsqrt_core\expandafter\CALX_frt_kg \expanded{{\the\numexpr\xint_c_ii*#5}{\CALX_fa_z#3.\unexpanded{#2}}}% {#4}{#5}% }% \def\CALX_frt_kg #1#2#3#4#5#6#7% s, r, j, K, sh, e, P {% \ifnum\numexpr#3*100+\xint_c_viii*#4-#7=\xint_c_ \xint_dothis{\CALX_frt_kh#2#1\CALX_frt_ki0{#1}{#3}% {\xint_c_iv*#6-#5/\xint_c_ii}{#7}}\fi \xint_orthat{\CALX_frt_ki0{#1}{#3}{\xint_c_iv*#6-#5/\xint_c_ii-#3}{#7}}% }% \def\CALX_frt_kh N+#1.#2N+#3.#4\CALX_frt_ki0% {% \ifnum#1<#3 \xint_dothis{\CALX_frt_ki0}\fi \ifnum#1>#3 \xint_dothis{\CALX_frt_ki1}\fi \xint_orthat{\expandafter\CALX_frt_kj\the\numexpr \CALX_nskip\CALX_frt_kt #1-\xint_c_ii.#2\xint:{0}-% (\CALX_nskip\CALX_frt_kt #1-\xint_c_ii.#4\xint:{0})\relax.% N+#1.#2\xint:N+#3.#4\xint:}% }% \def\CALX_frt_kj #1.#2\xint:#3\xint:% {% \ifnum#1<\xint_c_ \xint_dothis{\CALX_frt_ki0}\fi \ifnum#1>\xint_c_ \xint_dothis{\CALX_frt_ki1}\fi \xint_orthat{\expandafter\CALX_frt_kk\romannumeral0\CALX_nsub{#2}{#3}% \xint:}% }% \def\CALX_frt_kk N#1#2.#3\xint:% {% \if-#1\xint_dothis{\CALX_frt_ki0}\fi \ifnum#2=\xint_c_ \xint_dothis{\CALX_frt_ki0}\fi \xint_orthat{\CALX_frt_ki1}% }% \def\CALX_frt_ki #1#2#3#4% d, s, j, E {\expandafter\CALX_frt_km\the\numexpr(\xint_c_ii*(#4)-\xint_c_vii)/16.% #1{#2}{#3}{#4}}% \def\CALX_frt_km #1.#2#3#4#5% a, d, s, j, E (P follows) {% \expandafter\CALX_fm_gb\romannumeral0\CALX_frt_mul {\ifcase#4 1\or5\or25\or125\fi*\CALX_pten{#5-\xint_c_viii*#1}}#2% {#3}\xint:{#1}% }% \def\CALX_frt_mul #1#2#3% {\expandafter\CALX_frt_mua\the\numexpr(#1+5000)/10000-\xint_c_i.% {#1}#2#3\xint:}% \def\CALX_frt_mua #1.#2#3N+#4.#5\xint:% {\expanded{\noexpand\CALX_nnorm+% \expandafter\CALX_frt_mi\the\numexpr#2-#1*10000.#1.#3.#51;!}}% \def\CALX_frt_mi #1.#2.#3.1#4!% {\expandafter\CALX_frt_mj\the\numexpr#4+#3.#1.#2.}% \def\CALX_frt_mj #1.#2.#3.% {\expandafter\CALX_frt_mn\the\numexpr(#1+5000)/10000-\xint_c_i.% #1.#2.#3.0.0.}% \def\CALX_frt_mm #1.#2.#3.#4.1#5#6!% {% \xint_gob_til_sc#5\CALX_frt_mz;% \expandafter\CALX_frt_mn\the\numexpr(#5#6+5000)/10000-\xint_c_i.% #5#6.#1.#2.#3.#4.% }% \def\CALX_frt_mz;#1.#2.#3.#4.#5.#6.% {% \the\numexpr#5*#4+#6-((#5*#4+#6+50000000)/\xint_c_e_viii-\xint_c_i)*% \xint_c_e_viii+\xint_c_e_viii!% \the\numexpr(#5*#4+#6+50000000)/\xint_c_e_viii-\xint_c_i+% \xint_c_e_viii!1;!% }% \def\CALX_frt_mn #1.#2.#3.#4.#5.#6.% gh, x, w0, w1, ph, c {\expandafter\CALX_frt_mo\the\numexpr(#2-#1*10000)*#3+#5*#4+#6.% #1.#2.#3.#4.}% \def\CALX_frt_mo #1.#2.#3.#4.#5.% t0, gh, x, w0, w1 {\expandafter\CALX_frt_mp\the\numexpr#2*#4+(#3-#2*10000)*#5+% (#1+5000)/10000-\xint_c_i.#1.#2.#4.#5.}% \def\CALX_frt_mp #1.#2.#3.#4.#5.% t1, t0, gh, w0, w1 {% \the\numexpr(#1-((#1+5000)/10000-\xint_c_i)*10000)*10000+% #2-((#2+5000)/10000-\xint_c_i)*10000+\xint_c_e_viii!% \expandafter\CALX_frt_mq\the\numexpr(#1+5000)/10000-\xint_c_i.% #4.#5.#3.% }% \def\CALX_frt_mq #1.#2.#3.#4.{\CALX_frt_mm #2.#3.#4.#1.}% \def\CALX_frt_gb #1#2#3#4% {% \expandafter\CALX_frt_c\the\numexpr (\xint_c_ii*(\xint_c_ii*#4+\xint_c_i-#1)+\xint_c_vii)/16.% {#1}{#2}{#3}{#4}% }% \def\CALX_frt_c #1.#2#3% {% \expandafter\CALX_frt_d\the\numexpr \ifnum#1<\xint_c_ 0\else#1\fi \ifodd\numexpr\ifnum#1<\xint_c_ 0\else#1\fi-#3\relax+\xint_c_i\fi.% {#2}{#3}% }% \def\CALX_frt_d #1.#2#3#4% {% \expandafter\CALX_frt_e\romannumeral0\CALX_nsqrtrem {\expanded{N+\the\numexpr(\xint_c_ii*#2+\xint_c_vii)/16+#1.% \CALX_fa_z#1.}#4}% \xint:{(#3-#1)/\xint_c_ii}% }% \def\CALX_frt_e #1#2{\CALX_fm_gb #1}% % \end{macrocode} % \subsection{Factorials and binomial coefficients} %\begin{lverb} % Syntax (use with \romannumeral0; P, n, a, b, x, y \numexpr expressions % with integer values): %( % \CALX_ffac{P}{n} -> Y n! %: \CALX_fpfac{P}{a}{b} -> Y (a+1)(a+2)...b %: \CALX_fbinom{P}{x}{y} -> Y binomial(x, y) %) % Y: the native F value rounded to P digits, or I? (InvalidOperation: % n < 0 or n >= 10^8; a < b with b >= 10^8 or a <= -10^8; x < 0 or % x >= 10^8). 0! = 1; pfactorial is 1 if a >= b, 0 if a < 0 <= b, and % for a < b < 0 the product of the negative factors; binomial is 0 if % y < 0 or y > x, 1 if y = 0 or y = x. % % The engine is xintfrac's: the value is kept as Q blocks 1<8d>! (least % significant first), terminated by 1;!, followed by [E], E a multiple of % 8, and multiplied by products of 4, 3, 2 or 1 consecutive integers % (each product < 10^8; \CALX_ffac_smallmul, own small multiplication % which reports a carry). When a carry creates a block Q + 1 the least % significant one is dropped and E increases by 8. \CALX_ffac_increaseP % (\CALX_fpfac_increaseP) chooses Q from the target p and a factor c % (their last two arguments) so that the relative error is below % c 10^(-p-1): 8Q >= p + 9 + k, k the number of digits of the count of % products divided by c (\CALX_ndig). The blocks are those of a native % value: \CALX_ffac_out builds it (\CALX_nnorm, \CALX_fx_c) and rounds it % once (\CALX_fnround). % % Precisions. n! and pfactorial: p = P + 2, c = 1, relative error below % 10^(-P-3), at most 0.001 ulp of the P-digit result. Binomial: pfac(y, x) % / (x - y)! if y >= x - y, else pfac(x - y, x) / y!; numerator and % denominator with p = P + 4, c = 4, each rounded to P + 5 digits, the % quotient correctly rounded to P digits by \CALX_fr_xk (calxfp's division % of natives): relative error below 2 (4 10^(-P-5) + 5 10^(-P-5)), less than % 0.002 ulp. %\end{lverb} % \begin{macrocode} \def\CALX_ffac #1#2% {\expandafter\CALX_ffac_fork_a\the\numexpr#2.\xint_c_i{#1+\xint_c_ii}% \CALX_ffac_out{#1}}% \def\CALX_ffac_fork_a #1% {% \xint_UDzerominusfork #1-\CALX_ffac_iszero 0#1\CALX_ffac_isneg 0-{\CALX_ffac_fork_b #1}% \krof }% \def\CALX_ffac_iszero #1.#2#3#4#5{ F+1.0.100000001!}% \def\CALX_ffac_isneg #1.#2#3#4#5% {\CALX_nsig{InvalidOperation}{factorial of a negative integer}{}}% \def\CALX_ffac_fork_b #1.% {% \ifnum #1>\xint_c_e_viii_mone\xint_dothis\CALX_ffac_toobig\fi \ifnum #1>\xint_c_e_iv\xint_dothis\CALX_ffac_vbig \fi \ifnum #1>465 \xint_dothis\CALX_ffac_big\fi \ifnum #1>101 \xint_dothis\CALX_ffac_med\fi \xint_orthat\CALX_ffac_small #1.% }% \def\CALX_ffac_toobig #1.#2#3#4#5% {\CALX_nsig{InvalidOperation}{factorial of an integer >= 10^8}{}}% \def\CALX_ffac_vbig {\expandafter\CALX_ffac_vbigloop_a \the\numexpr \CALX_ffac_increaseP \xint_c_i }% \def\CALX_ffac_big {\expandafter\CALX_ffac_bigloop_a \the\numexpr \CALX_ffac_increaseP \xint_c_ii }% \def\CALX_ffac_med {\expandafter\CALX_ffac_medloop_a \the\numexpr \CALX_ffac_increaseP \xint_c_iii }% \def\CALX_ffac_small {\expandafter\CALX_ffac_smallloop_a \the\numexpr \CALX_ffac_increaseP \xint_c_iv }% \def\CALX_ffac_increaseP #1#2.#3#4% {% #2\expandafter.\the\numexpr\xint_c_viii*% ((\xint_c_iv+#4+\CALX_ndig{#2/(#1*#3)})/\xint_c_viii).% }% \def\CALX_ffac_out #1;![#2]#3% {\CALX_fnround{#3}{\expandafter\CALX_fx_c\the\numexpr#2/\xint_c_viii \expandafter.\romannumeral0\CALX_nnorm +#1;!\xint:}}% \def\CALX_ffac_vbigloop_a #1.#2.% {% \CALX_ffac_bigloop_a \xint_c_e_iv.#2.% {\expandafter\CALX_ffac_vbigloop_loop\the\numexpr 100010001\expandafter.% \the\numexpr \xint_c_e_viii+#1.}% }% \def\CALX_ffac_vbigloop_loop #1.#2.% {% \ifnum #1>#2 \expandafter\CALX_ffac_loop_exit\fi \expandafter\CALX_ffac_vbigloop_loop \the\numexpr #1+\xint_c_i\expandafter.% \the\numexpr #2\expandafter.\the\numexpr\CALX_ffac_mul #1!% }% \def\CALX_ffac_bigloop_a #1.% {% \expandafter\CALX_ffac_bigloop_b \the\numexpr #1+\xint_c_i-\xint_c_ii*((#1-464)/\xint_c_ii).#1.% }% \def\CALX_ffac_bigloop_b #1.#2.#3.% {% \expandafter\CALX_ffac_medloop_a \the\numexpr #1-\xint_c_i.#3.{\CALX_ffac_bigloop_loop #1.#2.}% }% \def\CALX_ffac_bigloop_loop #1.#2.% {% \ifnum #1>#2 \expandafter\CALX_ffac_loop_exit\fi \expandafter\CALX_ffac_bigloop_loop \the\numexpr #1+\xint_c_ii\expandafter.% \the\numexpr #2\expandafter.\the\numexpr\CALX_ffac_bigloop_mul #1!% }% \def\CALX_ffac_bigloop_mul #1!% {% \expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)!% }% \def\CALX_ffac_medloop_a #1.% {% \expandafter\CALX_ffac_medloop_b \the\numexpr #1+\xint_c_i-\xint_c_iii*((#1-100)/\xint_c_iii).#1.% }% \def\CALX_ffac_medloop_b #1.#2.#3.% {% \expandafter\CALX_ffac_smallloop_a \the\numexpr #1-\xint_c_i.#3.{\CALX_ffac_medloop_loop #1.#2.}% }% \def\CALX_ffac_medloop_loop #1.#2.% {% \ifnum #1>#2 \expandafter\CALX_ffac_loop_exit\fi \expandafter\CALX_ffac_medloop_loop \the\numexpr #1+\xint_c_iii\expandafter.% \the\numexpr #2\expandafter.\the\numexpr\CALX_ffac_medloop_mul #1!% }% \def\CALX_ffac_medloop_mul #1!% {% \expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_ffac_smallloop_a #1.% {% \csname CALX_ffac_smallloop_\the\numexpr #1-\xint_c_iv*(#1/\xint_c_iv)\relax \endcsname #1.% }% \expandafter\def\csname CALX_ffac_smallloop_1\endcsname #1.#2.% {% \CALX_ffac_addzeros #2.100000001!.{2.#1.}{#2}% }% \expandafter\def\csname CALX_ffac_smallloop_-2\endcsname #1.#2.% {% \CALX_ffac_addzeros #2.100000002!.{3.#1.}{#2}% }% \expandafter\def\csname CALX_ffac_smallloop_-1\endcsname #1.#2.% {% \CALX_ffac_addzeros #2.100000006!.{4.#1.}{#2}% }% \expandafter\def\csname CALX_ffac_smallloop_0\endcsname #1.#2.% {% \CALX_ffac_addzeros #2.100000024!.{5.#1.}{#2}% }% \def\CALX_ffac_addzeros #1.% {% \ifnum #1=\xint_c_viii \expandafter\CALX_ffac_addzeros_exit\fi \expandafter\CALX_ffac_addzeros \the\numexpr #1-\xint_c_viii.100000000!% }% \def\CALX_ffac_addzeros_exit #1.#2.#3#4% {\CALX_ffac_smallloop_loop #3#21;![-#4]}% \def\CALX_ffac_smallloop_loop #1.#2.% {% \ifnum #1>#2 \expandafter\CALX_ffac_loop_exit\fi \expandafter\CALX_ffac_smallloop_loop \the\numexpr #1+\xint_c_iv\expandafter.% \the\numexpr #2\expandafter.\romannumeral0\CALX_ffac_smallloop_mul #1!% }% \def\CALX_ffac_smallloop_mul #1!% {% \expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% }%[[ \def\CALX_ffac_loop_exit #1!#2]#3{#3#2]}% \def\CALX_ffac_mul 1#1!% {\expandafter\CALX_ffac_mul_a\the\numexpr\CALX_ffac_smallmul 10!{#1}}% \def\CALX_ffac_mul_a #1-#2% {% \if#21\xint_afterfi{\expandafter\space\xint_gob_til_exclam}\else \expandafter\space\fi #11;!% }% \def\CALX_ffac_minimulwc_a #1#2#3#4#5!#6#7#8#9% {% \CALX_ffac_minimulwc_b {#1#2#3#4}{#5}{#6#7#8#9}% }% \def\CALX_ffac_minimulwc_b #1#2#3#4!#5% {% \expandafter\CALX_ffac_minimulwc_c \the\numexpr \xint_c_e_ix+#5+#2*#4!{{#1}{#2}{#3}{#4}}% }% \def\CALX_ffac_minimulwc_c 1#1#2#3#4#5#6!#7% {% \expandafter\CALX_ffac_minimulwc_d {#1#2#3#4#5}#7{#6}% }% \def\CALX_ffac_minimulwc_d #1#2#3#4#5% {% \expandafter\CALX_ffac_minimulwc_e \the\numexpr \xint_c_e_ix+#1+#2*#5+#3*#4!{#2}{#4}% }% \def\CALX_ffac_minimulwc_e 1#1#2#3#4#5#6!#7#8#9% {% 1#6#9\expandafter!% \the\numexpr\expandafter\CALX_ffac_smallmul \the\numexpr \xint_c_e_viii+#1#2#3#4#5+#7*#8!% }% \def\CALX_ffac_smallmul 1#1!#21#3!% {% \xint_gob_til_sc #3\CALX_ffac_smallmul_end;% \CALX_ffac_minimulwc_a #2!#3!{#1}{#2}% }% \def\CALX_ffac_smallmul_end;\CALX_ffac_minimulwc_a #1!;!#2#3[#4]% {% \ifnum #2=\xint_c_ \expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo \fi {-2\relax[#4]}% {1#2\expandafter!\expandafter-\expandafter1\expandafter [\the\numexpr #4+\xint_c_viii]}% }% \def\CALX_fpfac #1#2#3% {% \expandafter\CALX_fpfac_fork \the\numexpr #2\expandafter.\the\numexpr #3.\xint_c_i{#1+\xint_c_ii}{#1}% }% \def\CALX_fpfac_fork #1#2.#3#4.% {% \unless\ifnum #1#2<#3#4 \xint_dothis\CALX_fpfac_one\fi \if-#3\xint_dothis\CALX_fpfac_neg \fi \if-#1\xint_dothis\CALX_fpfac_zero\fi \ifnum #3#4>\xint_c_e_viii_mone\xint_dothis\CALX_fpfac_outofrange\fi \xint_orthat \CALX_fpfac_increaseP #1#2.#3#4.% }% \def\CALX_fpfac_outofrange #1.#2.#3#4#5{\CALX_iipfac_inv #1.#2.}% \def\CALX_fpfac_one #1.#2.#3#4#5{ F+1.0.100000001!}% \def\CALX_fpfac_zero #1.#2.#3#4#5{ F+0.0.}% \def\CALX_fpfac_neg -#1.-#2.% {% \ifnum #1>\xint_c_e_viii\xint_dothis\CALX_fpfac_outofrange\fi \xint_orthat {% \ifodd\numexpr#2-#1\relax \xint_afterfi{\expandafter\CALX_fpfac_m\romannumeral0}\fi \expandafter\CALX_fpfac_increaseP}% \the\numexpr #2-\xint_c_i\expandafter.\the\numexpr#1-\xint_c_i.% }% \def\CALX_fpfac_m F+{ F-}% \def\CALX_fpfac_increaseP #1.#2.#3#4% {% \expandafter\CALX_fpfac_a \the\numexpr \xint_c_viii*((\xint_c_iv+#4+\CALX_ndig{(#2-#1-\xint_c_i)% /\ifnum #2>\xint_c_e_iv #3\else(#3*\xint_c_ii)\fi})/\xint_c_viii).% #1.#2.% }% \def\CALX_fpfac_a #1.#2.#3.% {% \expandafter\CALX_fpfac_b\the\numexpr \xint_c_i+#2\expandafter.% \the\numexpr#3\expandafter.% \romannumeral0\CALX_fpfac_addzeroes #1.100000001!1;![-#1]% }% \def\CALX_fpfac_addzeroes #1.% {% \ifnum #1=\xint_c_viii \expandafter\CALX_fpfac_addzeroes_exit\fi \expandafter\CALX_fpfac_addzeroes\the\numexpr #1-\xint_c_viii.100000000!% }% \def\CALX_fpfac_addzeroes_exit #1.{ }% \def\CALX_fpfac_b #1.% {% \ifnum #1>9999 \xint_dothis\CALX_fpfac_vbigloop \fi \ifnum #1>463 \xint_dothis\CALX_fpfac_bigloop \fi \ifnum #1>98 \xint_dothis\CALX_fpfac_medloop \fi \xint_orthat\CALX_fpfac_smallloop #1.% }% \def\CALX_fpfac_smallloop #1.#2.% {% \ifcase\numexpr #2-#1\relax \expandafter\CALX_fpfac_end_ \or \expandafter\CALX_fpfac_end_i \or \expandafter\CALX_fpfac_end_ii \or \expandafter\CALX_fpfac_end_iii \else\expandafter\CALX_fpfac_smallloop_a \fi #1.#2.% }% \def\CALX_fpfac_smallloop_a #1.#2.% {% \expandafter\CALX_fpfac_smallloop_b \the\numexpr #1+\xint_c_iv\expandafter.% \the\numexpr #2\expandafter.% \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*% (#1+\xint_c_iii)!% }% \def\CALX_fpfac_smallloop_b #1.% {% \ifnum #1>98 \expandafter\CALX_fpfac_medloop \else \expandafter\CALX_fpfac_smallloop \fi #1.% }% \def\CALX_fpfac_medloop #1.#2.% {% \ifcase\numexpr #2-#1\relax \expandafter\CALX_fpfac_end_ \or \expandafter\CALX_fpfac_end_i \or \expandafter\CALX_fpfac_end_ii \else\expandafter\CALX_fpfac_medloop_a \fi #1.#2.% }% \def\CALX_fpfac_medloop_a #1.#2.% {% \expandafter\CALX_fpfac_medloop_b \the\numexpr #1+\xint_c_iii\expandafter.% \the\numexpr #2\expandafter.% \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_fpfac_medloop_b #1.% {% \ifnum #1>463 \expandafter\CALX_fpfac_bigloop \else \expandafter\CALX_fpfac_medloop \fi #1.% }% \def\CALX_fpfac_bigloop #1.#2.% {% \ifcase\numexpr #2-#1\relax \expandafter\CALX_fpfac_end_ \or \expandafter\CALX_fpfac_end_i \else\expandafter\CALX_fpfac_bigloop_a \fi #1.#2.% }% \def\CALX_fpfac_bigloop_a #1.#2.% {% \expandafter\CALX_fpfac_bigloop_b \the\numexpr #1+\xint_c_ii\expandafter.% \the\numexpr #2\expandafter.% \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)!% }% \def\CALX_fpfac_bigloop_b #1.% {% \ifnum #1>9999 \expandafter\CALX_fpfac_vbigloop \else \expandafter\CALX_fpfac_bigloop \fi #1.% }% \def\CALX_fpfac_vbigloop #1.#2.% {% \ifnum #2=#1 \expandafter\CALX_fpfac_end_ \else\expandafter\CALX_fpfac_vbigloop_a \fi #1.#2.% }% \def\CALX_fpfac_vbigloop_a #1.#2.% {% \expandafter\CALX_fpfac_vbigloop \the\numexpr #1+\xint_c_i\expandafter.% \the\numexpr #2\expandafter.% \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr\xint_c_e_viii+#1!% }% \def\CALX_fpfac_end_iii #1.#2.% {% \expandafter\CALX_ffac_out \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*% (#1+\xint_c_iii)!% }% \def\CALX_fpfac_end_ii #1.#2.% {% \expandafter\CALX_ffac_out \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% }% \def\CALX_fpfac_end_i #1.#2.% {% \expandafter\CALX_ffac_out \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1*(#1+\xint_c_i)!% }% \def\CALX_fpfac_end_ #1.#2.% {% \expandafter\CALX_ffac_out \romannumeral0\expandafter\CALX_ffac_mul \the\numexpr \xint_c_e_viii+#1!% }% \def\CALX_fbinom #1#2#3% {% \expandafter\CALX_fbinom_a\the\numexpr#2\expandafter.% \the\numexpr#3\expandafter.\the\numexpr#1.% }% \def\CALX_fbinom_a #1.#2.% {% \expandafter\CALX_fbinom_fork \the\numexpr #1-#2.#2.#1.% }% \def\CALX_fbinom_fork #1#2.#3#4.#5#6.% {% \if-#5\xint_dothis \CALX_fbinom_inv\fi \if-#1\xint_dothis \CALX_fbinom_zero\fi \if-#3\xint_dothis \CALX_fbinom_zero\fi \if0#1\xint_dothis \CALX_fbinom_one\fi \if0#3\xint_dothis \CALX_fbinom_one\fi \ifnum #5#6>\xint_c_e_viii_mone \xint_dothis\CALX_fbinom_inv\fi \ifnum #1#2>#3#4 \xint_dothis\CALX_fbinom_ab \fi \xint_orthat\CALX_fbinom_aa #1#2.#3#4.#5#6.% }% \def\CALX_fbinom_inv #1.#2.#3.#4.{\CALX_iibinom_inv}% \def\CALX_fbinom_one #1.#2.#3.#4.{ F+1.0.100000001!}% \def\CALX_fbinom_zero #1.#2.#3.#4.{ F+0.0.}% \def\CALX_fbinom_ab #1.#2.{\CALX_fbinom_aa #2.#1.}% \def\CALX_fbinom_aa #1.#2.#3.#4.% {% \expandafter\CALX_fbinom_q\romannumeral0\CALX_fpfac_increaseP #2.#3.\xint_c_iv{#4+\xint_c_iv}{#4+\xint_c_v}\xint:#1.{#4}% }% \def\CALX_fbinom_q #1\xint:#2.#3% {% \expandafter\CALX_fbinom_r\romannumeral0\CALX_ffac_fork_b #2.\xint_c_iv{#3+\xint_c_iv}\CALX_ffac_out{#3+\xint_c_v}% \xint:#1\xint:{#3}% }% \def\CALX_fbinom_r #1\xint:#2\xint:{\CALX_fr_xk #2\xint:#1\xint:}% % \end{macrocode} % \subsection{Fixed-point multiply-subtract} %\begin{lverb} % \CALX_xf (s = 1..9, n = s or s+1 <= 9, written as letters; % generated by tools/xfix_gen.py), used by the sin/cos series of % calxtrig.sty, one call per level: %( %: \CALX_xf{u1}..{u4}{t1}..{ts}{w1}..{w4} %: gives {w1}..{w4}{r1}..{rn} %) % Limbs of four digits, most significant first. T is the integer sum of % the tj 10^(4(s-j)), U the fraction sum of the ui 10^(-4i), given as % q = 4 ceil(s/4) limbs: are u5 to uq, flat. C has n limbs ci: % with ec = max(s-6, 0), is {cn}{c(n-1)}... for the columns % e = 0..ec-1, is +c(n-ec);+c(n-ec-1);...;+c1; with {} after the % `;` of column 0 when ec = 0. is one token, {w1}..{w4} one braced % chunk put back in front of the result (the first limbs of U for the % next level). R is C minus U T truncated, modulo 10^(4n): column e % (weight 10^(4e)), e = n-1 down to -2, is %( %: 2100000000 + c(n-e) - (sum of ui tj, i + j = s - e) + carry, %) % with c(n-e) only for e >= 0, i, j <= s, and also u(s+1) t1 in column -2 % when s mod 4 > 0 (the terms of the former \CALX_m_ of calxtrig: % same results). The value has ten digits (s <= 11 products, see % calxtrig); its first six minus 210000 are the carry, floor, into the % next column; its last four are the limb, dropped for e < 0 and for the % carry out of the top column. % % Layout, after l3fp's \__fp_fixed_mul:wwn: one nested \numexpr chain, % innermost column evaluated first, written in two passes. Down pass: % every column is opened from the top with its products u1..u4 times a % sliding window of T. Up pass: the rest of column -2 (products with % i >= 5), then `;`, the rest of column -1, `;`, and so on up to column % ec, whose c and the following ones come from . A column is thus % continued after its inner columns: its pack \CALX_xq or \CALX_xp % takes the next `;`-delimited text into the enclosing \numexpr and puts % the limb behind it; \CALX_xp collects the limbs in one braced group % (empty group after the `;` of column 0), \CALX_xe and \CALX_xg output % , the chunk that follows it, the top limb, the group's contents. % Successive macros (suffixes x, y, z, w, v, u, r) take at most nine % arguments: limbs passed on, the low limbs of T needed by the up pass % in one braced group, the next items of the stream. %\end{lverb} % \begin{macrocode} \def\CALX_xe #1#2#3#4#5#6#7;#8{\CALX_xg{{#7}#8}}% \def\CALX_xg #1#2#3{#2#3#1}% \def\CALX_xp #1#2#3#4#5#6#7;#8#9;{+#1#2#3#4#5#6-210000#9;{{#7}#8}}% \def\CALX_xq #1#2#3#4#5#6#7;#8;{+#1#2#3#4#5#6-210000#8;}% % generated by tools/xfix_gen.py \def\CALX_xfab #1#2#3#4#5% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xq\the\numexpr2100000000-#1*#5% \expandafter\CALX_xq\the\numexpr2100000000-#2*#5;;% }% \def\CALX_xfbb #1#2#3#4#5#6% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xq\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xq\the\numexpr2100000000-#3*#5-#2*#6;;% }% \def\CALX_xfbc #1#2#3#4#5#6% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xq\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xq\the\numexpr2100000000-#3*#5-#2*#6;;% }% \def\CALX_xfcc #1#2#3#4#5#6#7% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xq\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#7;;% }% \def\CALX_xfcd #1#2#3#4#5#6#7% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xq\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#7;;% }% \def\CALX_xfdd #1#2#3#4#5#6#7#8% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#7-#2*#8;;% }% \def\CALX_xfde #1#2#3#4#5#6#7#8% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#7-#2*#8;;% }% \def\CALX_xfee #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfeex{#5}{#6}% }% \def\CALX_xfeex #1#2#3#4#5#6% {% -#3*#2-#4*#1;-#3*#1;% }% \def\CALX_xfef #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfefx{#5}{#6}% }% \def\CALX_xfefx #1#2#3#4#5#6% {% -#3*#2-#4*#1;-#3*#1;% }% \def\CALX_xfff #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfffx{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xfffx #1#2#3#4#5#6#7#8% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8% \CALX_xfffy#7% }% \def\CALX_xfffy #1#2#3#4#5#6#7% {% -#4*#3-#5*#2-#6*#1;-#4*#2-#5*#1;-#4*#1% }% \def\CALX_xffg #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xffgx{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xffgx #1#2#3#4#5#6#7#8% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8% \CALX_xffgy#7% }% \def\CALX_xffgy #1#2#3#4#5#6#7% {% -#4*#3-#5*#2-#6*#1;-#4*#2-#5*#1;-#4*#1% }% \def\CALX_xfgg #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xp\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfggx{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xfggx #1#2#3#4#5#6#7#8#9% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#8-#2*#9% \CALX_xfggy{#5}#7% }% \def\CALX_xfggy #1#2#3#4#5#6#7#8#9% {% -#5*#1-#6*#4-#7*#3-#8*#2;-#5*#4-#6*#3-#7*#2;-#5*#3-#6*#2+#9;{}-#5*#2% }% \def\CALX_xfgh #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xp\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfghx{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xfghx #1#2#3#4#5#6#7#8#9% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#8-#2*#9% \CALX_xfghy{#5}#7% }% \def\CALX_xfghy #1#2#3#4#5#6#7#8#9% {% -#5*#1-#6*#4-#7*#3-#8*#2;-#5*#4-#6*#3-#7*#2;-#5*#3-#6*#2+#9;{}-#5*#2% }% \def\CALX_xfhh #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xp\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfhhx{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xfhhx #1#2#3#4#5#6#7#8#9% {% -#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#8-#2*#9% \CALX_xfhhy{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}#7}% }% \def\CALX_xfhhy #1#2#3#4#5#6#7#8% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8% \CALX_xfhhz#7% }% \def\CALX_xfhhz #1#2#3#4#5#6#7#8#9% {% -#6*#2-#7*#1-#8*#5-#9*#4;-#6*#1-#7*#5-#8*#4-#9*#3;-#6*#5-#7*#4-#8*#3% \CALX_xfhhw{#3}{#4}{#6}{#7}% }% \def\CALX_xfhhw #1#2#3#4#5#6% {% +#5;{}-#3*#2-#4*#1+#6;-#3*#1% }% \def\CALX_xfhi #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xp\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfhix{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xfhix #1#2#3#4#5#6#7#8#9% {% -#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#8-#2*#9% \CALX_xfhiy{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}#7}% }% \def\CALX_xfhiy #1#2#3#4#5#6#7#8% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8% \CALX_xfhiz#7% }% \def\CALX_xfhiz #1#2#3#4#5#6#7#8#9% {% -#6*#2-#7*#1-#8*#5-#9*#4;-#6*#1-#7*#5-#8*#4-#9*#3;-#6*#5-#7*#4-#8*#3% \CALX_xfhiw{#3}{#4}{#6}{#7}% }% \def\CALX_xfhiw #1#2#3#4#5#6% {% +#5;{}-#3*#2-#4*#1+#6;-#3*#1% }% \def\CALX_xfii #1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_xe\the\numexpr2100000000% \expandafter\CALX_xp\the\numexpr2100000000-#1*#5% \expandafter\CALX_xp\the\numexpr2100000000-#2*#5-#1*#6% \expandafter\CALX_xp\the\numexpr2100000000-#3*#5-#2*#6-#1*#7% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#7-#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#7-#2*#8-#1*#9% \expandafter\CALX_xp\the\numexpr2100000000-#4*#7-#3*#8-#2*#9% \CALX_xfiix{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}{#7}}% }% \def\CALX_xfiix #1#2#3#4#5#6#7#8#9% {% -#1*#8% \expandafter\CALX_xp\the\numexpr2100000000-#4*#5-#3*#6-#2*#8-#1*#9% \expandafter\CALX_xp\the\numexpr2100000000-#4*#6-#3*#8-#2*#9% \CALX_xfiiy{#1}{#2}{#3}{#4}{#8}{#9}{{#5}{#6}#7}% }% \def\CALX_xfiiy #1#2#3#4#5#6#7#8#9% {% -#1*#8% \expandafter\CALX_xq\the\numexpr2100000000-#4*#5-#3*#6-#2*#8-#1*#9% \expandafter\CALX_xq\the\numexpr2100000000-#4*#6-#3*#8-#2*#9% \CALX_xfiiz{#5}{#7}% }% \def\CALX_xfiiz #1#2#3#4#5#6% {% -#3*#1% \CALX_xfiiw{#4}{#5}{#6}#2{{#3}}% }% \def\CALX_xfiiw #1#2#3#4#5#6#7#8#9% {% -#1*#5-#2*#4-#3*#8% \CALX_xfiiv{#5}{#6}{#7}#9{{#1}{#2}{#3}{#4}{#8}}% }% \def\CALX_xfiiv #1#2#3#4#5#6#7#8#9% {% -#6*#3-#7*#2;-#4*#1% \CALX_xfiiu{#2}{#3}{#4}{#6}#5% }% \def\CALX_xfiiu #1#2#3#4#5#6#7#8#9% {% -#5*#8-#6*#9-#7*#2-#4*#1;-#3*#8-#5*#9-#6*#2-#7*#1% \CALX_xfiir{#1}{#2}{#3}{#5}{#6}{#9}% }% \def\CALX_xfiir #1#2#3#4#5#6#7#8#9% {% +#7;{}-#3*#6-#4*#2-#5*#1+#8;-#3*#2-#4*#1+#9;-#3*#1% }% \catcode`F=11 \catcode`N=11 \catcode`I=11 % \end{macrocode} % \subsection{\csh{calxFpFloat}, \csh{calxFpFloatdigits}, % \csh{calxFpRoundTo}, \csh{calxFpTruncTo}} %\begin{lverb} % Syntax (f-expandable; P, n \numexpr expressions, X an F, I or xint raw % value, f-expanded; \calxFpRoundTo and \calxFpTruncTo accept M values % too): %( % \calxFpFloat[P]{X} -> Y %: \calxFpFloatdigits{X} -> Y (P = \XINTdigits) %: \calxFpRoundTo{n}{X} -> Y the multiple of 10^-n nearest to X %: \calxFpTruncTo{n}{X} -> Y the multiple of 10^-n between 0 and X %) % \calxFpFloat, \calxFpFloatdigits: X rounded to P significant digits by % \CALX_fround (F or I value). They implement float(), float_dgt(), % sfloat() of \xintfloateval. \calxFpRoundTo, \calxFpTruncTo: exact F % value (ties away from zero), I unchanged, by \CALX_rt_a; they implement % round(x, n) and trunc(x, n). The \xint: after Y is removed by \CALX_fbr. %\end{lverb} % \begin{macrocode} \def\CALX_fbr #1\xint:{ #1}% \def\calxFpFloatdigits {\romannumeral0\expandafter\CALX_fbr\romannumeral0\CALX_fround\XINTdigits}% \def\calxFpFloat [#1]% {\romannumeral0\expandafter\CALX_fbr\romannumeral0\CALX_fround{#1}}% \def\calxFpRoundTo #1#2% {\romannumeral0\expandafter\CALX_fbr\romannumeral0\expandafter \CALX_rt_a\expandafter\CALX_fr_b\the\numexpr#1\expandafter.% \romannumeral`&&@#2\xint:}% \def\calxFpTruncTo #1#2% {\romannumeral0\expandafter\CALX_fbr\romannumeral0\expandafter \CALX_rt_a\expandafter\CALX_rt_t\the\numexpr#1\expandafter.% \romannumeral`&&@#2\xint:}% % \end{macrocode} % \subsection{\csh{calxFpFac}, \csh{calxFpFacdigits}, \csh{calxFpPFactorial}, % \csh{calxFpBinomial}} %\begin{lverb} % Syntax (f-expandable; X, A, B parser values, f-expanded; P a \numexpr % expression): %( % \calxFpFacdigits{X} -> Y X! (P = \XINTdigits) %: \calxFpFac[P]{X} -> Y X! %: \calxFpPFactorial{A}{B} -> Y (A+1)(A+2)...B %: \calxFpBinomial{X}{A} -> Y binomial(X, A) %) % factorial(), !, pfactorial() and binomial() of \xintfloateval. The % arguments are truncated to integers by \CALX_fnum (an I value signals % InvalidOperation and counts as 0); Y: native F rounded to P digits, or % I? (\CALX_ffac, \CALX_fpfac, \CALX_fbinom). %\end{lverb} % \begin{macrocode} \def\CALX_fpint #1% {\romannumeral0\expandafter\CALX_fnum\romannumeral`&&@#1\xint:}% \def\calxFpFacdigits #1{\romannumeral0\CALX_ffac\XINTdigits{\CALX_fpint{#1}}}% \def\calxFpFac [#1]#2{\romannumeral0\CALX_ffac{#1}{\CALX_fpint{#2}}}% \def\calxFpPFactorial #1#2% {\romannumeral0\CALX_fpfac\XINTdigits{\CALX_fpint{#1}}{\CALX_fpint{#2}}}% \def\calxFpBinomial #1#2% {\romannumeral0\CALX_fbinom\XINTdigits{\CALX_fpint{#1}}{\CALX_fpint{#2}}}% % \end{macrocode} % \subsection{(WIP) \csh{XINTinRandomFloatS}, \csh{XINTinRandomFloatSdigits}} % \added{1.3b} %\begin{lverb} % Support for random() function. % % Thus as it is a priori only for xintexpr usage, it expands inside \csname % context, but as we need to get rid of initial zeros we use \xintRandomDigits % not \xintXRandomDigits (\expanded would have a use case here). % % And anyway as we want to be able to use random() in % \xintdeffunc/\xintNewExpr, it is good to have f-expandable macros, so we add % the small overhead to make it f-expandable. % % We don't have to be very efficient in removing leading zeroes, as there is % only 10$% % chance for each successive one. Besides we use (current) internal storage % format of the type A[N], where A is not required to be with \xintDigits % digits, so N will simply be -\xintDigits and needs no adjustment. % % In case we use in future with #1 something else than \xintDigits we do % the 0-(#1) construct. % % I had some qualms about doing a random float like this which means that % when there are leading zeros in the random digits the (virtual) mantissa % ends up with trailing zeros. That did not feel right but I checked random() % in Python (which of course uses radix 2), and indeed this is what happens % there. %\end{lverb} % \begin{macrocode} \def\XINTinRandomFloatS{\romannumeral0\XINTinrandomfloatS}% \def\XINTinRandomFloatSdigits{\XINTinRandomFloatS[\XINTdigits]}% \def\XINTinrandomfloatS[#1]% {% \expandafter\XINT_inrandomfloatS\the\numexpr\xint_c_-(#1)\xint: }% \def\XINT_inrandomfloatS-#1\xint: {% \expandafter\XINT_inrandomfloatS_a \romannumeral0\xintrandomdigits{#1}[-#1]% }% % \end{macrocode} %\begin{lverb} % We add one macro to handle a tiny bit faster 90$% % of cases, after all % we also use one extra macro for the completely improbable all 0 case. %\end{lverb} % \begin{macrocode} \def\XINT_inrandomfloatS_a#1% {% \if#10\xint_dothis{\XINT_inrandomfloatS_b}\fi \xint_orthat{ #1}% }%[ \def\XINT_inrandomfloatS_b#1% {% \if#1[\xint_dothis{\XINT_inrandomfloatS_zero}\fi% ] \if#10\xint_dothis{\XINT_inrandomfloatS_b}\fi \xint_orthat{ #1}% }%[ \def\XINT_inrandomfloatS_zero#1]{ 0[0]}% % \end{macrocode} % \subsection{(WIP) \csh{XINTinRandomFloatSixteen}} % \added{1.3b} %\begin{lverb} % Support for qrand() function. %\end{lverb} % \begin{macrocode} \def\XINTinRandomFloatSixteen% {% \romannumeral0\expandafter\XINT_inrandomfloatS_a \romannumeral`&&@\expandafter\XINT_eightrandomdigits \romannumeral`&&@\XINT_eightrandomdigits[-16]% }% % \end{macrocode} %\begin{lverb} % calx: random() and qrand() of \xintfloateval push native F values, % the raw A[N] of the two macros above converted once by \CALX_ffromraw. %\end{lverb} % \begin{macrocode} \def\calxFpRandomSdigits {\romannumeral0\CALX_ffromraw{\XINTinRandomFloatSdigits}}% \def\calxFpRandomSixteen {\romannumeral0\CALX_ffromraw{\XINTinRandomFloatSixteen}}% % \end{macrocode} % \subsection{\csh{XINT_pfloat_fork} and the \cshnolabel{xintPFloat} hooks} % \label{\xintimplabelprefix xintPFloatE} % \label{\xintimplabelprefix xintPFloatNoSciEmax} % \label{\xintimplabelprefix xintPFloatNoSciEmin} % \label{\xintimplabelprefix xintPFloatIntSuffix} % \label{\xintimplabelprefix xintPFloatLengthOneSuffix} % \label{\xintimplabelprefix xintPFloatZero} % \label{\xintimplabelprefix xintPFloatMinTrimmed} %\begin{lverb} % Moved verbatim from xintfrac.sty at 2.0a1: the formatting core of % \xintPFloat, used by the \xintfloateval printer (calx.sty's \CALX_fpr_a, % fed by \CALX_frez) and by xintfrac's \xintPFloat (fed by \xintrez). %\end{lverb} % \begin{macrocode} \def\xintPFloatE{e}% \def\xintPFloatNoSciEmax{\xint_c_v}% 1e6 uses sci.not. \def\xintPFloatNoSciEmin{-\xint_c_iv}% 1e-5 uses sci.not. \def\xintPFloatIntSuffix{}% \def\xintPFloatLengthOneSuffix{}% \def\xintPFloatZero{0}% \def\xintPFloatMinTrimmed{\xint_c_iv}% \def\XINT_pfloat_fork#1% {% \xint_UDzerominusfork #1-\XINT_pfloat_zero 0#1\XINT_pfloat_neg 0-\XINT_pfloat_pos \krof #1% }% \def\XINT_pfloat_zero#1]#2.{\expanded{ \xintPFloatZero}}% \def\XINT_pfloat_neg-{\expandafter-\romannumeral0\XINT_pfloat_pos}% \def\XINT_pfloat_pos#1/1[#2]#3.% {% \expandafter\XINT_pfloat_aa\the\numexpr\xintLength{#1}.% #3.#2.#1.% }% % \end{macrocode} %\begin{lverb} %( #1 est la longueur de la mantisse trimmée %: #2 est Digits ou P %: Si #2-#1 < MinTrimmed, on se prépare à peut-être remettre les trailing zeros %) % % On teste pour #2=#1, car c'est le cas le plus fréquent (mais est-ce % une bonne idée) car on sait qu'alors il n'y a pas de trailing zéros % donc on va direct vers \XINT_pfloat_a. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_aa #1.#2.% {% \unless\ifnum\xintPFloatMinTrimmed>\numexpr#2-#1\relax \xint_dothis\XINT_pfloat_a\fi \ifnum#2>#1 \xint_dothis{\XINT_pfloat_i #2.}\fi \xint_orthat\XINT_pfloat_a #1.% }% % \end{macrocode} %\begin{lverb} % Needed for \xintFracToSci, which uses old pre 1.4k interface, % where the P parameter was not stored for counting how many zeros % were trimmed. \xintFracToSci trims always. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_a_fork#1% {% \xint_UDzerominusfork #1-\XINT_pfloat_a_zero 0#1\XINT_pfloat_a_neg 0-\XINT_pfloat_a_pos \krof #1% }% \def\XINT_pfloat_a_zero#1]{\expanded{ \xintPFloatZero}}% \def\XINT_pfloat_a_neg-{\expandafter-\romannumeral0\XINT_pfloat_a_pos}% \def\XINT_pfloat_a_pos#1/1[#2]% {% \expandafter\XINT_pfloat_a\the\numexpr\xintLength{#1}.#2.#1.% }% % \end{macrocode} %\begin{lverb} %( #1 est P > #2 mais peut être encore sous la forme \XINTdigits %: #2 est la longueur de la mantisse trimmée %: #3 est l'exposant non normalisé %: #4 est la mantisse %) % On reconstitue les trailing zéros à remettre éventuellement. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_i #1.#2.%#3.#4.% {% \expandafter\XINT_pfloat_j\romannumeral\xintreplicate{#1-#2}0.#2.% }% % \end{macrocode} %\begin{lverb} %( #1 est les trailing zeros à remettre peut-être %: #2 est la longueur de la mantisse trimmée %: #3#4 est l'exposant N pour mantisse trimmée entière %: #5 serait la mantisse trimmée %) % On calcule l'exposant scientifique. % % La façon bizarre de mettre #3 est liée aux versions anciennes % de la macro, héritage conservé pour minimiser effort d'adaptation. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_j #1.#2.#3#4.%#5. {% \expandafter\XINT_pfloat_b\the\numexpr#2+#3#4-\xint_c_i.% #3#2.#1.% }% % \end{macrocode} %\begin{lverb} %( #1 est la longueur de la mantisse trimmée %: #2#3 est l'exposant N pour mantisse trimmée %: #4 serait la mantisse %) % On calcule l'exposant scientifique. On est arrivé ici dans % une branche où on n'a pas besoin de remettre les zéros trimmés % donc on positionne un dernier argument vide pour \XINT_pfloat_b %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_a #1.#2#3.%#4. {% \expandafter\XINT_pfloat_b\the\numexpr#1+#2#3-\xint_c_i.% #2#1..% }% % \end{macrocode} %\begin{lverb} %( #1 est l'exposant scientifique K %: #2 est le signe ou premier chiffre de l'exposant N pour mantisse trimmée %: #3 serait la longueur de la mantisse trimmée %: #4 serait les trailing zéros %: #5 serait la mantisse trimmée %) % On va vers \XINT_float_P lorsque l'on n'utilise pas la notation % scientifique, mais qu'on a besoin de chiffres non nuls fractionnaires, % et vers \XINT_float_Ps si on n'en a pas besoin. % % On va vers \XINT_pfloat_N lorsque l'on n'utilise pas la notation % scientifique et que l'exposant scientifique était strictement négatif. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_b #1.#2%#3.#4.#5. {% \ifnum \xintPFloatNoSciEmax<#1 \xint_dothis\XINT_pfloat_sci\fi \ifnum \xintPFloatNoSciEmin>#1 \xint_dothis\XINT_pfloat_sci\fi \ifnum #1<\xint_c_ \xint_dothis\XINT_pfloat_N\fi \if-#2\xint_dothis\XINT_pfloat_P\fi \xint_orthat\XINT_pfloat_Ps #1.% }% % \end{macrocode} %\begin{lverb} % #1 is the scientific exponent, #2 is the length of the trimmed mantissa, % #3 are the trailing zeros, #4 is the trimmed integer mantissa % % \xintPFloatE can be replaced by any f-expandable macro with a dot-delimited % argument which produces a dot-delimited output. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_sci #1.#2.% {% \ifnum#2=\xint_c_i\expandafter\XINT_pfloat_sci_i\expandafter\fi \expandafter\XINT_pfloat_sci_a\romannumeral`&&@\xintPFloatE #1.% }% \def\XINT_pfloat_sci_a #1.#2.#3#4.{ #3.#4#2#1}% % \end{macrocode} %\begin{lverb} % #1#2=\fi\XINT_pfloat_sci_a % % 1-digit mantissa, hesitation between d.0eK or deK % Finally at 1.4k, \xintPFloatLengthOneSuffix for customization. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_sci_i #1#2#3.#4.#5.{\expanded{#1 #5\xintPFloatLengthOneSuffix}#3}% % \end{macrocode} %\begin{lverb} % #1=sci.exp. K, #2=mant. wd L, #3=trailing zéros, #4=trimmed mantissa % % For _N, #1 is at most -1, for _P, #1 is at least 0. For _P there % will be fractional digits, and #1+1 digits before the mark. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_N#1.#2.#3.#4.% {% \expandafter\XINT_pfloat_N_e\romannumeral\xintreplicate{-#1}{0}#4#3% }% \def\XINT_pfloat_N_e 0{ 0.}% % \end{macrocode} %\begin{lverb} % #1=sci.exp. K, #2=mant. wd L, #3=trailing zéros, #4=trimmed mantissa % % Abusive usage of internal \XINT_split_fromleft_a. % It means using x = -1 - #1 in \xintDecSplit from xint.sty. % We benefit also with the way \xintDecSplit is built upon % \XINT_split_fromleft with a final clean-up which here % we can shortcut via using terminator "\xint_bye." not "\xint_bye.." %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_P #1.#2.#3.#4.% {% \expandafter\XINT_split_fromleft_a \the\numexpr\xint_c_vii-#1.#4\xint_bye2345678\xint_bye.#3% }% % \end{macrocode} %\begin{lverb} % Here we have an integer so we only need to postfix the trimmed mantissa #4 % with #1+1-#2 zeros (#1=sci exp., #2=trimmed mantissa width). Less cumbersome % to do that with \expanded. And the trailing zeros #3 ignored here. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_Ps #1.#2.#3.#4.% {% \expanded{ #4% \romannumeral\xintreplicate{#1+\xint_c_i-#2}{0}\xintPFloatIntSuffix}% }% % \end{macrocode} %\begin{lverb} % calx: \CALX_frez F..\xint: (use with \romannumeral0; the % tag token is a parameter): A/1[N] with A without trailing zeros % (the form \xintrez gives), 0/1[0] for zero (first digit of D zero). Zero % low blocks are dropped (\CALX_frez_b, e + 1 each); the t trailing zeros of % the lowest nonzero block b (\CALX_frez_t, t <= 7) are removed: one block, % A = b/10^t; else A = the digits of the higher blocks (\CALX_ntoraw_b) % followed by the 8 - t leading digits of b; N = 8e + t. %\end{lverb} % \begin{macrocode} \def\CALX_frez #1#2#3#4.#5.% {\xint_gob_til_zero #3\CALX_frez_z 0\CALX_frez_a #2#5.}% \def\CALX_frez_z 0\CALX_frez_a #1\xint:{ 0/1[0]}% \def\CALX_frez_a #1#2.1#3!% {\xint_gob_til_eightzeroes #3\CALX_frez_b 00000000\CALX_frez_c #1#2.#3.}% \def\CALX_frez_b 00000000\CALX_frez_c #1#2.#3.% {\expandafter\CALX_frez_a\expandafter#1\the\numexpr#2+\xint_c_i.}% \def\CALX_frez_c #1#2.#3.% {\expandafter\CALX_frez_d\the\numexpr\CALX_frez_t#3.#1#2.#3.}% \def\CALX_frez_t #1#2#3#4#5#6#7#8% {\if0#8\if0#7\if0#6\if0#5\if0#4\if0#3\if0#2 7\else6\fi\else5\fi\else4\fi \else3\fi\else2\fi\else1\fi\else0\fi}% \def\CALX_frez_p #1% {\ifcase#1 1\or10\or100\or1000\or10000\or100000\or1000000\or10000000\fi}% \def\CALX_frez_d #1.#2#3.#4.#5\xint:% {% \expanded{ \if-#2-\fi \if\relax\detokenize{#5}\relax \the\numexpr#4/\CALX_frez_p#1\relax \else \romannumeral0\CALX_ntoraw_b #5\xint:% \expandafter\xint_gobble_i\the\numexpr1#4/\CALX_frez_p#1\relax \fi /1[\the\numexpr\xint_c_viii*#3+#1\relax]}% }% \XINTrestorecatcodesendinput% % \end{macrocode} % \StoreCodelineNo {calxfp} % \cleardoublepage\let\calxfpnameUp\undefined %\gardesactifs %\let\relax %\let<*calx>\gardesinactifs %^^A------------------------------------------------------- %<*calx>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxnameUp\endcsname % \let\MakePrivateLetters\xintexprMakePrivateLetters % \section{Package \calxnameimp implementation} % \RaisedLabel{sec:calximp} % \etocarticlestylenomarks % \etocstandardlines % \etocsettocdepth {paragraph} % % \localtableofcontents % % \subsection{Introduction} % % This is release \expandafter|\calxbndlversion| of % \expandafter|\calxbndldate|. THIS FILE IS AN EVOLUTION OF % A PART OF FORMER \xintexprnameimp|.sty|. The latter now loads % this file as a dependency. % % \etocsettocstyle{}{} % % \subsection{READ ME! Important warnings and explanations relative to the % status of the code source at the time of the 1.4 release} % \def\mybeginitemize{\begin{itemize}\catcode`\% 9 }^^A % \def\myenditemize{\end{itemize}}^^A %\begin{lverb} % At release 1.4 the csname encapsulation of intermediate evaluations during % parsing of expressions is dropped, and $xintexprnameimp requires the % \expanded primitive. This means that there is no more impact on the string % pool. And as internal storage now uses simply core \TeX{} syntax with braces % rather than comma separated items inside a csname dummy control sequence, % it became much easier to let the [...] syntax be associated to a true internal type of «tuple» % or «list». % % The output of \xintexpr (after \romannumeral0 or \romannumeral-`0 triggered % expansion or double expansion) is thus modified at 1.4. It now looks like % this:& % $oneargcs$footnote{The \XINTfstop was a simple$noexpand % \def\XINTfstop$string{\noexpand\XINTfstop$string} at 1.4 but has been$noexpand % converted into a fancier token at 1.5, to avoid the $myenquote{blinking} effect$noexpand % when submitted to finitely many expansions à la \expandafter as first token of a$noexpand % replacement text.} % % \XINTfstop \XINTexprprint .{{}} in simplest case % % \XINTfstop \XINTexprprint .{{...}...{...}} in general case % % where ... stands for nested braces ultimately ending in {} leaves. % The stands for some internal representation of numeric data. It % may be empty, and currently as well as probably in future uses only catcode % 12 tokens (no spaces currently). % % {{}} corresponds (in input as in output) to []. The external TeX braces also % serve as set-theoretical braces. The comma is concatenation, so for example % [], [] will become {{}{}}, or rather {}{} if sub-unit of something else. % % The associated vocabulary is explained in the user manual and we avoid % too much duplication here. $xintfracnameimp numerical macros receiving an % empty argument usually handle it as being 0, but this is not the case of the % $xintcorenameimp macros supporting \xintiiexpr, they usually break if % exercised on some empty argument. % % The above expansion result \XINTfstop \XINTexprprint .{{}{\relax is a complete expansion, % i.e. one whose result remains invariant under \edef. % % \xintthe\xintexpr \relax or \xinteval{} serve as % formerly to deliver the explicit digits, or more exactly some prettifying % view of the actual . % % Nested contents like this % % {{1}{{2}{3}{{4}{5}{6}}}{9}} % % $noindent will get delivered using nested square brackets like that % % 1, [2, 3, [4, 5, 6]], 9 % % $noindent and as conversely \xintexpr 1, [2, 3, [4, 5, 6]], 9\relax expands to % % \XINTfstop \XINTexprprint .{{1}{{2}{3}{{4}{5}{6}}}{9}} % % $noindent we obtain the gratifying result that % % \xinteval{1, [2, 3, [4, 5, 6]], 9} % % $noindent expands to % % 1, [2, 3, [4, 5, 6]], 9 % % See user manual for explanations on the plasticity of \xintexpr syntax % regarding functions with multiple arguments, and the 1.4 «unpacking» % Python-like * prefix operator. % %\end{lverb} % % \begin{framed} % I have suppressed (from the public dtx) many big chunks of % comments. Some became obsolete and need to be updated, others are % currently of value only to the author as a historical record. % % ATTENTION! As the removal process itself took too much time, I ended up % leaving as is many comments which are obsoleted and wrong to various % degrees after the |1.4| release. Precedence levels of operators have all % been doubled to make room for new constructs % % Even comments added during 1.4 developement may now be obsolete because % the preparation of 1.4 took a few weeks and that's enough of duration to % provide the author many chances to contradict in the code what has been % already commented upon. % % Thus don't believe (fully) anything which is said here!\IMPORTANTf{} % \end{framed} % % %\begin{lverb} % Warning: in text below and also in left-over old comments I may refer % to «until» and «op» macros; due to the change of data storage at 1.4, I % needed to refactor a bit the way expansion is controlled, and the situation % now is mainly governed by «op», «exec», «check-» and «checkp» macros the % latter three replacing the two «until_a» and «until_b» of former code. This % allows to diminish the number of times an accumulated result will be grabbed % in order to propagate expansion to its right. Formerly this was not an issue % because such things were only a single token! I do not describe here how % this is all articulated but it is not hard to see it from the code (the % hardest thing in all such matter was in 2013 to actually write how the % expansion would be initially launched because to do that one basically has to % understand the mechanism in its whole and such things are not easy to % develop piecemeal). Another thing to keep in mind is that operators in truth % have a left precedence (i.e. the precedence they show to operators arising % earlier) and a right precedence (which determines how they react to % operators coming after them from the right). Only the first one is usually % encapsulated in a chardef, the second one is most of the times identical to % the first one and if not it is only virtual but implemented via \ifcase of % \ifnum branching. A final remark is that some things are achieved by special % «op» macros, which are a favorite tool to hack into the normal regular flow % of things, via injection of special syntax elements. I did not rename these % macros for avoiding too large git diffs, and besides the nice thing is that % the 1.4 refactoring minimally had to modify them, and all hacky things using % them kept on working with not a single modification. And a post-scriptum is % that advanced features crucially exploit injecting sub-\xintexpr-essions, as % all is expandable there is no real «context» (only a minimal one) which one % would have to perhaps store and restore and doing this sub-expression % injection is rather cheap and efficient operation. %\end{lverb} % % \subsection{Old comments} % % These general comments were last updated at the end of the |1.09x| series in % 2014. The principles remain in place to this day but refer to % \href{http://www.ctan.org/pkg/xint/CHANGES.html}{CHANGES.html} for some % significant evolutions since. % % The first version was released in June 2013. I was greatly helped in this task % of writing an expandable parser of infix operations by the comments provided % in |l3fp-parse.dtx| (in its version as available in April-May 2013). One will % recognize in particular the idea of the `until' macros; I have not looked into % the actual |l3fp| code beyond the very useful comments provided in its % documentation. % % A main worry was that my data has no a priori bound on its size; to keep the % code reasonably efficient, I experimented with a technique of storing and % retrieving data expandably as \emph{names} of control sequences. Intermediate % computation results are stored as control sequences |\.=a/b[n]|. % % % Roughly speaking, the parser mechanism is as follows: at any given time the % last found ``operator'' has its associated |until| macro awaiting some news % from the token flow; first |getnext| expands forward in the hope to construct % some number, which may come from a parenthesized sub-expression, from some % braced material, or from a digit by digit scan. After this number has been % formed the next operator is looked for by the |getop| macro. Once |getop| has % finished its job, |until| is presented with three tokens: the first one is the % precedence level of the new found operator (which may be an end of expression % marker), the second is the operator character token (earlier versions had here % already some macro name, but in order to keep as much common code to expr and % floatexpr common as possible, this was modified) of the new found operator, and % the third one is the newly found number (which was encountered just before the % new operator). % % The |until| macro of the earlier operator examines the precedence level of the % new found one, and either executes the earlier operator (in the case of a % binary operation, with the found number and a previously stored one) or it % delays execution, giving the hand to the |until| macro of the operator having % been found of higher precedence. % % A minus sign acting as prefix gets converted into a (unary) operator % inheriting the precedence level of the previous operator. % % Once the end of the expression is found (it has to be marked by a |\relax|) % the final result is output as four tokens (five tokens since |1.09j|) the % first one a catcode 11 exclamation mark, the second one an error generating % macro, the third one is a protection mechanism, the fourth one a printing % macro and the fifth is |\.=a/b[n]|. The prefix |\xintthe| makes the output % printable by killing the first three tokens. % % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko % Oberdiek}'s packages, then modified. % % The method for catcodes was also initially directly inspired by these % packages. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \catcode35=6 % # \def\odef#1{\expandafter\def\expandafter#1\expandafter}% \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@calx.sty\endcsname \expandafter\let\expandafter\t\csname ver@xinttools.sty\endcsname \expandafter\let\expandafter\b\csname ver@xintbinhex.sty\endcsname \expandafter\let\expandafter\f\csname ver@xintfrac.sty\endcsname \expandafter\let\expandafter\fp\csname ver@calxfp.sty\endcsname % I assume engines do not exist providing \expanded but not \numexpr \expandafter\ifx\csname expanded\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage calx Warning:^^J% \space\space\space\space \expanded not available, aborting input.^^J}% \else \PackageWarningNoLine{calx}{\expanded not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % not LaTeX (perhaps Plain+miniltx), first loading of calx.sty \ifx\t\relax % but xinttools.sty not yet loaded. \odef\z{\z\input xinttools.sty\relax}% \fi \ifx\b\relax % but xintbinhex.sty not yet loaded. \odef\z{\z\input xintbinhex.sty\relax}% \fi \ifx\fp\relax % but calxfp.sty not yet loaded. \odef\z{\z\input calxfp.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\t\relax % xinttools not yet loaded. \odef\z{\z\RequirePackage{xinttools}}% \fi \ifx\b\relax % xintbinhex not yet loaded. \odef\z{\z\RequirePackage{xintbinhex}}% \fi \ifx\fp\relax % calxfp not yet loaded. \odef\z{\z\RequirePackage{calxfp}}% \fi \else \def\z{\endgroup\endinput}% xintexpr already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% % \end{macrocode} % \subsection{Package identification} % The |!| is of catcode LETTER for most of the duration of the package. Prior % to |1.4| it was the first token in the complete expansion of % |\xintexpr...\relax| (i.e. without |\xintthe| prefix). It has since lost to % |\XINTfstop| this prominent rôle, but its usage in various places of the % code as delimiter in otherwise catcode 12 contexts has stuck. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{calx}% [2026/11/01 v2.0a1 Expandable fp and bigint expression parsers (JFB)]% \catcode`! 11 % \end{macrocode} %\begin{lverb} % calx: ^^B, ^^C are the fake operators of the integer, resp. decimal % and exponent, exits of the number scanner; catcode 12, restored at % the end of the file. %\end{lverb} % \begin{macrocode} \edef\CALX_restorecc{\catcode2=\the\catcode2\relax \catcode3=\the\catcode3\relax}\catcode2=12 \catcode3=12 % \end{macrocode} % \subsection{\csh{XINTfstop}} % \added{1.4} % % This replaced in 2019 the legacy usage of a catcode 11 exclamation mark to % signal the start of a sub-expression (it was followed by some other tokens). % % % From 2022 (aiming at |1.5|) to 2025 (releasing |1.4n|) I had replaced the % definition used here with a fancier one originating in a ``fake'' \cs{relax} % from \ctanpackage{unravel}. % I think in 2022, \ctanpackage{unravel} used a frozen let to |\the|, which I % had transferred here as a definition of |\XINTfstop|, now reverted. When I % checked again \ctanpackage{unravel} in 2025, I saw a definition of the type % \centeredline{|\expandafter\let\expandafter\foo\noexpand\foo|} % % If I did that with \cs{foo} being |\XINTfstop| then |\XINTfstop| % would test equal via \cs{ifx} to the \ctanpackage{unravel} or any % such |\foo| (if |\foo| is at first undefined)... % % The inconvenience with our more naive |\XINTfstop| here, is that % expanding a finite number of times |\xintexpr...\relax| depends % on parity of number of expansions. Not really a problem as far as % I can tell. The advantage is that |\ifx| will never confuse it % with something else. % \begin{macrocode} \def\XINTfstop{\noexpand\XINTfstop}% % \end{macrocode} % \subsection{Support for output and transform of nested braced contents as % core data type} % New at 1.4, of course. The former |\csname.=...\endcsname| encapsulation % technique made very difficult implementation of nested structures. % \subsubsection{Bracketed list rendering with prettifying of leaves from nested % braced contents} % \added{1.4} % The braces in |\XINT:expr:toblistwith| are there because there is % an |\expanded| trigger. % \changed{1.4d} %\begin{lverb} % Add support for the polexpr 0.8 polynomial type. See \XINT:expr:toblist_a. %\end{lverb} % \changed{1.4l} %\begin{lverb} % Let \XINT:expr:toblist_b use #1{#2} with regular { and } in case % macro #1 is \protected and things are output to external file where former % #1<#2> would end up with catcode 12 < and >. %\end{lverb} % \begin{macrocode} \def\XINT:expr:toblistwith#1#2% {% {\expandafter\XINT:expr:toblist_checkempty \expanded{\noexpand#1!\expandafter}\detokenize{#2}^}% }% \def\XINT:expr:toblist_checkempty #1!#2% {% \if ^#2\expandafter\xint_gob_til_^\else\expandafter\XINT:expr:toblist_a\fi #1!#2% }% \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \def\XINT:expr:toblist_a #1{#2% <% \if{#2\xint_dothis<[\XINT:expr:toblist_a>\fi \if P#2\xint_dothis<\XINT:expr:toblist_pol>\fi \xint_orthat\XINT:expr:toblist_b #1#2% >% \def\XINT:expr:toblist_pol #1!#2.{#3}}% <% pol([\XINT:expr:toblist_b #1!#3}^])\XINT:expr:toblist_c #1!}% >% \catcode`{ 1 \catcode`} 2 \def\XINT:expr:toblist_b #1{% \def\XINT:expr:toblist_b ##1!##2#1% {% \if\relax##2\relax \xintexprEmptyItem\else##1{##2}\fi\XINT:expr:toblist_c ##1!#1% }}\catcode`{ 12 \catcode`} 12 \XINT:expr:toblist_b<}>% \def\XINT:expr:toblist_c #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if{#2\xint_dothis<, \XINT:expr:toblist_a>\fi \xint_orthat<]\XINT:expr:toblist_c>#1#2% >% \catcode`{ 1 \catcode`} 2 \catcode`< 12 \catcode`> 12 % \end{macrocode} % \subsubsection{Flattening nested % braced contents} %\begin{lverb} % 1.4b I hesitated whether using this technique or some variation of % the method of the ListSel macros. I chose this one which I downscaled from % toblistwith, I will revisit later. I only have a few minutes right now. % % Call form is \expanded\XINT:expr:flatten % % See \XINT_expr_func_flat. I hesitated with «flattened», but short names % are faster parsed. %\end{lverb} % \begin{macrocode} \def\XINT:expr:flatten#1% {% {{\expandafter\XINT:expr:flatten_checkempty\detokenize{#1}^}}% }% \def\XINT:expr:flatten_checkempty #1% {% \if ^#1\expandafter\xint_gobble_i\else\expandafter\XINT:expr:flatten_a\fi #1% }% \begingroup \catcode`[ 1 \catcode`] 2 \lccode`[`{ \lccode`]`} \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \lowercase<\endgroup \def\XINT:expr:flatten_a {#1% <% \if{#1\xint_dothis<\XINT:expr:flatten_a>\fi \xint_orthat\XINT:expr:flatten_b #1% >% \def\XINT:expr:flatten_b #1}% <% [#1]\XINT:expr:flatten_c }% >% \def\XINT:expr:flatten_c }#1% <% \if ^#1\xint_dothis<\xint_gobble_i>\fi \if{#1\xint_dothis<\XINT:expr:flatten_a>\fi \xint_orthat<\XINT:expr:flatten_c>#1% >% >% back to normal catcodes % \end{macrocode} % \subsubsection{Braced contents rendering via a \TeX{} alignment with prettifying of leaves} %\begin{lverb} % 1.4. % % Breaking change at 1.4a as helper macros were renamed and their meanings % refactored: no more \xintexpraligntab nor \xintexpraligninnercomma or % \xintexpralignoutercomma but \xintexpraligninnersep, etc... % % At 1.4c I remove the \protected from \xintexpralignend. I had made note a % year ago that it served nothing. Let's trust myself on this one (risky one % year later!). %\end{lverb} % \begin{macrocode} \catcode`& 4 \protected\def\xintexpralignbegin {\halign\bgroup\tabskip2ex\hfil##&&##\hfil\cr}% \def\xintexpralignend {\crcr\egroup}% \protected\def\xintexpralignlinesep {,\cr}% \protected\def\xintexpralignleftbracket {[}% \protected\def\xintexpralignrightbracket{]}% \protected\def\xintexpralignleftsep {&}% \protected\def\xintexpralignrightsep {&}% \protected\def\xintexpraligninnersep {,&}% \catcode`& 7 \def\XINT:expr:toalignwith#1#2% {% {\expandafter\XINT:expr:toalign_checkempty \expanded{\noexpand#1!\expandafter}\detokenize{#2}^\expandafter}% \xintexpralignend }% \def\XINT:expr:toalign_checkempty #1!#2% {% \if ^#2\expandafter\xint_gob_til_^\else\expandafter\XINT:expr:toalign_a\fi #1!#2% }% \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \def\XINT:expr:toalign_a #1{#2% <% \if{#2\xint_dothis<\xintexpralignleftbracket\XINT:expr:toalign_a>\fi \xint_orthat<\xintexpralignleftsep\XINT:expr:toalign_b>#1#2% >% \def\XINT:expr:toalign_b #1!#2}% <% \if\relax#2\relax\xintexprEmptyItem\else#1<#2>\fi\XINT:expr:toalign_c #1!}% >% \def\XINT:expr:toalign_c #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if {#2\xint_dothis<\xintexpraligninnersep\XINT:expr:toalign_A>\fi \xint_orthat<\xintexpralignrightsep\xintexpralignrightbracket \XINT:expr:toalign_C>#1#2% >% \def\XINT:expr:toalign_A #1{#2% <% \if{#2\xint_dothis<\xintexpralignleftbracket\XINT:expr:toalign_A>\fi \xint_orthat\XINT:expr:toalign_b #1#2% >% \def\XINT:expr:toalign_C #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if {#2\xint_dothis<\xintexpralignlinesep\XINT:expr:toalign_a>\fi \xint_orthat<\xintexpralignrightbracket\XINT:expr:toalign_C>#1#2% >% \catcode`{ 1 \catcode`} 2 \catcode`< 12 \catcode`> 12 % \end{macrocode} % \subsubsection{Transforming all leaves within nested % braced contents} % %\begin{lverb} % 1.4. Leaves must be of catcode 12... This is currently not a % constraint (or rather not a new constraint) for xintexpr because formerly % anyhow all data went through csname encapsulation and extraction via string. % % In order to share code with the functioning of universal functions, which % will be allowed to transform a number into an ople, the applied macro % is supposed to apply one level of bracing to its ouput. Thus to apply this % with an xintfrac macro such as \xintiRound{0} one needs first to define % a wrapper which will expand it inside an added brace pair: % % \def\foo#1{{\xintiRound{0}{#1}}} % % As the things will expand inside expanded, propagating expansion is not an % issue. % % This code is used by \xintiexpr and \xintfloatexpr in case of optional % argument and by the «Universal functions». % % Comment at 1.4l: this seems to be used only at private package level, else % I should modify \XINT:expr:mapwithin_b like I did with \XINT:expr:toblist_b % to use regular braces in case the applied macro is \protected and % things end up in external file. %\end{lverb} % % \begin{macrocode} \def\XINT:expr:mapwithin#1#2% {% {{\expandafter\XINT:expr:mapwithin_checkempty \expanded{\noexpand#1!\expandafter}\detokenize{#2}^}}% }% \def\XINT:expr:mapwithin_checkempty #1!#2% {% \if ^#2\expandafter\xint_gob_til_^\else \expandafter\XINT:expr:mapwithin_a\fi #1!#2% }% \begingroup \catcode`[ 1 \catcode`] 2 \lccode`[`{ \lccode`]`} \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \lowercase<\endgroup \def\XINT:expr:mapwithin_a #1{#2% <% \if{#2\xint_dothis<[\iffalse]\fi\XINT:expr:mapwithin_a>\fi% \xint_orthat\XINT:expr:mapwithin_b #1#2% >% \def\XINT:expr:mapwithin_b #1!#2}% <% #1<#2>\XINT:expr:mapwithin_c #1!}% >% \def\XINT:expr:mapwithin_c #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if{#2\xint_dothis<\XINT:expr:mapwithin_a>\fi% \xint_orthat<\iffalse[\fi]\XINT:expr:mapwithin_c>#1#2% >% >% back to normal catcodes % \end{macrocode} % \subsection{Top level user \TeX{} interface: % \cshnolabel{xintfloateval}, \cshnolabel{xintiieval}} % \localtableofcontents % \subsubsection{\csh{xintfloatexpr}, % \csh{xintiiexpr}} % % \changed{1.4o} % % While preparing |1.4n| I had made changes to tame Babel active characters % via a |\csname| trick. At last minute, after having first implemented % correctly the feature both here and in \ctanpackage{bnumexpr} I thought I % had a way requiring not so many ``top level'' changes, but this was a grave % logic error on my part, due to having a bit forgotten the way things are % done here, and due to external circumstances. I released too hastily |1.4n|. % But the feature was working only with \csbxint{iieval}. Any test other than % simply evaluating |3!| with |!| the Babel-French (e.g.\@ |1+3!|) would have % revealed it. I was planning to add test units after (what?) doing the % release. By the way one has to be careful to do such tests after a % |\noindent| because the French active |!| in vertical mode does things not % breaking the parser. Anyway, here I do it right. % % So this is why for example |\XINT_flexpr_noopt| has a |\csname| construct. % \begin{macrocode} \def\xintfloatexpr {\romannumeral0\xintfloatexpro }% \def\xintiiexpr {\romannumeral0\xintiiexpro }% \def\xintiiexpro {\csname XINT_iiexpr_wrap\expandafter\endcsname \romannumeral0\xintbareiieval }% \def\xintfloatexpro #1% {% \ifx [#1\expandafter\XINT_flexpr_withopt\else\expandafter\XINT_flexpr_noopt \fi #1% }% \def\XINT_flexpr_noopt {% \csname XINT_flexpr_wrap\expandafter\endcsname \the\numexpr\XINTdigits\expandafter.% \romannumeral0\xintbarefloateval }% \def\XINT_flexpr_withopt [#1]% {% \csname XINT_flexpr_withopt_a\expandafter\endcsname \the\numexpr\xint_zapspaces #1 \xint_gobble_i\expandafter.% \romannumeral0\xintbarefloateval }% \def\XINT_flexpr_withopt_a #1#2.% {% \expandafter\XINT_flexpr_withopt_b\the\numexpr\if#1-\XINTdigits\fi#1#2.% }% \def\XINT_flexpr_withopt_b #1.% {% \expandafter\XINT_flexpr_wrap \the\numexpr#1\expandafter.% \expanded \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTinFloat_braced[#1]}% }% % \end{macrocode} %\begin{lverb} % calx: [Q] rounding of native leaves. Legacy was %\end{lverb} % \centeredline{|\def\XINTinFloat_braced[#1]#2{{\XINTinFloat[#1]{#2}}}|}^^A$ %\begin{lverb} % but xe don't want an xintfrac.sty dependency. % % There was a legacy comment "utiliser \XINTinFloatS ?", let us recall that % this is a variant of \XINTinFloat which does not insist on a length P mantissa. % So this is purely a legacy question which is obsolete with calx. % % Maybe consider in this context \CALX_frez which trims trailing zeros, % but if this ends up being fed as I believe it is again to \CALX_fround % when going through the printer, it would be probably only a waste of % time. % % FIXME: calxfp.sty has \def\CALX_fbr #1\xint:{ #1}. Check % \CALX_fround final stage to see if the \xint: removal % could happen earlier. %\end{lverb} % \begin{macrocode} \def\XINTinFloat_braced[#1]#2% {{\romannumeral0\expandafter\CALX_fbr \romannumeral0\CALX_fround{#1}{#2}}}% % \end{macrocode} % \subsubsection{\csh{XINT_iiexpr_wrap}, % \csh{XINT_flexpr_wrap}} %\begin{lverb} % 1.3e removes some leading space tokens which served nothing. % % 1.4e has \XINT_iexpr_wrap separated from \XINT_expr_wrap, thus simplifying % internal matters as output printer for \xintexpr will not have to handle % fixed point input but only extended-raw type input (i.e. A, A/B, A[N] or A/B[N]). %\end{lverb} % \begin{macrocode} \def\XINT_iiexpr_wrap {\XINTfstop\XINTiiexprprint.}% \def\XINT_flexpr_wrap {\XINTfstop\XINTflexprprint}% % \end{macrocode} % \subsubsection{\csh{XINTiiexprprint}, \csh{XINTflexprprint}} % \label{\xintimplabelprefix xintfloatexprPrintOne} % \label{\xintimplabelprefix xintiiexprprintone} % % \changed{1.4} % Requires |\expanded|. % % Comments here also apply to material moved to \xintexprnameimp.sty at |2.0a1|. % \changed{1.4e} %\begin{lverb} % 1.4e has a breaking change of \XINTflexprprint and \xintfloatexprPrintOne % which now requires \xintfloatexprPrintOne[D]{x} syntax, with first argument % in brackets. % %\end{lverb} % \changed{1.4l} % The code does |\let\xintexprPrintOne\xint_FracToSci_x| but the latter is not yet % defined so this is delayed until |\xint_FracToSci_x| definition. % \changed[2022/06/05]{1.4m} % \csa{xintboolexprPrintOne} outputs |true| or |false|, not |True| or |False|. % By the way (undocumented) all four keywords |true|, |false|, |True|, % |False| are recognized as genuine variables since |1.4i|. % \begin{macrocode} \def\xintexprEmptyItem{[]}% \protected\def\XINTiiexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\CALX_iipr}% \def\CALX_iipr #1{\expandafter\xintiiexprPrintOne \romannumeral0\CALX_mr_a#1\xint:}% \def\xintiiexprPrintOne #1{% \def\xintiiexprPrintOne ##1% {% \xint_gob_til_Ixii ##1\CALX_iipr_special #1##1% }}\expandafter\xintiiexprPrintOne\string I% \def\CALX_iipr_special #1#2#3{% \if ?#3\xint_dothis{NaN}\fi \xint_orthat{#3Infinity}% }% \protected\def\XINTflexprprint #1.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith{\xintfloatexprPrintOne[#1]}}% % \end{macrocode} %\begin{lverb} % calx: native leaves: \CALX_fround then \CALX_ftoraw replace the % \XINTinfloatS of xint's \xintPFloat_wopt, whose formatting macros % (\XINT_pfloat, hooks \xintPFloatE etc.) are used unchanged. % Specials I+, I-, I? are printed as is (provisional). %\end{lverb} % \begin{macrocode} \def\xintfloatexprPrintOne[#1]#2% {% \romannumeral0\expandafter\CALX_fpr_a \romannumeral0\CALX_fround{#1}{#2}#1.% }% \def\CALX_fpr_a#1{% \def\xint_gob_til_Ixii##1#1{}% \def\CALX_fpr_a ##1% {% \xint_gob_til_Ixii ##1\CALX_fpr_special #1% \expandafter\XINT_pfloat_fork\romannumeral0\CALX_frez ##1% }% }\expandafter\CALX_fpr_a\string I% \def\CALX_fpr_special #1\CALX_frez #2#3\xint:#4.{% \if ?#3\xint_dothis{ NaN}\fi \xint_orthat{ #3Infinity}% }% % \end{macrocode} % \subsubsection{\csh{xintthe}, \csh{xintthealign}, \csh{xintthefloatexpr}, % \csh{xinttheiiexpr}} %\begin{lverb} % The reason why \xinttheiexpr et \xintthefloatexpr are handled % differently is that they admit an optional argument which acts via a custom % «printing» stage. % % We exploit here that \expanded expands forward until finding an implicit or % explicit brace, and that this expansion overrules \protected macros, forcing % them to expand, similarly as \romannumeral expands \protected macros, and % contrarily to what happens *within* the actual \expanded scope. I discovered % this fact by testing (with pdftex) and I don't know where this is documented % apart from the source code of the relevant engines. This is useful to us % because there are contexts where we will want to apply a complete expansion % before printing, but in purely numerical context this is not needed (if I % converted correctly after dropping at 1.4 the \csname governed expansions; % however I rely at various places on the fact that the xint macros are % f-expandable, so I have tried to not use zillions of expanded all over the % place), hence it is not needed to add the expansion overhead by default. But % the \expanded here will allow \xintNewExpr to create macro with suitable % modification or the printing step, via some hook rather than having to % duplicate all macros here with some new «NE» meaning (aliasing does not work % or causes big issues due to desire to support \xinteval also in «NE» context % as sub-constituent. The \XINT:NEhook:x:toblist is something else which % serves to achieve this support of *sub* \xinteval, it serves nothing for % the actual produced macros. For \xintdeffunc, things are simpler, but still % we support the [N] optional argument of \xintiexpr and \xintfloatexpr, which % required some work... % % The \expanded upfront ensures \xintthe mechanism does expand % completely in two steps. %\end{lverb} % % The fact that |\xintthe| grabs a |#1| is legacy and I am not sure why. I % vaguely remember thinking the overhead was minimal because |#1| will % simply be one token such as \csbxint{expr} and that it could potentially % be useful. Of course |\xintthealign| imitates |\xintthe| in that matter. % % \changed{1.4o} % Again here some |\csname|'s to handle babel-active characters. % \begin{macrocode} \def\xintthe #1{\expanded\expandafter\xint_gobble_i\romannumeral`&&@#1}% \def\xintthealign #1{\expandafter\xintexpralignbegin \expanded\expandafter\XINT:expr:toalignwith \romannumeral0\expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\xint_gob_andstop_ii \expandafter\xint_gobble_i\romannumeral`&&@#1}% \def\xinttheiiexpr {\expanded\csname XINTiiexprprint\expandafter\endcsname \expandafter.\romannumeral0\xintbareiieval}% % \end{macrocode} % \changed{1.4p} I don't know why I had been using % |\romannumeral`&&@\xintiexpr|. Perhaps at some point |\xintiexpro| and % |\xintfloatexpro| were not available? Or maybe I simply was under % influence of |\xintthe|. I have not checked history. % % No need at |1.4o| of |\csname|'s for Babel here, as \csbxint{iexpro} and % \csbxint{floatexpro} are already taken care of. % \begin{macrocode} \def\xintthefloatexpr {\expanded\expandafter\xint_gobble_i\romannumeral0\xintfloatexpro}% % \end{macrocode} % \subsubsection{\csh{xintbarefloateval}, \csh{xintbareiieval}} % % \changed{1.4} % one expansion step added via \csbXINT{_expr_start}, % \csbXINT{_iiexpr_start}, \csbXINT{_flexpr_start}. Trigger is expected to be % via |\romannumeral`^^@| or |\romannumeral0|. % % For the benefit of those who like the author while finishing |1.4n| looked % in vain for where the ``|_start|'' macros were defined, this documentation % was updated so that one can find the location via clicking on their names in % the previous paragraph. Spoiler: they are in % \autoref{ssec:expansionspanning}. This was hidden because the three are % defined in an \csbxint{For} in one-go. % \begin{macrocode} \def\xintbarefloateval{\XINT_flexpr_start}% \def\xintbareiieval {\XINT_iiexpr_start}% % \end{macrocode} % \subsubsection{\csh{xintthebarefloateval}, % \csh{xintthebareiieval}} %\begin{lverb} % For matters of \XINT_NewFunc %\end{lverb} % % \changed{1.4o} % % The matter of Babel active here too, although these macros are destined to % use by \csbxint{deffunc} and \csbxint{NewExpr} and both attempt to sanitize % catcodes. But I had already edited at |1.4n| the user documentation to % mention cases where changing catcodes is impossible. It would have been too % time-costly late at night to re-edit while I was eager to push the |1.4o| % hotfix. So let's live with some added overhead. % % \changed{1.4p} % |s/_stop_atfirstofone/_firstofone| because anyhow it will encounter an % opening brace. % \begin{macrocode} \def\XINT_expr_unlock{\expandafter\xint_firstofone\romannumeral`&&@}% \def\xintthebareiieval{% \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbareiieval }% \def\xintthebarefloateval{% \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbarefloateval }% \def\xintthebareroundedfloateval{% \romannumeral0\csname xintthebareroundedfloateval_a\expandafter\endcsname \romannumeral0\xintbarefloateval }% \def\xintthebareroundedfloateval_a{% \expandafter\xint_firstofone \expanded\XINT:NEhook:x:mapwithin \XINT:expr:mapwithin{\XINTinFloatSdigits_braced}% }% % \end{macrocode} %\begin{lverb} % calx: native rounding (F, I, or raw input) for \xintdeffloatvar. %\end{lverb} % \begin{macrocode} \def\XINTinFloatSdigits_braced#1% {{\romannumeral0\expandafter\CALX_fbr \romannumeral0\CALX_fround{\XINTdigits}{#1}}}% % \end{macrocode} % \subsubsection{\csh{xintfloateval}, % \csh{xintiieval}} %\begin{lverb} % Refactored at 1.4. % % The \expanded upfront ensures \xinteval still expands % completely in two steps. No \romannumeral trigger here, in relation to the % fact that \XINTexprprint is not f-expandable, only e-expandable. % % (and attention that \xintexpr\relax is now legal, and an empty ople can be % produced in output also from \xintexpr [17][1]\relax for example) %\end{lverb} % \changed[2022/05/16]{1.4k} % % The \csbxint{ieval} and \csbxint{floateval} optional bracketed argument can now % be located outside the braces... took me years to finally make the step towards LaTeX % users expectations for the interface. % % \changed{1.4o} % Some |\csname|'s for the Babel-active feature which was botched at |1.4n|. % But |\xintiexpr| and |\xintifloatexpr| are already taken care of. % % Should I use |#{| rather delimited argument? (as for \csbxint{iieval} at |1.4n|). % % Same updates at |1.4p| as for \csbxint{ieval}. % \begin{macrocode} \def\xintfloateval {\expanded\expandafter\xint_floateval_chkopt\string}% \def\xint_floateval_chkopt #1% {% \ifx [#1\expandafter\xint_floateval_opt \else\expandafter\xint_floateval_noopt \fi #1% }% \def\xint_floateval_opt [#1]#2{% \expandafter\xint_gobble_i\romannumeral0\XINT_flexpr_withopt[#1]#2\relax }% \def\xint_floateval_noopt #1% {\expandafter\xint_floateval\expandafter{\iffalse}\fi}% \def\xint_floateval#1{% \expandafter\xint_gobble_i\romannumeral0\xintfloatexpro#1\relax }% % \end{macrocode} % \changed{1.4n} % \csbxint{iieval} admits optional arguments |[h]|, |[o]| and |[b]|. % The way this is implemented tames Babel active characters. % \begin{macrocode} \def\xintiieval #1#{\expanded\xintiieval_a{#1}}% \def\xintiieval_a#1#2% {% \csname XINTiiexprprint\xint_zapspaces #1 \xint_gobble_i \expandafter\endcsname \expandafter.\romannumeral0\xintbareiieval#2\relax }% \expandafter\def\csname XINTiiexprprint[h]\endcsname.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\CALX_iiprhex}% \expandafter\def\csname XINTiiexprprint[o]\endcsname.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\CALX_iiproct}% \expandafter\def\csname XINTiiexprprint[b]\endcsname.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\CALX_iiprbin}% \expandafter\let\csname XINTiiexprprint[]\endcsname\XINTiiexprprint \def\CALX_iiprhex #1{\xintiiexprPrintOneHex{\CALX_mr{#1}}}% \def\CALX_iiproct #1{\xintiiexprPrintOneOct{\CALX_mr{#1}}}% \def\CALX_iiprbin #1{\xintiiexprPrintOneBin{\CALX_mr{#1}}}% \let\xintiiexprPrintOneHex\xintDecToHex \let\xintiiexprPrintOneOct\xintDecToOct \let\xintiiexprPrintOneBin\xintDecToBin % \end{macrocode} % \subsubsection{\csh{xintifboolfloatexpr}, % \csh{xintifbooliiexpr}} % % \added{1.09c} % They do not accept (i.e.\@ they cause breakage if used this way) % comma separated expressions as input. % % \changed{1.4p} % Sadly at |1.4e|, some internal changes to the output format % of \csbxint{theexpr} broke that the assumptions which excused the use of % integer only \csbxint{iiifnotzero}. As a result the macro became badly % broken as it started thinking that for example |0.75| is zero. Fortunately % most usage of it is with some inequality test, which produces either one or % zero. So the author became aware of this only 5 years later. % \begin{macrocode} \def\xintifboolfloatexpr #1{% \romannumeral0\expandafter\CALX_ifnz \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbarefloateval #1\relax }% \def\xintifbooliiexpr #1{% \romannumeral0\expandafter\CALX_ifnz \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbareiieval #1\relax }% % \end{macrocode} % \subsubsection{\csh{xintifNonFinitefloatexpr}} %\begin{lverb} % The expression is evaluated once. Branch on its native result, I+, I-, % or I? for non-finite, any other numeric form for finite. This is independent % of signal flags and of the configurable printed spelling of special values. %\end{lverb} % \begin{macrocode} \def\xintifNonFinitefloatexpr #1{% \romannumeral0\expandafter\CALX_ifnonfinite \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbarefloateval #1\relax }% \def\CALX_ifnonfinite #1{% \expandafter\CALX_ifnonfinite_a\romannumeral`&&@#1\xint:}% \def\CALX_ifnonfinite_a #1{% \if I#1\expandafter\CALX_ifnonfinite_y \else\expandafter\CALX_ifnonfinite_n \fi }% \def\CALX_ifnonfinite_y #1\xint:{\xint_stop_atfirstoftwo}% \def\CALX_ifnonfinite_n #1\xint:{\xint_stop_atsecondoftwo}% % \end{macrocode} % \subsubsection{\csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} % % \added{1.3d} % They do not accept (i.e.\@ they will cause breakage if used with) comma % separated expressions. % % \changed{1.4p} % Badly broken since a |1.4e| regression, see \csbxint{ifboolexpr}. Situation % here was much worse, of course. I use \csbxint{thebareeval} to fix this as % I am stubborn and do not want the parsing from \csbxint{ifsgn} but this is % silly. For \csbxint{ifsgniiexpr}, matters are more moot but there is always % the danger of a custom \csbxint{iiexprPrintOne}, so \csbxint{bareiieval} % here too. For the other two really I should stop using the |ii| macros. % % \begin{macrocode} \def\xintifsgnfloatexpr #1{% \romannumeral0\expandafter\CALX_ifsgn \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbarefloateval #1\relax }% \def\xintifsgniiexpr #1{% \romannumeral0\expandafter\CALX_ifsgn \romannumeral0\csname xint_firstofone\expandafter\endcsname \romannumeral0\xintbareiieval #1\relax }% % \end{macrocode} % \subsubsection{Small bits we have to put somewhere} %\begin{lverb} % Some renaming and modifications here with release 1.2 to switch from % using chains of \romannumeral-`0 in order to gather numbers, possibly % hexadecimals, to using a \csname governed expansion. In this way no more % limit at 5000 digits, and besides this is a logical move because the % \xintexpr parser is already based on \csname...\endcsname storage of numbers % as one token. % % The limitation at 5000 digits didn't worry me too much because it was not % very realistic to launch computations with thousands of digits... such % computations are still slow with 1.2 but less so now. Chains or % \romannumeral are still used for the gathering of function names and other % stuff which I have half-forgotten because the parser does many things. % % In the earlier versions we used the lockscan macro after a chain of % \romannumeral-`0 had ended gathering digits; this uses has been replaced by % direct processing inside a \csname...\endcsname and the macro is kept only % for matters of dummy variables. % % Currently, the parsing of hexadecimal numbers needs two nested % \csname...\endcsname, first to gather the letters (possibly with a hexadecimal % fractional part), and in a second stage to apply \xintHexToDec to do the % actual conversion. This should be faster than updating on the fly the number % (which would be hard for the fraction part...). %\end{lverb} % \begin{macrocode} \def\XINT_embrace#1{{#1}}% \def\xint_gob_til_! #1!{}% ! with catcode 11 \def\xintError:noopening {% \XINT_expandableerror{Extra ). This is serious and prospects are bleak.}% }% % \end{macrocode} % \paragraph{\csh{xintthecoords}} % \added{1.1} (see user manual for interface) % % \begin{macrocode} \def\xintthecoords#1% {\romannumeral`&&@\expandafter\XINT_thecoords_a\romannumeral0#1}% \def\XINT_thecoords_a #1#2.#3% #2.=\XINTfloatprint. etc... {\expanded{\expandafter\XINT_thecoords_b\expanded#2.{#3},!,!,^}}% \def\XINT_thecoords_b #1#2,#3#4,% {\xint_gob_til_! #3\XINT_thecoords_c ! (#1#2, #3#4)\XINT_thecoords_b }% \def\XINT_thecoords_c #1^{}% % \end{macrocode} % \paragraph{\csh{xintthespaceseparated}} % \added{1.4a} % % This is a utility macro which was distributed previously % separately for usage with PSTricks \csa{listplot}. % \begin{macrocode} \def\xintthespaceseparated#1% {\expanded\expandafter\xintthespaceseparated_a\romannumeral0#1}% \def\xintthespaceseparated_a #1#2.#3% {{\expandafter \xintthespaceseparated_b\expanded#2.{#3},!,!,!,!,!,!,!,!,!,^}}% \def\xintthespaceseparated_b #1,#2,#3,#4,#5,#6,#7,#8,#9,% {\xint_gob_til_! #9\xintthespaceseparated_c !% #1#2#3#4#5#6#7#8#9% \xintthespaceseparated_b}% % \end{macrocode} %\begin{lverb} % 1.4c I add a space here to stop the \romannumeral`$&$&@ in case of % empty input. % But this space induces an extra un-needed space token after 9, 18, 27,... % items before the last group of less than 9 items. % % Fix (at 1.4h) is simple because I already use \expanded anyhow: I don't need % at all the \romannumeral`$&$&@ which was first in \xintthespaceseparated, % let's move the first \expanded which was in \xintthespaceseparated_a to % \xintthespaceseparated, and remove the extra space here in _c. % % (alternative would have been to put the space after #1 and accept a % systematic trailing space, at least it is more aesthetic). % % Again, I did have a test file, but it was not incorporated in my test suite, % so I discovered the problem accidentally by compiling all files in an archive. %\end{lverb} % \begin{macrocode} \def\xintthespaceseparated_c !#1!#2^{#1}% % \end{macrocode} % \subsection{Hooks into the numeric parser for usage by the % \cshnolabel{xintdeffunc} symbolic parser} %\begin{lverb} % This is new with 1.3 and considerably refactored at 1.4. See % «Mysterious stuff». %\end{lverb} % \begin{macrocode} \let\XINT:NEhook:f:one:from:one\expandafter \let\XINT:NEhook:f:one:from:one:direct\empty \let\XINT:NEhook:f:one:from:two\expandafter \let\XINT:NEhook:f:one:from:two:direct\empty \let\XINT:NEhook:x:one:from:two\empty \let\XINT:NEhook:f:one:and:opt:direct \empty \let\XINT:NEhook:f:tacitzeroifone:direct \empty \let\XINT:NEhook:f:iitacitzeroifone:direct \empty \let\XINT:NEhook:x:select:obey\empty \let\XINT:NEhook:x:listsel\empty \let\XINT:NEhook:f:reverse\empty % \end{macrocode} %\begin{lverb} % At 1.4 it was \def\XINT:NEhook:f:from:delim:u #1#2^{#1#2^} % which was trick to allow automatic unpacking of a nutple argument % to multi-arguments functions such as gcd() or max(). But this % sacrificied the usage with a single numeric argument. %\end{lverb} % \changed{1.4i} %\begin{lverb} % More sophisticated code to check if the argument ople % was actually a single number. Notice that this forces numeric % types to actually use catcode 12 tokens, and polexpr diverges % a bit using P, but actually always testing with \if not \ifx. % % This is used by gcd(), lcm(), max(), min(), `+`(), `*`(), all(), any(), % xor(). % % The nil and None will give the same result due to the initial brace % stripping done by \XINT:NEhook:f:from:delim:u (there was even a prior brace % stripping to provide the #2 which is empty here for the nil and {} for the % None). %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:f:from:delim:u #1#2^% {% \expandafter\XINT_fooof_checkifnumber\expandafter#1\string#2^% }% \def\XINT_fooof_checkifnumber#1#2% {% \expandafter#1% \romannumeral0\expanded{\if ^#2^\else \if\bgroup#2\noexpand\XINT_fooof_no\else \noexpand\XINT_fooof_yes#2\fi\fi}% }% \def\XINT_fooof_yes#1^{{#1}^}% \def\XINT_fooof_no{\expandafter{\iffalse}\fi}% % \end{macrocode} % \changed{1.4i} %\begin{lverb} % Same changes as for the other multiple arguments functions, % making them again usable with a single numeric input. % % Was at 1.4 \def\XINT:NEhook:f:noeval:from:braced:u#1#2^{#1{#2}} which % is not compatible with a single numeric input. % % Used by len(), first(), last() but it is a potential implementation bug that % the three share this as the location where expansion takes places is one % level deeper for the support macro of len(). % % The None is here handled as nil, i.e. it is unpacked, which is fine % as the documentations says nutples are unpacked. % %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:f:LFL #1{\expandafter#1\expandafter}% \def\XINT:NEhook:r:check #1^% {% \expandafter\XINT:NEhook:r:check_a\string#1^% }% \let\XINT:NEsaved:r:check \XINT:NEhook:r:check \def\XINT:NEhook:r:check_a #1% {% \if ^#1\xint_dothis\xint_c_\fi \if\bgroup#1\xint_dothis\XINT:NEhook:r:check_no\fi \xint_orthat{\XINT:NEhook:r:check_yes#1}% }% \def\XINT:NEhook:r:check_no {% \expandafter\XINT:NEhook:r:check_no_b \expandafter\xint_c_\expandafter{\iffalse}\fi }% \def\XINT:NEhook:r:check_no_b#1^{#1}% \def\XINT:NEhook:r:check_yes#1^{\xint_c_{#1}}% \let\XINT:NEhook:branch\expandafter \let\XINT:NEhook:seqx\empty \let\XINT:NEhook:iter\expandafter \let\XINT:NEhook:opx\empty \let\XINT:NEhook:rseq\expandafter \let\XINT:NEhook:iterr\expandafter \let\XINT:NEhook:rrseq\expandafter \let\XINT:NEhook:x:toblist\empty \let\XINT:NEhook:x:mapwithin\empty \let\XINT:NEhook:x:ndmapx\empty % \end{macrocode} % \subsection{\csh{XINT_expr_getnext}: fetch some value then an operator and % present them to last waiter with the found operator precedence, then % the operator, then the value} %\begin{lverb} % Big change in 1.1, no attempt to detect braced stuff anymore as the % [N] notation is implemented otherwise. Now, braces should not be used at % all; one level removed, then \romannumeral-`0 expansion. % % Refactored at 1.4 to put expansion of \XINT_expr_getop after the fetched % number, thus avoiding it to have to fetch it (which could happen then % multiple times, it was not really important when it was only one token in % pre-1.4 xintexpr). % % Allow \xintexpr\relax at 1.4. % % Refactored at 1.4 the articulation % \XINT_expr_getnext/XINT_expr_func/XINT_expr_getop. For some legacy reason % the first token picked by getnext was soon turned to catcode 12 The next % ones after the first were not a priori stringified but the first token was, % and this made allowing things such as \xintexpr\relax, \xintexpr,,\relax, % [], 1+(), [:] etc... complicated and requiring each time specific measures. % % The \expandafter chain in \XINT_expr_put_op_first is an overhead related % to an 1.4 attempt, the "varvalue" mechanism. I.e.: expansion of % \XINT_expr_var_foo is {\XINT_expr_varvalue_foo } and then for example % \XINT_expr_varvalue_foo expands to {4/1[0]}. The mechanism was originally % conceived to have only one token with idea its makes things faster. But the % xintfrac macros break with syntax such as \xintMul\foo\bar and \foo % expansion giving braces. So at 1.4c I added here these \expandafter, but % this is REALLY not satisfactory because the \expandafter are needed it seems % only for this variable "varvalue" mechanism. % % See also the discussion of \XINT_expr_op__ which distinguishes variables from % functions. % % After a 1.4g refactoring it would be possible to drop here the % \expandafter if the \XINT_expr_var_foo macro was defined to f-expand to % {actual expanded value (as ople)} for example explicit {{3}}. I have to % balance the relative weights of doing always the \expandafter but they are % needed only for the case the value was encapsulated in a variable, and of % never doing the \expandafter and ensure f-expansion of the _var_foo gives % explicit value (now that the refactoring let it be f-expanded, and the case % of fake variables omit and abort in particular was safely separated instead % of being treated like other and imposing restrictions on general variable % handling), and then there is the overhead of possibly moving around many % digits in the #1 of \XINT_expr_put_op_first. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_getnext #1% {% \expandafter\XINT_expr_put_op_first\romannumeral`&&@% \expandafter\XINT_expr_getnext_a\romannumeral`&&@#1% }% \def\XINT_expr_put_op_first #1#2#3{% \expandafter#2\expandafter#3\expandafter{#1}% }% \def\XINT_expr_getnext_a #1% {% \ifx\relax #1\xint_dothis\XINT_expr_foundprematureend\fi \ifx\XINTfstop#1\xint_dothis\XINT_expr_subexpr\fi \ifcat\relax#1\xint_dothis\XINT_expr_countetc\fi \xint_orthat{}\XINT_expr_getnextfork #1% }% \def\XINT_expr_foundprematureend\XINT_expr_getnextfork #1{{}\xint_c_\relax}% \def\XINT_expr_subexpr #1.#2% {% \expanded{\xint_noxpd{{#2}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} % % The "fetch as number" must be avoided for those cases where \cs{number} % can not be hoped to need only one token. Hence the liste of exceptions. % % \changed{1.2} % Add \cs{ht}, \cs{dp}, \cs{wd} and the e\TeX{} font related primitives. % % \changed{1.4} % Refactor for readability to avoid huge amounts of \cs{fi}'s. % % \changed{1.4g} % Check also for \cs{catcode} so that |\xinteval{\catcode`@}| does not crash. % But later I observed that |\fpeval{\catcode`@}| does crash, so in retrospect % I wonder if I should have added the overhead. % % \changed[2025/08/09]{1.4n} % Added \cs{_catcode} to the list for Op\TeX. This means though that an % undefined token with other engines will be expanded via \cs{number}... % \begin{macrocode} \def\XINT_expr_countetc\XINT_expr_getnextfork#1% {% \if0\ifx\count#11\fi \ifx\numexpr#11\fi \ifx\catcode#11\fi \ifx\dimen#11\fi \ifx\dimexpr#11\fi \ifx\skip#11\fi \ifx\glueexpr#11\fi \ifx\fontdimen#11\fi \ifx\ht#11\fi \ifx\dp#11\fi \ifx\wd#11\fi \ifx\fontcharht#11\fi \ifx\fontcharwd#11\fi \ifx\fontchardp#11\fi \ifx\fontcharic#11\fi \ifx\_catcode#11\fi 0\expandafter\XINT_expr_fetch_as_number\fi \expandafter\XINT_expr_getnext_a\number #1% }% \def\XINT_expr_fetch_as_number \expandafter\XINT_expr_getnext_a\number #1% {% \expanded{{{\number#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % This is the key initial dispatch component. It has been refactored at % 1.4g to give priority to identifying letter and digit tokens first. It % thus combines former \XINT_expr_getnextfork, \XINT_expr_scan_nbr_or_func and % \XINT_expr_scanfunc. A branch of the latter having become % \XINT_expr_startfunc. The handling of non-catcode 11 underscore _ has % changed: it is now skipped completely like the +. Formerly it would cause an % infinite loop because it triggered first insertion of a nil variable, (being % confused with a possible operator at a location where one looks for a % value), then tacit multiplication (being now interpreted as starting some % name), and then it came back to getnextfork creating loop. The @ of catcode % 12 could have caused the same issue if it was not handled especially because % it is used in the syntax as special variable for recursion hence was % recognized even if of catcode 12. Anyway I could have handled the _ like the % @, to avoid this problem of infinite loop with a non-letter underscore used % as first character but decided finally to have it be ignored (it is already % ignored if among digits, but it can be a constituent of a function of % variable name). It is not ignored of course if of catcode 11. It may then % start a variable or function name, but only for use by the package (by % polexpr for example), not by users. % % Then the matter is handed over to specialized routines: gathering digits % of a number (inclusive of a decimal mark, an exponential part) or letters % of a function or variable. And we have to intercept some tokens to implement % various functionalities. % % In each dothis/orthat structure, the first encountered branches are usually % handled slower than the next, because \if..\fi test cost less than grabbing % tokens. The exception is in the first one where letters pass through % slightly faster than digits, presumably because the \ifnum test is more % costly. Prior to this 1.4g refactoring the case of a starting letter of % a variable or function name was handled last, it is now handled first. Now, % this is only first letter... % % Here are the various possibilities in order that they are appear below % (the indicative order of speed of treatment is given as a number). % %( -1 tokens of catcode letter start a variable or function name %: -2 digits (I apply \string for the test, but I will have to review,& % it seems natural anyhow to require digits to be of catcode 12 and& % this is in fact basically done by the package, \numexpr does not& % work if not the case.), %: -7 support for Python-like * "unpacking" unary operator (added at 1.4), %: -6 support for [ as opener for the [..] nutple constructor (1.4), %: -5 support for the minus as unary operator of variable precedence, %: -4 support for @ as first character of special variables even if not letter, %: -3 support for opening parentheses (possibly triggering tacit multiplication), %: -13 support for skipping over ignored + character, %: -12 support for numbers starting with a decimal point, %: -11 support for the `+`() and `*`() functions, %: -10 support for the !() function, %: -9 support for the ?() function, %: -8 support for " for input of hexadecimal numbers and (1.4n) of ' for octal numbers. %: -17 support for \xintdeffunc via special handling of # token, %: -16 support for ignoring _ if not of catcode 11 and at start of& % numbers or names (this 1.4g change fixes \xinteval{_4} creating& % infinite loop) %: -15 support for inserting "nil" in front of operators, as needed in particular& % for the Python slicing syntax. This covers the comma, the :, the ] and& % the ) and also the ; although I don't think using ; to delimit nil is licit. %: -14 support for inserting 0 as missing value if / or ^ are encountered& % directly. This 1.4g changes avoids \xinteval{/3} causing& % unrecoverable low level errors from \xintDiv receiving only one argument. % I did not see here other bad syntax to protect. %) % % The handling of "nil" insertion penalizes Python slicing but anyway time % differences in the 14-15-16-17 group are less than % 5$%. The alternative will be % to do some positive test for the targets (:, ], the comma and closing % parenthesis) and do this in the prior group but this then penalizes % others. Anyway. This is all negligible compared to actual computations... % % Note: the above may not be in sync with code as it is extremely % time-consuming to maintain correspondence in case of re-factoring. %\end{lverb} %\odef\MakePrivateLetters{\MakePrivateLetters\catcode`` 11 }^^A % \begin{macrocode} \def\XINT_expr_getnextfork #1% {% \ifcat a#1\xint_dothis\XINT_expr_startfunc\fi \ifnum \xint_c_ix<1\string#1 \xint_dothis\XINT_expr_startint\fi \xint_orthat\XINT_expr_getnextfork_a #1% }% \def\XINT_expr_getnextfork_a #1% {% \if#1*\xint_dothis {{}\xint_c_ii^v 0}\fi \if#1[\xint_dothis {{}\xint_c_ii^v \XINT_expr_itself_obracket}\fi \if#1-\xint_dothis {{}{}-}\fi \if#1@\xint_dothis{\XINT_expr_startfunc @}\fi \if#1(\xint_dothis {{}\xint_c_ii^v (}\fi \xint_orthat{\XINT_expr_getnextfork_b#1}% }% \catcode96 11 % ` \def\XINT_expr_getnextfork_b #1% {% \if#1+\xint_dothis \XINT_expr_getnext_a\fi \if#1.\xint_dothis \XINT_expr_startdec\fi \if#1`\xint_dothis {\XINT_expr_onliteral_`}\fi \if#1!\xint_dothis {\XINT_expr_startfunc !}\fi \if#1?\xint_dothis {\XINT_expr_startfunc ?}\fi \if#1'\xint_dothis \XINT_expr_startoct\fi \if#1"\xint_dothis \XINT_expr_starthex\fi \xint_orthat{\XINT_expr_getnextfork_c#1}% }% \def\XINT_tmpa #1{% \def\XINT_expr_getnextfork_c ##1% {% \if##1#1\xint_dothis \XINT_expr_getmacropar\fi \if##1_\xint_dothis \XINT_expr_getnext_a\fi \if0\if##1/1\fi\if##1^1\fi0\xint_dothis{\XINT_expr_insertnil##1}\fi \xint_orthat{\XINT_expr_missing_arg##1}% }% }\expandafter\XINT_tmpa\string#% % \end{macrocode} %\begin{lverb} % The ` syntax is here used for special constructs like `+`(..), `*`(..) where % + or * will be treated as functions. Current implementation picks only one % token (could have been braced stuff), here it will be + or *, and via % \XINT_expr_op_` this then becomes a suitable % \XINT_{expr|iiexpr|flexpr}_func_+ (or *). Documentation says to use % `+`(...), but `+(...) is also valid. The opening parenthesis must be there, % it is not allowed to require some expansion. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_` #1#2({{#1}\xint_c_ii^v `}% \catcode96 12 % ` % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % Prior to 1.4g, I was using a \lowercase technique to insert the % catcode 12 #, but this is a bit risky when one does not ensure a priori control of all % lccodes. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1{% \def\XINT_expr_getmacropar ##1% {% \expandafter{\expandafter{\expandafter#1\expandafter ##1\expandafter}\expandafter}\romannumeral`&&@\XINT_expr_getop }% }\expandafter\XINT_tmpa\string#% \def\XINT_expr_insertnil #1% {% \expandafter{\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1% }% \def\XINT_expr_missing_arg#1% {% \expanded{\XINT_expandableerror {Expected a value, got nothing before `#1'. Inserting 0.}{{0}}\expandafter}% \romannumeral`&&@\XINT_expr_getop_a#1% }% % \end{macrocode} % \subsection{\csh{XINT_expr_startint}} % \localtableofcontents % Following comments are in part OBSOLETE as the code was refactored % at some stage to use \cs{expanded}. % %\begin{lverb} % 1.2 release has replaced chains of \romannumeral-`0 by \csname % governed expansion. Thus there is no more the limit at about 5000 digits for % parsed numbers. % % In order to avoid having to lock and unlock in succession to handle the % scientific part and adjust the exponent according to the number of digits of % the decimal part, the parsing of this decimal part counts on the fly the % number of digits it encounters. % % OBSOLETE START % There is some slight annoyance with \xintiiexpr which should never be given % a [n] inside its \csname.=\endcsname storage of numbers (because its % arithmetic uses the ii macros which know nothing about the [N] notation). % Hence if the parser has only seen digits when hitting something else than % the dot or e (or E), it will not insert a [0]. Thus we very slightly % compromise the efficiency of \xintexpr and \xintfloatexpr in order to be % able to share the same code with \xintiiexpr. % % Indeed, the parser at this location is completely common to all, it does not % know if it is working inside \xintexpr or \xintiiexpr. On the other hand if % a dot or a e (or E) is met, then the (common) parser has no scrupules ending % this number with a [n], this will provoke an error later if that was within % an \xintiiexpr, as soon as an arithmetic macro is used. % OBSOLETE END % % calx: the scanner is common to the three parsers; it ends a number by % a fake operator of precedence 22 (above every right precedence), which % the waiting operator of the running parser executes at once through % \XINT_

_op_. Integer exits (digits only, zeros, an integer % followed by .., integer hexadecimal, octal, binary): ^^B; the % receivers append [0] (\xintexpr, \xintfloatexpr) or build the native % integer M (\xintiiexpr). Decimal mark or exponent (and fractional % hexadecimal...): the exponent N is handed to ^^C outside the value % braces; the receivers append [N] (\xintexpr, \xintfloatexpr) or check % for an integer value (\xintiiexpr, \CALX_iilit). The receivers call % \XINT_expr_getop for the real operator. % % As the gathered numbers have no spaces, no pluses, no minuses, the only % remaining issue is with leading zeroes, which are discarded on the fly. The % hexadecimal numbers leading zeroes are stripped in a second stage by the % \xintHexToDec macro. % % With 1.2, \xinttheexpr . \relax does not work anymore (it did in earlier % releases). There must be digits either before or after the decimal mark. Thus % both \xinttheexpr 1.\relax and \xinttheexpr .1\relax are legal. % % Attention at this location #1 was of catcode 12 in all versions prior to % 1.4. % % We assume anyhow that catcodes of digits are 12... %\end{lverb} % % Style of location of the braces around replacement text varies, % but is kept as is to avoid wasting time on cosmetics. % % \changed[2025/09/01]{1.4n} Support for the |0b|, |0o| and |0x| prefixes! % Implementation of this extension of the syntax was very easy. % I may have thought of it briefly in the past but presumed it would % break things. % % This change seems to only break stuff such as |+0bar+3| with |bar| a % variable being interpreted |+0*bar+3| (tacit multiplication) and will cause % the parser to raise then an error message, but this is not very serious % breaking change. % % Supporting |0b| meant that like for octal |1.4n| needed to add the % needed support macros, which opens this TODO: perhaps try to share % code between binary, octal, hexadecimal more than currently. % \begin{macrocode} \def\XINT_expr_startint #1% {% \if #10\expandafter\XINT_expr_gobz_a\else \expandafter\XINT_expr_scanint_a\fi #1% }% \def\XINT_expr_scanint_a #1#2% {\expanded\bgroup{{\iffalse}}\fi #1% spare a \string \expandafter\XINT_expr_scanint_main\romannumeral`&&@#2}% \def\XINT_expr_gobz_a #1#2% {\expandafter\XINT_expr_gobz_b\romannumeral`&&@#2}% % \end{macrocode} % Perhaps use \cs{if} and not \cs{ifx} tests here? % \begin{macrocode} \def\XINT_expr_gobz_b #1%% {% \ifx b#1\xint_dothis \XINT_expr_startbin \fi \ifx o#1\xint_dothis \XINT_expr_startoct \fi \ifx x#1\xint_dothis \XINT_expr_starthex \fi \xint_orthat {\XINT_expr_gobz_c #1}% }% \def\XINT_expr_gobz_c #1% {\expanded\bgroup{{\iffalse}}\fi \expandafter\XINT_expr_gobz_scanint_main#1}% \def\XINT_expr_startdec #1% {\expanded\bgroup{{\iffalse}}\fi \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1}% % \end{macrocode} % \subsubsection{Integral part (skipping zeroes)} %\begin{lverb} % 1.2 has modified the code to give highest priority to digits, the % accelerating impact is non-negligeable. I don't think the doubled \string is % a serious penalty. % % (reference to \string is obsolete: it is only used in the test but the % tokens are not submitted to \string anymore) %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanint_main #1% {% \ifcat \relax #1\expandafter\XINT_expr_scanint_hit_cs \fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanint_next\fi #1\XINT_expr_scanint_again }% \def\XINT_expr_scanint_again #1% {% \expandafter\XINT_expr_scanint_main\romannumeral`&&@#1% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scanint_hit_cs \ifnum#1\fi#2\XINT_expr_scanint_again {% \iffalse{{{\fi}}}\xint_c_xxii&&B#2% }% % \end{macrocode} %\begin{lverb} % With 1.2d the tacit multiplication in front of a variable name or % function name is now done with a higher precedence, intermediate between the % common one of * and / and the one of ^. Thus x/2y is like x/(2y), but x^2y % is like x^2*y and 2y! is not (2y)! but 2*y!. % % Finally, 1.2d has moved away from the _scan macros all the business of the % tacit multiplication in one unique place via \XINT_expr_getop. For this, the % ending token is not first given to \string as was done earlier before % handing over back control to \XINT_expr_getop. Earlier we had to identify % the catcode 11 ! signaling a sub-expression here. With no \string applied % we can do it in \XINT_expr_getop. As a corollary of this displacement, % parsing of big numbers should be a tiny bit faster now. % % Extended for 1.2l to ignore underscore character _ if encountered within % digits; so it can serve as separator for better readability. %\end{lverb} % %\begin{lverb} % It is not obvious at 1.4 to support [] for three things: packing, % slicing, ... and raw xintfrac syntax A/B[N]. The only good way would be to % actually really separate completely \xintexpr, \xintfloatexpr and % \xintiiexpr code which would allow to handle both / and [] from A/B[N] as we % handle e and E. But triplicating the code is something I need to think % about. It is not possible as in pre 1.4 to consider [ only as an operator of % same precedence as multiplication and division which was the way we did % this, but we can use the technique of fake operators. Thus we intercept % hitting a [ here, which is not too much of a problem as anyhow we dropped % temporarily 3*[1,2,3]+5 syntax so we don't have to worry that 3[1,2,3] % should do tacit multiplication. I think only way in future will be to really % separate the code of the three parsers (or drop entirely support for A/B[N]; % as 1.4 has modified output of \xinteval to not use this notation this is not % too dramatic). % % Anyway we find a way to inject here the former handling of [N], which will % use a delimited macro to directly fetch until the closing]. We do still need % some fake operator because A/B[N] is (A/B) times 10^N and the /B is allowed % to be missing. We hack this using the $textdollar$space which is not used currently as % operator elsewhere in the syntax and need to hook into \XINT_expr_getop_b. % No finally I use the null char. It must be of catcode 12. % % 1.4f had _getop here, but let's jump directly to _getop_a. %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanint_next #1\XINT_expr_scanint_again {% \if [#1\xint_dothis\XINT_expr_rawxintfrac\fi \if _#1\xint_dothis\XINT_expr_scanint_again\fi \if e#1\xint_dothis{\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr0\XINT_expr_scanexp_a +}\fi \if E#1\xint_dothis{\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr0\XINT_expr_scanexp_a +}\fi \if .#1\xint_dothis{\XINT_expr_startdec_a .}\fi \xint_orthat {\iffalse{{{\fi}}}\xint_c_xxii&&B#1}% }% \def\XINT_expr_rawxintfrac {% [0]\iffalse{{{\fi}}\expandafter}% \csname XINT_expr_precedence_&&@\endcsname&&@% }% \def\XINT_expr_gobz_scanint_main #1% {% \ifcat \relax #1\expandafter\XINT_expr_gobz_scanint_hit_cs\fi \ifnum\xint_c_x<1\string#1 \else\expandafter\XINT_expr_gobz_scanint_next\fi #1\XINT_expr_scanint_again }% \def\XINT_expr_gobz_scanint_again #1% {% \expandafter\XINT_expr_gobz_scanint_main\romannumeral`&&@#1% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_gobz_scanint_hit_cs\ifnum#1\fi#2\XINT_expr_scanint_again {% 0\iffalse{{{\fi}}}\xint_c_xxii&&B#2% }% \def\XINT_expr_gobz_scanint_next #1\XINT_expr_scanint_again {% \if [#1\xint_dothis{\expandafter0\XINT_expr_rawxintfrac}\fi \if _#1\xint_dothis\XINT_expr_gobz_scanint_again\fi \if e#1\xint_dothis{0\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr0\XINT_expr_scanexp_a +}\fi \if E#1\xint_dothis{0\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr0\XINT_expr_scanexp_a +}\fi \if .#1\xint_dothis{\XINT_expr_gobz_startdec_a .}\fi \if 0#1\xint_dothis\XINT_expr_gobz_scanint_again\fi \xint_orthat {0\iffalse{{{\fi}}}\xint_c_xxii&&B#1}% }% % \end{macrocode} % \subsubsection{Fractional part} %\begin{lverb} % Annoying duplication of code to allow 0. as input. % % 1.2a corrects a very bad bug in 1.2 \XINT_expr_gobz_scandec_b which should % have stripped leading zeroes in the fractional part but didn't; as a result % \xinttheexpr 0.01\relax returned 0 =:-((( Thanks to Kroum Tzanev who % reported the issue. Does it improve things if I say the bug was introduced % in 1.2, it wasn't present before ? % % 1.4f had _getop here, but let's jump directly to _getop_a. %\end{lverb} % \begin{macrocode} \def\XINT_expr_startdec_a .#1% {% \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1% }% \def\XINT_expr_scandec_a #1% {% \if .#1\xint_dothis{\iffalse{{{\fi}}}\xint_c_xxii&&B..}\fi \xint_orthat {\XINT_expr_scandec_main 0.#1}% }% \def\XINT_expr_gobz_startdec_a .#1% {% \expandafter\XINT_expr_gobz_scandec_a\romannumeral`&&@#1% }% \def\XINT_expr_gobz_scandec_a #1% {% \if .#1\xint_dothis {0\iffalse{{{\fi}}}\xint_c_xxii&&B..}\fi \xint_orthat {\XINT_expr_gobz_scandec_main 0.#1}% }% \def\XINT_expr_scandec_main #1.#2% {% \ifcat \relax #2\expandafter\XINT_expr_scandec_hit_cs\fi \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_scandec_next\fi #2\expandafter\XINT_expr_scandec_again\the\numexpr #1-\xint_c_i.% }% \def\XINT_expr_scandec_again #1.#2% {% \expandafter\XINT_expr_scandec_main \the\numexpr #1\expandafter.\romannumeral`&&@#2% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scandec_hit_cs\ifnum#1\fi #2\expandafter\XINT_expr_scandec_again\the\numexpr#3-\xint_c_i.% {% \iffalse{{{\fi}}}\xint_c_xxii&&C#3]#2% }% \def\XINT_expr_scandec_next #1#2\the\numexpr#3-\xint_c_i.% {% \if _#1\xint_dothis{\XINT_expr_scandec_again#3.}\fi \if e#1\xint_dothis{\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr#3\XINT_expr_scanexp_a +}\fi \if E#1\xint_dothis{\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr#3\XINT_expr_scanexp_a +}\fi \xint_orthat {\iffalse{{{\fi}}}\xint_c_xxii&&C#3]#1}% }% \def\XINT_expr_gobz_scandec_main #1.#2% {% \ifcat \relax #2\expandafter\XINT_expr_gobz_scandec_hit_cs\fi \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_gobz_scandec_next\fi \if0#2\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expandafter\XINT_expr_gobz_scandec_main}% {#2\expandafter\XINT_expr_scandec_again}\the\numexpr#1-\xint_c_i.% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_gobz_scandec_hit_cs \ifnum#1\fi\if0#2#3\xint_c_i.% {% 0\iffalse{{{\fi}}}\xint_c_xxii&&B#2% }% \def\XINT_expr_gobz_scandec_next\if0#1#2\fi #3\numexpr#4-\xint_c_i.% {% \if _#1\xint_dothis{\XINT_expr_gobz_scandec_main #4.}\fi \if e#1\xint_dothis{0\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr0\XINT_expr_scanexp_a +}\fi \if E#1\xint_dothis{0\iffalse{{\fi}}\xint_c_xxii&&C% \the\numexpr0\XINT_expr_scanexp_a +}\fi \xint_orthat {0\iffalse{{{\fi}}}\xint_c_xxii&&B#1}% }% % \end{macrocode} % \subsubsection{Scientific notation} %\begin{lverb} % Some pluses and minuses are allowed at the start of the scientific % part, however not later, and no parenthesis. % % ATTENTION! 1e\numexpr2+3\relax or 1e\xintiexpr i\relax, i=1..5 % are not allowed and 1e1\numexpr2\relax does 1e1 * \numexpr2\relax. % Use \the\numexpr, \xinttheiexpr, etc... %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanexp_a #1#2% {% #1\expandafter\XINT_expr_scanexp_main\romannumeral`&&@#2% }% \def\XINT_expr_scanexp_main #1% {% \ifcat \relax #1\expandafter\XINT_expr_scanexp_hit_cs\fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_next\fi #1\XINT_expr_scanexp_again }% \def\XINT_expr_scanexp_again #1% {% \expandafter\XINT_expr_scanexp_main_b\romannumeral`&&@#1% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scanexp_hit_cs\ifnum#1\fi#2\XINT_expr_scanexp_again {% ]\iffalse{\fi}#2% }% \def\XINT_expr_scanexp_next #1\XINT_expr_scanexp_again {% \if _#1\xint_dothis \XINT_expr_scanexp_again \fi \if +#1\xint_dothis {\XINT_expr_scanexp_a +}\fi \if -#1\xint_dothis {\XINT_expr_scanexp_a -}\fi \xint_orthat {]\iffalse{\fi}#1}% }% \def\XINT_expr_scanexp_main_b #1% {% \ifcat \relax #1\expandafter\XINT_expr_scanexp_hit_cs_b\fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_next_b\fi #1\XINT_expr_scanexp_again_b }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scanexp_hit_cs_b\ifnum#1\fi#2\XINT_expr_scanexp_again_b {% ]\iffalse{\fi}#2% }% \def\XINT_expr_scanexp_again_b #1% {% \expandafter\XINT_expr_scanexp_main_b\romannumeral`&&@#1% }% \def\XINT_expr_scanexp_next_b #1\XINT_expr_scanexp_again_b {% \if _#1\xint_dothis\XINT_expr_scanexp_again\fi \xint_orthat {]\iffalse{\fi}#1}% }% % \end{macrocode} % \subsubsection{Hexadecimal numbers} %\begin{lverb} % 1.2d has moved most of the handling of tacit multiplication to % \XINT_expr_getop, but we have to do some of it here, because we apply % \string before calling \XINT_expr_scanhexI_aa. I do not insert the * % in \XINT_expr_scanhexI_a, because it is its higher precedence variant which % will is expected, to do the same as when a non-hexadecimal number prefixes a % sub-expression. Tacit multiplication in front of variable or function names % will not work (because of this \string). % % Extended for 1.2l to ignore underscore character _ if encountered within % digits. % % (some above remarks have been obsoleted for some long time, no more applied % \string since 1.4) % % Notice that internal representation adds a [N] part only in case input % used "DDD.dddd form, for compatibility with \xintiiexpr which is not % compatible with such internal representation. % % At 1.4g a very long-standing bug was fixed: input such as "\foo broke the % parser because (incredibly) the \foo token was picked up unexpanded and % ended up as is in an \ifcat ! % % Another long-standing bug was fixed at 1.4g: contrarily to the decimal case, % here in the hexadecimal input leading zeros were not trimmed. This was ok, % because formerly \xintHexToDec trimmed leading zeros, but at 1.2m 2017/07/31 % xintbinhex.sty was modified and this ceased being the case. But I forgot to % upgrade the parser here at that time. Leading zeros would in many % circumstances (presence of a fractional part, or \xintiiexpr context) lead % to wrong results. Leading zeros are now trimmed during input. % % Sadly this fix forgot the case of integer part being zero itself. % So \xinteval{"0.0001»} produced 0 because of this oversight. % Fixed in un-released 1.4q, soon superseded by 2.0a1. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_hex_in #1.#2#3;% {% \expanded{{{\if#2>% \xintHexToDec{#1}}}\xint_c_xxii&&B% \else \expandafter\CALX_rdx\the\numexpr \XINT_length_loop #3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye \relax.{#1#3}% \xinthextodec{100000625}4% \fi}% }% % \end{macrocode} %\begin{lverb} % Syntax (inside the \expanded of the scanner exits; A the digits of the % integer and fractional parts, k the number of fractional digits): %( % \CALX_rdx k.{A}{b} -> }}\xint_c_xxii<-jk>] %) % Fractional literal in radix 2^j (j = 4, 3, 1: hexadecimal, octal, % binary). A' = {A} (\xinthextodec, \xintocttodec, \xintbintodec) % is the integer of all the digits; the value is A' 2^(-jk) = A' 5^(jk) % 10^(-jk). is the native block of 5^j (100000625, 100000125, % 100000005): A' 5^(jk) is calxint's \CALX_npowmul. The loop of % \xintiNum (\XINT_num_loop, \XINT_num_cleanup) removes the leading % zeros of A' (there are some when the integer part is zero: the % conversions keep leading zeros of their input). The closing braces % come from `\iffalse{{\fi}}`, as in the other exits of the scanner; % is the fake operator (character 3) of the decimal and exponent exits. %\end{lverb} % \begin{macrocode} \def\CALX_rdx #1.#2#3#4#5% {% \romannumeral0\CALX_npowmul#1.{#4}% {\expandafter\XINT_num_cleanup \the\numexpr\expandafter\XINT_num_loop\romannumeral0#3{#2}% \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z}% \iffalse{{\fi}}\xint_c_xxii&&C\the\numexpr-#5*#1]% }% % \end{macrocode} %\begin{lverb} % Let's not forget to grab-expand next token first as is normal rule % of operation. Formerly called \XINT_expr_scanhex_I and had " upfront. %\end{lverb} % \begin{macrocode} \def\XINT_expr_starthex #1% {% \expandafter\XINT_expr_hex_in\expanded\bgroup \expandafter\XINT_expr_scanhexIgobz_a\romannumeral`&&@#1% }% \def\XINT_expr_scanhexIgobz_a #1% {% \ifcat #1\relax 0.>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanhexIgobz_aa #1% }% \def\XINT_expr_scanhexIgobz_aa #1% {% \if\ifnum`#1>`0 \ifnum`#1>`9 \ifnum`#1>`@ \ifnum`#1>`F 0\else1\fi\else0\fi\else1\fi\else0\fi 1% \xint_dothis\XINT_expr_scanhexI_b \fi \if 0#1\xint_dothis\XINT_expr_scanhexIgobz_bgob\fi \if _#1\xint_dothis\XINT_expr_scanhexIgobz_bgob\fi \if .#1\xint_dothis\XINT_expr_scanhexIgobz_toII\fi \xint_orthat {\XINT_expandableerror {Expected hexadecimal digit, `_', or `.'. got `#1'. Using `0'.}% 0.>;\iffalse{\fi}}% #1% }% \def\XINT_expr_scanhexIgobz_bgob #1#2% {% \expandafter\XINT_expr_scanhexIgobz_a\romannumeral`&&@#2% }% \def\XINT_expr_scanhexIgobz_toII .#1% {% 0..\expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanhexI_a #1% {% \ifcat #1\relax .>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanhexI_aa #1% }% \def\XINT_expr_scanhexI_aa #1% {% \if\ifnum`#1>`/ \ifnum`#1>`9 \ifnum`#1>`@ \ifnum`#1>`F 0\else1\fi\else0\fi\else1\fi\else0\fi 1% \expandafter\XINT_expr_scanhexI_b \else \if _#1\xint_dothis{\expandafter\XINT_expr_scanhexI_bgob}\fi \if .#1\xint_dothis{\expandafter\XINT_expr_scanhexI_toII}\fi \xint_orthat {.>;\iffalse{\fi\expandafter}}% \fi #1% }% \def\XINT_expr_scanhexI_b #1#2% {% #1\expandafter\XINT_expr_scanhexI_a\romannumeral`&&@#2% }% \def\XINT_expr_scanhexI_bgob #1#2% {% \expandafter\XINT_expr_scanhexI_a\romannumeral`&&@#2% }% \def\XINT_expr_scanhexI_toII .#1% {% ..\expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanhexII_a #1% {% \ifcat #1\relax\xint_dothis{;\iffalse{\fi}#1}\fi \xint_orthat {\XINT_expr_scanhexII_aa #1}% }% \def\XINT_expr_scanhexII_aa #1% {% \if\ifnum`#1>`/ \ifnum`#1>`9 \ifnum`#1>`@ \ifnum`#1>`F 0\else1\fi\else0\fi\else1\fi\else0\fi 1% \expandafter\XINT_expr_scanhexII_b \else \if _#1\xint_dothis{\expandafter\XINT_expr_scanhexII_bgob}\fi \xint_orthat{;\iffalse{\fi\expandafter}}% \fi #1% }% \def\XINT_expr_scanhexII_b #1#2% {% #1\expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#2% }% \def\XINT_expr_scanhexII_bgob #1#2% {% \expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#2% }% % \end{macrocode} % \subsubsection{Octal numbers} % \added{1.4n} % % The parsing goes exactly as with hexadecimal inputs, % except that we require an octal digit when expected. % % TODO: think about perhaps sharing code between binary, octal, and % hexadecimal. % \begin{macrocode} \def\XINT_expr_oct_in #1.#2#3;% {% \expanded{{{\if#2>% \xintOctToDec{#1}}}\xint_c_xxii&&B% \else \expandafter\CALX_rdx\the\numexpr \XINT_length_loop #3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye \relax.{#1#3}% \xintocttodec{100000125}3% \fi}% }% \def\XINT_expr_startoct #1% {% \expandafter\XINT_expr_oct_in\expanded\bgroup \expandafter\XINT_expr_scanoctIgobz_a\romannumeral`&&@#1% }% \def\XINT_expr_scanoctIgobz_a #1% {% \ifcat #1\relax 0.>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanoctIgobz_aa #1% }% % \end{macrocode} % Wondering if a bunch of \cs{if} tests comparing with 0 to 7 would % not be more efficient here. But testing would take some time % I am not motivated enough to use for that. In the code, also added % at |1.4n| for parsing binary input, I do this, but of course then % it was rather more natural to do. But I did not test either comparing % with style as here. % \begin{macrocode} \def\XINT_expr_scanoctIgobz_aa #1% {% \if\ifnum`#1>`0 \ifnum`#1>`7 0\else1\fi\else0\fi 1% \xint_dothis\XINT_expr_scanoctI_b \fi \if 0#1\xint_dothis\XINT_expr_scanoctIgobz_bgob\fi \if _#1\xint_dothis\XINT_expr_scanoctIgobz_bgob\fi \if .#1\xint_dothis\XINT_expr_scanoctIgobz_toII\fi \xint_orthat {\XINT_expandableerror {Expected an octal digit, `_', or `.'. Got `#1'. Using `0'.}% 0.>;\iffalse{\fi}}% #1% }% \def\XINT_expr_scanoctIgobz_bgob #1#2% {% \expandafter\XINT_expr_scanoctIgobz_a\romannumeral`&&@#2% }% \def\XINT_expr_scanoctIgobz_toII .#1% {% 0..\expandafter\XINT_expr_scanoctII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanoctI_a #1% {% \ifcat #1\relax .>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanoctI_aa #1% }% \def\XINT_expr_scanoctI_aa #1% {% \if\ifnum`#1>`/ \ifnum`#1>`7 0\else1\fi\else0\fi 1% \expandafter\XINT_expr_scanoctI_b \else \if _#1\xint_dothis{\expandafter\XINT_expr_scanoctI_bgob}\fi \if .#1\xint_dothis{\expandafter\XINT_expr_scanoctI_toII}\fi \xint_orthat {.>;\iffalse{\fi\expandafter}}% \fi #1% }% \def\XINT_expr_scanoctI_b #1#2% {% #1\expandafter\XINT_expr_scanoctI_a\romannumeral`&&@#2% }% \def\XINT_expr_scanoctI_bgob #1#2% {% \expandafter\XINT_expr_scanoctI_a\romannumeral`&&@#2% }% \def\XINT_expr_scanoctI_toII .#1% {% ..\expandafter\XINT_expr_scanoctII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanoctII_a #1% {% \ifcat #1\relax\xint_dothis{;\iffalse{\fi}#1}\fi \xint_orthat {\XINT_expr_scanoctII_aa #1}% }% \def\XINT_expr_scanoctII_aa #1% {% \if\ifnum`#1>`/ \ifnum`#1>`7 0\else1\fi\else0\fi 1% \expandafter\XINT_expr_scanoctII_b \else \if _#1\xint_dothis{\expandafter\XINT_expr_scanoctII_bgob}\fi \xint_orthat{;\iffalse{\fi\expandafter}}% \fi #1% }% \def\XINT_expr_scanoctII_b #1#2% {% #1\expandafter\XINT_expr_scanoctII_a\romannumeral`&&@#2% }% \def\XINT_expr_scanoctII_bgob #1#2% {% \expandafter\XINT_expr_scanoctII_a\romannumeral`&&@#2% }% % \end{macrocode} % \subsubsection{Binary numbers} % \added{1.4n} % Analogous to hexadecimal or octal with some simpler tests for digits. % \begin{macrocode} \def\XINT_expr_bin_in #1.#2#3;% {% \expanded{{{\if#2>% \xintBinToDec{#1}}}\xint_c_xxii&&B% \else \expandafter\CALX_rdx\the\numexpr \XINT_length_loop #3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye \relax.{#1#3}% \xintbintodec{100000005}1% \fi}% }% \def\XINT_expr_startbin #1% {% \expandafter\XINT_expr_bin_in\expanded\bgroup \expandafter\XINT_expr_scanbinIgobz_a\romannumeral`&&@#1% }% \def\XINT_expr_scanbinIgobz_a #1% {% \ifcat #1\relax 0.>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanbinIgobz_aa #1% }% \def\XINT_expr_scanbinIgobz_aa #1% {% \if _#1\xint_dothis\XINT_expr_scanbinIgobz_bgob\fi \if .#1\xint_dothis\XINT_expr_scanbinIgobz_toII\fi \if 0#1\xint_dothis\XINT_expr_scanbinIgobz_bgob\fi \if 1#1\xint_dothis\XINT_expr_scanbinI_b\fi \xint_orthat {\XINT_expandableerror {Expected a binary digit, `_', or `.'. Got `#1'. Using `0'.}% 0.>;\iffalse{\fi}}% #1% }% \def\XINT_expr_scanbinIgobz_bgob #1#2% {% \expandafter\XINT_expr_scanbinIgobz_a\romannumeral`&&@#2% }% \def\XINT_expr_scanbinIgobz_toII .#1% {% 0..\expandafter\XINT_expr_scanbinII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanbinI_a #1% {% \ifcat #1\relax .>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanbinI_aa #1% }% \def\XINT_expr_scanbinI_aa #1% {% \if _#1\xint_dothis\XINT_expr_scanbinI_bgob\fi \if .#1\xint_dothis\XINT_expr_scanbinI_toII\fi \if 0#1\xint_dothis\XINT_expr_scanbinI_b\fi \if 1#1\xint_dothis\XINT_expr_scanbinI_b\fi \xint_orthat {.>;\iffalse{\fi}}% #1% }% \def\XINT_expr_scanbinI_b #1#2% {% #1\expandafter\XINT_expr_scanbinI_a\romannumeral`&&@#2% }% \def\XINT_expr_scanbinI_bgob #1#2% {% \expandafter\XINT_expr_scanbinI_a\romannumeral`&&@#2% }% \def\XINT_expr_scanbinI_toII .#1% {% ..\expandafter\XINT_expr_scanbinII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanbinII_a #1% {% \ifcat #1\relax\xint_dothis{;\iffalse{\fi}#1}\fi \xint_orthat {\XINT_expr_scanbinII_aa #1}% }% \def\XINT_expr_scanbinII_aa #1% {% \if _#1\xint_dothis\XINT_expr_scanbinII_bgob\fi \if 0#1\xint_dothis\XINT_expr_scanbinII_b\fi \if 1#1\xint_dothis\XINT_expr_scanbinII_b\fi \xint_orthat{;\iffalse{\fi}}% #1% }% \def\XINT_expr_scanbinII_b #1#2% {% #1\expandafter\XINT_expr_scanbinII_a\romannumeral`&&@#2% }% \def\XINT_expr_scanbinII_bgob #1#2% {% \expandafter\XINT_expr_scanbinII_a\romannumeral`&&@#2% }% % \end{macrocode} % \subsubsection{\csh{XINT_expr_startfunc}: collecting names of functions and % variables} % %\begin{lverb} % At 1.4 the first token left over has not been submitted to % \string. We also know it is not a control sequence. So we can test catcode % to identify if operator is found. And it is allowed to hit some operator % such as a closing parenthesis we will then insert the «nil» value (edited: which % however will cause certain breakage of the infix binary operators: I notice % I did not insert None {{}} but nil {}, perhaps by oversight). % % There was prior to 1.4 solely the dispatch in \XINT_expr_scanfunc_b % but now we do it immediately and issue \XINT_expr_func only in certain % cases. % % Comments here have been removed because 1.4g did a refactoring % and renamed \XINT_expr_scanfunc to \XINT_expr_startfunc, moving half of % it earlier inside the getnextfork macros. %\end{lverb} % \begin{macrocode} \def\XINT_expr_startfunc #1% {\expandafter\XINT_expr_func\expanded\bgroup#1\XINT_expr_scanfunc_a}% \def\XINT_expr_scanfunc_a #1% {% \expandafter\XINT_expr_scanfunc_b\romannumeral`&&@#1% }% % \end{macrocode} %\begin{lverb} % This handles: 1) (indirectly) tacit multiplication by a variable in % front a of sub-expression, 2) (indirectly) tacit multiplication in front of % a \count etc..., 3) functions which are recognized via an encountered opening % parenthesis (but later this must be disambiguated from variables with tacit % multiplication) 4) 5) 6) 7) acceptable components of a variable or function % names: @, underscore, digits, letters (or chars of category code letter.) % % The short lived 1.2d which followed the even shorter lived 1.2c managed to % introduce a bug here as it removed the check for catcode 11 !, which must be % recognized if ! is not to be taken as part of a variable name. Don't know % what I was thinking, it was the time when I was moving the handling of tacit % mutliplication entirely to the \XINT_expr_getop side. Fixed in 1.2e. % % I almost decided to remove the \ifcat\relax test whose rôle is to avoid the % \string#1 to do something bad is the escape char is a digit! Perhaps I will % remove it at some point ! I truly almost did it, but also the case of no % escape char is a problem (\string\0, if \0 is a count ...) % % The (indirectly) above means that via \XINT_expr_func then \XINT_expr_op__ % one goes back to \XINT_expr_getop then \XINT_expr_getop_b which is the % location where tacit multiplication is now centralized. This makes the % treatment of tacit multiplication for situations such as \count or % \xintexpr..\relax, perhaps a bit sub-optimal, but first the % variable name must be gathered, second the variable must expand to its % value. %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanfunc_b #1% {% \ifcat \relax#1\xint_dothis{\iffalse{\fi}(_#1}\fi \if (#1\xint_dothis{\iffalse{\fi}(`}\fi \if 1\ifcat a#10\fi \ifnum\xint_c_ix<1\string#1 0\fi \if @#10\fi \if _#10\fi 1% \xint_dothis{\iffalse{\fi}(_#1}\fi \xint_orthat {#1\XINT_expr_scanfunc_a}% }% % \end{macrocode} % \subsubsection{\csh{XINT_expr_func}: dispatch to variable replacement or to % function execution} %\begin{lverb} % Comments written 2015/11/12: earlier there was an \ifcsname test for % checking if we had a variable in front of a (, for tacit multiplication for % example in x(y+z(x+w)) to work. But after I had implemented functions (that % was yesterday...), I had the problem if was impossible to re-declare a % variable name such as "f" as a function name. The problem is that here we % can not test if the function is available because we don't know if we are in % expr, iiexpr or floatexpr. The \xint_c_ii^v causes all fetching operations % to stop and control is handed over to the routines which will be expr, % iiexpr ou floatexpr specific, i.e. the \XINT_{expr|iiexpr|flexpr}_op_{`|_} % which are invoked by the until__b macros earlier in the stream. % Functions may exist for one but not the two other parsers. Variables are % declared via one parser and usable in the others, but naturally \xintiiexpr % has its restrictions. % % Thinking about this again I decided to treat a priori cases such as x(...) % as functions, after having assigned to each variable a low-weight macro % which will convert this into _getop\.=*(...). To activate that % macro at the right time I could for this exploit the "onliteral" intercept, % which is parser independent (1.2c). % % This led to me necessarily to rewrite partially the seq, add, mul, subs, % iter ... routines as now the variables fetch only one token. I think the % thing is more efficient. % % 1.2c had \def\XINT_expr_func #1(#2{\xint_c_ii^v #2{#1}} % % In \XINT_expr_func the #2 is _ if #1 must be a variable name, or #2=` if #1 % must be either a function name or possibly a variable name which will then % have to be followed by tacit multiplication before the opening parenthesis. % % The \xint_c_ii^v is there because _op_` must know in which parser % it works. Dispendious for _. Hence I modify for 1.2d. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func #1(#2{\if _#2\xint_dothis{\XINT_expr_op__{#1}}\fi \xint_orthat{{#1}\xint_c_ii^v #2}}% % \end{macrocode} % \subsection{\csh{XINT_expr_op_`}: launch function or % pseudo-function, or evaluate variable and insert operator of multiplication % in front of parenthesized contents} % %\begin{lverb} % The "onliteral" intercepts is for bool, togl, protect, ... but also % for add, mul, seq, etc... Genuine functions have expr, iiexpr and flexpr % versions (or only one or two of the three) and trigger here the use of the % suitable parser-dependant form. The former (pseudo functions and functions % handling dummy variables) first trigger a parser independent mechanism. % % With 1.2c "onliteral" is also used to disambiguate a variable followed % by an opening parenthesis from a function and then apply tacit multiplication. % However as I use only a \ifcsname test, in order to be able to % re-define a variable as function, I move the check for being a function % first. Each variable name now has its onliteral_ associated macro. % This used to be decided much earlier at the time of % \XINT_expr_func. % % The advantage of 1.2c code is that the same name can be used for % a variable or a function. %\end{lverb} % % \changed[2021/06/11]{1.4i} %\begin{lverb} % The 1.2c abuse of «onliteral» for both tacit multiplication in front % of an opening parenthesis and «generic» functions or pseudo-functions meant % that the latter were vulnerable against user redefinition of a function name % as a variable name. This applied to subs, subsm, subsn, seq, add, mul, % ndseq, ndmap, ndfillraw, bool, togl, protect, qint, qfrac, qfloat, qraw, % random, qrand, rbit and the most susceptible in real life was probably "seq". % % Now variables have an associated «var*» named macro, not «onliteral». % % In passing I refactor here in a \romannumeral inspired way how \csname and % TeX booleans are intertwined, minimizing \expandafter usage. %\end{lverb} % % \changed{2.0a1} % Per-parser "onliteral" macros. % % \begin{macrocode} \def\XINT_tmpa #1#2#3{% \def #1##1% {% \csname XINT_\ifcsname XINT_#3_func_##1\endcsname #3_func_##1\expandafter\endcsname\romannumeral`&&@\expandafter#2% \romannumeral\else \ifcsname XINT_#3_onliteral_##1\endcsname #3_onliteral_##1\expandafter\endcsname\romannumeral \else \ifcsname XINT_expr_var*_##1\endcsname expr_var*_##1\expandafter\endcsname\romannumeral \else #3_func_\XINT_expr_unknown_function {##1}% \expandafter\endcsname\romannumeral`&&@\expandafter#2% \romannumeral \fi\fi\fi\xint_c_ }% }% \xintFor #1 in {flexpr,iiexpr} \do {% \expandafter\XINT_tmpa \csname XINT_#1_op_`\expandafter\endcsname \csname XINT_#1_oparen\endcsname {#1}% }% \def\XINT_expr_unknown_function #1% {\XINT_expandableerror{`#1' is unknown, say `Isome_func' or I use 0.}}% \def\XINT_expr_func_ #1#2#3{#1#2{{0}}}% \let\XINT_flexpr_func_\XINT_expr_func_ \let\XINT_iiexpr_func_\XINT_expr_func_ % \end{macrocode} % % \subsection{\csh{XINT_expr_op__}: replace a variable by its value and % then fetch next operator} %\begin{lverb} % The 1.1 mechanism for \XINT_expr_var_ has been % modified in 1.2c. The associated macro is now only expanded % once, not twice. We arrive here via \XINT_expr_func. % % At 1.4 \XINT_expr_getop is launched with accumulated result on its left. % But the omit and abort keywords are implemented via fake variables % which rely on possibility to modify incoming upfront tokens. If we did here % something such as % $centeredline$bgroup_var_#1\expandafter\endcsname\romannumeral`^^@\XINT_expr_getop$egroup % the premature expansion of getop would break the var_omit and % var_abort mechanism. Thus we revert % to former code which locates an \XINT_expr_getop (call it _legacy) % before the tokens from the variable expansion (in xintexpr < 1.4 the % normal variables expanded % to a single token so the overhead was not serious) so we can expand fake % variables first. % % Abusing variables to manipulate the incoming token stream is a bit bad, % usually I prefer functions for this (such as the break() function) but then % I have to define 3 macros for the 3 parsers. % % This trick of fake variables puts thus a general overhead at various % locations, and the situation here is REALLY not satisfactory. But 1.4 has % (had) to be released now. % % Even if I could put the \csname XINT_expr_var_foo\endcsname upfront, which % would then be f-expanded, this would still need \XINT_expr_put_op_first to % use its \expandafter's as long as \XINT_expr_var_foo expands to % {\XINT_expr_varvalue_foo} with a not-yet expanded \XINT_expr_var_value. % % I could let \XINT_expr_var_foo expand to % \expandafter{\XINT_expr_varvalue_foo} allowing then (if it gets f-expanded) % probably to drop the \expandafter in \XINT_expr_put_op_first. But I can not % consider this option in the form % $centeredline$bgroup_var_foo\expandafter\endcsname\romannumeral`^^@\XINT_expr_getop$egroup % until the issue with fake variables such as omit and % abort which must act before \XINT_expr_getop has some workaround. % This could be implemented here with some extra branch, i.e. there would not % be some \XINT_expr_var_omit but something else filtered out in the \else % branch here. % % The above comments mention only omit and abort, but the case of real dummy % variables also needs consideration. % % At 1.4g, I test first for existence of \XINT_expr_onliteral_foo. % % Updated for 1.4i: now rather existence of \XINT_expr_var*_foo is tested. % % This is % a trick which allows to distinguish actual or dummy variables from really % fake variables omit and abort (must check if there are others). For the real % or dummy variables we can trigger the expansion of the \XINT_expr_getop % before the one of the variable. I could test vor varvalue_foo but this % applies only to real variables not dummy variables. Actual and dummy % variables are thus handled slightly faster at 1.4g as there is less % induced moving around (the \expandafter chain in \XINT_expr_put_op_first % still applies at this stage, as I have not yet re-examined the var/varlue % mechanism). And the test for var_foo is moved directly inside the \csname % construct in the \else branch which now handles together % fake variables and non-existing variables. % % I only have to make sure dummy variables are really safe being handled this % way with the getop action having being done before they expand, but it looks % ok. Attention it is crucial that if \XINT_expr_getop finds a \relax it inserts % \xint_c_\relax so the \relax token is still there! % % With this refactoring the \XINT_expr_getop_legacy is applied only in case % of non-existent variables or fake variables omit/abort or things such as % nil, None, false, true, False, True. % % If user in interactive mode fixes the variable name, the \XINT_expr_var_foo % expanded once with deliver {\XINT_expr_varvalue_foo} (if not dummy), and the % braces are maintained by \XINT_expr_getop_legacy. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_op__ #1% op__ with two _'s {% \ifcsname XINT_expr_var*_#1\endcsname \csname XINT_expr_var_#1\expandafter\endcsname \romannumeral`&&@\expandafter\XINT_expr_getop \else \expandafter\expandafter\expandafter\XINT_expr_getop_legacy \csname XINT_expr_var_% \ifcsname XINT_expr_var_#1\endcsname#1% \else\XINT_expr_unknown_variable{#1}\fi \expandafter\endcsname \fi }% \def\XINT_expr_unknown_variable #1% {\XINT_expandableerror {`#1' unknown, say `Isome_var' or I use 0.}}% \def\XINT_expr_var_{{{0}}}% \let\XINT_flexpr_op__ \XINT_expr_op__ \let\XINT_iiexpr_op__ \XINT_expr_op__ \def\XINT_expr_getop_legacy #1% {% \expanded{\xint_noxpd{{#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} % \subsection{\csh{XINT_expr_getop}: fetch the next operator or closing % parenthesis or end of expression} %\begin{lverb} % Release 1.1 implements multi-character operators. % % 1.2d adds tacit mutiplication also in front of variable or functions names % starting with a letter, not only a @ or a _ as was already the case. This is % for (x+y)z situations. It also applies higher precedence in cases like x/2y % or x/2@, or x/2max(3,5), or x/2\xintexpr 3\relax. % % In fact, finally I decide that all sorts of tacit multiplication will always % use the higher precedence. % % Indeed I hesitated somewhat: with the current code one does not know if % \XINT_expr_getop as invoked after a closing parenthesis or because a number % parsing ended, and I felt distinguishing the two was unneeded extra stuff. % This means cases like (a+b)/(c+d)(e+f) will first multiply the last two % parenthesized terms. % % % 1.2q adds tacit multiplication in cases such as (1+1)3 or 5!7! % % 1.4 has simplified coding here as \XINT_expr_getop expansion happens % at a time when a fetched value has already being stored. % % Prior to 1.4g there was an \if _#1\xint_dothis\xint_secondofthree\fi % because the _ can be used to start names, for private use by package (for % example by polexpr). But this test was silly because these usages are only % with a _ of catcode 11. And allowing non-catcode 11 _ also to trigger tacit % multiplication caused an infinite loop in collaboration with % \XINT_expr_scanfunc, see explanations there (now removed after refactoring, % see \XINT_expr_startfunc). % % The situation with the @ is different because we must allow it even as % catcode 12 as a name, as it used in the syntax and must work the same if of % catcode 11 or 12. No infinite loop because it is filtered out by one of the % \XINT_expr_getnextfork macros. % % The check for : to send it to thirdofthree "getop" branch is needed, last % time I checked, because during some part of at least \xintdeffunc, some % scantokens are done which need to work with the : of catcode 11, and it % would be misconstrued to start a name if not filtered out. % %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`* 11 }^^A % \begin{macrocode} \def\XINT_expr_getop #1% {% \expandafter\XINT_expr_getop_a\romannumeral`&&@#1% }% \catcode`* 11 \def\XINT_expr_getop_a #1% {% \ifx \relax #1\xint_dothis\xint_firstofthree\fi \ifcat \relax #1\xint_dothis\xint_secondofthree\fi \ifnum\xint_c_ix<1\string#1 \xint_dothis\xint_secondofthree\fi \if :#1\xint_dothis \xint_thirdofthree\fi \if @#1\xint_dothis \xint_secondofthree\fi \if (#1\xint_dothis \xint_secondofthree\fi %) \ifcat a#1\xint_dothis \xint_secondofthree\fi \xint_orthat \xint_thirdofthree % \end{macrocode} %\begin{lverb} % Formerly \XINT_expr_foundend as firstofthree but at 1.4g let's % simply insert \xint_c_ as the #1 is \relax (and anyhow a place-holder % according to remark in definition of \XINT_expr_foundend %\end{lverb} % \begin{macrocode} \xint_c_ % \end{macrocode} %\begin{lverb} % Tacit multiplication with higher precedence. Formerly % \XINT_expr_precedence_*** was used, renamed to \XINT_expr_prec_tacit at % 1.4g in case a backport is done of the \bnumdefinfix from bnumexpr. %\end{lverb} % \begin{macrocode} {\XINT_expr_prec_tacit *}% % \end{macrocode} %\begin{lverb} % This is only location which jumps to \XINT_expr_getop_b. At 1.4f and % perhaps for old legacy reasons this was \expandafter\XINT_expr_getop_b % \string#1 but I see no reason now for applying \string to #1. Removed at % 1.4g. And the #1 now moved out of the secondofthree and thirdofthree % branches. %\end{lverb} % \begin{macrocode} \XINT_expr_getop_b #1% }% \catcode`* 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % \relax is a place holder here. At 1.4g, we don't use % \XINT_expr_foundend anymore in \XINT_expr_getop_a which was slightly % refactored, but it is used elsewhere. % % Attention that keeping a \relax around if \XINT_expr_getop hits it is % crucial to good functioning of dummy variables after 1.4g refactoring of % \XINT_expr_op__, the \relax being used as delimiter by dummy variables, and % \XINT_expr_getop is now expanded before the variable itself does its thing. %\end{lverb} % \begin{macrocode} \def\XINT_expr_foundend {\xint_c_ \relax}% % \end{macrocode} %\begin{lverb} % ? is a very special operator with top precedence which will check if % the next token is another ?, while avoiding removing a brace pair from token % stream due to its syntax. Pre 1.1 releases used : rather than ??, but we % need : for Python like slices of lists. %\end{lverb} % %\begin{lverb} % null char is used as hack to implement A/B[N] raw input at 1.4. See % also \XINT_expr_scanint_c. %\end{lverb} % %\begin{lverb} % Memo: 1.4g, the token fetched by \XINT_expr_getop_b has not anymore % been previously submitted in \XINT_expr_getop_a to \string. %\end{lverb} % \begin{macrocode} \def\XINT_expr_getop_b#1{\def\XINT_expr_getop_b ##1% {% \if &&@##1\xint_dothis{#1&&@}\fi \if '##1\xint_dothis{\XINT_expr_binopwrd }\fi \if ?##1\xint_dothis{\XINT_expr_precedence_? ?}\fi \xint_orthat {\XINT_expr_scanop_a ##1}% }}\expandafter\XINT_expr_getop_b\csname XINT_expr_precedence_&&@\endcsname \def\XINT_expr_binopwrd #1'% {% \expandafter\XINT_expr_foundop_a \csname XINT_expr_itself_\xint_zapspaces #1 \xint_gobble_i\endcsname }% \def\XINT_expr_scanop_a #1#2% {% \expandafter\XINT_expr_scanop_b\expandafter#1\romannumeral`&&@#2% }% % \end{macrocode} %\begin{lverb} % Multi-character operators have an associated itself macro at each % stage of decomposition starting at two characters. Here, nothing imposes to % the operator characters not to be of catcode letter, this constraint applies % only on the first character and is done via \XINT_expr_getop_a, to handle in % particular tacit multiplication in front of variable or function names. % % But it would be dangerous to allow letters in operator characters, again due % to existence of variables and functions, and anyhow there is no user % interface to add such custom operators. However in bnumexpr, such a % constraint does not exist. % % I don't worry too much about efficiency here... and at 1.4g I have % re-written for code readability only. Once we see that #1#2 is not a % candidate to be or start an operator, we need to check if single-character % operator #1 is really an operator and this is done via the existence of the % precedence token. % % Unfortunately the 1.4g refactoring of the scanop macros had a bad bug: % \XINT_expr_scanop_c inserted \romannumeral`^^@ in stream but did not grab a % token first so a space would stop the \romannumeral and then the #2 in % \XINT_expr_scanop_d was not pre-expanded and ended up alone in \ifcat. It % is too distant in the past the time when I wrote the core of xintexpr in % 2013... older and dumber now. %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanop_b #1#2% {% \unless\ifcat#2\relax \ifcsname XINT_expr_itself_#1#2\endcsname \XINT_expr_scanop_c \fi\fi \XINT_expr_foundop_a #1#2% }% \def\XINT_expr_scanop_c #1#2#3#4#5#6% #1#2=\fi\fi {% #1#2% \expandafter\XINT_expr_scanop_d \csname XINT_expr_itself_#4#5\expandafter\endcsname \romannumeral`&&@#6% }% \def\XINT_expr_scanop_d #1#2% {% \unless\ifcat#2\relax \ifcsname XINT_expr_itself_#1#2\endcsname \XINT_expr_scanop_c \fi\fi \XINT_expr_foundop #1#2% }% \def\XINT_expr_foundop_a #1% {% \ifcsname XINT_expr_precedence_#1\endcsname \csname XINT_expr_precedence_#1\expandafter\endcsname \expandafter #1% \else \expandafter\XINT_expr_getop\romannumeral`&&@% \xint_afterfi{\XINT_expandableerror {Expected an operator but got `#1'. Ignoring.}}% \fi }% \def\XINT_expr_foundop #1{\csname XINT_expr_precedence_#1\endcsname #1}% % \end{macrocode} % \subsection{Expansion spanning; opening and closing parentheses} % \label{ssec:expansionspanning} % This is also where |\XINT_iiexpr_start| and % |\XINT_flexpr_start| are defined. % % \xintFor #1 in {flexpr,iiexpr} \do{\label{\xintimplabelprefix XINT_#1_start}} %\begin{lverb} % % These comments apply to all definitions coming next relative % to execution of operations from parsing of syntax. % % Refactored (and unified) at 1.4. In particular % the 1.4 scheme uses op, exec, check-, and checkp. Formerly % it was until_a (check-) and until_b (now split into checkp and exec). % % This way neither check- nor checkp have to % grab the accumulated number so far (top of stack if you like) and besides % one never has to go back to check- from checkp (and neither from check-). % % % % Prior to 1.4, accumulated % intermediate results were stored as one token, but now we have to use % \expanded to propagate expansion beyond possibly arbitrary long braced % nested data. With the 1.4 refactoring we do this only once and only grab % a second time the data if we actually have to act upon it. % % Version 1.1 had a hack inside the until macros for handling the omit % and abort in iterations over dummy variables. This has been removed by % 1.2c, see the subsection where omit and abort are discussed. % % Exceptionally, the check- is here abbreviated to check. % %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`) 11 }^^A % \begin{macrocode} \catcode`) 11 \def\XINT_def_start_and_check #1#2#3#4#5#6% {% \def#1% \XINT_expr_start, \XINT_iiexpr_start, \XINT_flexpr_start {% \expandafter#2\romannumeral`&&@\XINT_expr_getnext }% \def#2##1% check {% \xint_UDsignfork ##1{\expandafter#3\romannumeral`&&@#4}% -{#3##1}% \krof }% \def#3##1##2% checkp {% \ifcase ##1% \expandafter\XINT_expr_done \or\expandafter#5% \else \expandafter#3% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% \def#5% {% \XINT_expandableerror {Extra ) removed. Hit , fingers crossed.}% \expandafter#2\romannumeral`&&@\expandafter\XINT_expr_put_op_first \romannumeral`&&@\XINT_expr_getop_legacy }% }% \let\XINT_expr_done\space \xintFor #1 in {flexpr,iiexpr} \do {% \expandafter\XINT_def_start_and_check \csname XINT_#1_start\expandafter\endcsname \csname XINT_#1_check\expandafter\endcsname \csname XINT_#1_checkp\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_#1_extra_)\endcsname {#1}% }% % \end{macrocode} %\begin{lverb} % Here also we take some shortcuts relative to general philosophy and have no explicit % exec macro. %\end{lverb} % \begin{macrocode} \def\XINT_defop_oparen #1#2#3#4#5#6#7% {% \def #1##1% op_( {% \expandafter #4\romannumeral`&&@\XINT_expr_getnext }% \def #2##1% op_) {% \expanded{\xint_noxpd{\XINT_expr_put_op_first{##1}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def #3% oparen {% \expandafter #4\romannumeral`&&@\XINT_expr_getnext }% \def #4##1% check- {% \xint_UDsignfork ##1{\expandafter#5\romannumeral`&&@#6}% -{#5##1}% \krof }% \def #5##1##2% checkp {% \ifcase ##1\expandafter\XINT_expr_missing_) \or \csname XINT_#7_op_##2\expandafter\endcsname \else \expandafter #5% \romannumeral`&&@\csname XINT_#7_op_##2\expandafter\endcsname \fi }% }% \def\XINT_expr_missing_) {\XINT_expandableerror {End of expression found, but some ) was missing there.}% \xint_c_ \XINT_expr_done }% \xintFor #1 in {flexpr,iiexpr} \do {% \expandafter\XINT_defop_oparen \csname XINT_#1_op_(\expandafter\endcsname \csname XINT_#1_op_)\expandafter\endcsname \csname XINT_#1_oparen\expandafter\endcsname \csname XINT_#1_check-_)\expandafter\endcsname \csname XINT_#1_checkp_)\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \let\XINT_expr_precedence_)\xint_c_i \catcode`) 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{The comma as binary operator} %\begin{lverb} % New with 1.09a. Refactored at 1.4. %\end{lverb} % \begin{macrocode} \def\XINT_defop_comma #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_, {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4{##2##3{##1##4}}% \XINT_expr_exec_, \def #3##1% \XINT_expr_check-_, {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_, {% \ifnum ##1>\xint_c_iii \expandafter#4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \else \expandafter##1\expandafter##2% \fi }% }% \xintFor #1 in {flexpr,iiexpr} \do {% \expandafter\XINT_defop_comma \csname XINT_#1_op_,\expandafter\endcsname \csname XINT_#1_exec_,\expandafter\endcsname \csname XINT_#1_check-_,\expandafter\endcsname \csname XINT_#1_checkp_,\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \expandafter\let\csname XINT_expr_precedence_,\endcsname\xint_c_iii % \end{macrocode} % \subsection{The minus as prefix operator of variable precedence level} %\begin{lverb} % Inherits the precedence level of the previous infix operator, if the % latter has at least the precedence level of binary + and -, i.e. currently % 12. % % Refactored at 1.4. % % At 1.4g I belatedly observe that I have been defining architecture for % op_-xvi but such operator can never be created, because there are no infix % operators of precedence level 16. Perhaps in the past this was really % needed? But now such 16 is precedence level of tacit multiplication which % is implemented simply by the \XINT_expr_prec_tacit token, there is no macro % check-_*** which would need an op_-xvi. % % For the record: at least one scenario exists % which creates tacit multiplication in front of a unary -, it is 2\count0 % which first generates tacit multiplication then applies \number to \count0, % but the operator % is still *, so this triggers only \XINT_expr_op_-xiv, not -xvi. % % At 1.4g we need 17 and not 18 anymore as the precedence of unary minus % following power operators ^ and **. The needed \xint_c_xvii creation was % added to xintkernel.sty. %\end{lverb} % \begin{macrocode} \def\XINT_defop_minus_i #1#2#3#4#5#6#7% {% \def #1% \XINT_expr_op_- {% \expandafter #2\romannumeral`&&@\expandafter#3% \romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3% \XINT_expr_exec_- {% \expandafter ##1\expandafter ##2\expandafter {% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@#7##3}% }% }% \def #3##1% \XINT_expr_check-_- {% \xint_UDsignfork ##1{\expandafter #4\romannumeral`&&@#1}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_- {% \ifnum ##1>#5% \expandafter #4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_defop_minus #1#2#3% {% \expandafter\XINT_defop_minus_i \csname XINT_#1_op_-#3\expandafter\endcsname \csname XINT_#1_exec_-#3\expandafter\endcsname \csname XINT_#1_check-_-#3\expandafter\endcsname \csname XINT_#1_checkp_-#3\expandafter\endcsname \csname xint_c_#3\endcsname {#1}#2% }% \xintApplyInline{\XINT_defop_minus {flexpr}\calxFpOpp}{{xii}{xiv}{xvii}}% \xintApplyInline{\XINT_defop_minus {iiexpr}\calxiiOpp}{{xii}{xiv}{xvii}}% % \end{macrocode} % \subsection{The \texorpdfstring{\protect\lowast}{*}{} as Python-like «unpacking» prefix operator} % %\begin{lverb} % New with 1.4. Prior to 1.4 the internal data structure was % the one of \csname encapsulated comma separated numbers. No hierarchical % structure was (easily) possible. At 1.4, we can use TeX braces because there % is no detokenization to catcode 12. %\end{lverb} % % % \begin{macrocode} \def\XINT_defpost_unpack#1#2#3% {% \def#1##1{\expandafter#2\romannumeral`&&@\XINT_expr_getnext}% \def#2##1##2% {% \ifnum ##1>\xint_c_xx \expandafter #2% \romannumeral`&&@\csname XINT_#3_op_##2\expandafter\endcsname \else \expandafter##1% \expandafter##2\romannumeral0\expandafter\XINT:NEhook:unpack \fi }% }% \def\XINT:NEhook:unpack{\xint_stop_atfirstofone}% \xintFor* #1 in {{flexpr}{iiexpr}}: {\expandafter\XINT_defpost_unpack\csname XINT_#1_op_0\expandafter\endcsname \csname XINT_#1_until_unpack\endcsname {#1}}% % \end{macrocode} % \subsection{Infix operators} % % \localtableofcontents % %\begin{lverb} % 1.2d adds the *** for tying via tacit multiplication, for example % x/2y. Actually I don't need the _itself mechanism for ***, only a % precedence. % % At 1.4b we must make sure that the ! in expansion of \XINT_expr_itself_!= is % of catcode 12 and not of catcode 11. This is because implementation of % chaining of comparison operators proceeds via inserting the itself macro % directly into upcoming token stream, whereas formerly such itself macros % would be expanded only in a \csname...\endcsname context. %\end{lverb} % \begin{macrocode} \catcode`& 12 \catcode`! 12 \xintFor* #1 in {{==}{!=}{<=}{>=}{&&}{||}{//}{/:}{..}{..[}{].}{]..}}% \do {\expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}}% \catcode`& 7 \catcode`! 11 % \end{macrocode} % \subsubsection{\&\&, \textbar\textbar, //, /:, +, % \textendash, \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, % \texorpdfstring{\protect\lowast\protect\lowast}{**}{}, \textquotesingle and\textquotesingle, \textquotesingle % or\textquotesingle, \textquotesingle xor\textquotesingle, and % \textquotesingle mod\textquotesingle} % %\begin{lverb} % At 1.4g I finally decide to enact the switch to right % associativity for the power operators ^ and **. % % This goes via inserting into the checkp macros not anymore the precedence % chardef token (which now only serves as left precedence, inserted in the % token stream) but in its place an \xint_c_ token holding the right % precedence. Which is also transmitted to spanned unary minus operators. % % Here only levels 12, 14, and 17 are created as right precedences. % % #6 and #7 got permuted and the new #7 is directly a control sequence. % Also #3 and #4 are now integers which need \romannumeral. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_ai #1#2#3#4#5#6#7#8% {% \def #1##1% \XINT_expr_op_ {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_ {% \expandafter##2\expandafter##3\expandafter {\romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@#7##1##4}}% }% \def #3##1% \XINT_expr_check-_ {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_ {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#8_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_expr_defbin_a #1#2#3#4#5% {% \expandafter\XINT_expr_defbin_ai \csname XINT_#1_op_#2\expandafter\endcsname \csname XINT_#1_exec_#2\expandafter\endcsname \csname XINT_#1_check-_#2\expandafter\endcsname \csname XINT_#1_checkp_#2\expandafter\endcsname \csname XINT_#1_op_-\romannumeral\ifnum#4>12 #4\else12\fi\expandafter\endcsname \csname xint_c_\romannumeral#4\endcsname #5% {#1}% \expandafter % done 3 times but well \let\csname XINT_expr_precedence_#2\expandafter\endcsname \csname xint_c_\romannumeral#3\endcsname }% \XINT_expr_defbin_a {flexpr}{||} {6} {6} \calxFpOR \XINT_expr_defbin_a {iiexpr}{||} {6} {6} \calxOR \catcode`& 12 \XINT_expr_defbin_a {flexpr}{&&} {8} {8} \calxFpAND \XINT_expr_defbin_a {iiexpr}{&&} {8} {8} \calxAND \catcode`& 7 \XINT_expr_defbin_a {flexpr}{xor}{6} {6} \calxFpXOR \XINT_expr_defbin_a {iiexpr}{xor}{6} {6} \calxXOR \XINT_expr_defbin_a {flexpr}{//} {14}{14}\calxFpDivFloor \XINT_expr_defbin_a {iiexpr}{//} {14}{14}\calxiiDivFloor \XINT_expr_defbin_a {flexpr}{/:} {14}{14}\calxFpMod \XINT_expr_defbin_a {iiexpr}{/:} {14}{14}\calxiiMod \XINT_expr_defbin_a {flexpr} + {12}{12}\calxFpAdd \XINT_expr_defbin_a {iiexpr} + {12}{12}\calxiiAdd \XINT_expr_defbin_a {flexpr} - {12}{12}\calxFpSub \XINT_expr_defbin_a {iiexpr} - {12}{12}\calxiiSub \XINT_expr_defbin_a {flexpr} * {14}{14}\calxFpMul \XINT_expr_defbin_a {iiexpr} * {14}{14}\calxiiMul \let\XINT_expr_prec_tacit \xint_c_xvi \XINT_expr_defbin_a {flexpr} / {14}{14}\calxFpDiv \XINT_expr_defbin_a {iiexpr} / {14}{14}\calxiiDivRound % \end{macrocode} %\begin{lverb} % At 1.4g, right associativity is implemented via % a lowered right precedence here. %\end{lverb} % \begin{macrocode} \XINT_expr_defbin_a {flexpr} ^ {18}{17}\XINTinFloatSciPow \XINT_expr_defbin_a {iiexpr} ^ {18}{17}\calxiiPow % \end{macrocode} %\begin{lverb} % 1.4g This is a trick (which was in old version of bnumexpr, I % wonder why I did not have it here) but it will make error messages in case % of ** confusing. The ^ here is of catcode 11 but it does not matter. %\end{lverb} % \begin{macrocode} \expandafter\def\csname XINT_expr_itself_**\endcsname{^}% \catcode`& 12 % \end{macrocode} %\begin{lverb} % For this which contributes to implementing 'and', 'or', etc... see % \XINT_expr_binopwrd. %\end{lverb} % \begin{macrocode} \xintFor #1 in {and,or,xor,mod} \do {% \expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}% }% \expandafter\let\csname XINT_expr_precedence_and\expandafter\endcsname \csname XINT_expr_precedence_&&\endcsname \expandafter\let\csname XINT_expr_precedence_or\expandafter\endcsname \csname XINT_expr_precedence_||\endcsname \expandafter\let\csname XINT_expr_precedence_mod\expandafter\endcsname \csname XINT_expr_precedence_/:\endcsname \xintFor #1 in {flexpr, iiexpr} \do {% \expandafter\let\csname XINT_#1_op_and\expandafter\endcsname \csname XINT_#1_op_&&\endcsname \expandafter\let\csname XINT_#1_op_or\expandafter\endcsname \csname XINT_#1_op_||\endcsname \expandafter\let\csname XINT_#1_op_mod\expandafter\endcsname \csname XINT_#1_op_/:\endcsname }% \catcode`& 7 % \end{macrocode} % \subsubsection{.., ..[, and ].. for a..b and a..[b]..c syntax} % \begin{macrocode} \def\XINT_expr_defbin_bi #1#2#3#4#5#6#7% {% \def #1##1% \XINT_expr_op_..[ {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_..[ {% ##2##3{{##1##4}}% }% \def #3##1% \XINT_expr_check-_..[ {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_..[ {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#7_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_expr_defbin_b #1% {% \expandafter\XINT_expr_defbin_bi \csname XINT_#1_op_..[\expandafter\endcsname \csname XINT_#1_exec_..[\expandafter\endcsname \csname XINT_#1_check-_..[\expandafter\endcsname \csname XINT_#1_checkp_..[\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_expr_precedence_..[\endcsname {#1}% }% \XINT_expr_defbin_b {flexpr}% \XINT_expr_defbin_b {iiexpr}% \expandafter\let\csname XINT_expr_precedence_..[\endcsname\xint_c_vi \def\XINT_expr_defbin_ci #1#2#3#4#5#6#7#8% {% \def #1##1% \XINT_expr_op_ {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_ {% \expandafter##2\expandafter##3\expanded {{\XINT:NEhook:x:one:from:two#8##1##4}}% }% \def #3##1% \XINT_expr_check-_ {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_ {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#7_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_expr_defbin_c #1#2#3% {% \expandafter\XINT_expr_defbin_ci \csname XINT_#1_op_#2\expandafter\endcsname \csname XINT_#1_exec_#2\expandafter\endcsname \csname XINT_#1_check-_#2\expandafter\endcsname \csname XINT_#1_checkp_#2\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_expr_precedence_#2\endcsname {#1}#3% \expandafter\let \csname XINT_expr_precedence_#2\expandafter\endcsname\xint_c_vi }% \XINT_expr_defbin_c {flexpr} {..}\xintfloatSeq:tl:x \XINT_expr_defbin_c {iiexpr} {..}\xintSeq:tl:x \XINT_expr_defbin_c {flexpr}{]..}\xintfloatSeqB:tl:x \XINT_expr_defbin_c {iiexpr}{]..}\calxiiSeqB:tl:x % \end{macrocode} % \subsubsection{<, >, ==, <=, >=, != with Python-like chaining} % % \added{1.4b} % This is preliminary implementation of chaining of comparison % operators like Python and (I think) l3fp do. I am not too happy % with how many times the (second) operand (already evaluated) is fetched. % % \changed{1.4p} % Sadly this was broken ever since creation if used inside \csbxint{iieval} or % \csbxint{floateval} due to a macro using by oversight the parser type in the % name of a token defining the precedence of the inserted |&&|. But this % token never got defined. Anyhow we don't need another one beyond the one % suitable for \csbxint{eval}. A unit test existed, \emph{of course}, but it % tested only \csbxint{eval}! Thanks to Thomas Ossig for report. % % \begin{macrocode} \def\XINT_expr_defbin_dii #1#2% {% \def #1##1##2##3##4% \XINT__exec_ {% \expandafter##2\expandafter##3\expandafter {\romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@#2##1##4}}% }% }% \def\XINT_expr_defbin_di #1#2#3#4#5#6#7#8#9% {% \def #1##1% \XINT__op_ {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#7% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #3##1% \XINT__check-_ {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT__checkp_ {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#9_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% \let #6\xint_c_x \def #7##1% \XINT_expr_checkc_ {% \ifnum ##1=\xint_c_x\expandafter#8\fi ##1% }% \edef #8##1##2##3% \XINT_expr_execc_ {% \csname XINT_expr_precedence_\string&\string&\endcsname \expandafter\noexpand\csname XINT_expr_itself_\string&\string&\endcsname {##3}% \XINTfstop.{##3}##2% }% \XINT_expr_defbin_dii #2% \XINT_expr_exec_ }% \def\XINT_expr_defbin_d #1#2%#3% {% \expandafter\XINT_expr_defbin_di \csname XINT_#1_op_#2\expandafter\endcsname \csname XINT_#1_exec_#2\expandafter\endcsname \csname XINT_#1_check-_#2\expandafter\endcsname \csname XINT_#1_checkp_#2\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_expr_precedence_#2\expandafter\endcsname \csname XINT_#1_checkc_#2\expandafter\endcsname \csname XINT_#1_execc_#2\endcsname {#1}%#3% }% % \end{macrocode} %\begin{lverb} % Attention that third token here is left in stream by defbin_b, then % also by defbin_c and is picked up as #2 of defbin_d. Had to work around TeX % accepting only 9 arguments. Why did it not start counting at #0 like all % decent mathematicians do? %\end{lverb} % \begin{macrocode} \XINT_expr_defbin_d {flexpr}<\calxFpLt% calx \XINT_expr_defbin_d {iiexpr}<\calxiiLt \XINT_expr_defbin_d {flexpr}>\calxFpGt% calx \XINT_expr_defbin_d {iiexpr}>\calxiiGt \XINT_expr_defbin_d {flexpr}{==}\calxFpEq% calx \XINT_expr_defbin_d {iiexpr}{==}\calxiiEq \XINT_expr_defbin_d {flexpr}{<=}\calxFpLtorEq% calx \XINT_expr_defbin_d {iiexpr}{<=}\calxiiLtorEq \XINT_expr_defbin_d {flexpr}{>=}\calxFpGtorEq% calx \XINT_expr_defbin_d {iiexpr}{>=}\calxiiGtorEq \XINT_expr_defbin_d {flexpr}{!=}\calxFpNotEq% calx \XINT_expr_defbin_d {iiexpr}{!=}\calxiiNotEq % \end{macrocode} % \subsubsection{Support macros for .., ..[ and ]..} % \localtableofcontents % % \paragraph{\csh{xintSeq:tl:x}, \csh{xintfloatSeq:tl:x}} %\begin{lverb} % a..b: the integers from ceil(a) to floor(b), decreasing if floor(b) < % ceil(a), both ends included, never an empty list (a = b non-integer: % ceil(a), floor(a)). Values of any of the three parsers; the ends must be % TeX integers. \xintSeq:tl:x (\xinteval, \xintiieval): M items % (\CALX_seq_m); \xintfloatSeq:tl:x (\xintfloateval): F items (\CALX_seq_f). % b = I-: the single item ceil(a). b = I+ or I?, or a an I value: an % expandable error, empty list. % % ceil and floor by calxfp's \CALX_fint (sign s, |trunc| T, first omitted % digit d, non-zero flag z) and its kind macros \CALX_fintk_c, % \CALX_fintk_f: \CALX_seq_k writes sTssdz, i.e. s(T + a), in \numexpr. % The loop carries the item builder after the two ends. %\end{lverb} % \begin{macrocode} \def\xintSeq:tl:x {\CALX_seq\CALX_seq_m}% \def\xintfloatSeq:tl:x {\CALX_seq\CALX_seq_f}% \def\CALX_seq_f #1.{\romannumeral0\CALX_ffromraw{#1[0]}}% \def\CALX_seq #1#2#3% {\expandafter\CALX_seq_b\romannumeral`&&@#3\xint:#1{#2}}% \def\CALX_seq_b #1#2\xint:#3#4% {% \if I#1\xint_dothis{\CALX_seq_i#2\xint:#3{#4}}\fi \xint_orthat{\expandafter\CALX_seq_c\the\numexpr\expandafter\CALX_seq_k \romannumeral0\CALX_fint#1#2\xint:\CALX_fintk_f.#3{#4}}% }% \def\CALX_seq_k #1#2.#3#4#5{#1#2#1#5#1#3#4}% \def\CALX_seq_i #1\xint:#2#3% {\if-#1\xint_dothis{\CALX_seq_c.#2{#3}}\fi\xint_orthat\CALX_seq_err}% \def\CALX_seq_c #1.#2#3% {\expandafter\CALX_seq_d\romannumeral`&&@#3\xint:#1.#2}% \def\CALX_seq_d #1#2\xint:#3.#4% {% \if I#1\xint_dothis\CALX_seq_err\fi \xint_orthat{\expandafter\CALX_seq_e\the\numexpr\expandafter\CALX_seq_k \romannumeral0\CALX_fint#1#2\xint:\CALX_fintk_c.#3.#4}% }% \def\CALX_seq_err{\XINT_expandableerror{a..b: invalid range.}}% \def\CALX_seq_e #1.#2.#3% {% \if\relax\detokenize{#2}\relax\xint_dothis{{#3#1.}}\fi \ifnum#2=#1 \xint_dothis{{#3#1.}}\fi \ifnum#2<#1 \xint_dothis{\CALX_seq_n #1.#2.#3}\fi \xint_orthat{\CALX_seq_p #1.#2.#3}% }% \def\CALX_seq_p #1.#2.#3% {{#3#1.}\ifnum#1=#2 \CALX_seq_x\fi \expandafter\CALX_seq_p\the\numexpr#1+\xint_c_i.#2.#3}% \def\CALX_seq_n #1.#2.#3% {{#3#1.}\ifnum#1=#2 \CALX_seq_x\fi \expandafter\CALX_seq_n\the\numexpr#1-\xint_c_i.#2.#3}% \def\CALX_seq_x #1#2.#3.#4{#1}% % \end{macrocode} %\begin{lverb} % a..[d]..b of \xintfloateval and \xintiieval: from a by steps d while not % beyond b; d = 0: a alone; nil if b is on the wrong side of a. Exact % stepping and comparison: \xintfloatSeqB:tl:x on F values (\CALX_fexact: % F, M and raw A[N] exactly, A/B[N] with B > 1 rounded to P digits; % \CALX_faddx, \CALX_fcmp), \calxiiSeqB:tl:x on M values (\CALX_tom, % \CALX_iiadd, \CALX_iicmp_x). An I value among a, d, b: expandable error, % empty list. \xinteval has its own (xintexpr.sty). % % \CALX_seqb {a}{d}{b}: the three ends converted by % (output Y\xint:), the sign of d by calxcore's \CALX_ifsgn. The loop \CALX_seqb_l % {x}{d}{b}: one comparison of x with b per item, the % selectors \xint_stop_at...ofthree of (equal, greater, less) taken % in the order of \CALX_seqb_sw (d > 0: x against b) or \CALX_seqb_id % (d < 0: b against x); the first step is a loop step with x = a. %\end{lverb} % \begin{macrocode} \def\xintfloatSeqB:tl:x #1#2% {\CALX_seqb\CALX_fexact\CALX_faddx\CALX_seqb_fc#1{#2}}% \def\calxiiSeqB:tl:x #1#2{\CALX_seqb\CALX_tom\CALX_iiadd\CALX_seqb_ic#1{#2}}% \def\CALX_seqb_fc #1#2% {\ifcase\CALX_fcmp{#1}{#2} \expandafter\xint_stop_atfirstofthree \or\expandafter\xint_stop_atsecondofthree \else\expandafter\xint_stop_atthirdofthree\fi}% \def\CALX_seqb_ic #1#2{\CALX_iicmp_x#1\xint:#2\xint:}% \def\CALX_seqb #1#2#3#4#5% {\expandafter\CALX_seqb_a\romannumeral0#1{#5}#1#2#3{#4}}% \def\CALX_seqb_a #1\xint:#2#3#4#5% {\expandafter\CALX_seqb_b\romannumeral0#2{#5}{#1}#2#3#4}% \def\CALX_seqb_b #1\xint:#2#3#4#5#6% {\expandafter\CALX_seqb_c\romannumeral0#3{#6}{#1}{#2}#4#5}% \def\CALX_seqb_c #1\xint:#2#3% {\CALX_seqb_d #1\xint:#2\xint:#3\xint:{#1}{#2}{#3}}% \def\CALX_seqb_d #1#2\xint:#3#4\xint:#5#6\xint:% {% \if I#1\xint_dothis\CALX_seqb_e\fi \if I#3\xint_dothis\CALX_seqb_e\fi \if I#5\xint_dothis\CALX_seqb_e\fi \xint_orthat\CALX_seqb_f }% \def\CALX_seqb_e #1#2#3#4#5{\CALX_seq_err}% \def\CALX_seqb_f #1#2#3#4#5% {\romannumeral0\CALX_ifsgn{#3}{\CALX_seqb_l{#2}{#3}{#1}#4#5\CALX_seqb_id}% {{#2}}{\CALX_seqb_l{#2}{#3}{#1}#4#5\CALX_seqb_sw}}% \def\CALX_seqb_l #1#2#3#4#5#6% {\romannumeral0#6#5{#3}{#1}{{#1}}{}% {{#1}\expandafter\CALX_seqb_m\romannumeral0#4{#1}{#2}\xint: {#2}{#3}#4#5#6}}% \def\CALX_seqb_m #1\xint:{\CALX_seqb_l{#1}}% \def\CALX_seqb_id #1{#1}% \def\CALX_seqb_sw #1#2#3{#1{#3}{#2}}% % \end{macrocode} % \subsection{Square brackets [\texorpdfstring{\,}{ }] both as a container and a Python slicer} % Refactored at |1.4| % %\begin{lverb} % The architecture allows to implement separately a «left» and a «right» % precedence and this is crucial. %\end{lverb} % \localtableofcontents % % % \subsubsection{[...] as «oneple» constructor} % %\begin{lverb} % In the definition of \XINT_expr_op_obracket the parameter % is trash {}. The [ is intercepted by the getnextfork and handled % via the \xint_c_ii^v highest precedence trick to get op_obracket % executed. %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`[ 11 \catcode`] 11 }^^A % \begin{macrocode} \def\XINT_expr_itself_obracket{obracket}% \catcode`] 11 \catcode`[ 11 \def\XINT_expr_defbin_ei #1#2#3#4#5#6% {% \def #1##1% {% \expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1% op_] {% \expanded{\xint_noxpd{\XINT_expr_put_op_first{{##1}}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def #3##1% until_cbracket_a {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% #5 = op_-xii -{#4##1}% \krof }% \def #4##1##2% until_cbracket_b {% \ifcase ##1\expandafter\XINT_expr_missing_] \or \expandafter\XINT_expr_missing_] \or \expandafter#2% \else \expandafter #4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% }% \def\XINT_expr_defbin_e #1% {% \expandafter\XINT_expr_defbin_ei \csname XINT_#1_op_obracket\expandafter\endcsname \csname XINT_#1_op_]\expandafter\endcsname \csname XINT_#1_until_cbracket_a\expandafter\endcsname \csname XINT_#1_until_cbracket_b\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \XINT_expr_defbin_e {flexpr}% \XINT_expr_defbin_e {iiexpr}% \def\XINT_expr_missing_] {\XINT_expandableerror{Ooops, looks like we are missing a ]. Aborting!}% \xint_c_ \XINT_expr_done}% \let\XINT_expr_precedence_]\xint_c_ii % \end{macrocode} % \subsubsection{[...] brackets and : operator for NumPy-like slicing and item % indexing syntax} %\begin{lverb} % The opening bracket [ for the nutple constructor is filtered out by % \XINT_expr_getnextfork and becomes «obracket» which behaves with % precedence level 2. For the [..] Python slicer on the other hand, a real % operator [ is defined with precedence level 4 (it must be higher than % precedence level of commas) on its right and maximal precedence on its left. % % Important: although slicing and indexing shares many rules with Python/NumPy % there are some significant differences: in particular there can not be any % out-of-range error generated, slicing applies also to «oples» and not only % to «nutple», and nested lists do not have to have their leaves at a constant % depth. See the user manual. % % Currently, NumPy-like nested (basic) slicing is implemented, i.e [a:b, c:d, % N, e:f, M] type syntax with Python rules regarding negative integers. This % is parsed as an expression and can arise from expansion or contain % calculations. % % Currently stepping, Ellipsis, and simultaneous multi-index extracting are % not yet implemented. % % There are some subtle things here with possibility of variables been passed % by reference. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_fi #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_[ {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_] {% \expandafter\XINT_expr_put_op_first \expanded {% {\XINT:NEhook:x:listsel\XINT_ListSel_top ##1__##4&% ({##1}\expandafter}% \expandafter }% \romannumeral`&&@\XINT_expr_getop }% \def #3##1% \XINT_expr_check-_] {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_] {% \ifcase ##1\XINT_expr_missing_] \or \XINT_expr_missing_] \or \expandafter##1\expandafter##2% \else \expandafter#4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% }% \let\XINT_expr_precedence_[ \xint_c_xx \def\XINT_expr_defbin_f #1% {% \expandafter\XINT_expr_defbin_fi \csname XINT_#1_op_[\expandafter\endcsname \csname XINT_#1_exec_]\expandafter\endcsname \csname XINT_#1_check-_]\expandafter\endcsname \csname XINT_#1_checkp_]\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \XINT_expr_defbin_f {flexpr}% \XINT_expr_defbin_f {iiexpr}% \catcode`] 12 \catcode`[ 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % At 1.4 the getnext, scanint, scanfunc, getop chain got revisited to % trigger automatic insertion of the nil variable if needed, without having in % situations like here to define operators to support «[:» or «:]». And as we % want to implement nested slicing à la NumPy, we would have had to handle % also «:,» for example. Thus here we simply have to define the sole operator % «:» and it will be some sort of inert joiner preparing a slicing spec. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_gi #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_: {% \expanded{\xint_noxpd{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_: {% ##2##3{:##1{0};##4:_}% }% \def #3##1% \XINT_expr_check-_: {\xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_: {% \ifnum ##1>\XINT_expr_precedence_: \expandafter #4\romannumeral`&&@% \csname XINT_#6_op_##2\expandafter\endcsname \else \expandafter##1\expandafter##2% \fi }% }% \let\XINT_expr_precedence_: \xint_c_vi \def\XINT_expr_defbin_g #1% {% \expandafter\XINT_expr_defbin_gi \csname XINT_#1_op_:\expandafter\endcsname \csname XINT_#1_exec_:\expandafter\endcsname \csname XINT_#1_check-_:\expandafter\endcsname \csname XINT_#1_checkp_:\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \XINT_expr_defbin_g {flexpr}% \XINT_expr_defbin_g {iiexpr}% % \end{macrocode} % \subsubsection{Macro layer implementing indexing and slicing} %\begin{lverb} % xintexpr applies slicing not only to «objects» (which can be passed % as arguments to functions) but also to «oples». % % Our «nlists» are not necessarily regular N-dimensional arrays à la NumPy. % Leaves can be at arbitrary depths. If we were handling regular «ndarrays», % we could proceed a bit differently. % % For the related % explanations, refer to the user manual. % % Notice that currently the code uses f-expandable (and not using \expanded) % macros \xintApply, \xintApplyUnbraced, \xintKeep, \xintTrim, \xintNthOne from % $xinttoolsnameimp. % % But the whole expansion happens inside an \expanded context, so possibly % some gain could be achieved with x-expandable variants (xintexpr < 1.4 % had an \xintKeep:x:csv). % % I coded \xintApply:x and \xintApplyUnbraced:x in $xinttoolsnameimp, Brief % testing indicated they were perhaps a bit better for 5x5x5x5 and 15x15x15x15 % arrays of 8 digits numbers and for 30x30x15 with 16 digits numbers: say % 1$% gain... this seems to raise to between 4$% and % 5$% for 400x400 array of 1 digit... % % Currently sticking with old macros. %\end{lverb} % \begin{macrocode} \def\XINT_ListSel_deeper #1% {% \if :#1\xint_dothis\XINT_ListSel_slice_next\fi \xint_orthat {\XINT_ListSel_extract_next {#1}}% }% \def\XINT_ListSel_slice_next #1(% {% \xintApply{\XINT_ListSel_recurse{:#1}}% }% \def\XINT_ListSel_extract_next #1(% {% \xintApplyUnbraced{\XINT_ListSel_recurse{#1}}% }% \def\XINT_ListSel_recurse #1#2% {% \XINT_ListSel_check #2__#1({#2}\expandafter\empty\empty }% \def\XINT_ListSel_check{\expandafter\XINT_ListSel_check_a \string}% \def\XINT_ListSel_check_a #1% {% \if #1\bgroup\xint_dothis\XINT_ListSel_check_is_ok\fi \xint_orthat\XINT_ListSel_check_leaf }% \def\XINT_ListSel_check_leaf #1\expandafter{\expandafter}% \def\XINT_ListSel_check_is_ok {% \expandafter\XINT_ListSel_check_is_ok_a\expandafter{\string}% }% \def\XINT_ListSel_check_is_ok_a #1__#2% {% \if :#2\xint_dothis{\XINT_ListSel_slice}\fi \xint_orthat {\XINT_ListSel_nthone {#2}}% }% \def\XINT_ListSel_top #1#2% {% \if _\noexpand#2% \expandafter\XINT_ListSel_top_one_or_none\string#1.\else \expandafter\XINT_ListSel_top_at_least_two\fi }% \def\XINT_ListSel_top_at_least_two #1__{\XINT_ListSel_top_ople}% \def\XINT_ListSel_top_one_or_none #1% {% \if #1_\xint_dothis\XINT_ListSel_top_nil\fi \if #1.\xint_dothis\XINT_ListSel_top_nutple_a\fi \if #1\bgroup\xint_dothis\XINT_ListSel_top_nutple\fi \xint_orthat\XINT_ListSel_top_number }% \def\XINT_ListSel_top_nil #1\expandafter#2\expandafter{\fi\expandafter}% \def\XINT_ListSel_top_nutple {% \expandafter\XINT_ListSel_top_nutple_a\expandafter{\string}% }% \def\XINT_ListSel_top_nutple_a #1_#2#3(#4% {% \fi\if :#2\xint_dothis{{\XINT_ListSel_slice #3(#4}}\fi \xint_orthat {\XINT_ListSel_nthone {#2}#3(#4}% }% \def\XINT_ListSel_top_number #1_{\fi\XINT_ListSel_top_ople}% \def\XINT_ListSel_top_ople #1% {% \if :#1\xint_dothis\XINT_ListSel_slice\fi \xint_orthat {\XINT_ListSel_nthone {#1}}% }% \def\XINT_ListSel_slice #1% {% \expandafter\XINT_ListSel_slice_a \expandafter{\romannumeral0% \expandafter\CALX_fnum\romannumeral`&&@\xint_firstofone#1\xint:}% }% \def\XINT_ListSel_slice_a #1#2;#3#4% {% \if _#4\expandafter\XINT_ListSel_s_b \else\expandafter\XINT_ListSel_slice_b\fi #1;#3% }% \def\XINT_ListSel_s_b #1#2;#3#4% {% \if \expandafter\XINT_ListSel_s_last\fi \XINT_ListSel_s_c #1{#1#2}{#4}% }% \def\XINT_ListSel_s_last\XINT_ListSel_s_c #1#2#3(#4% {% \if-#1\expandafter\xintKeep\else\expandafter\xintTrim\fi {#2}{#4}% }% \def\XINT_ListSel_s_c #1#2#3(#4% {% \expandafter\XINT_ListSel_deeper \expanded{\xint_noxpd{#3}(\expandafter}\expandafter{% \romannumeral0% \if-#1\expandafter\xintkeep\else\expandafter\xinttrim\fi {#2}{#4}}% }% % \end{macrocode} %\begin{lverb} % % \xintNthElt from xinttools (knowingly) strips one level of % braces when fetching kth «item» from {v1}...{vN}. If we expand % {\xintNthElt{k}{{v1}...{vN}}} (notice external braces): % %( if k is out of range we end up with {} %: if k is in range and the kth braced item was {} we end up with {} %: if k is in range and the kth braced item was {17} we end up with {17} %) % % Problem is that individual numbers such as 17 are stored {{17}}. So % we must have one more brace pair and in the first two cases we end up % with {{}}. But in the first case we should end up with the empty ople % {}, not the empty bracketed ople {{}}. % % I have thus added \xintNthOne to $xinttoolsnameimp which does not % strip brace pair from an extracted item. % % Attention: \XINT_nthonepy_a does no expansion on second argument. % But here arguments are either numerical or already expanded. % Normally. % %\end{lverb} % \begin{macrocode} \def\XINT_ListSel_nthone #1#2% {% \if \expandafter\XINT_ListSel_nthone_last\fi \XINT_ListSel_nthone_a {#1}{#2}% }% \def\XINT_ListSel_nthone_a #1#2(#3% {% \expandafter\XINT_ListSel_deeper \expanded{\xint_noxpd{#2}(\expandafter}\expandafter{% \romannumeral0\expandafter\XINT_nthonepy_a\the\numexpr \calxListItemToNum{#1}.{#3}}% }% \def\XINT_ListSel_nthone_last\XINT_ListSel_nthone_a #1#2(%#3% {% \romannumeral0\expandafter\XINT_nthonepy_a\the\numexpr \calxListItemToNum{#1}.%{#3} }% % \end{macrocode} %\begin{lverb} % The macros here are basically f-expandable and use the % f-expandable \xintKeep and \xintTrim. Prior to xint 1.4, there was % here an x-expandable \xintKeep:x:csv dealing with comma separated % items, for time being we make do with our f-expandable toolkit. %\end{lverb} % \begin{macrocode} \def\XINT_ListSel_slice_b #1;#2_#3% {% \if \expandafter\XINT_ListSel_slice_last\fi \expandafter\XINT_ListSel_slice_c \expandafter{\romannumeral0% \expandafter\CALX_fnum\romannumeral`&&@\xint_firstofone#2\xint:};#1;{#3}% }% \def\XINT_ListSel_slice_last\expandafter\XINT_ListSel_slice_c #1;#2;#3(%#4 {% \expandafter\XINT_ListSel_slice_last_c #1;#2;%{#4} }% % \end{macrocode} % \changed{1.4n} % Compatibility with LuaMeta\TeX{} regarding |;| not usable as \cs{numexpr} % delimiter. Fortunately I had mostly used \cs{xint:} or a dot in the past % throughout the code base, so not many locations needed adjustments. Here I % simpy replaced all semi-colons by fullstops starting here with how % \csbXINT{_ListSel_slice_d} receives arguments. Fortuntely % \csbxint{_gob_til_sc} was not used around here. % \begin{macrocode} \def\XINT_ListSel_slice_last_c #1;#2;#3% {% \romannumeral0\XINT_ListSel_slice_d #2.#1.{#3}% }% \def\XINT_ListSel_slice_c #1;#2;#3(#4% {% \expandafter\XINT_ListSel_deeper \expanded{\xint_noxpd{#3}(\expandafter}\expandafter{% \romannumeral0\XINT_ListSel_slice_d #2.#1.{#4}}% }% \def\XINT_ListSel_slice_d #1#2.#3#4.% {% \xint_UDsignsfork #1#3\XINT_ListSel_N:N #1-\XINT_ListSel_N:P -#3\XINT_ListSel_P:N --\XINT_ListSel_P:P \krof #1#2.#3#4.% }% \def\XINT_ListSel_P:P #1.#2.#3% {% \unless\ifnum #1<#2 \expandafter\xint_gob_andstop_iii\fi \xintkeep{#2-#1}{\xintTrim{#1}{#3}}% }% \def\XINT_ListSel_N:N #1.#2.#3% {% \expandafter\XINT_ListSel_N:N_a \the\numexpr #2-#1\expandafter.\the\numexpr#1+\xintLength{#3}.{#3}% }% \def\XINT_ListSel_N:N_a #1.#2.#3% {% \unless\ifnum #1>\xint_c_ \expandafter\xint_gob_andstop_iii\fi \xintkeep{#1}{\xintTrim{\ifnum#2<\xint_c_\xint_c_\else#2\fi}{#3}}% }% \def\XINT_ListSel_N:P #1.#2.#3% {% \expandafter\XINT_ListSel_N:P_a \the\numexpr #1+\xintLength{#3}.#2.{#3}% }% \def\XINT_ListSel_N:P_a #1#2.% {\if -#1\expandafter\XINT_ListSel_O:P\fi\XINT_ListSel_P:P #1#2.}% \def\XINT_ListSel_O:P\XINT_ListSel_P:P #1.{\XINT_ListSel_P:P 0.}% \def\XINT_ListSel_P:N #1.#2.#3% {% \expandafter\XINT_ListSel_P:N_a \the\numexpr #2+\xintLength{#3}.#1.{#3}% }% \def\XINT_ListSel_P:N_a #1#2.#3.% {\if -#1\expandafter\XINT_ListSel_P:O\fi\XINT_ListSel_P:P #3.#1#2.}% \def\XINT_ListSel_P:O\XINT_ListSel_P:P #1.#2.{\XINT_ListSel_P:P #1.0.}% % \end{macrocode} % \subsection{Support for raw A/B[N]} %\begin{lverb} % Releases earlier than 1.1 required the use of braces around A/B[N] % input. The [N] is now implemented directly. *BUT* this uses a delimited macro! % thus N is not allowed to be itself an expression (I could add it...). % \xintE, \xintiiE, and \XINTinFloatE all put #2 in a \numexpr. But attention % to the fact that \numexpr stops at spaces separating digits: % \the\numexpr 3 + 7 9\relax gives 109\relax !! Hence we have to be % careful. % % \numexpr will not handle catcode 11 digits, but adding a \detokenize will % suddenly make illicit for N to rely on macro expansion. % % At 1.4, [ is already overloaded and it is not easy to support this. We do % this by a kludge maintaining more or less former (very not efficient) way % but using $$ sign which is free for time being. No, finally I use the null % character, should be safe enough! (I hesitated about using R with catcode % 12). % % As for ? operator we needed % to hack into \XINT_expr_getop_b for intercepting that pseudo operator. See % also \XINT_expr_scanint_c (\XINT_expr_rawxintfrac). % % calx: the precedence 14 of &&@ is not above the right precedence of ^ % (17): 2^3[1] is (2^3)[1]. The finisher operators &&B, &&C below use 22. % \xintiieval: raw [N] goes through \CALX_iilit (integer check, M or % raw), not \xintiiE. %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`& 11 }^^A % \begin{macrocode} \catcode0 11 \let\XINT_expr_precedence_&&@ \xint_c_xiv \def\CALX_iiE #1{\CALX_iiE_a #1[0]\xint:}% \def\CALX_iiE_a #1[#2]#3\xint:#4% {\expandafter\CALX_iiE_b\the\numexpr#2+#4.{#1}}% \def\CALX_iiE_b #1.#2{\CALX_iilit{#2}{#1}}% \def\CALX_rawE #1{\CALX_rawE_a #1[0]\xint:}% \def\CALX_rawE_a #1[#2]#3\xint:#4{\xint_noxpd{#1}[\the\numexpr#2+#4\relax]}% \def\XINT_iiexpr_op_&&@ #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\romannumeral0\CALX_iiE#1{\xint_zapspaces #2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_flexpr_op_&&@ #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\calxFpE#1{\xint_zapspaces #2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % calx: fake operator &&B (integer exits of the number scanner): % [0] appended in \xinteval and \xintfloateval; M in \xintiieval % (\CALX_mfromraw; raw in compiled functions, see % \XINT_expr_redefinemacros). %\end{lverb} % \begin{macrocode} \catcode2 11 \def\XINT_flexpr_op_&&B #1% {% \expandafter\XINT_expr_put_op_first \expanded{{{\xint_noxpd#1[0]}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def\XINT_iiexpr_op_&&B #1% {% \expandafter\XINT_expr_put_op_first \expanded{{{\romannumeral0\CALX_mfromraw#1}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \catcode2 12 % \end{macrocode} %\begin{lverb} % calx: fake operator &&C (decimal and exponent exits of the number % scanner): #2 is the exponent; [#2] appended (as 1.4p); \xintiieval: % \CALX_iilit (M if the value is an integer, else raw A[N]). Raw [N] % (&&@) in \xintiieval: same. In compiled functions and macros the three % \xintiieval operators keep the literal raw (\XINT_expr_redefinemacros). %\end{lverb} % \begin{macrocode} \catcode3 11 \def\XINT_flexpr_op_&&C #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\xint_noxpd#1[#2]}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def\XINT_iiexpr_op_&&C #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\romannumeral0\CALX_iilit#1{#2}}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \catcode3 12 \catcode0 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{? as two-way and ?? as three-way «short-circuit» conditionals} %\begin{lverb} % Comments undergoing reconstruction. %\end{lverb} % % \begin{macrocode} \let\XINT_expr_precedence_? \xint_c_xx \catcode`- 11 % \end{macrocode} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT_flexpr_op_?{\XINT_expr_op__? \XINT_flexpr_op_-xii}% \def\XINT_iiexpr_op_?{\XINT_expr_op__? \XINT_iiexpr_op_-xii}% \catcode`- 12 \def\XINT_expr_op__? #1#2#3% {\XINT_expr_op__?_a #3!\xint_bye\XINT_expr_exec_? {#1}{#2}{#3}}% \def\XINT_expr_op__?_a #1{\expandafter\XINT_expr_op__?_b\detokenize{#1}}% \def\XINT_expr_op__?_b #1% {\if ?#1\expandafter\XINT_expr_op__?_c\else\expandafter\xint_bye\fi }% \def\XINT_expr_op__?_c #1{\xint_gob_til_! #1\XINT_expr_op_?? !\xint_bye}% \def\XINT_expr_op_?? !\xint_bye\xint_bye\XINT_expr_exec_?{\XINT_expr_exec_??}% \catcode`- 11 \def\XINT_expr_exec_? #1#2% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\CALX_ifnz#2% }% \def\XINT_expr_exec_?? #1#2#3% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\CALX_ifsgn#2% }% \def\XINT_expr_check-_after? #1{% \def\XINT_expr_check-_after? ##1##2% {% \xint_UDsignfork ##2{##1}% #1{##2}% \krof }}\expandafter\XINT_expr_check-_after?\string -% \catcode`- 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{! as postfix factorial operator} % \begin{macrocode} \let\XINT_expr_precedence_! \xint_c_xx \def\XINT_flexpr_op_! #1% {% \expandafter\XINT_expr_put_op_first \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpFacdigits#1}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def\XINT_iiexpr_op_! #1% {% \expandafter\XINT_expr_put_op_first \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiFac#1}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % At 1.4g, fix for input "x! == y" via a fake operator !==. The ! % is of catcode 11 but this does not matter here. The definition of % \XINT_expr_itself_!== is required by the functioning of the scanop macros. % % We don't have to worry about "x! = y" as the single-character Boolean % comparison = operator has been removed from syntax. Fixing it would have % required obeying space tokens when parsing operators. For "x! == y" case, % obeying space tokens would not solve "x!==y" input case anyhow. %\end{lverb} % \begin{macrocode} \expandafter \def\csname XINT_expr_precedence_!==\expandafter\endcsname \csname XINT_expr_itself_!==\endcsname {\XINT_expr_precedence_! !==}% \expandafter\def\csname XINT_expr_itself_!==\endcsname{!==}% % \end{macrocode} % \subsection{User defined variables} % \localtableofcontents % % \subsubsection{\csh{xintdefiivar}, % \csh{xintdeffloatvar}} % \changed{1.1} % \changed[2017/12/01]{1.2p} Extends |\xintdefvar| et al.\@{} to accept % simultaneous assignments to multiple variables. % \changed[2018/06/17]{1.3c} % Use \csbxint{exprSafeCatcodes} (to palliate issue with % active semi-colon from Babel+French if in body of a \LaTeX{} document). % % And allow usage with both syntaxes |name:=expr;| or |name=expr;|. Also the % colon may have catcode 11, 12, or 13 with no issue. % Variable names may contain letters, digits, underscores, and must not start % with a digit. Names starting with |@| or an underscore are reserved. % % \begin{itemize}[nosep] % \item currently |@|, |@1|, |@2|, |@3|, and |@4| are reserved because they % have special meanings for use in iterations, % \item |@@|, |@@@|, |@@@@| are also reserved but % are technically functions, not variables: a user may possibly define |@@| as % a variable name, but if it is followed by parentheses, the function % interpretation will be applied (rather than the variable interpretation % followed by a tacit multiplication), % \item since |1.2l|, the underscore |_| may be used as separator of digits in % long numbers. % Hence a variable whose name starts with |_| will not play well with the % mechanism of tacit multiplication of variables by numbers: the underscore % will be removed from input stream by the number scanner, thus creating % an undefined or wrong variable name, or none at all if the variable % name was an initial |_| followed by digits. % \end{itemize} % %\begin{lverb} % Note that the optional argument [P] as usable with % \xintfloatexpr is **not** % supported by \xintdeffloatvar. One must do \xintdeffloatvar % foo = \xintfloatexpr[16] blabla \relax; to achieve the effect. %\end{lverb} % % \changed[2020/01/27]{1.4} % The expression will be fetched up to final semi-colon in a manner % allowing inner semi-colons as used in the iter(), rseq(), subsm(), % subsn() etc... syntax. They don't need to be hidden within a % braced pair anymore. % % \changed{1.4} % Automatic unpacking in case of simultaneous assignments if the expression % evaluates to a nutple. % % Notes (added much later on 2021/06/10 during preparation of |1.4i|): % \begin{enumerate} % \item the code did not try to intercept illicit syntax such as % |\xintdefvar a,b,c:=;|. It blindly «unpacked» the number handling it as if % it was a nutple. The extended functionality added at |1.4i| requires to % check for such a situation, as the syntax is not illicit anymore. % \item the code was broken in case the expression to evaluate was an ople of % length 10 or more, due to a silly mistake at some point during |1.4| % development which replaced some |\ifnum| by an |\if|, perhaps due to % mental confusion with the fact that functions can have at most 9 % arguments, but here the code is about defining variables. Anyway this got % fixed as corollary to the |1.4i| extension. % \end{enumerate} % % % \changed[2021/02/20]{1.4c} One year later I realized I had broken tacit % multiplication for situations such as |variable(1+2)|. As hinted at in % comments above before |1.4| release I had been doing some deep refactoring % here, which I cancelled almost completely in the end... but not quite, and % as a result there was a problem that some macro holding braced contents was % expanded to late, once it was in old core routines of xintfrac not expecting % other things than digits. I do an emergency bugfix here with some % |\expandafter|'s but I don't have the code in my brain at this time, and % don't have the luxury now to invest into it. Let's hope this does not induce % breakage elsewhere, and that the February 2020 |1.4| did not break something % else. % % \changed[2021/04/17]{1.4e} %\begin{lverb} % Modifies \xintdeffloatvar to round to the prevailing % precision (formerly, any operation would induce rounding, but in case of % things such as \xintdeffloatvar foo:=\xintexpr 1/100!\relax; there was no % automatic rounding. One could use 0+ syntax to trigger it, and for oples, % some trick like \xintfloatexpr[\XINTdigits]...\relax extra wrapper. %\end{lverb} % \changed[2021/05/22]{1.4g} %\begin{lverb} % The \expandafter\expandafter\expandafter et al. chain % which was kept by \XINT_expr_defvar_one_b for expanding only at time of use % the \XINT_expr_var_foo in \XINT_expr_onliteral_foo were senseless overhead % added at 1.4c. This is used only for real variables, not dummy variables or % fake variables and it is simpler to have the \XINT_expr_var_foo % pre-expanded. So let's use some \edef here. % % The \XINT_expr_onliteral_foo is expanded as result of action of \XINT_expr_op_` % (or \XINT_flexpr_op_`, \XINT_iiexpr_op_`) which itself was triggered consuming % already an \XINT_expr_put_op_first, so its expansion has to produce tokens % as expected after \XINT_expr_put_op_first$empty: % {expanded value}. %\end{lverb} % % \changed[2021/06/10]{1.4i} % Implement extended notion of simultaneous assignments: if there are more % variables than values, define the extra variables to be nil. If there are % less variables than values let the last variable % be defined as the ople concatenating all non reclaimed values. % % If there are at least two variables, the right hand side, if it turns out to % be a nutple, is (as since |1.4|) automatically unpacked, then the above % rules apply. % % \changed[2021/06/11]{1.4i} %\begin{lverb} % Fix the long-standing «seq renaming bug» via a change here of the % name of auxiliary macro. Previously «onliteral_» now % «var*_». I hesitated with using «var_varname*» rather. % % Hesitated adding \XINT_expr_letvar_one (motivation: case of simultaneous % assignments leading to defining «nil» variables). Finally, no. %\end{lverb} % % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`* 11 }^^A % \begin{macrocode} \catcode`* 11 \def\XINT_expr_defvar_one #1#2% {% \XINT_global \expandafter\edef\csname XINT_expr_varvalue_#1\endcsname {#2}% \XINT_expr_defvar_one_b {#1}% }% \def\XINT_expr_defvar_one_b #1% {% \XINT_global \expandafter\edef\csname XINT_expr_var_#1\endcsname {{\expandafter\noexpand\csname XINT_expr_varvalue_#1\endcsname}}% \XINT_global \expandafter\edef\csname XINT_expr_var*_#1\endcsname {\XINT_expr_prec_tacit *\csname XINT_expr_var_#1\endcsname(}% \ifxintverbose\xintMessage{xintexpr}{Info}% {Variable #1 \ifxintglobaldefs globally \fi defined with value \csname XINT_expr_varvalue_#1\endcsname.}% \fi }% \catcode`* 12 \catcode`~ 13 \catcode`: 12 \def\XINT_expr_defvar_getname #1:#2~% {% \endgroup \def\XINT_defvar_tmpa{#1}\edef\XINT_defvar_tmpc{\xintCSVLength{#1}}% }% \def\XINT_expr_defvar #1#2% {% \def\XINT_defvar_tmpa{#2}% \expandafter\XINT_expr_defvar_a\expanded{\xint_noxpd{{#1}}\expandafter}% \romannumeral\XINT_expr_fetch_to_semicolon }% \def\XINT_expr_defvar_a #1#2% {% \xintexprRestoreCatcodes % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % Maybe SafeCatcodes was without effect because the colon and the rest % are from some earlier macro definition. Give a safe definition to active % colon (even if in math mode with a math active colon..). % % The \XINT_expr_defvar_getname closes the group opened here. %\end{lverb} % \begin{macrocode} \begingroup\lccode`~`: \lowercase{\let~}\empty \edef\XINT_defvar_tmpa{\XINT_defvar_tmpa}% \edef\XINT_defvar_tmpa{\xint_zapspaces_o\XINT_defvar_tmpa}% \expandafter\XINT_expr_defvar_getname \detokenize\expandafter{\XINT_defvar_tmpa}:~% \ifcase\XINT_defvar_tmpc\space \xintMessage {xintexpr}{Error} {Aborting: not allowed to declare variable with empty name.}% \or \XINT_global \expandafter \edef\csname XINT_expr_varvalue_\XINT_defvar_tmpa\endcsname{#1#2\relax}% \XINT_expr_defvar_one_b\XINT_defvar_tmpa \else \edef\XINT_defvar_tmpb{#1#2\relax}% \edef\XINT_defvar_tmpd{\expandafter\xintLength\expandafter {\XINT_defvar_tmpb}}% \ifnum\XINT_defvar_tmpd=\xint_c_i \oodef\XINT_defvar_tmpb{\expandafter\xint_firstofone \XINT_defvar_tmpb}% \if0\expandafter\expandafter\expandafter\XINT_defvar_checkifnutple \expandafter\string\XINT_defvar_tmpb _\xint_bye \odef\XINT_defvar_tmpb{\expandafter{\XINT_defvar_tmpb}}% \else \edef\XINT_defvar_tmpd{\expandafter\xintLength \expandafter{\XINT_defvar_tmpb}}% \fi \fi \xintAssignArray\xintCSVtoList\XINT_defvar_tmpa\to\XINT_defvar_tmpvar \def\XINT_defvar_tmpe{1}% \expandafter\XINT_expr_defvar_multiple\XINT_defvar_tmpb\relax \fi }% \def\XINT_defvar_checkifnutple#1% {% \if#1_1\fi \if#1\bgroup1\fi 0\xint_bye }% \def\XINT_expr_defvar_multiple {% \ifnum\XINT_defvar_tmpe<\XINT_defvar_tmpc\space \expandafter\XINT_expr_defvar_multiple_one \else \expandafter\XINT_expr_defvar_multiple_last\expandafter\empty \fi }% \def\XINT_expr_defvar_multiple_one {% \ifnum\XINT_defvar_tmpe>\XINT_defvar_tmpd\space \expandafter\XINT_expr_defvar_one \csname XINT_defvar_tmpvar\XINT_defvar_tmpe\endcsname{}% \edef\XINT_defvar_tmpe{\the\numexpr\XINT_defvar_tmpe+1}% \expandafter\XINT_expr_defvar_multiple \else \expandafter\XINT_expr_defvar_multiple_one_a \fi }% \def\XINT_expr_defvar_multiple_one_a #1% {% \expandafter\XINT_expr_defvar_one \csname XINT_defvar_tmpvar\XINT_defvar_tmpe\endcsname{{#1}}% \edef\XINT_defvar_tmpe{\the\numexpr\XINT_defvar_tmpe+1}% \XINT_expr_defvar_multiple }% \def\XINT_expr_defvar_multiple_last #1\relax {% \expandafter\XINT_expr_defvar_one \csname XINT_defvar_tmpvar\XINT_defvar_tmpe\endcsname{#1}% \xintRelaxArray\XINT_defvar_tmpvar \let\XINT_defvar_tmpa\empty \let\XINT_defvar_tmpb\empty \let\XINT_defvar_tmpc\empty \let\XINT_defvar_tmpd\empty \let\XINT_defvar_tmpe\empty }% \catcode`~ 3 \catcode`: 11 % \end{macrocode} %\begin{lverb} % This SafeCatcodes is mainly in the hope that semi-colon ending the % expression can still be sanitized. % % Pre 1.4e definition: %(\def\xintdeffloatvar {\xintexprSafeCatcodes\xintdeffloatvar_a}% %:\def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintthebarefloateval{#1}}% %) % This would keep the value (or values) with extra digits, now. % If this is actually wanted one can use % \xintdefvar foo:=\xintfloatexpr...\relax; % syntax, but recalling that only operations trigger the rounding inside % \xintfloatexpr. Some tricks are needed for no operations case if multiple or % nested values. But for a single one, one can use simply the float() % function. % %\end{lverb} % \begin{macrocode} \def\xintdefiivar {\xintexprSafeCatcodes\xintdefiivar_a}% \def\xintdefiivar_a#1={\XINT_expr_defvar\xintthebareiieval{#1}}% \def\xintdeffloatvar {\xintexprSafeCatcodes\xintdeffloatvar_a}% \def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintthebareroundedfloateval{#1}}% % \end{macrocode} % \subsubsection{\csh{xintunassignvar}} % \changed{1.2e} % \changed{1.3d} % Embarrassingly I had for a long time a misunderstanding of |\ifcsname| % (let's blame its documentation) and I was not aware that it chooses FALSE % branch if tested control sequence has been |\let| to |\undefined|... So % earlier version didn't do the right thing (and had another bug: failure to % protect |\.=0| from expansion). % % The |\ifcsname| tests are done in \csbXINT{_expr_op__} and % \csbXINT{_expr_op_`}. % % \changed{1.4i} % Track |s/onliteral/var*/| change in macro names. % \begin{macrocode} \def\xintunassignvar #1{% \edef\XINT_unvar_tmpa{#1}% \edef\XINT_unvar_tmpa {\xint_zapspaces_o\XINT_unvar_tmpa}% \ifcsname XINT_expr_var_\XINT_unvar_tmpa\endcsname \ifnum\expandafter\xintLength\expandafter{\XINT_unvar_tmpa}=\@ne \expandafter\xintnewdummy\XINT_unvar_tmpa \else \XINT_global\expandafter \let\csname XINT_expr_varvalue_\XINT_unvar_tmpa\endcsname \XINT_undefined \XINT_global\expandafter \let\csname XINT_expr_var_\XINT_unvar_tmpa\endcsname \XINT_undefined \XINT_global\expandafter \let\csname XINT_expr_var*_\XINT_unvar_tmpa\endcsname \XINT_undefined \ifxintverbose\xintMessage {xintexpr}{Info}% {Variable \XINT_unvar_tmpa\space has been \ifxintglobaldefs globally \fi ``unassigned''.}% \fi \fi \else \xintMessage {xintexpr}{Warning} {Error: there was no such variable \XINT_unvar_tmpa\space to unassign.}% \fi }% % \end{macrocode} % \subsection{Support for dummy variables} % \localtableofcontents % \subsubsection{\csh{xintnewdummy}} %\begin{lverb} % Comments under reconstruction. % % 1.4 adds multi-letter names as usable dummy variables! %\end{lverb} % \changed[2021/06/11]{1.4i} %\begin{lverb} % s/onliteral/var*/ to fix the «seq renaming bug». %\end{lverb} % \begin{macrocode} \catcode`* 11 \def\XINT_expr_makedummy #1% {% \edef\XINT_tmpa{\xint_zapspaces #1 \xint_gobble_i}% \ifcsname XINT_expr_var_\XINT_tmpa\endcsname \XINT_global \expandafter\let\csname XINT_expr_var_\XINT_tmpa/old\expandafter\endcsname \csname XINT_expr_var_\XINT_tmpa\expandafter\endcsname \fi \ifcsname XINT_expr_var*_\XINT_tmpa\endcsname \XINT_global \expandafter\let\csname XINT_expr_var*_\XINT_tmpa/old\expandafter \endcsname\csname XINT_expr_var*_\XINT_tmpa\expandafter\endcsname \fi \expandafter\XINT_global \expanded {\edef\expandafter\noexpand \csname XINT_expr_var_\XINT_tmpa\endcsname ##1\relax !\XINT_tmpa##2}% {{##2}##1\relax !\XINT_tmpa{##2}}% \expandafter\XINT_global \expanded {\edef\expandafter\noexpand \csname XINT_expr_var*_\XINT_tmpa\endcsname ##1\relax !\XINT_tmpa##2}% {\XINT_expr_prec_tacit *{##2}(##1\relax !\XINT_tmpa{##2}}%) }% \xintApplyUnbraced \XINT_expr_makedummy {abcdefghijklmnopqrstuvwxyz}% \xintApplyUnbraced \XINT_expr_makedummy {ABCDEFGHIJKLMNOPQRSTUVWXYZ}% \def\xintnewdummy #1{% \XINT_expr_makedummy{#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% {\XINT_tmpa\space now \ifxintglobaldefs globally \fi usable as dummy variable.}% \fi }% \catcode`* 12 % \end{macrocode} % The |nil| variable was need in |xint < 1.4| (with some other meaning) % in places the syntax could not allow emptiness, such as |,,|, and % other things, but at |1.4| meaning as changed. % % The other variables are new with |1.4|. % Don't use the |None|, it is tentative, and may be input as |[]|. % % Refactored at |1.4i| to define them as really genuine variables, % i.e. also with associated |var*| macros involved in tacit multiplication % (even though it will be broken with |nil|, and with |None| in |\xintiiexpr|). % No real reason, because |\XINT_expr_op__| managed them fine even in absence % of |var*| macros. % \begin{macrocode} \XINT_expr_defvar_one{nil}{}% \XINT_expr_defvar_one{None}{{}}% ? tentative \XINT_expr_defvar_one{false}{{0}}% Maple, TeX \XINT_expr_defvar_one{true}{{1}}% \XINT_expr_defvar_one{False}{{0}}% Python \XINT_expr_defvar_one{True}{{1}}% \XINT_expr_defvar_one{NaN}{{I?}}% \XINT_expr_defvar_one{Infinity}{{I+}}% % \end{macrocode} % \subsubsection{\csh{xintensuredummy}, \csh{xintrestorevariable}} %\begin{lverb} % 1.3e \xintensuredummy differs from \xintnewdummy only in the informational message... % Attention that this is not meant to be nested. % % 1.4 fixes that the message mentioned non-existent \xintrestoredummy (real % name was \xintrestorelettervar and renames the latter to % \xintrestorevariable as it applies also to multi-letter names. %\end{lverb} % \begin{macrocode} \def\xintensuredummy #1{% \XINT_expr_makedummy{#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% {\XINT_tmpa\space now \ifxintglobaldefs globally \fi usable as dummy variable.&&J Issue \string\xintrestorevariable{\XINT_tmpa} to restore former meaning.}% \fi }% \def\xintrestorevariablesilently #1{% \edef\XINT_tmpa{\xint_zapspaces #1 \xint_gobble_i}% \ifcsname XINT_expr_var_\XINT_tmpa/old\endcsname \XINT_global \expandafter\let\csname XINT_expr_var_\XINT_tmpa\expandafter\endcsname \csname XINT_expr_var_\XINT_tmpa/old\expandafter\endcsname \fi \ifcsname XINT_expr_var*_\XINT_tmpa/old\endcsname \XINT_global \expandafter\let\csname XINT_expr_var*_\XINT_tmpa\expandafter\endcsname \csname XINT_expr_var*_\XINT_tmpa/old\expandafter\endcsname \fi }% \def\xintrestorevariable #1{% \xintrestorevariablesilently {#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% {\XINT_tmpa\space \ifxintglobaldefs globally \fi restored to its earlier status, if any.}% \fi }% % \end{macrocode} % \subsubsection{Checking (without expansion) that a symbolic expression % contains correctly nested parentheses} % %\begin{lverb} % Expands to \xint_c_mone in case a closing ) had no opening ( matching % it, to \@ne if opening ( had no closing ) matching it, to \z@ if expression % was balanced. Call it as: % % \XINT_isbalanced_a \relax #1(\xint_bye)\xint_bye % % This is legacy f-expandable code not using \expanded even at 1.4. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_a #1({\XINT_isbalanced_b #1)\xint_bye }% \def\XINT_isbalanced_b #1)#2% {\xint_bye #2\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error }% % \end{macrocode} %\begin{lverb} % if #2 is not \xint_bye, a ) was found, but there was no (. Hence error -> -1 %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_error #1)\xint_bye {\xint_c_mone}% % \end{macrocode} %\begin{lverb} % #2 was \xint_bye, was there a ) in original #1? %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error #1% {\xint_bye #1\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d #1}% % \end{macrocode} %\begin{lverb} % #1 is \xint_bye, there was never ( nor ) in original #1, hence OK. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d\xint_bye )\xint_bye {\xint_c_ }% % \end{macrocode} %\begin{lverb} % #1 is not \xint_bye, there was indeed a ( in original #1. We check if % we see a ). If we do, we then loop until no ( nor ) is to be found. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_d #1)#2% {\xint_bye #2\XINT_isbalanced_no\xint_bye\XINT_isbalanced_a #1#2}% % \end{macrocode} %\begin{lverb} % #2 was \xint_bye, we did not find a closing ) in original #1. Error. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_no\xint_bye #1\xint_bye\xint_bye {\xint_c_i }% % \end{macrocode} % \subsubsection{Fetching balanced expressions E1, E2 and a variable name Name from E1, Name=E2)} % % Multi-letter dummy variables added at |1.4|. % \begin{macrocode} \def\XINT_expr_fetch_E_comma_V_equal_E_a #1#2,% {% \ifcase\XINT_isbalanced_a \relax #1#2(\xint_bye)\xint_bye \expandafter\XINT_expr_fetch_E_comma_V_equal_E_c \or\expandafter\XINT_expr_fetch_E_comma_V_equal_E_b \else\expandafter\xintError:noopening \fi {#1#2},% }% \def\XINT_expr_fetch_E_comma_V_equal_E_b #1,% {\XINT_expr_fetch_E_comma_V_equal_E_a {#1,}}% \def\XINT_expr_fetch_E_comma_V_equal_E_c #1,#2#3=% {% \expandafter\XINT_expr_fetch_E_comma_V_equal_E_d\expandafter {\expanded{{\xint_zapspaces #2#3 \xint_gobble_i}}{#1}}{}% }% \def\XINT_expr_fetch_E_comma_V_equal_E_d #1#2#3)% {% \ifcase\XINT_isbalanced_a \relax #2#3(\xint_bye)\xint_bye \or\expandafter\XINT_expr_fetch_E_comma_V_equal_E_e \else\expandafter\xintError:noopening \fi {#1}{#2#3}% }% \def\XINT_expr_fetch_E_comma_V_equal_E_e #1#2% {\XINT_expr_fetch_E_comma_V_equal_E_d {#1}{#2)}}% % \end{macrocode} % \subsubsection{Fetching a balanced expression delimited by a semi-colon} % %\begin{lverb} % 1.4. For subsn() leaner syntax of nested substitutions. % % Will also serve to \xintdeffunc, to not have to hide inner semi-colons in % for example an iter() from \xintdeffunc. % % Adding brace removal protection for no serious reason, anyhow the xintexpr % parsers always removes braces when moving forward, but well. % % Trigger by \romannumeral\XINT_expr_fetch_to_semicolon upfront. %\end{lverb} % % \begin{macrocode} \def\XINT_expr_fetch_to_semicolon {\XINT_expr_fetch_to_semicolon_a {}\empty}% \def\XINT_expr_fetch_to_semicolon_a #1#2;% {% \ifcase\XINT_isbalanced_a \relax #1#2(\xint_bye)\xint_bye \xint_dothis{\expandafter\XINT_expr_fetch_to_semicolon_c}% \or\xint_dothis{\expandafter\XINT_expr_fetch_to_semicolon_b}% \else\expandafter\xintError:noopening \fi\xint_orthat{}\expandafter{#2}{#1}% }% \def\XINT_expr_fetch_to_semicolon_b #1#2% {\XINT_expr_fetch_to_semicolon_a {#2#1;}\empty}% \def\XINT_expr_fetch_to_semicolon_c #1#2{\xint_c_{#2#1}}% % \end{macrocode} % \subsubsection{Low-level support for omit and abort keywords, the break() % function, the n++ construct and the semi-colon as used in the syntax of % seq(), add(), mul(), iter(), rseq(), iterr(), rrseq(), subsm(), subsn(), ndseq(), % ndmap()} %\begin{lverb} % There is some clever play simply based on setting suitable precedence % levels combined with special meanings given to op macros. % % The special !? internal operator is a helper for omit and abort keywords in % list generators. % % Prior to 1.4 support for +[, *[, ..., ]+, ]*, had some elements here. %\end{lverb} % \paragraph{The n++ construct} %\begin{lverb} % 1.1 2014/10/29 did \expandafter\.=+\xintiCeil which transformed it into % \romannumeral0\xinticeil, which seems a bit weird. This exploited the fact % that dummy variables macros could back then pick braced material (which in the % case at hand here ended being {\romannumeral0\xinticeil...} and were submitted % to two expansions. The result of this was to provide a not value which got % expanded only in the first loop of the :_A and following macros of seq, % iter, rseq, etc... % % Anyhow with 1.2c I have changed the implementation of dummy variables which % now need to fetch a single locked token, which they do not expand. % % The \xintiCeil appears a bit dispendious, but I need the starting value in a % \numexpr compatible form in the iteration loops. %\end{lverb} % \begin{macrocode} \expandafter\def\csname XINT_expr_itself_++\endcsname {++}% \expandafter\def\csname XINT_expr_itself_++)\endcsname {++)}% \expandafter\let\csname XINT_expr_precedence_++)\endcsname \xint_c_i \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\def\csname XINT_#1_op_++)\endcsname ##1##2\relax {\expandafter\XINT_expr_foundend \expanded{{+{\XINT:NEhook:f:one:from:one:direct% \calxCeilToNum##1}}}% }% }% % \end{macrocode} % \paragraph{The \cshn{break()} function} %\begin{lverb} % break is a true function, the parsing via expansion of the enclosed % material proceeds via _oparen macros as with any other function. %\end{lverb} % \begin{macrocode} \catcode`? 3 \def\XINT_expr_func_break #1#2#3{#1#2{?#3}}% \catcode`? 11 \let\XINT_flexpr_func_break \XINT_expr_func_break \let\XINT_iiexpr_func_break \XINT_expr_func_break % \end{macrocode} % \paragraph{The \cshn{omit} and \cshn{abort} keywords} %\begin{lverb} % Comments are currently undergoing reconstruction. % % The mechanism is somewhat complex. The operator !? will fetch a dummy value % ! or ^ which is then recognized int the loops implementing the various seq % etc... construct using dummy variables and implement omit and abort. % % In May 2021 I realized that the January 2020 1.4 had broken omit and abort % if used inside a subs(). The definition %(\edef\XINT_expr_var_omit #1\relax !{1\string !?!\relax !}% %) % conflicted with the 1.4 refactoring of «subs» and similar things % which had replaced formerly clean-up macros (of ! and what's next, as in % now defunct % \def\XINT_expr_subx:_end #1!#2#3{#1} which was involved in subs mechanism, % and by the way would be incompatible with multi-letter dummy variables) by usage % of an \iffalse as in "\relax\iffalse\relax !" to delimite a sub-expression, which was % supposed to be clever (the "\relax !" being delimiter for dummy variables). % % This \iffalse from subs mechanism ended up being gobbled by omit/abort thus % inducing breakage. % % Grabbing \relax #2! would be a fix but looks a bit dangerous, as there can % be a subexpression after the omit or abort bringing its own \relax, although % this is very very unlikely. % % I considered to modify the dummy variables delimiter from \relax ! to % \xint_Bye ! for example but got afraid from the ramifications, as all % structures handling dummy variables would have needed refactoring. % % So finally things here remain unchanged and the refactoring to fix this % breakage was done in \XINT_allexpr_subsx (and also subsm). % Done at 1.4h. See \XINT_allexpr_subsx for comments. %\end{lverb} % % \begin{macrocode} \edef\XINT_expr_var_omit #1\relax !{1\string !?!\relax !}% \edef\XINT_expr_var_abort #1\relax !{1\string !?^\relax !}% \def\XINT_expr_itself_!? {!?}% \def\XINT_expr_op_!? #1#2\relax{\XINT_expr_foundend{#2}}% \let\XINT_iiexpr_op_!? \XINT_expr_op_!? \let\XINT_flexpr_op_!? \XINT_expr_op_!? \let\XINT_expr_precedence_!? \xint_c_iv % \end{macrocode} % \paragraph{The semi-colon} % %\begin{lverb} % Obsolete comments undergoing re-construction %\end{lverb} % % \begin{macrocode} \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\def\csname XINT_#1_op_;\endcsname {\xint_c_i ;}% }% \expandafter\let\csname XINT_expr_precedence_;\endcsname\xint_c_i \expandafter\def\csname XINT_expr_itself_;)\endcsname {)}% \expandafter\let\csname XINT_expr_precedence_;)\endcsname\xint_c_i % \end{macrocode} % \subsubsection{Reserved dummy variables @, @1, @2, @3, @4, @@, @@(1), \dots, @@@, % @@@(1), \dots{} for recursions} %\begin{lverb} % Comments currently under reconstruction. % % 1.4 breaking change: @ and @1 behave differently and one can not use @ in % place of @1 in iterr() and rrseq(). Formerly @ and @1 had the same % definition. % % Brace stripping in \XINT_expr_func_@@ % is prevented by some ending 0 or other token see iterr() and rrseq() code. % % For the record, the ~ and ? have catcode 3 in this code. % %\end{lverb} % % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`* 11 }^^A % \begin{macrocode} \catcode`* 11 \def\XINT_expr_var_@ #1~#2{{#2}#1~{#2}}% \def\XINT_expr_var*_@ #1~#2{\XINT_expr_prec_tacit *{#2}(#1~{#2}}% \expandafter \def\csname XINT_expr_var_@1\endcsname #1~#2{{{#2}}#1~{#2}}% \expandafter \def\csname XINT_expr_var_@2\endcsname #1~#2#3{{{#3}}#1~{#2}{#3}}% \expandafter \def\csname XINT_expr_var_@3\endcsname #1~#2#3#4{{{#4}}#1~{#2}{#3}{#4}}% \expandafter \def\csname XINT_expr_var_@4\endcsname #1~#2#3#4#5{{{#5}}#1~{#2}{#3}{#4}{#5}}% \expandafter\def\csname XINT_expr_var*_@1\endcsname #1~#2% {\XINT_expr_prec_tacit *{{#2}}(#1~{#2}}% \expandafter\def\csname XINT_expr_var*_@2\endcsname #1~#2#3% {\XINT_expr_prec_tacit *{{#3}}(#1~{#2}{#3}}% \expandafter\def\csname XINT_expr_var*_@3\endcsname #1~#2#3#4% {\XINT_expr_prec_tacit *{{#4}}(#1~{#2}{#3}{#4}}% \expandafter\def\csname XINT_expr_var*_@4\endcsname #1~#2#3#4#5% {\XINT_expr_prec_tacit *{{#5}}(#1~{#2}{#3}{#4}{#5}}% \catcode`* 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters\FixInterMacrocodeVspace % \begin{macrocode} \catcode`? 3 \def\XINT_expr_func_@@ #1#2#3#4~#5?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\calxListItemToNum#3}{#5}}}#4~#5?% }% \def\XINT_expr_func_@@@ #1#2#3#4~#5~#6?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\calxListItemToNum#3}{#6}}}% #4~#5~#6?% }% \def\XINT_expr_func_@@@@ #1#2#3#4~#5~#6~#7?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\calxListItemToNum#3}{#7}}}% #4~#5~#6~#7?% }% \let\XINT_flexpr_func_@@\XINT_expr_func_@@ \let\XINT_flexpr_func_@@@\XINT_expr_func_@@@ \let\XINT_flexpr_func_@@@@\XINT_expr_func_@@@@ \def\XINT_iiexpr_func_@@ #1#2#3#4~#5?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\CALX_mr#3}{#5}}}#4~#5?% }% \def\XINT_iiexpr_func_@@@ #1#2#3#4~#5~#6?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\CALX_mr#3}{#6}}}#4~#5~#6?% }% \def\XINT_iiexpr_func_@@@@ #1#2#3#4~#5~#6~#7?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\CALX_mr#3}{#7}}}#4~#5~#6~#7?% }% \catcode`? 11 % \end{macrocode} % \subsection{Pseudo-functions involving dummy variables and generating scalars or sequences} % \localtableofcontents % % \subsubsection{Comments} %\begin{lverb} % Comments added 2020/01/16. % % The mechanism for «seq» is the following. When the parser encounters «seq», % which means it parsed these letters and encountered (from expansion) an % opening parenthesis, the \XINT_expr_func mechanism triggers the «`» operator % which realizes that «seq» is a pseudo-function (there is no _func_seq) and % thus spans the \XINT_expr_onliteral_seq macro (currently this means however % that the knowledge of which parser we are in is lost, see comments of % \XINT_expr_op_` code). The latter will use delimited macros and parenthesis % check to fetch (without any expansion), the symbolic expression ExprSeq to % evaluate, the Name (now possibly multi-letter) of the variable and the % expression ExprValues to evaluate which will give the values to assign to % the dummy variable Name. It then positions upstream ExprValues suitably % terminated (see next) and after it {{Name}{ExprSeq}}. Then it inserts a % second call to the «`» operator with now «seqx» as argument hence % the appropriate «{,fl,ii}expr_func_seqx» macros gets executed. The general % way function macros work is that first all their arguments are evaluated via % a call not to \xintbare{,float,ii}eval but to the suitable % \XINT_{expr,flexpr,iiexpr}_oparen core macro which does almost same excepts % it expects a final closing parenthesis (of course allowing nested % parenthesis in-between) and stops there. Here, this closing parenthesis got positioned % deliberately with a \relax after it, so the parser, which always after % having gathered a value looks ahead to find the next operator, thinks it has % hit the end of the expression and as result inserts a \xint_c_ (i.e. \z@) % token for precedence level and a dummy \relax token (place-holder for a % non-existing operator). Generally speaking «func_foo» macros expect to % be executed with three parameters #1#2#3, #1 = precedence, #2 = operator, #3 % = values (call it «args») i.e. the fully evaluated list of all its % arguments. The special «func_seqx» and cousins know that the first two % tokens are trash and they now proceed forward, having thus lying before them % upstream the values to loop over, now fully evaluated, and % {{Name}{ExprSeq}}. It then positions appropriately ExprSeq inside a % sub-expression and after it, following suitable delimiter, Name and the % evaluated values to assign to Name. % % Dummy variables are essentially simply delimited macros where the delimiter % is the variable name preceded by a \relax token and a catcode 11 exclamation % point. Thus the various «subsx», «seqx», «iterx» position the tokens % appropriately and launch suitable loops. % % All of this nests well, inner «seq»'s (or more often in practice «subs»'s) % being allowed to refer to the dummy variables used by outer «seq»'s because % the outer «seq»'s have the values to assign to their variables evaluated % first and their ExprSeq evaluated last. For inner dummy variables to be able % to refer to outer dummy variables the author must be careful of course to % not use in the implementation braces { and } which would break dummy % variables to fetch values beyond the closing brace. % % The above «seq» mechanism was done around June 15-25th 2014 at the time of % the transition from 1.09n to 1.1 but already in October 2014 I made a note % that I had a hard time to understand it again: % % « [START OF YEAR 2014 COMMENTS] % % All of seq, add, mul, rseq, etc... (actually all of the extensive % changes from xintexpr 1.09n to 1.1) was done around June 15-25th 2014, but the % problem is that I did not document the code enough, and I had a hard time % understanding in October what I had done in June. Despite the lesson, again % being short on time, I do not document enough my current understanding of the % innards of the beast... % % I added subs, and iter in October (also the [:n], [n:] list extractors), % proving I did at least understand a bit (or rather could imitate) my earlier % code (but don't ask me to explain \xintNewExpr !) % % The \XINT_expr_fetch_E_comma_V_equal_E_a parses: "expression, variable=list)" % (when it is called the opening ( has been swallowed, and it looks for % the ending one.) Both expression and list may themselves contain % parentheses and commas, we allow nesting. For example "x^2,x=1..10)", % at the end of seq_a we have {variable{expression}}{list}, in this % example {x{x^2}}{1..10}, or more complicated % "seq(add(y,y=1..x),x=1..10)" will work too. The variable is a single % lowercase Latin letter. % % The complications with \xint_c_ii^v in seq_f is for the recurrent % thing that we don't know in what type of expressions we are, hence we % must move back up, with some loss of efficiency (superfluous check for % minus sign, etc...). But the code manages simultaneously expr, flexpr % and iiexpr. % % [END OF YEAR 2014 OLD COMMENTS]» % % On Jeudi 16 janvier 2020 à 15:13:32 I finally did the documentation as % above. % % The case of «iter», «rseq», «iterr», «rrseq» differs slightly because the % initial values need evaluation. This is done by genuine functions % \XINT__func_iter etc... (there was no \XINT__func_seq). The % trick is via the semi-colon ; which is a genuine operator having the % precedence of a closing parenthesis and whose action is only to stop % expansion. Thus this first step of gathering the initial values is done as % part of the reguler expansion job of the parser not using delimited macros % and the ; can be hidden in braces {;} because the three parsers when moving % forward remove one level of braces always. Thus % \XINT__func_seq simply hand over to \XINT_allexpr_iter which will % then trigger the fetching without expansion of ExprIter, Name=ExprValues as % described previously for «seq». % % With 1.4, multi-letter names for dummy variables are allowed. % % Also there is the additional 1.4 ambition to make the whole thing parsable % by \xintNewExpr/\xintdeffunc. This is done by checking if all is numerical, % because the omit, abort and break() mechanisms have no translation into % macros, and the only solution for symbolic material is to simply keep it as % is, so that expansion will again activate the xintexpr parsers. At 1.4 this % approach is fine although the initial goals of \xintNewExpr/\xintdeffunc was % to completely replace the parsers (whose storage method hit the string pool % formerly) by macros. Now that 1.4 does not impact the string pool we can % make \xintdeffunc much more powerful but it will not be a construct using % only xintfrac macros, it will still be partially the \xintexpr etc... % parsers in such cases. %\end{lverb} % %\begin{lverb} % Got simpler with 1.2c as now the dummy variable fetches an % already encapsulated value, which is anyhow the form in which we get % it. % % Refactored at 1.4 using \expanded rather than \csname. % % And support for multi-letter variables, which means function declarations % can now use multi-letter variables ! %\end{lverb} % % \changed{2.0a1} % Per parser "onliteral" macros for matters UNRELATED with subs() et al. % Here defining the \csbxint{eval} interface. The needed |\let| done below. % % % \subsubsection{\cshn{subs()}: substitution of one variable} % \begin{macrocode} \def\XINT_expr_onliteral_subs {% \expandafter\XINT_allexpr_subs_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_subs_f #1#2{\xint_c_ii^v `{subsx}#2)\relax #1}% \def\XINT_expr_func_subsx #1#2{\XINT_allexpr_subsx \xintbareeval }% \def\XINT_flexpr_func_subsx #1#2{\XINT_allexpr_subsx \xintbarefloateval}% \def\XINT_iiexpr_func_subsx #1#2{\XINT_allexpr_subsx \xintbareiieval }% % \end{macrocode} %\begin{lverb} % #2 is the value to assign to the dummy variable % #3 is the dummy variable name (possibly multi-letter), #4 is the expression % to evaluate % % 1.4 was doing something clever to get rid of the ! and tokens following it, % via an \iffalse...\fi which erased them and propagated the expansion to % trigger the getopt: % %(\expanded\bgroup\romannumeral0#1#4\relax \iffalse\relax !#3{#2}{\fi\expandafter} %) % % But sadly, with a delay of more than one year later (right after having % released 1.4g) I realized that this had broken omit and abort if inside a % subs. As omit and abort would clean all up to \relax !, this meant here % swallowing in particular the above \iffalse, leaving a dangling \fi. I had % the files which show this bug already at time of 1.4 release but did not % compile them, and they were not included in my test suite. % % I hesitated with modifying the delimiter from "\relax !" (catcode % 11 !) to "\relax \xint_Bye" for the dummy variables which would % have allowed some trickery using \xint_Bye...\xint_bye clean-up but got % afraid from the breakage potential of such refactoring with many induced % changes. % % A variant like this: %( \def\XINT_allexpr_subsx #1#2#3#4% %: {% %: \expandafter\XINT_expr_clean_and_put_op_first %: \expanded %: {\romannumeral0#1#4\relax !#3{#2}\xint:\expandafter}\romannumeral`$&$&\XINT_expr_getop %: }% %: \def\XINT_expr_clean_and_put_op_first #1#2\xint:#3#4{#3#4{#1}}% %) % breaks nesting: the braces make variables encountered in #4 unable to % match their definition. This would work: % %( \def\XINT_allexpr_subsx #1#2#3#4% %: {% %: \expandafter\XINT_allexpr_subsx_clean\romannumeral0#1#4\relax !#3{#2}\xint: %: }% %: \def\XINT_allexpr_subsx_clean #1#2\xint: %: {% %: \expandafter\XINT_expr_put_op_first %: \expanded{\xint_noxpd{{#1}}\expandafter}\romannumeral`$&$&@\XINT_expr_getop %: }% %) % (not tested). % % But in the end I decided to simply fix the first envisioned code above. % This accepts expansion of supposedly inert #3{#2}. There is again the % \iffalse but it is moved to the right. This change limits possibly hacky % future developments. Done at 1.4h (2021/01/27). % % No need for the \expandafter's from \XINT_expr_put_op_first in % \XINT_expr_clean_and_put_op_first. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsx #1#2#3#4% {% \expandafter\XINT_expr_clean_and_put_op_first \expanded \bgroup\romannumeral0#1#4\relax !#3{#2}\xint:\iffalse{\fi\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def\XINT_expr_clean_and_put_op_first #1#2\xint:#3#4{#3#4{#1}}% % \end{macrocode} % \subsubsection{\cshn{subsm()}: simultaneous independent substitutions} %\begin{lverb} % New with 1.4. Globally the var1=expr1; var2=expr2; var2=expr3;... % part can arise from expansion, except that once a semi-colon has been found % (from expansion) the varK= thing following it must be there. And as for % subs() the final parenthesis must be there from the start. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_subsm {% \expandafter\XINT_allexpr_subsm_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_subsm_f #1#2{\xint_c_ii^v `{subsmx}#2)\relax #1}% \def\XINT_expr_func_subsmx {% \expandafter\XINT_allexpr_subsmx\expandafter\xintbareeval \expanded\bgroup{\iffalse}\fi\XINT_allexpr_subsm_A\XINT_expr_oparen }% \def\XINT_flexpr_func_subsmx {% \expandafter\XINT_allexpr_subsmx\expandafter\xintbarefloateval \expanded\bgroup{\iffalse}\fi\XINT_allexpr_subsm_A\XINT_flexpr_oparen }% \def\XINT_iiexpr_func_subsmx {% \expandafter\XINT_allexpr_subsmx\expandafter\xintbareiieval \expanded\bgroup{\iffalse}\fi\XINT_allexpr_subsm_A\XINT_iiexpr_oparen }% \def\XINT_allexpr_subsm_A #1#2#3% {% \ifx#2\xint_c_ \expandafter\XINT_allexpr_subsm_done \else \expandafter\XINT_allexpr_subsm_B \fi #1% }% \def\XINT_allexpr_subsm_B #1#2#3#4=% {% {#2}\relax !\xint_zapspaces#3#4 \xint_gobble_i \expandafter\XINT_allexpr_subsm_A\expandafter#1\romannumeral`&&@#1% }% % \end{macrocode} %\begin{lverb} %( #1 = \xintbareeval, or \xintbarefloateval or \xintbareiieval %: #2 = evaluation of last variable assignment %) %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsm_done #1#2{{#2}\iffalse{{\fi}}}% % \end{macrocode} %\begin{lverb} %( #1 = \xintbareeval or \xintbarefloateval or \xintbareiieval %: #2 = {value1}\relax !var2{value2}....\relax !varN{valueN} (value's may be oples) %: #3 = {var1} %: #4 = the expression to evaluate %) % Refactored at 1.4h as for \XINT_allexpr_subsx, see comments there related % to the omit/abort conundrum. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsmx #1#2#3#4% {% \expandafter\XINT_expr_clean_and_put_op_first \expanded \bgroup\romannumeral0#1#4\relax !#3#2\xint:\iffalse{\fi\expandafter}% \romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} % \subsubsection{\cshn{subsn()}: leaner syntax for nesting (possibly dependent) substitutions} %\begin{lverb} % New with 1.4. 2020/01/24 % %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_subsn {% \expandafter\XINT_allexpr_subsn_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_subsn_f #1{\XINT_allexpr_subsn_g #1}% % \end{macrocode} %\begin{lverb} %( #1 = Name1 %: #2 = Expression in all variables which is to evaluate %: #3 = all the stuff after Name1 = and up to final parenthesis %) % % This one needed no reactoring at 1.4h to fix the omit/abort problem, as % there was no \iffalse..\fi clean-up: the clean-up is done directly via % \XINT_allexpr_subsnx_J. % % I only added usage of \XINT_expr_put_op_first_noexpand. There may be other % locations where it could be used, but I can't afford now reviewing % usage. For next release after 1.4h bugfix. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsn_g #1#2#3% {% \expandafter\XINT_allexpr_subsn_h \expanded\bgroup{\iffalse}\fi\expandafter\XINT_allexpr_subsn_B \romannumeral\XINT_expr_fetch_to_semicolon #1=#3;\hbox=;;^{#2}% }% \def\XINT_allexpr_subsn_B #1{\XINT_allexpr_subsn_C #1\vbox}% \def\XINT_allexpr_subsn_C #1#2=#3\vbox {% \ifx\hbox#1\iffalse{{\fi}\expandafter}\else {{\xint_zapspaces #1#2 \xint_gobble_i}};\xint_noxpd{{{#3}}}% \expandafter\XINT_allexpr_subsn_B \romannumeral\expandafter\XINT_expr_fetch_to_semicolon\fi }% % \end{macrocode} % \changed{1.4p} % % I used here formerly |\xintundefined| as a delimiter token, perhaps also % initially as debugging helper in case expansion went beyond the expected, % but elsewhere in the code base there is |\XINT_undefined|, but both feel % inappopriate. The problem attow is that I wrote the code many years ago and % I can not be fully certain using |\xint:| may not cause a problem in case % this delimiter could appear earlier, but I think not, so let's go for % |\xint:|. % % \begin{macrocode} \def\XINT_allexpr_subsn_h {% \xint_c_ii^v `{subsnx}\romannumeral0\xintreverseorder }% \def\XINT_expr_func_subsnx #1#2#3#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_H ^% \expandafter\XINT_allexpr_subsnx\expandafter \xintbareeval\romannumeral0\xintbareeval #5\relax !#4{#3}\xint: {\relax !#4{#3}\relax !#6}% }% \def\XINT_iiexpr_func_subsnx #1#2#3#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_H ^% \expandafter\XINT_allexpr_subsnx\expandafter \xintbareiieval\romannumeral0\xintbareiieval #5\relax !#4{#3}\xint: {\relax !#4{#3}\relax !#6}% }% \def\XINT_flexpr_func_subsnx #1#2#3#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_H ^% \expandafter\XINT_allexpr_subsnx\expandafter \xintbarefloateval\romannumeral0\xintbarefloateval #5\relax !#4{#3}\xint: {\relax !#4{#3}\relax !#6}% }% \def\XINT_allexpr_subsnx #1#2!#3\xint:#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_I ^% \expandafter\XINT_allexpr_subsnx\expandafter #1\romannumeral0#1#5\relax !#4{#2}\xint: {\relax !#4{#2}\relax !#6}% }% \def\XINT_allexpr_subsnx_H ^#1\romannumeral0#2#3!#4\xint:#5#6% {% \expandafter\XINT_allexpr_subsnx_J\romannumeral0#2#6#5% }% \def\XINT_allexpr_subsnx_I ^#1\romannumeral0#2#3\xint:#4#5% {% \expandafter\XINT_allexpr_subsnx_J\romannumeral0#2#5#4% }% \def\XINT_allexpr_subsnx_J #1#2^% {% \expandafter\XINT_expr_put_op_first_noexpand \expanded{\xint_noxpd{{#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_expr_put_op_first_noexpand#1#2#3{#2#3{#1}}% % \end{macrocode} % \subsubsection{\cshn{seq()}: sequences from assigning values to a % dummy variable} %\begin{lverb} % In seq_f, the #2 is the ExprValues expression which needs evaluation to % provide the values to the dummy variable and #1 is {Name}{ExprSeq} % where Name is the name of dummy variable and {ExprSeq} the expression % which will have to be evaluated. %\end{lverb} % % % \begin{macrocode} \def\XINT_allexpr_seq_f #1#2{\xint_c_ii^v `{seqx}#2)\relax #1}% \def\XINT_expr_onliteral_seq {\expandafter\XINT_allexpr_seq_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}}% \def\XINT_expr_func_seqx #1#2% {\XINT:NEhook:seqx\XINT_allexpr_seqx\xintbareeval }% \def\XINT_flexpr_func_seqx #1#2% {\XINT:NEhook:seqx\XINT_allexpr_seqx\xintbarefloateval}% \def\XINT_iiexpr_func_seqx #1#2% {\XINT:NEhook:seqx\XINT_allexpr_seqx\xintbareiieval }% \def\XINT_allexpr_seqx #1#2#3#4% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi\XINT_expr_seq:_b {#1#4\relax !#3}#2^% \XINT_expr_cb_and_getop }% \def\XINT_expr_cb_and_getop{\iffalse{\fi\expandafter}% \romannumeral`&&@\XINT_expr_getop}% % \end{macrocode} % %\begin{lverb} % Comments undergoing reconstruction. %\end{lverb} % \begin{macrocode} \catcode`? 3 \def\XINT_expr_seq:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_seq:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_seq:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_seq:_end\fi \xint_orthat{\XINT_expr_seq:_c}{#2}{#1}% }% \def\XINT_expr_seq:_noop #1{\XINT_expr_seq:_b }% \def\XINT_expr_seq:_end #1#2{\iffalse{\fi}}% \def\XINT_expr_seq:_c #1#2% {\expandafter\XINT_expr_seq:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_seq:_d #1{\ifx ^#1\xint_dothis\XINT_expr_seq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_seq:_break\fi \ifx !#1\xint_dothis\XINT_expr_seq:_omit\fi \xint_orthat{\XINT_expr_seq:_goon {#1}}}% \def\XINT_expr_seq:_abort #1!#2^{\iffalse{\fi}}% \def\XINT_expr_seq:_break #1!#2^{#1\iffalse{\fi}}% \def\XINT_expr_seq:_omit #1!#2#{\expandafter\XINT_expr_seq:_b\xint_gobble_i}% \def\XINT_expr_seq:_goon #1!#2#% {#1\expandafter\XINT_expr_seq:_b\xint_gobble_i}% \def\XINT_expr_seq:_Ca #1#2#3{\XINT_expr_seq:_Cc#3.{#2}}% \def\XINT_expr_seq:_Cb #1% {\expandafter\XINT_expr_seq:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_seq:_Cc #1.#2% {\expandafter\XINT_expr_seq:_D\romannumeral0#2{{#1[0]}}{#1}{#2}}% \def\XINT_expr_seq:_D #1{\ifx ^#1\xint_dothis\XINT_expr_seq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_seq:_break\fi \ifx !#1\xint_dothis\XINT_expr_seq:_Omit\fi \xint_orthat{\XINT_expr_seq:_Goon {#1}}}% \def\XINT_expr_seq:_Omit #1!#2#{\expandafter\XINT_expr_seq:_Cb\xint_gobble_i}% \def\XINT_expr_seq:_Goon #1!#2#{#1\expandafter\XINT_expr_seq:_Cb\xint_gobble_i}% % \end{macrocode} % \subsubsection{\cshn{iter()}} % %\begin{lverb} % Prior to 1.2g, the iter keyword was what is now called iterr, % analogous with rrseq. Somehow I forgot an iter functioning like rseq % with the sole difference of printing only the last iteration. Both rseq and % iter work well with list selectors, as @ refers to the whole comma separated % sequence of the initial values. I have thus deliberately done the backwards % incompatible renaming of iter to iterr, and the new iter. % % To understand the tokens which are presented to \XINT_allexpr_iter it is % needed to check elsewhere in the source code how the ; hack is done. % % The #2 in \XINT_allexpr_iter is \xint_c_i from the ; hack. Formerly (xint < % 1.4) there was no such token. The change is motivated to using ; also in % subsm() syntax. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_iter {\XINT_allexpr_iter \xintbareeval }% \def\XINT_flexpr_func_iter {\XINT_allexpr_iter \xintbarefloateval }% \def\XINT_iiexpr_func_iter {\XINT_allexpr_iter \xintbareiieval }% \def\XINT_allexpr_iter #1#2#3#4% {% \expandafter\XINT_expr_iterx \expandafter#1\expanded{\xint_noxpd{{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_iterx #1#2#3#4% {% \XINT:NEhook:iter\XINT_expr_itery\romannumeral0#1(#4)\relax {#2}#3#1% }% \def\XINT_expr_itery #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi \XINT_expr_iter:_b {#5#4\relax !#3}#1^~{#2}\XINT_expr_cb_and_getop }% \def\XINT_expr_iter:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_iter:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_iter:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_iter:_end\fi \xint_orthat{\XINT_expr_iter:_c}{#2}{#1}% }% \def\XINT_expr_iter:_noop #1{\XINT_expr_iter:_b }% \def\XINT_expr_iter:_end #1#2~#3{#3\iffalse{\fi}}% \def\XINT_expr_iter:_c #1#2% {\expandafter\XINT_expr_iter:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_iter:_d #1{\ifx ^#1\xint_dothis\XINT_expr_iter:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iter:_break\fi \ifx !#1\xint_dothis\XINT_expr_iter:_omit\fi \xint_orthat{\XINT_expr_iter:_goon {#1}}}% \def\XINT_expr_iter:_abort #1!#2^~#3{#3\iffalse{\fi}}% \def\XINT_expr_iter:_break #1!#2^~#3{#1\iffalse{\fi}}% \def\XINT_expr_iter:_omit #1!#2#{% \expandafter\XINT_expr_iter:_b\xint_gobble_i }% \def\XINT_expr_iter:_goon #1!#2#{\XINT_expr_iter:_goon_a {#1}}% \def\XINT_expr_iter:_goon_a #1#2#3~#4{\XINT_expr_iter:_b #3~{#1}}% \def\XINT_expr_iter:_Ca #1#2#3{\XINT_expr_iter:_Cc#3.{#2}}% \def\XINT_expr_iter:_Cb #1% {\expandafter\XINT_expr_iter:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_iter:_Cc #1.#2% {\expandafter\XINT_expr_iter:_D\romannumeral0#2{{#1[0]}}{#1}{#2}}% \def\XINT_expr_iter:_D #1{\ifx ^#1\xint_dothis\XINT_expr_iter:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iter:_break\fi \ifx !#1\xint_dothis\XINT_expr_iter:_Omit\fi \xint_orthat{\XINT_expr_iter:_Goon {#1}}}% \def\XINT_expr_iter:_Omit #1!#2#{% \expandafter\XINT_expr_iter:_Cb\xint_gobble_i }% \def\XINT_expr_iter:_Goon #1!#2#{\XINT_expr_iter:_Goon_a {#1}}% \def\XINT_expr_iter:_Goon_a #1#2#3~#4{\XINT_expr_iter:_Cb #3~{#1}}% % \end{macrocode} % \subsubsection{\cshn{add()}, \cshn{mul()}} %\begin{lverb} % Comments under reconstruction. % % These were a bit anomalous as they did not implement omit and abort keyword % and the break() function (and per force then neither the n++ syntax). % % At 1.4 they are simply mapped to using adequately % iter(). Thus, there is small loss in efficiency, but supporting omit, abort % and break is important. Using dedicated macros here would have caused also % slight efficiency drop. Simpler to remove the old approach. %\end{lverb} % % \begin{macrocode} \def\XINT_expr_onliteral_add {\expandafter\XINT_allexpr_add_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}}% \def\XINT_allexpr_add_f #1#2{\xint_c_ii^v `{opx}#2)\relax #1{+}{0[0]}}% \def\XINT_expr_onliteral_mul {\expandafter\XINT_allexpr_mul_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}}% \def\XINT_allexpr_mul_f #1#2{\xint_c_ii^v `{opx}#2)\relax #1{*}{1[0]}}% \def\XINT_expr_func_opx {\XINT:NEhook:opx \XINT_allexpr_opx \xintbareeval }% \def\XINT_flexpr_func_opx {\XINT:NEhook:opx \XINT_allexpr_opx \xintbarefloateval}% \def\XINT_iiexpr_func_opx {\XINT:NEhook:opx \XINT_allexpr_opx \xintbareiieval }% % \end{macrocode} %\begin{lverb} % 1.4a In case of usage of omit (did I not test it? obviously % I didn't as neither omit nor abort could work; and break neither), % 1.4 code using (#6) syntax caused a % (somewhat misleading) «missing )» error message which originated in the % #6. This is non-obvious problem (perhaps explained why prior to 1.4 I had % not added support for omit and break() to add() and mul()... % % Allowing () is not enough as it would have to be 0 or 1 depending on % whether we are using add() or mul(). Hence the somewhat complicated % detour (relying on precise way var_omit and var_abort work) via % \XINT_allexpr_opx_ifnotomitted. % % \break() has special meaning here as it is used as last operand, not as last % value. The code is very unsatisfactory and inefficient but this is hotfix % for 1.4a. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_opx #1#2#3#4#5#6#7#8% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi \XINT_expr_iter:_b {#1% \expandafter\XINT_allexpr_opx_ifnotomitted \romannumeral0#1#6\relax#7@\relax !#5}#4^~{{#8}}\XINT_expr_cb_and_getop }% \def\XINT_allexpr_opx_ifnotomitted #1% {% \ifx !#1\xint_dothis{@\relax}\fi \ifx ^#1\xint_dothis{\XINTfstop. ^\relax}\fi \if ?\xintFirstItem{#1}\xint_dothis{\XINT_allexpr_opx_break{#1}}\fi \xint_orthat{\XINTfstop.{#1}}% }% \def\XINT_allexpr_opx_break #1#2\relax {% break% (\expandafter\XINTfstop\expandafter.\expandafter{\xint_gobble_i#1}#2)\relax }% % \end{macrocode} % \subsubsection{\cshn{rseq()}} % %\begin{lverb} % When func_rseq has its turn, initial segment has been scanned by % oparen, the ; mimicking the rôle of a closing parenthesis, and stopping % further expansion (and leaving a \xint_c_i left-over token since 1.4). The ; % is discovered during standard parsing mode, it may be for example {;} or % arise from expansion as rseq does not use a delimited macro to locate it. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_rseq {\XINT_allexpr_rseq \xintbareeval }% \def\XINT_flexpr_func_rseq {\XINT_allexpr_rseq \xintbarefloateval }% \def\XINT_iiexpr_func_rseq {\XINT_allexpr_rseq \xintbareiieval }% \def\XINT_allexpr_rseq #1#2#3#4% {% \expandafter\XINT_expr_rseqx \expandafter #1\expanded{\xint_noxpd{{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_rseqx #1#2#3#4% {% \XINT:NEhook:rseq \XINT_expr_rseqy\romannumeral0#1(#4)\relax {#2}#3#1% }% \def\XINT_expr_rseqy #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi #2% \XINT_expr_rseq:_b {#5#4\relax !#3}#1^~{#2}\XINT_expr_cb_and_getop }% \def\XINT_expr_rseq:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_rseq:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_rseq:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_rseq:_end\fi \xint_orthat{\XINT_expr_rseq:_c}{#2}{#1}% }% \def\XINT_expr_rseq:_noop #1{\XINT_expr_rseq:_b }% \def\XINT_expr_rseq:_end #1#2~#3{\iffalse{\fi}}% \def\XINT_expr_rseq:_c #1#2% {\expandafter\XINT_expr_rseq:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_rseq:_d #1{\ifx ^#1\xint_dothis\XINT_expr_rseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rseq:_omit\fi \xint_orthat{\XINT_expr_rseq:_goon {#1}}}% \def\XINT_expr_rseq:_abort #1!#2^~#3{\iffalse{\fi}}% \def\XINT_expr_rseq:_break #1!#2^~#3{#1\iffalse{\fi}}% \def\XINT_expr_rseq:_omit #1!#2#{% \expandafter\XINT_expr_rseq:_b\xint_gobble_i }% \def\XINT_expr_rseq:_goon #1!#2#{\XINT_expr_rseq:_goon_a {#1}}% \def\XINT_expr_rseq:_goon_a #1#2#3~#4{#1\XINT_expr_rseq:_b #3~{#1}}% \def\XINT_expr_rseq:_Ca #1#2#3{\XINT_expr_rseq:_Cc#3.{#2}}% \def\XINT_expr_rseq:_Cb #1% {\expandafter\XINT_expr_rseq:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_rseq:_Cc #1.#2% {\expandafter\XINT_expr_rseq:_D\romannumeral0#2{{#1[0]}}{#1}{#2}}% \def\XINT_expr_rseq:_D #1{\ifx ^#1\xint_dothis\XINT_expr_rseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rseq:_Omit\fi \xint_orthat{\XINT_expr_rseq:_Goon {#1}}}% \def\XINT_expr_rseq:_Omit #1!#2#{% \expandafter\XINT_expr_rseq:_Cb\xint_gobble_i }% \def\XINT_expr_rseq:_Goon #1!#2#{\XINT_expr_rseq:_Goon_a {#1}}% \def\XINT_expr_rseq:_Goon_a #1#2#3~#4{#1\XINT_expr_rseq:_Cb #3~{#1}}% % \end{macrocode} % \subsubsection{\cshn{iterr()}} %\begin{lverb} % ATTENTION! at 1.4 the @ and @1 are not synonymous anymore. One *must* use % @1 in iterr() context. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_iterr {\XINT_allexpr_iterr \xintbareeval }% \def\XINT_flexpr_func_iterr {\XINT_allexpr_iterr \xintbarefloateval }% \def\XINT_iiexpr_func_iterr {\XINT_allexpr_iterr \xintbareiieval }% \def\XINT_allexpr_iterr #1#2#3#4% {% \expandafter\XINT_expr_iterrx \expandafter #1\expanded{{\xintRevWithBraces{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_iterrx #1#2#3#4% {% \XINT:NEhook:iterr\XINT_expr_iterry\romannumeral0#1(#4)\relax {#2}#3#1% }% \def\XINT_expr_iterry #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi \XINT_expr_iterr:_b {#5#4\relax !#3}#1^~#20?\XINT_expr_cb_and_getop }% \def\XINT_expr_iterr:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_iterr:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_iterr:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_iterr:_end\fi \xint_orthat{\XINT_expr_iterr:_c}{#2}{#1}% }% \def\XINT_expr_iterr:_noop #1{\XINT_expr_iterr:_b }% \def\XINT_expr_iterr:_end #1#2~#3#4?{{#3}\iffalse{\fi}}% \def\XINT_expr_iterr:_c #1#2% {\expandafter\XINT_expr_iterr:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_iterr:_d #1{\ifx ^#1\xint_dothis\XINT_expr_iterr:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iterr:_break\fi \ifx !#1\xint_dothis\XINT_expr_iterr:_omit\fi \xint_orthat{\XINT_expr_iterr:_goon {#1}}}% \def\XINT_expr_iterr:_abort #1!#2^~#3?{\iffalse{\fi}}% \def\XINT_expr_iterr:_break #1!#2^~#3?{#1\iffalse{\fi}}% \def\XINT_expr_iterr:_omit #1!#2#{% \expandafter\XINT_expr_iterr:_b\xint_gobble_i }% \def\XINT_expr_iterr:_goon #1!#2#{\XINT_expr_iterr:_goon_a{#1}}% \def\XINT_expr_iterr:_goon_a #1#2#3~#4?% {% \expandafter\XINT_expr_iterr:_b \expanded{\xint_noxpd{#3~}\xintTrim{-2}{#1#4}}0?% }% \def\XINT_expr_iterr:_Ca #1#2#3{\XINT_expr_iterr:_Cc#3.{#2}}% \def\XINT_expr_iterr:_Cb #1% {\expandafter\XINT_expr_iterr:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_iterr:_Cc #1.#2% {\expandafter\XINT_expr_iterr:_D\romannumeral0#2{{#1[0]}}{#1}{#2}}% \def\XINT_expr_iterr:_D #1{\ifx ^#1\xint_dothis\XINT_expr_iterr:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iterr:_break\fi \ifx !#1\xint_dothis\XINT_expr_iterr:_Omit\fi \xint_orthat{\XINT_expr_iterr:_Goon {#1}}}% \def\XINT_expr_iterr:_Omit #1!#2#{% \expandafter\XINT_expr_iterr:_Cb\xint_gooble_i }% \def\XINT_expr_iterr:_Goon #1!#2#{\XINT_expr_iterr:_Goon_a{#1}}% \def\XINT_expr_iterr:_Goon_a #1#2#3~#4?% {% \expandafter\XINT_expr_iterr:_Cb \expanded{\xint_noxpd{#3~}\xintTrim{-2}{#1#4}}0?% }% % \end{macrocode} % \subsubsection{\cshn{rrseq()}} % %\begin{lverb} % When func_rrseq has its turn, initial segment has been scanned % by oparen, the ; mimicking the rôle of a closing parenthesis, and % stopping further expansion. #2 = \xint_c_i and #3 are left-over trash. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_rrseq {\XINT_allexpr_rrseq \xintbareeval }% \def\XINT_flexpr_func_rrseq {\XINT_allexpr_rrseq \xintbarefloateval }% \def\XINT_iiexpr_func_rrseq {\XINT_allexpr_rrseq \xintbareiieval }% \def\XINT_allexpr_rrseq #1#2#3#4% {% \expandafter\XINT_expr_rrseqx\expandafter#1\expanded {\xint_noxpd{{#4}}{\xintRevWithBraces{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_rrseqx #1#2#3#4#5% {% \XINT:NEhook:rrseq\XINT_expr_rrseqy\romannumeral0#1(#5)\relax {#2}{#3}#4#1% }% \def\XINT_expr_rrseqy #1#2#3#4#5#6% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi #2\XINT_expr_rrseq:_b {#6#5\relax !#4}#1^~#30?\XINT_expr_cb_and_getop }% \def\XINT_expr_rrseq:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_rrseq:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_rrseq:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_rrseq:_end\fi \xint_orthat{\XINT_expr_rrseq:_c}{#2}{#1}% }% \def\XINT_expr_rrseq:_noop #1{\XINT_expr_rrseq:_b }% \def\XINT_expr_rrseq:_end #1#2~#3?{\iffalse{\fi}}% \def\XINT_expr_rrseq:_c #1#2% {\expandafter\XINT_expr_rrseq:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_rrseq:_d #1{\ifx ^#1\xint_dothis\XINT_expr_rrseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rrseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rrseq:_omit\fi \xint_orthat{\XINT_expr_rrseq:_goon {#1}}}% \def\XINT_expr_rrseq:_abort #1!#2^~#3?{\iffalse{\fi}}% \def\XINT_expr_rrseq:_break #1!#2^~#3?{#1\iffalse{\fi}}% \def\XINT_expr_rrseq:_omit #1!#2#{% \expandafter\XINT_expr_rrseq:_b\xint_gobble_i }% \def\XINT_expr_rrseq:_goon #1!#2#{\XINT_expr_rrseq:_goon_a {#1}}% \def\XINT_expr_rrseq:_goon_a #1#2#3~#4?% {% #1\expandafter\XINT_expr_rrseq:_b \expanded{\xint_noxpd{#3~}\xintTrim{-2}{#1#4}}0?% }% \def\XINT_expr_rrseq:_Ca #1#2#3{\XINT_expr_rrseq:_Cc#3.{#2}}% \def\XINT_expr_rrseq:_Cb #1% {\expandafter\XINT_expr_rrseq:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_rrseq:_Cc #1.#2% {\expandafter\XINT_expr_rrseq:_D\romannumeral0#2{{#1[0]}}{#1}{#2}}% \def\XINT_expr_rrseq:_D #1{\ifx ^#1\xint_dothis\XINT_expr_rrseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rrseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rrseq:_Omit\fi \xint_orthat{\XINT_expr_rrseq:_Goon {#1}}}% \def\XINT_expr_rrseq:_Omit #1!#2#{% \expandafter\XINT_expr_rrseq:_Cb\xint_gobble_i }% \def\XINT_expr_rrseq:_Goon #1!#2#{\XINT_expr_rrseq:_Goon_a {#1}}% \def\XINT_expr_rrseq:_Goon_a #1#2#3~#4?% {% #1\expandafter\XINT_expr_rrseq:_Cb \expanded{\xint_noxpd{#3~}\xintTrim{-2}{#1#4}}0?% }% \catcode`? 11 % \end{macrocode} % \subsection{Pseudo-functions related to N-dimensional hypercubic lists} % \subsubsection{\cshn{ndseq()}} %\begin{lverb} % New with 1.4. 2020/01/23. It is derived from subsm() but instead of % evaluating one expression according to one value per variable, it constructs % a nested bracketed seq... this means the expression is parsed each time ! % Anyway, proof of concept. Nota Bene : omit, abort, break() work ! %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_ndseq {% \expandafter\XINT_allexpr_ndseq_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_ndseq_f #1#2{\xint_c_ii^v `{ndseqx}#2)\relax #1}% \def\XINT_expr_func_ndseqx {% \expandafter\XINT_allexpr_ndseqx\expandafter\xintbareeval \expandafter{\romannumeral0\expandafter\xint_gobble_i\string}% \expandafter\xintrevwithbraces \expanded\bgroup{\iffalse}\fi\XINT_allexpr_ndseq_A\XINT_expr_oparen }% \def\XINT_flexpr_func_ndseqx {% \expandafter\XINT_allexpr_ndseqx\expandafter\xintbarefloateval \expandafter{\romannumeral0\expandafter\xint_gobble_i\string}% \expandafter\xintrevwithbraces \expanded\bgroup{\iffalse}\fi\XINT_allexpr_ndseq_A\XINT_flexpr_oparen }% \def\XINT_iiexpr_func_ndseqx {% \expandafter\XINT_allexpr_ndseqx\expandafter\xintbareiieval \expandafter{\romannumeral0\expandafter\xint_gobble_i\string}% \expandafter\xintrevwithbraces \expanded\bgroup{\iffalse}\fi\XINT_allexpr_ndseq_A\XINT_iiexpr_oparen }% \def\XINT_allexpr_ndseq_A #1#2#3% {% \ifx#2\xint_c_ \expandafter\XINT_allexpr_ndseq_C \else \expandafter\XINT_allexpr_ndseq_B \fi #1% }% \def\XINT_allexpr_ndseq_B #1#2#3#4=% {% {#2}{\xint_zapspaces#3#4 \xint_gobble_i}% \expandafter\XINT_allexpr_ndseq_A\expandafter#1\romannumeral`&&@#1% }% % \end{macrocode} %\begin{lverb} % #1 = \xintbareeval, or \xintbarefloateval or \xintbareiieval % #2 = values for last coordinate %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_ndseq_C #1#2{{#2}\iffalse{{{\fi}}}}% % \end{macrocode} %\begin{lverb} % #1 = \xintbareeval or \xintbarefloateval or \xintbareiieval % #2 = {valuesN}...{values2}{var2}{values1} % #3 = {var1} % #4 = the expression to evaluate %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_ndseqx #1#2#3#4% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup \romannumeral0#1\empty \expanded{\xintReplicate{\xintLength{{#3}#2}/2}{[seq(}% \xint_noxpd{#4}% \XINT_allexpr_ndseqx_a #2{#3}^^% }% \relax \iffalse{\fi\expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_allexpr_ndseqx_a #1#2% {% \xint_gob_til_^ #1\XINT_allexpr_ndseqx_e ^% \xint_noxpd{,#2=\XINTfstop.{#1})]}\XINT_allexpr_ndseqx_a }% \def\XINT_allexpr_ndseqx_e ^#1\XINT_allexpr_ndseqx_a{}% % \end{macrocode} % \subsubsection{\cshn{ndmap()}} %\begin{lverb} % New with 1.4. 2020/01/24. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_ndmap #1,{\xint_c_ii^v `{ndmapx}\XINTfstop.{#1};}% \def\XINT_expr_func_ndmapx #1#2#3% {% \expandafter\XINT_allexpr_ndmapx \csname XINT_expr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname \XINT_expr_oparen }% \def\XINT_flexpr_func_ndmapx #1#2#3% {% \expandafter\XINT_allexpr_ndmapx \csname XINT_flexpr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname \XINT_flexpr_oparen }% \def\XINT_iiexpr_func_ndmapx #1#2#3% {% \expandafter\XINT_allexpr_ndmapx \csname XINT_iiexpr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname \XINT_iiexpr_oparen }% \def\XINT_allexpr_ndmapx #1#2% {% \expandafter\XINT_expr_put_op_first \expanded\bgroup{\iffalse}\fi \expanded {\noexpand\XINT:NEhook:x:ndmapx \noexpand\XINT_allexpr_ndmapx_a \noexpand#1{}\expandafter}% \expanded\bgroup\expandafter\XINT_allexpr_ndmap_A \expandafter#2\romannumeral`&&@#2% }% \def\XINT_allexpr_ndmap_A #1#2#3% {% \ifx#3;% \expandafter\XINT_allexpr_ndmap_B \else \xint_afterfi{\XINT_allexpr_ndmap_C#2#3}% \fi #1% }% \def\XINT_allexpr_ndmap_B #1#2% {% {#2}\expandafter\XINT_allexpr_ndmap_A\expandafter#1\romannumeral`&&@#1% }% \def\XINT_allexpr_ndmap_C #1#2#3#4% {% {#4}^\relax\iffalse{{{\fi}}}#1#2% }% \def\XINT_allexpr_ndmapx_a #1#2#3% {% \xint_gob_til_^ #3\XINT_allexpr_ndmapx_l ^% \XINT_allexpr_ndmapx_b #1{#2}{#3}% }% \def\XINT_allexpr_ndmapx_l ^#1\XINT_allexpr_ndmapx_b #2#3#4\relax {% #2\empty\xint_firstofone{#3}% }% \def\XINT_allexpr_ndmapx_b #1#2#3#4\relax {% {\iffalse}\fi\XINT_allexpr_ndmapx_c {#4\relax}#1{#2}#3^% }% \def\XINT_allexpr_ndmapx_c #1#2#3#4% {% \xint_gob_til_^ #4\XINT_allexpr_ndmapx_e ^% \XINT_allexpr_ndmapx_a #2{#3{#4}}#1% \XINT_allexpr_ndmapx_c {#1}#2{#3}% }% \def\XINT_allexpr_ndmapx_e ^#1\XINT_allexpr_ndmapx_c {\iffalse{\fi}\xint_gobble_iii}% % \end{macrocode} % \subsubsection{\cshn{ndfillraw()}} %\begin{lverb} % New with 1.4. 2020/01/24. J'hésite à autoriser un #1 quelconque, % ou plutôt à le wrapper dans un \xintbareval. Mais il faut alors distinguer % les trois. De toute façon les variables ne marcheraient pas donc j'hésite % à mettre un wrapper automatique. Mais ce n'est pas bien d'autoriser l'injection % de choses quelconques. % % Pour des choses comme ndfillraw(\xintRandomBit,[10,10]). % % Je n'aime pas le nom !. Le changer. ndconst? Surtout je n'aime pas % que dans le premier argument il faut rajouter explicitement si nécessaire % \xintiiexpr wrap. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_ndfillraw #1,% {\xint_c_ii^v `{ndfillrawx}\XINTfstop.{{#1}},}% \def\XINT_expr_func_ndfillrawx #1#2#3% {% \expandafter#1\expandafter#2% \expanded{{{\XINT_allexpr_ndfillrawx_a #3}}}% }% \let\XINT_iiexpr_func_ndfillrawx\XINT_expr_func_ndfillrawx \let\XINT_flexpr_func_ndfillrawx\XINT_expr_func_ndfillrawx \def\XINT_allexpr_ndfillrawx_a #1#2% {% \expandafter\XINT_allexpr_ndfillrawx_b \romannumeral0\xintApply{\calxListItemToNum}{#2}^\relax {#1}% }% \def\XINT_allexpr_ndfillrawx_b #1#2\relax#3% {% \xint_gob_til_^ #1\XINT_allexpr_ndfillrawx_c ^% \xintReplicate{#1}{{\XINT_allexpr_ndfillrawx_b #2\relax {#3}}}% }% \def\XINT_allexpr_ndfillrawx_c ^\xintReplicate #1#2% {% \expandafter\XINT_allexpr_ndfillrawx_d\xint_firstofone #2% }% \def\XINT_allexpr_ndfillrawx_d\XINT_allexpr_ndfillrawx_b \relax #1{#1}% % \end{macrocode} % \subsubsection{Making them known to the other parsers} % \changed{2.0a1} % The "onliteral" handlers are now per-parser for reasons unrelated % to the above constructs. Very poorly documented, see next section. % \begin{macrocode} \xintFor* #1 in {{subs}{subsm}{subsn}{seq}{add}{mul}{ndseq}{ndmap}{ndfillraw}}\do{% \expandafter\let\csname XINT_flexpr_onliteral_#1\expandafter\endcsname \csname XINT_expr_onliteral_#1\endcsname \expandafter\let\csname XINT_iiexpr_onliteral_#1\expandafter\endcsname \csname XINT_expr_onliteral_#1\endcsname }% % \end{macrocode} % \subsection{Other pseudo-functions: \cshn{bool()}, \cshn{togl()}, \cshn{protect()}, % \cshn{qraw()}, \cshn{qint()}, \cshn{qfrac()}, \cshn{qfloat()}, \cshn{qrand()}, % \cshn{random()}, \cshn{rbit()}} % %\begin{lverb} % bool, togl and protect use delimited macros. They are not true % functions, they turn off the parser to gather their "variable". %\end{lverb} % % \changed{1.2} Adds |qint()|, |qfrac()|, |qfloat()|. % % \changed{1.3c} Adds |qraw()|. Useful to limit impact on \TeX{} memory % from abuse of |\csname|'s storage when generating many comma separated % values from a loop. % % \changed{1.3e} |qfloat()| keeps a short mantissa if possible. % %\begin{lverb} % They allow the user to hand over quickly a big number to the parser, % spaces not immediately removed but should be harmless in general. The qraw() % does no post-processing at all apart complete expansion, useful for % comma-separated values, but must be obedient to (non really documented) % expected format. Each uses a delimited macro, the closing parenthesis can % not emerge from expansion. %\end{lverb} % %\begin{lverb} % 1.3b. random(), qrand() % Function-like syntax but with no argument currently, so let's % use fast parsing which requires though the closing parenthesis to be % explicit. %\end{lverb} % %\begin{lverb} % Attention that qraw() % which pre-supposes knowledge of internal storage model is fragile % and may break at any release. % % 1.4 adds rbit(). Short for random bit. %\end{lverb} % % \changed{2.0a1} Now needs |\let| to make "onliteral" handlers known % to other parsers. % \begin{macrocode} \def\XINT_expr_onliteral_bool #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\xintBool{#1}[0]}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_togl #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\xintToggle{#1}[0]}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_protect #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\detokenize{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qint #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\xintiNum{#1}[0]}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \xintFor* #1 in {{bool}{togl}{protect}{qint}}\do{% \expandafter\let\csname XINT_flexpr_onliteral_#1\expandafter\endcsname \csname XINT_expr_onliteral_#1\endcsname \expandafter\let\csname XINT_iiexpr_onliteral_#1\expandafter\endcsname \csname XINT_expr_onliteral_#1\endcsname }% % \end{macrocode} % % \changed{2.0a1} % %\begin{lverb} % BREAKING CHANGE. The qfloat() interface is REMOVED from \xintiieval. % Only kept in \xintfloateval and \xinteval (with xintexpr.sty). % % qraw() should never have been mentioned in user manual. % It is a use-at-own-risk. Depends on knowing internals. %\end{lverb} % %\begin{lverb} % THIS AI COMMENT IS PARTLY OBSOLETE. IT LOCATED \xintFor LOOPS % AT WRONG PLACES REGARDING CODE LEGIBILITY. USER MANUAL INTERVENTION % MODIFIED LAYOUT. BESIDES THE \xintFor LOOPS THEMSELVES USED AN % INTERMEDIATE MACRO \XINT_tmpa STILL REDUCING LEGIBILIT. % THE AI HAS MESSED UP THE INTERNAL LOGIC. % % calx: the onliterals are looked up per parser % (\XINT_

_onliteral_): the \xinteval ones are copied % for \xintfloateval and \xintiieval. qint() of \xintiieval % gives an M value, qfloat() of \xintfloateval an F value (as float()), % random() and qrand() of \xintfloateval F values (calxfp's % \calxFpRandomSdigits, \calxFpRandomSixteen). % The argument of qfloat() of \xintfloateval is read by \CALX_fround: a % raw value A, A[N], A/B, A/B[N] (any xintfrac input with xintexpr.sty). % qfrac(A/B) (the slash is mandatory; A and B f-expand to integers in % strict format: 0 or an optional - then digits without leading zero): % \xintfloateval: A/B rounded to P digits (\CALX_fqfrac: exact F values % of A and B by calxfp's \CALX_ffromraw, then its correctly rounded % division \CALX_fr_xk; B may be negative; B = 0 signals as x / 0); % \xintiieval: A/B[0] (B > 0), for round(), trunc(), num() etc. The % \xinteval qfrac() (\xintRaw, any xintfrac input) is xintexpr.sty's; % loading it does not change the two calx ones. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_qraw #1)% {\expandafter\XINT_expr_put_op_first\expanded{{#1}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \let\XINT_flexpr_onliteral_qraw\XINT_expr_onliteral_qraw \let\XINT_iiexpr_onliteral_qraw\XINT_expr_onliteral_qraw \def\XINT_expr_onliteral_qfloat #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\calxFpFloatdigits{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \let\XINT_flexpr_onliteral_qfloat\XINT_expr_onliteral_qfloat \def\XINT_expr_onliteral_random #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\XINTinRandomFloatSdigits}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \let\XINT_iiexpr_onliteral_random\XINT_expr_onliteral_random \def\XINT_flexpr_onliteral_random #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\calxFpRandomSdigits}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qrand #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\XINTinRandomFloatSixteen}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \let\XINT_iiexpr_onliteral_qrand\XINT_expr_onliteral_qrand \def\XINT_flexpr_onliteral_qrand #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\calxFpRandomSixteen}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_rbit #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\xintRandBit[0]}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \let\XINT_flexpr_onliteral_rbit\XINT_expr_onliteral_rbit \let\XINT_iiexpr_onliteral_rbit\XINT_expr_onliteral_rbit \def\XINT_iiexpr_onliteral_qint #1)% {\expandafter\XINT_expr_put_op_first \expanded{{{\romannumeral0\CALX_mfromraw{\xintiNum{#1}}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qfrac #1/#2)% {\expandafter\XINT_expr_put_op_first \expanded{{{#1/#2[0]}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \let\XINT_iiexpr_onliteral_qfrac\XINT_expr_onliteral_qfrac \def\XINT_flexpr_onliteral_qfrac #1/#2)% {\expandafter\XINT_expr_put_op_first \expanded{{{\CALX_fqfrac{#1}{#2}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% % \end{macrode} % \begin{macrocode} \def\CALX_fqfrac #1#2% {\romannumeral0\expandafter\CALX_fr_xk\expanded {\romannumeral0\CALX_ffromraw{#1[0]}\xint:% \romannumeral0\CALX_ffromraw{#2[0]}\xint:{\the\numexpr\XINTdigits}}}% % \end{macrocode} % \def\auxiliarymacro#1{ \noexpand\cshn{#1()}} % \edef\zzz{Regular built-in functions: \xintListWithSep{, }{\xintApply\auxiliarymacro % {{num}{reduce}{preduce} % {abs}{sgn}{frac}{floor}{ceil}{sqr} % {?}{!}{not}{odd}{even}{isint}{isone} % {factorial}{sqrt}{sqrtr} % {inv}{round}{trunc} % {float}{sfloat}{ilog10} % {divmod}{mod}{binomial}{pfactorial} % {randrange} % {iquo}{irem}{gcd}{lcm}{max}{min} % {`+`}{`*`} % {all}{any}{xor} % {len}{first}{last}{reversed} % {if}{ifint}{ifone}{ifsgn} % {nuple}{unpack}{flat}}} % and \noexpand\cshn{zip()}} % \expandafter\subsection\expandafter{\zzz} % \begin{macrocode} \def\XINT:expr:f:one:and:opt #1#2#3!#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {#4}{#5[\calxListItemToNum{#2}]}{#1}% }% \def\XINT:expr:f:tacitzeroifone #1#2#3!#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {#4{0}}{#5{\calxListItemToNum{#2}}}{#1}% }% \def\XINT:expr:f:iitacitzeroifone #1#2#3!#4% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {#4{0[0]}}{#4{#2}}{#1}% }% \def\XINT_iiexpr_func_num #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxListItemToNum#3}}% }% \def\XINT_flexpr_func_num #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpTrunc#3}}% }% \def\XINT_flexpr_func_abs #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAbs#3}}% }% \def\XINT_iiexpr_func_abs #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiAbs#3}}% }% \def\XINT_iiexpr_func_sgn #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxSgn#3}}% }% \def\XINT_flexpr_func_sgn #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSgn#3}}% }% \def\XINT_flexpr_func_frac #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpFrac#3}}% }% % \end{macrocode} %\begin{lverb} % no \XINT_iiexpr_func_frac %\end{lverb} % \begin{macrocode} \def\XINT_flexpr_func_floor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpFloor#3}}% }% % \end{macrocode} %\begin{lverb} % The floor and ceil functions in \xintiiexpr require protect(a/b) or, % better, \qfrac(a/b); else the / will be executed first and do an integer % rounded division. %\end{lverb} % \begin{macrocode} \def\XINT_iiexpr_func_floor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiFloor#3}}% }% \def\XINT_flexpr_func_ceil #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCeil#3}}% }% \def\XINT_iiexpr_func_ceil #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiCeil#3}}% }% \def\XINT_flexpr_func_sqr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSqr#3}}%% calx }% \def\XINT_iiexpr_func_sqr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiSqr#3}}% }% \def\XINT_iiexpr_func_? #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxIsNotZero#3}}% }% \def\XINT_flexpr_func_? #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpIsNotZero#3}}% }% \def\XINT_iiexpr_func_! #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxIsZero#3}}% }% \def\XINT_flexpr_func_! #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpIsZero#3}}% }% \def\XINT_iiexpr_func_not #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxIsZero#3}}% }% \def\XINT_flexpr_func_not #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpIsZero#3}}% }% \def\XINT_flexpr_func_odd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpOdd#3}}% }% \def\XINT_iiexpr_func_odd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiOdd#3}}% }% \def\XINT_flexpr_func_even #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpEven#3}}% }% \def\XINT_iiexpr_func_even #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiEven#3}}% }% \def\XINT_flexpr_func_isint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpIsInt#3}}% }% \def\XINT_iiexpr_func_isint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiIsInt#3}}% }% \def\XINT_flexpr_func_isone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpIsOne#3}}% }% \def\XINT_iiexpr_func_isone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiIsOne#3}}% }% \def\XINT_flexpr_func_factorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt#3,!\calxFpFacdigits\calxFpFac }}% }% \def\XINT_iiexpr_func_factorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiFac#3}}% }% \def\XINT_flexpr_func_sqrt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\calxFpSqrtdigits\calxFpSqrt% calx }}% }% \def\XINT_iiexpr_func_sqrt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiSqrt#3}}% }% \def\XINT_iiexpr_func_sqrtr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiSqrtR#3}}% }% \def\XINT_flexpr_func_inv #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpInv#3}}% }% \def\XINT_flexpr_func_round #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:tacitzeroifone:direct \XINT:expr:f:tacitzeroifone #3,!\calxFpIRound\calxFpRoundTo }}% }% \def\XINT_iiexpr_func_round #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:iitacitzeroifone:direct \XINT:expr:f:iitacitzeroifone #3,!\calxiiRound }}% }% \def\XINT_flexpr_func_trunc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:tacitzeroifone:direct \XINT:expr:f:tacitzeroifone #3,!\calxFpITrunc\calxFpTruncTo }}% }% \def\XINT_iiexpr_func_trunc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:iitacitzeroifone:direct \XINT:expr:f:iitacitzeroifone #3,!\calxiiTrunc }}% }% % \end{macrocode} %\begin{lverb} % Hesitation at 1.3e about using \XINTinFloatSdigits and \XINTinFloatS. % Finally I add a sfloat() function. It helps for xinttrig.sty. % % At 2.0a1, there is no xinttrig.sty anymore. The sfloat() function % and its support macros \XINTinFloatSdigits and \XINTinFloatS have % no real rationale: the S variant goal was to produce smaller mantissas, % but there is hardly any utility for this with the calx float model. % So we let the sfloat() be like float() in \xintfloateval. Neither float() % nor sfloat() were ever defined in \xintiieval. The \xinteval float() % and sfloat() keep their legacy meanings and are defined in xintexpr.sty. % Most of the comments that folllow below are either outdate or regard % the \xinteval situation. %\end{lverb} % %\begin{lverb} % float_() was added at 1.4, as a shortcut alias to float() skipping the check % for an optional second argument. This is useful to transfer function % definitions between \xintexpr and \xintfloatexpr contexts. % % % No need for a similar shortcut for sfloat() as currently used in % xinttrig.sty to go from float to expr: as it is used there as sfloat(x) with % dummy x, it sees there is no optional argument, contrarily to for example % float(\xintexpr...\relax) which has to allow for the inner expression to % expand to an ople with two items, so does not know in which branch it is at % time of definiion. % % % After some hesitation at 1.4e regarding guard digits mechanism the float_() % got renamed to float_dgt(), but then renamed back to float_() to avoid a % breaking change and having to document it. % % Nevertheless the documentation of 1.4e mentioned float_dgt()... but it was still % float_()... now changed into float_dgt() for real at 1.4f. % % 1.4f also adds private float_dgtormax and sfloat_dgtormax for matters of xinttrig. % %\end{lverb} % \begin{macrocode} \def\XINT_flexpr_func_float #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\calxFpFloatdigits\calxFpFloat }}% }% \def\XINT_flexpr_func_float_dgt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpFloatdigits#3}}% }% \let\XINT_flexpr_func_sfloat\XINT_flexpr_func_float \expandafter\def\csname XINT_flexpr_func_ilog10\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\calxFpiLogTendigits\calxFpiLogTen }}% }% \expandafter\def\csname XINT_iiexpr_func_ilog10\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxiiLogTen#3}}% }% \def\XINT_flexpr_func_divmod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpDivMod #3}}% }% \def\XINT_iiexpr_func_divmod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxiiDivMod #3}}% }% \def\XINT_flexpr_func_mod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpMod#3}}% }% \def\XINT_iiexpr_func_mod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxiiMod#3}}% }% \def\XINT_flexpr_func_binomial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpBinomial #3}}% }% \def\XINT_iiexpr_func_binomial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxiiBinomial #3}}% }% \def\XINT_flexpr_func_pfactorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpPFactorial #3}}% }% \def\XINT_iiexpr_func_pfactorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxiiPFactorial #3}}% }% \def\XINT_flexpr_func_randrange #1#2#3% {% \expandafter #1\expandafter #2\expanded{{{% \XINT:expr:randrange #3,!% }}}% }% \def\XINT:expr:randrange #1#2#3!% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\calxintRandRange{\XINT:NEhook:f:one:from:one:direct\calxFpToM{#1}}}% {\calxintRandRangeAtoB {\XINT:NEhook:f:one:from:one:direct\calxFpToM{#1}}% {\XINT:NEhook:f:one:from:one:direct\calxFpToM{#2}}% }% }% \def\XINT_iiexpr_func_randrange #1#2#3% {% \expandafter #1\expandafter #2\expanded{{{% \XINT:iiexpr:randrange #3,!% }}}% }% \def\XINT:iiexpr:randrange #1#2#3!% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\calxintRandRange{#1}}% {\calxintRandRangeAtoB{#1}{#2}}% }% \def\XINT_iiexpr_func_iquo #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxiiQuo #3}}% }% \def\XINT_iiexpr_func_irem #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxiiRem #3}}% }% \def\XINT_iiexpr_func_gcd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_iiGCDof#3^}}% }% \def\XINT_iiexpr_func_lcm #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_iiLCMof#3^}}% }% \def\XINT_iiexpr_func_max #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_iiMaxof#3^}}% }% \def\XINT_flexpr_func_max #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpMaxof#3^}}% calx }% \def\XINT_iiexpr_func_min #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_iiMinof#3^}}% }% \def\XINT_flexpr_func_min #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpMinof#3^}}% calx }% \expandafter \def\csname XINT_flexpr_func_+\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpSum#3^}}% }% \expandafter \def\csname XINT_iiexpr_func_+\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_iiSum#3^}}% }% \expandafter \def\csname XINT_flexpr_func_*\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpPrd#3^}}% }% \expandafter \def\csname XINT_iiexpr_func_*\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_iiPrd#3^}}% }% \def\XINT_iiexpr_func_all #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_ANDof#3^}}% }% \def\XINT_flexpr_func_all #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpANDof#3^}}% }% \def\XINT_iiexpr_func_any #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_ORof#3^}}% }% \def\XINT_flexpr_func_any #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpORof#3^}}% }% \def\XINT_iiexpr_func_xor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\CALX_XORof#3^}}% }% \def\XINT_flexpr_func_xor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\calxFpXORof#3^}}% }% \def\XINT_iiexpr_func_len #1#2#3% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\xintLength {\romannumeral\XINT:NEhook:r:check#3^}% }}% }% \def\XINT_flexpr_func_len #1#2#3% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\calxFpLength {\romannumeral\XINT:NEhook:r:check#3^}% }}% }% \def\XINT_flexpr_func_first #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\xintFirstOne {\romannumeral\XINT:NEhook:r:check#3^}% }% }% \let\XINT_iiexpr_func_first\XINT_flexpr_func_first \def\XINT_flexpr_func_last #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\xintLastOne {\romannumeral\XINT:NEhook:r:check#3^}% }% }% \let\XINT_iiexpr_func_last\XINT_flexpr_func_last \def\XINT_flexpr_func_reversed #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:reverse\XINT_expr_reverse #3^^#3\xint:\xint:\xint:\xint: \xint:\xint:\xint:\xint:\xint_bye }% }% \def\XINT_expr_reverse #1#2% {% \if ^\noexpand#2% \expandafter\XINT_expr_reverse:_one_or_none\string#1.% \else \expandafter\XINT_expr_reverse:_at_least_two \fi }% \def\XINT_expr_reverse:_at_least_two #1^^{\XINT_revwbr_loop {}}% \def\XINT_expr_reverse:_one_or_none #1% {% \if #1\bgroup\xint_dothis\XINT_expr_reverse:_nutple\fi \if #1^\xint_dothis\XINT_expr_reverse:_nil\fi \xint_orthat\XINT_expr_reverse:_leaf }% \edef\XINT_expr_reverse:_nil #1\xint_bye{\noexpand\fi\space}% \def\XINT_expr_reverse:_leaf#1\fi #2\xint:#3\xint_bye {\fi\xint_gob_andstop_i#2}% \def\XINT_expr_reverse:_nutple% {% \expandafter\XINT_expr_reverse:_nutple_a\expandafter{\string}% }% \def\XINT_expr_reverse:_nutple_a #1^#2\xint:#3\xint_bye {% \fi\expandafter {\romannumeral0\XINT_revwbr_loop{}#2\xint:#3\xint_bye}% }% \let\XINT_iiexpr_func_reversed\XINT_flexpr_func_reversed \def\XINT_flexpr_func_if #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\calxifNotZero #3}}% }% \let\XINT_iiexpr_func_if\XINT_flexpr_func_if \def\XINT_flexpr_func_ifint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\calxFpifInt #3}}% }% \def\XINT_iiexpr_func_ifint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\calxiiifInt #3}}% }% \def\XINT_flexpr_func_ifone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\calxFpifOne #3}}% }% \def\XINT_iiexpr_func_ifone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\calxiiifOne #3}}% }% \def\XINT_flexpr_func_ifsgn #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\calxifSgn #3}}% }% \let\XINT_iiexpr_func_ifsgn\XINT_flexpr_func_ifsgn \def\XINT_flexpr_func_nuple #1#2#3{#1#2{{#3}}}% \let\XINT_iiexpr_func_nuple\XINT_flexpr_func_nuple \def\XINT_flexpr_func_unpack #1#2%#3% {\expandafter#1\expandafter#2\romannumeral0\XINT:NEhook:unpack}% \let\XINT_iiexpr_func_unpack\XINT_flexpr_func_unpack \def\XINT_flexpr_func_flat #1#2%#3% {% \expandafter#1\expandafter#2\expanded \XINT:NEhook:x:flatten\XINT:expr:flatten }% \let\XINT_iiexpr_func_flat\XINT_flexpr_func_flat \let\XINT:NEhook:x:flatten\empty \def\XINT_flexpr_func_zip #1#2%#3% {% \expandafter#1\expandafter#2\romannumeral`&&@% \XINT:NEhook:x:zip\XINT:expr:zip }% \let\XINT_iiexpr_func_zip\XINT_flexpr_func_zip \let\XINT:NEhook:x:zip\empty \def\XINT:expr:zip#1{\expandafter{\expanded\XINT_zip_A#1\xint_bye\xint_bye}}% % \end{macrocode} % \subsection{User declared functions} %\begin{lverb} % It is possible that % the author actually does understand at this time the % \xintNewExpr/\xintdeffunc refactored code and mechanisms for the first time % since 2014: past evolutions such as the 2018 1.3 refactoring were done a bit % in the fog (although they did accomplish a crucial step). % % The 1.4 version of function and macro definitions is much more powerful than % 1.3 one. But the mechanisms such as «omit», «abort» and «break()» in iter() % et al. can't be translated into much else than their actual code when they % potentially have to apply to non-numeric only context. The 1.4 \xintdeffunc % is thus apparently able to digest them but its pre-parsing benefits are % limited compared to simply assigning such parts of an expression to a % mock-function created by \xintNewFunction (which creates simply a TeX macro % from its substitution expression in macro parameters and add % syntactic sugar to let it appear to \xintexpr as a genuine «function» % although nothing of the syntax has really been pre-parsed.) % % At 1.4 fetching the expression up to final semi-colon is done using % \XINT_expr_fetch_to_semicolon, hence semi-colons arising in the syntax do % not need to be hidden inside braces. %\end{lverb} % % \localtableofcontents % % \subsubsection{\csh{xintdeffunc}, \csh{xintdefiifunc}, % \csh{xintdeffloatfunc}} % % \changed[2015/11/12]{1.2c} %\begin{lverb} % Note: it is possible to have same name assigned both to a variable % and a function: things such as add(f(f), f=1..10) are possible. %\end{lverb} % % \changed[2015/11/13]{1.2c} %\begin{lverb} % Function names first expanded then detokenized and cleaned of spaces. %\end{lverb} % % \changed[2015/11/21]{1.2e} %\begin{lverb} % No \detokenize anymore on the function % names. And #1(#2)#3=#4 parameter pattern to avoid to have to worry if a : is % there and it is active. %\end{lverb} % % \changed[2016/02/22]{1.2f} %\begin{lverb} % La macro associée à la fonction ne débute % plus par un \romannumeral, car de toute façon elle est pour emploi dans % \csname..\endcsname. %\end{lverb} % % \changed[2016/03/08]{1.2f} %\begin{lverb} % Comma separated expressions allowed (formerly this required using % parenthesis \xintdeffunc foo(x,..):=(.., .., ..); %\end{lverb} % % \changed[2018/06/17]{1.3c} %\begin{lverb} % Usage of \xintexprSafeCatcodes to be compatible with an active % semi-colon at time of use; the colon was not a problem (see ##3) already. %\end{lverb} % % \changed{1.3e} %\begin{lverb} % \xintdefefunc variant added for functions which will expand % completely if used with numeric arguments in other function definitions. % They can't be used for recursive definitions. % % Their functionality was merged into \xintdeffunc et al. at 1.4. The % original macros were removed at 1.4m. %\end{lverb} % % \changed[2020/01/10]{1.4} %\begin{lverb} % Multi-letter variables can be used (with no prior declaration) %\end{lverb} % % \changed[2020/01/11]{1.4} %\begin{lverb} % The new internal data model has caused many worries initially (such % as whether to allow functions with «ople» outputs in contrast to «numbers» % or «nutples») but in the end all is simpler again and the refactoring of ? % and ?? in function definitions allows to fuse inert functions (allowing % recursive definitions) and expanding functions (expanding completely if with % numeric arguments) into a single entity. % % A special situation is with % functions of no variables. In that case it will be handled as an inert % entity, else they would not be different from variables. % %\end{lverb} % % \changed[2020/01/19]{1.4} %\begin{lverb} % Addition de la syntaxe déclarative \xintdeffunc foo(a,b,...,*z) = ...; % %\end{lverb} % % \changed[2022/06/05]{1.4m} %\begin{lverb} % Removal of the \xintdefefunc et al.$@ macros deprecated at 1.4. %\end{lverb} % \begin{macrocode} \def\XINT_def_deffunc #1#2#3#4#5% {% \def #1##1(##2)##3={% \edef\XINT_deffunc_tmpa {##1}% \edef\XINT_deffunc_tmpa {\xint_zapspaces_o \XINT_deffunc_tmpa}% \def\XINT_deffunc_tmpb {0}% \edef\XINT_deffunc_tmpd {##2}% \edef\XINT_deffunc_tmpd {\xint_zapspaces_o\XINT_deffunc_tmpd}% \def\XINT_deffunc_tmpe {0}% \expandafter#5\romannumeral\XINT_expr_fetch_to_semicolon }% end of \xintdeffunc_a definition \def#5##1{% \def\XINT_deffunc_tmpc{(##1)}% \ifnum\xintLength:f:csv{\XINT_deffunc_tmpd}>\xint_c_ \xintFor ####1 in {\XINT_deffunc_tmpd}\do {% \xintifForFirst{\let\XINT_deffunc_tmpd\empty}{}% \def\XINT_deffunc_tmpf{####1}% \if*\xintFirstItem{####1}% \xintifForLast {% \def\XINT_deffunc_tmpe{1}% \edef\XINT_deffunc_tmpf{\xintTrim{1}{####1}}% }% {% \edef\XINT_deffunc_tmpf{\xintTrim{1}{####1}}% \xintMessage{xintexpr}{Error} {Only the last positional argument can be variadic. Trimmed ####1 to \XINT_deffunc_tmpf}% }% \fi \XINT_expr_makedummy{\XINT_deffunc_tmpf}% \edef\XINT_deffunc_tmpd{\XINT_deffunc_tmpd{\XINT_deffunc_tmpf}}% \edef\XINT_deffunc_tmpb {\the\numexpr\XINT_deffunc_tmpb+\xint_c_i}% \edef\XINT_deffunc_tmpc {subs(\xint_noxpd\expandafter{\XINT_deffunc_tmpc},% \XINT_deffunc_tmpf=################\XINT_deffunc_tmpb)}% }% \fi % \end{macrocode} % Logic at |1.4| is simplified here compared to % earlier releases. % % \changed{1.4n} % Usage of \cs{xintmeaning} wrapper of engine's \cs{meaning}. See near % \csbXINT{_NewExpr} for explanations. % % \begin{macrocode} \ifcase\XINT_deffunc_tmpb\space \expandafter\XINT_expr_defuserfunc_none\csname \else \expandafter\XINT_expr_defuserfunc\csname \fi XINT_#2_func_\XINT_deffunc_tmpa\expandafter\endcsname \csname XINT_#2_userfunc_\XINT_deffunc_tmpa\expandafter\endcsname \expandafter{\XINT_deffunc_tmpa}{#2}% \expandafter#3\csname XINT_#2_userfunc_\XINT_deffunc_tmpa\endcsname [\XINT_deffunc_tmpb]{\XINT_deffunc_tmpc}% \ifxintverbose\xintMessage {xintexpr}{Info}% {Function \XINT_deffunc_tmpa\space for \string\xint #4 parser associated to \string\XINT_#2_userfunc_\XINT_deffunc_tmpa\space with \ifxintglobaldefs global \fi meaning \expandafter\xintmeaning \csname XINT_#2_userfunc_\XINT_deffunc_tmpa\endcsname}% \fi \xintFor* ####1 in {\XINT_deffunc_tmpd}:{\xintrestorevariablesilently{####1}}% \xintexprRestoreCatcodes }% end of \xintdeffunc_b definition }% \def\xintdefiifunc {\xintexprSafeCatcodes\xintdefiifunc_a}% \def\xintdeffloatfunc {\xintexprSafeCatcodes\xintdeffloatfunc_a}% \XINT_def_deffunc\xintdefiifunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}\xintdefiifunc_b \XINT_def_deffunc\xintdeffloatfunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}\xintdeffloatfunc_b \def\XINT_expr_defuserfunc_none #1#2#3#4% {% \XINT_global \def #1##1##2##3% {% \expandafter##1\expandafter##2\expanded{% {\XINT:NEhook:usernoargfunc\csname XINT_#4_userfunc_#3\endcsname}% }% }% }% \let\XINT:NEhook:usernoargfunc \empty \def\XINT_expr_defuserfunc #1#2#3#4% {% \if0\XINT_deffunc_tmpe \XINT_global \def #1##1##2%##3% {% \expandafter ##1\expandafter##2\expanded\bgroup{\iffalse}\fi \XINT:NEhook:userfunc{XINT_#4_userfunc_#3}#2%##3% }% \else % \end{macrocode} %\begin{lverb} % Last argument in the call signature is variadic (was prefixed by *). %\end{lverb} % \begin{macrocode} \def #1##1{% \XINT_global\def #1####1####2%####3% {% \expandafter ####1\expandafter####2\expanded\bgroup{\iffalse}\fi \XINT:NEhook:userfunc:argv{##1}{XINT_#4_userfunc_#3}#2%####3% }}\expandafter#1\expandafter{\the\numexpr\XINT_deffunc_tmpb-1}% \fi }% % \end{macrocode} %\begin{lverb} % Deliberate brace stripping of #3 to reveal the elements of the ople, % which may be atoms i.e. numeric data such as {1}, or again oples, which % means that the corresponding item was a nutple, for example it came from % input syntax such as foo(1, 2, [1, 2], 3), so (up to details of raw % encoding) {1}{2}{{1}{2}}{3}, which gives 4 braced arguments to macro #2. %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:userfunc #1#2#3{#2#3\iffalse{{\fi}}}% % \end{macrocode} %\begin{lverb} % Here #1 indicates the number k-1 of standard positional arguments of % the call signature, the kth and last one having been declared of variadic % type. The braces around \xintTrim{#1}{#4} have the effect to gather all % these remaining elements to provide a single one to the TeX macro. % % For example input was foo(1,2,3,4,5) and call signature was foo(a,b,*z). % Then #4 will fetch {{1}{2}{3}{4}{5}}, with one level of brace removal. % We will have \xintKeep{2}{{1}{2}{3}{4}{5}} which produces {1}{2}. % Then {\xintTrim{2}{{1}{2}{3}{4}{5}}} which produces {{3}{4}{5}}. % So the macro will be used as \macro{1}{2}{{3}{4}{5}} having been % declared as a macro with 3 arguments. % % The above comments were added in June 2021 but the code was done on January % 19, 2020 for 1.4. % % Note on June 10, 2021: at core level \XINT_NewFunc is used which is derived % from \XINT_NewExpr which has always prepared TeX macros with non-delimited % parameters. A refactoring could add a final delimiter, for example \relax. % The macro with 3 arguments would be defined as \def\macro#1#2#3\relax{...} % for example. Then we could transfer to TeX core processing what is achieved % here via \xintKeep/\xintTrim, of course adding efficiency, via insertion of % the delimiter. In the case of foo(1,2,3,4,5) we would have the #3 of % delimited \macro fetch {3}{4}{5}, no brace removal, which is equivalent to % current situation fetching {{3}{4}{5}} with brace removal. But let's see in % case of foo(1,2,3) then. This would lead to delimited \macro{1}{2}{3}\relax % and #3 will fetch {3}, removing one brace pair. Whereas current % non-delimited \macro is used as \macro{1}{2}{{3}} from the Keep/Trim, then % #3 fetches {{3}}, removing one brace pair. Not the same thing. So it seems % there is a stumbling-block here to adopt such an alternative method, in % relation with brace removal. Rather relieved in fact, as my head starts % spinning in ople world. Seems better to stop thinking about doing something % like that, and what it would imply as consequences for user declarative % interface also. Oples are dangerous to mental health, let's stick with % one-ples: « named arguments in function body declaration must stand for % one-ples », even the last one, although a priori it could be envisioned if % foo has been declared with call signature (x,y,z) and is used with more % items that z is mapped to the ople of extra elements beyond the first % two ones. For my sanity I stick with my January 2020 concept of (x,y,*z) % which makes z stand for a nutple always and having to be used as such in the % function body (possibly unpacked there using *z). %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:userfunc:argv #1#2#3#4% {\expandafter#3\expanded{\xintKeep{#1}{#4}{\xintTrim{#1}{#4}}}\iffalse{{\fi}}}% % \end{macrocode} % \subsubsection{\csh{xintdefufunc}, \csh{xintdefiiufunc}, % \csh{xintdeffloatufunc}} % %\begin{lverb} % Added at 1.4 %\end{lverb} % \changed[2022/05/15]{1.4k} %\begin{lverb} % \xintexprRestoreCatcodes was in only one branch of \xint_defufunc_b, % and as a result sanitization of catcodes via \xintexprSafeCatcodes % was never reverted. That the % bug remained unseen and in particular did not break compilation of % user manual (where the | must be active), was a sort of unhappy miracle % due to the | ending up recovering its active catcode from some ulterior % \xintdefiifunc whose Safe/Restore behaved as described in the user manual, % i.e. it did a restore to the state before the first unpaired Safe, and this % miraculous recovery happened before breakage had happened, by sheer luck, % or rather lack of luck, else I would have seen and solved % the problem two years ago... %\end{lverb} % \begin{macrocode} \def\XINT_def_defufunc #1#2#3#4#5#6% {% \def #1##1(##2)##3={% \edef\XINT_defufunc_tmpa {##1}% \edef\XINT_defufunc_tmpa {\xint_zapspaces_o \XINT_defufunc_tmpa}% \edef\XINT_defufunc_tmpd {##2}% \edef\XINT_defufunc_tmpd {\xint_zapspaces_o\XINT_defufunc_tmpd}% \expandafter#5\romannumeral\XINT_expr_fetch_to_semicolon }% end of \xint_defufunc_a \def#5##1{% \def\XINT_defufunc_tmpc{(##1)}% \ifnum\xintLength:f:csv{\XINT_defufunc_tmpd}=\xint_c_i \expandafter#6% \else \xintMessage {xintexpr}{ERROR} {Universal functions must be functions of one argument only, but the declaration of \XINT_defufunc_tmpa\space has \xintLength:f:csv{\XINT_defufunc_tmpd} of them. Canceled.}% \xintexprRestoreCatcodes \fi }% end of \xint_defufunc_b \def #6{% \XINT_expr_makedummy{\XINT_defufunc_tmpd}% \edef\XINT_defufunc_tmpc {subs(\xint_noxpd\expandafter{\XINT_defufunc_tmpc},% \XINT_defufunc_tmpd=########1)}% \expandafter\XINT_expr_defuserufunc \csname XINT_#2_func_\XINT_defufunc_tmpa\expandafter\endcsname \csname XINT_#2_userufunc_\XINT_defufunc_tmpa\expandafter\endcsname \expandafter{\XINT_defufunc_tmpa}{#2}% \expandafter#3\csname XINT_#2_userufunc_\XINT_defufunc_tmpa\endcsname [1]{\XINT_defufunc_tmpc}% \ifxintverbose\xintMessage {xintexpr}{Info}% {Universal function \XINT_defufunc_tmpa\space for \string\xint #4 parser associated to \string\XINT_#2_userufunc_\XINT_defufunc_tmpa\space with \ifxintglobaldefs global \fi meaning \expandafter\xintmeaning \csname XINT_#2_userufunc_\XINT_defufunc_tmpa\endcsname}% \fi \xintexprRestoreCatcodes }% end of \xint_defufunc_c }% \def\xintdefiiufunc {\xintexprSafeCatcodes\xintdefiiufunc_a}% \def\xintdeffloatufunc {\xintexprSafeCatcodes\xintdeffloatufunc_a}% \XINT_def_defufunc\xintdefiiufunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}% \xintdefiiufunc_b\xintdefiiufunc_c \XINT_def_defufunc\xintdeffloatufunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}% \xintdeffloatufunc_b\xintdeffloatufunc_c \def\XINT_expr_defuserufunc #1#2#3#4% {% \XINT_global \def #1##1##2%##3% {% \expandafter ##1\expandafter##2\expanded \XINT:NEhook:userufunc{XINT_#4_userufunc_#3}#2%##3% }% }% \def\XINT:NEhook:userufunc #1{\XINT:expr:mapwithin}% % \end{macrocode} % % \subsubsection{\csh{xintunassignexprfunc}, % \csh{xintunassigniiexprfunc}, \csh{xintunassignfloatexprfunc}} % See the \csbxint{unassignvar} for the embarrassing explanations why I had % not done that earlier. A bit lazy here, no warning if undefining something % not defined, and attention no precaution respective built-in functions. % % \begin{macrocode} \def\XINT_def_unassignfunc #1{\expandafter\def\csname xintunassign#1func\endcsname ##1{% \edef\XINT_unfunc_tmpa{##1}% \edef\XINT_unfunc_tmpa {\xint_zapspaces_o\XINT_unfunc_tmpa}% \XINT_global\expandafter \let\csname XINT_#1_func_\XINT_unfunc_tmpa\endcsname\XINT_undefined \XINT_global\expandafter \let\csname XINT_#1_userfunc_\XINT_unfunc_tmpa\endcsname\XINT_undefined \XINT_global\expandafter \let\csname XINT_#1_userufunc_\XINT_unfunc_tmpa\endcsname\XINT_undefined \ifxintverbose\xintMessage {xintexpr}{Info}% {Function \XINT_unfunc_tmpa\space for \string\xint #1 parser now \ifxintglobaldefs globally \fi undefined.}% \fi}}% \XINT_def_unassignfunc{iiexpr}\XINT_def_unassignfunc{floatexpr}% % \end{macrocode} % \subsubsection{\csh{xintNewFunction}} %\begin{lverb} % 1.2h (2016/11/20). Syntax is \xintNewFunction{}[nb of % arguments]{expression with #1, #2,... as in \xintNewExpr}. This defines % a function for all three parsers but the expression parsing is delayed until % function execution. Hence the expression admits all constructs, contrarily % to \xintNewExpr or \xintdeffunc. % % As the letters used for variables in \xintdeffunc, #1, #2, etc... can not % stand for non numeric «oples», because at time of function call f(a, b, c, % ...) how to decide if #1 stands for a or a, b etc... ? Or course «a» can be % packed and thus the macro function can handle #1 as a «nutple» and for this % be defined with the * unpacking operator being applied to it. %\end{lverb} % \begin{macrocode} \def\xintNewFunction #1#2[#3]#4% {% \edef\XINT_newfunc_tmpa {#1}% \edef\XINT_newfunc_tmpa {\xint_zapspaces_o \XINT_newfunc_tmpa}% \def\XINT_newfunc_tmpb ##1##2##3##4##5##6##7##8##9{#4}% \begingroup \ifcase #3\relax \toks0{}% \or \toks0{##1}% \or \toks0{##1##2}% \or \toks0{##1##2##3}% \or \toks0{##1##2##3##4}% \or \toks0{##1##2##3##4##5}% \or \toks0{##1##2##3##4##5##6}% \or \toks0{##1##2##3##4##5##6##7}% \or \toks0{##1##2##3##4##5##6##7##8}% \else \toks0{##1##2##3##4##5##6##7##8##9}% \fi \expandafter \endgroup\expandafter \XINT_global\expandafter \def\csname XINT_expr_macrofunc_\XINT_newfunc_tmpa\expandafter\endcsname \the\toks0\expandafter{\XINT_newfunc_tmpb {\XINTfstop.{{##1}}}{\XINTfstop.{{##2}}}{\XINTfstop.{{##3}}}% {\XINTfstop.{{##4}}}{\XINTfstop.{{##5}}}{\XINTfstop.{{##6}}}% {\XINTfstop.{{##7}}}{\XINTfstop.{{##8}}}{\XINTfstop.{{##9}}}}% \expandafter\XINT_expr_newfunction \csname XINT_expr_func_\XINT_newfunc_tmpa\expandafter\endcsname \expandafter{\XINT_newfunc_tmpa}\xintbareeval \expandafter\XINT_expr_newfunction \csname XINT_iiexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname \expandafter{\XINT_newfunc_tmpa}\xintbareiieval \expandafter\XINT_expr_newfunction \csname XINT_flexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname \expandafter{\XINT_newfunc_tmpa}\xintbarefloateval \ifxintverbose \xintMessage {xintexpr}{Info}% {Function \XINT_newfunc_tmpa\space for the expression parsers is associated to \string\XINT_expr_macrofunc_\XINT_newfunc_tmpa\space with \ifxintglobaldefs global \fi meaning \expandafter\xintmeaning \csname XINT_expr_macrofunc_\XINT_newfunc_tmpa\endcsname}% \fi }% \def\XINT_expr_newfunction #1#2#3% {% \XINT_global \def#1##1##2##3% {\expandafter ##1\expandafter ##2% \romannumeral0\XINT:NEhook:macrofunc #3{\csname XINT_expr_macrofunc_#2\endcsname##3}\relax }% }% \let\XINT:NEhook:macrofunc\empty % \end{macrocode} % \subsubsection{Mysterious stuff} % % There was an |\xintNewExpr| already in 1.07 from May 2013, which was % modified in September 2013 to work with the \# macro parameter character, % and then refactored into a more powerful version in June 2014 for 1.1 % release of 2014/10/28. % % It is always too soon to try to comment and explain. In brief, this attempts % to hack into the \emph{purely numeric} |\xintexpr| parsers to transform them % into \emph{symbolic} parsers, allowing to do once and for all the parsing % job and inherit a gigantic nested macro. Originally only f-expandable % nesting. The initial motivation was that the |\csname| encapsulation impacted % the string pool memory. Later this work proved to be the basis to provide % support for implementing % user-defined functions and it is now its main purpose. % % Deep refactorings happened at 1.3 and 1.4. % % At 1.3 the crucial idea of the «hook» macros was introduced, reducing % considerably the preparatory work done by |\xintNewExpr|. % % At 1.4 further considerable simplifications happened, and it is possible % that the author currently does at long last understand the code! % % The 1.3 code had serious complications with trying % to identify would-be «list» arguments, distinguishing them from «single» % arguments (things like parsing |#2+[[#1..[#3]..#4][#5:#6]]*#7| and convert % it to a single nested f-exandable macro...) % % The conversion at 1.4 is both more powerful and simpler, due in part to the % new storage model which from |\csname| encapsulated comma separated values % up to 1.3f became simply a braced list of braced values, and also crucially % due to the possibilities opened up by usage of |\expanded| primitive. % % \begin{macrocode} \catcode`~ 12 \def\XINT:NE:hastilde#1~#2#3\relax{\unless\if !#21\fi}% \def\XINT:NE:hashash#1{% \def\XINT:NE:hashash##1#1##2##3\relax{\unless\if !##21\fi}% }\expandafter\XINT:NE:hashash\string#% \def\XINT:NE:unpack #1{% \def\XINT:NE:unpack ##1% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \expandafter\XINT:NE:unpack:p\fi \xint_stop_atfirstofone{##1}% }}\expandafter\XINT:NE:unpack\string#% \def\XINT:NE:unpack:p#1#2% {{~romannumeral0~expandafter~xint_stop_atfirstofone~expanded{#2}}}% \def\XINT:NE:f:one:from:one #1{% \def\XINT:NE:f:one:from:one ##1% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:from:one_a\fi \xint_orthat\XINT:NE:f:one:from:one_b ##1&&A% }}\expandafter\XINT:NE:f:one:from:one\string#% \def\XINT:NE:f:one:from:one_a\romannumeral`&&@#1#2&&A% {% \expandafter{\detokenize{\expandafter#1}#2}% }% \def\XINT:NE:f:one:from:one_b#1{% \def\XINT:NE:f:one:from:one_b\romannumeral`&&@##1##2&&A% {% \expandafter{\romannumeral`&&@% \if0\XINT:NE:hastilde ##2~!\relax \XINT:NE:hashash ##2#1!\relax 0\else \expandafter\string\fi ##1{##2}}% }}\expandafter\XINT:NE:f:one:from:one_b\string#% \def\XINT:NE:f:one:from:one:direct #1#2{\XINT:NE:f:one:from:one:direct_a #2&&A{#1}}% \def\XINT:NE:f:one:from:one:direct_a #1#2&&A#3% {% \if ###1\xint_dothis {\detokenize{#3}}\fi \if ~#1\xint_dothis {\detokenize{#3}}\fi \xint_orthat {#3}{#1#2}% }% \def\XINT:NE:f:one:from:two #1{% \def\XINT:NE:f:one:from:two ##1% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:from:two_a\fi \xint_orthat\XINT:NE:f:one:from:two_b ##1&&A% }}\expandafter\XINT:NE:f:one:from:two\string#% \def\XINT:NE:f:one:from:two_a\romannumeral`&&@#1#2&&A% {% \expandafter{\detokenize{\expandafter#1\expanded}{#2}}% }% \def\XINT:NE:f:one:from:two_b#1{% \def\XINT:NE:f:one:from:two_b\romannumeral`&&@##1##2##3&&A% {% \expandafter{\romannumeral`&&@% \if0\XINT:NE:hastilde ##2##3~!\relax \XINT:NE:hashash ##2##3#1!\relax 0\else \expandafter\string\fi ##1{##2}{##3}}% }}\expandafter\XINT:NE:f:one:from:two_b\string#% \def\XINT:NE:f:one:from:two:direct #1#2#3{\XINT:NE:two_fork #2&&A#3&&A#1{#2}{#3}}% \def\XINT:NE:two_fork #1#2&&A#3#4&&A{\XINT:NE:two_fork_nn#1#3}% \def\XINT:NE:two_fork_nn #1#2% {% \if #1##\xint_dothis\string\fi \if #1~\xint_dothis\string\fi \if #2##\xint_dothis\string\fi \if #2~\xint_dothis\string\fi \xint_orthat{}% }% \def\XINT:NE:f:one:and:opt:direct#1{% \def\XINT:NE:f:one:and:opt:direct##1!% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:and:opt_a\fi \xint_orthat\XINT:NE:f:one:and:opt_b ##1&&A% }}\expandafter\XINT:NE:f:one:and:opt:direct\string#% \def\XINT:NE:f:one:and:opt_a #1#2&&A#3#4% {% \detokenize{\romannumeral-`0\expandafter#1\expanded{#2}$XINT_expr_exclam#3#4}%$ }% \def\XINT:NE:f:one:and:opt_b\XINT:expr:f:one:and:opt #1#2#3&&A#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\XINT:NE:f:one:from:one:direct#4}% {\expandafter\XINT:NE:f:onewithopttoone\expandafter#5% \expanded{{\XINT:NE:f:one:from:one:direct\calxListItemToNum{#2}}}}% {#1}% }% \def\XINT:NE:f:onewithopttoone#1#2#3{\XINT:NE:two_fork #2&&A#3&&A#1[#2]{#3}}% \def\XINT:NE:f:tacitzeroifone:direct#1{% \def\XINT:NE:f:tacitzeroifone:direct##1!% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:and:opt_a\fi \xint_orthat\XINT:NE:f:tacitzeroifone_b ##1&&A% }}\expandafter\XINT:NE:f:tacitzeroifone:direct\string#% \def\XINT:NE:f:tacitzeroifone_b\XINT:expr:f:tacitzeroifone #1#2#3&&A#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\XINT:NE:f:one:from:two:direct#4{0}}% {\expandafter\XINT:NE:f:one:from:two:direct\expandafter#5% \expanded{{\XINT:NE:f:one:from:one:direct\calxListItemToNum{#2}}}}% {#1}% }% \def\XINT:NE:f:iitacitzeroifone:direct#1{% \def\XINT:NE:f:iitacitzeroifone:direct##1!% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:iitacitzeroifone_a\fi \xint_orthat\XINT:NE:f:iitacitzeroifone_b ##1&&A% }}\expandafter\XINT:NE:f:iitacitzeroifone:direct\string#% \def\XINT:NE:f:iitacitzeroifone_a #1#2&&A#3% {% \detokenize {\romannumeral`$XINT_expr_null\expandafter#1\expanded{#2}$XINT_expr_exclam#3}% }% \def\XINT:NE:f:iitacitzeroifone_b\XINT:expr:f:iitacitzeroifone #1#2#3&&A#4% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\XINT:NE:f:one:from:two:direct#4{0[0]}}% {\XINT:NE:f:one:from:two:direct#4{#2}}% {#1}% }% \def\XINT:NE:x:one:from:two #1#2#3{\XINT:NE:x:one:from:two_fork #2&&A#3&&A#1{#2}{#3}}% \def\XINT:NE:x:one:from:two_fork #1{% \def\XINT:NE:x:one:from:two_fork ##1##2&&A##3##4&&A% {% \if0\XINT:NE:hastilde ##1##3~!\relax\XINT:NE:hashash ##1##3#1!\relax 0% \else \expandafter\XINT:NE:x:one:from:two:p \fi }}\expandafter\XINT:NE:x:one:from:two_fork\string#% \def\XINT:NE:x:one:from:two:p #1#2#3% {~expanded{\detokenize{\expandafter#1}~expanded{{#2}{#3}}}}% \def\XINT:NE:x:listsel #1{% \def\XINT:NE:x:listsel ##1##2&% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash\detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:listsel:p \fi ##1##2&% }}\expandafter\XINT:NE:x:listsel\string#% \def\XINT:NE:x:listsel:p #1#2_#3&(#4% {% \detokenize{\expanded\XINT:expr:ListSel{{#3}{#4}}}% }% \def\XINT:expr:ListSel{\expandafter\XINT:expr:ListSel_i\expanded}% \def\XINT:expr:ListSel_i #1#2{{\XINT_ListSel_top #2_#1&({#2}}}% \def\XINT:NE:f:reverse #1{% \def\XINT:NE:f:reverse ##1^% {% \if0\expandafter\XINT:NE:hastilde\detokenize\expandafter{\xint_gobble_i##1}~!\relax \expandafter\XINT:NE:hashash\detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:f:reverse:p \fi ##1^% }}\expandafter\XINT:NE:f:reverse\string#% \def\XINT:NE:f:reverse:p #1^#2\xint_bye {% \expandafter\XINT:NE:f:reverse:p_i\expandafter{\xint_gobble_i#1}% }% \def\XINT:NE:f:reverse:p_i #1% {% \detokenize{\romannumeral0\XINT:expr:f:reverse{{#1}}}% }% \def\XINT:expr:f:reverse{\expandafter\XINT:expr:f:reverse_i\expanded}% \def\XINT:expr:f:reverse_i #1% {% \XINT_expr_reverse #1^^#1\xint:\xint:\xint:\xint: \xint:\xint:\xint:\xint:\xint_bye }% \def\XINT:NE:f:from:delim:u #1{% \def\XINT:NE:f:from:delim:u ##1##2^% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash\detokenize{##2}#1!\relax 0% \xint_afterfi{\expandafter\XINT_fooof_checkifnumber\expandafter##1\string}% \else \xint_afterfi{\XINT:NE:f:from:delim:u:p##1\empty}% \fi ##2^% }}\expandafter\XINT:NE:f:from:delim:u\string#% \def\XINT:NE:f:from:delim:u:p #1#2^% {% \detokenize {\expandafter\XINT:fooof:checkifnumber\expandafter#1}~expanded{#2}$XINT_expr_caret%$ }% \def\XINT:fooof:checkifnumber#1{\expandafter\XINT_fooof_checkifnumber\expandafter#1\string}% \def\XINT:NE:f:LFL#1#2{\expandafter\XINT:NE:f:LFL_a\expandafter#1#2\XINT:NE:f:LFL_a}% \def\XINT:NE:f:LFL_a#1#2% {% \if#2i\else\expandafter\XINT:NE:f:LFL_p \fi #1% }% \def\XINT:NE:r:check#1{% \def\XINT:NE:r:check##1\XINT:NE:f:LFL_a {% \if0\expandafter\XINT:NE:hastilde\detokenize{##1}~!\relax% \expandafter\XINT:NE:hashash\detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:r:check:p \fi 1\expandafter{\romannumeral\XINT:NEsaved:r:check##1}% }}\expandafter\XINT:NE:r:check\string#% \def\XINT:NE:r:check:p 1\expandafter#1{\XINT:NE:r:check:p_i#1}% \def\XINT:NE:r:check:p_i\romannumeral\XINT:NEsaved:r:check{\XINT:NE:r:check:p_ii\empty}% \def\XINT:NE:r:check:p_ii#1^% {% 5~expanded{{~romannumeral~XINT:NEsaved:r:check#1$XINT_expr_caret}}%$ }% \def\XINT:NE:f:LFL_p#1% {% \detokenize{\romannumeral`$XINT_expr_null\expandafter#1}%$ }% \catcode`- 11 \def\XINT:NE:exec_? #1#2% {% \XINT:NE:exec_?_b #2&&A#1{#2}% }% % \end{macrocode} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT:NE:exec_?_b #1{% \def\XINT:NE:exec_?_b ##1&&A% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0% \xint_dothis\XINT:NE:exec_?:x\fi \xint_orthat\XINT:NE:exec_?:p }}\expandafter\XINT:NE:exec_?_b\string#% \def\XINT:NE:exec_?:x #1#2#3% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\CALX_ifnz#3% }% \def\XINT:NE:exec_?:p #1#2#3#4#5% {% \csname XINT_expr_func_*If\expandafter\endcsname \romannumeral`&&@#2\XINTfstop.{#3},[#4],[#5])% }% \expandafter\def\csname XINT_expr_func_*If\endcsname #1#2#3% {% #1#2{~expanded{~calxifNotZero#3}}% }% \def\XINT:NE:exec_?? #1#2#3% {% \XINT:NE:exec_??_b #2&&A#1{#2}% }% \def\XINT:NE:exec_??_b #1{% \def\XINT:NE:exec_??_b ##1&&A% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0% \xint_dothis\XINT:NE:exec_??:x\fi \xint_orthat\XINT:NE:exec_??:p }}\expandafter\XINT:NE:exec_??_b\string#% \def\XINT:NE:exec_??:x #1#2#3% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\CALX_ifsgn#3% }% \def\XINT:NE:exec_??:p #1#2#3#4#5#6% {% \csname XINT_expr_func_*IfSgn\expandafter\endcsname \romannumeral`&&@#2\XINTfstop.{#3},[#4],[#5],[#6])% }% \expandafter\def\csname XINT_expr_func_*IfSgn\endcsname #1#2#3% {% #1#2{~expanded{~calxifSgn#3}}% }% \catcode`- 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT:NE:branch #1% {% \if0\XINT:NE:hastilde #1~!\relax 0\else \xint_dothis\XINT:NE:branch_a\fi \xint_orthat\XINT:NE:branch_b #1&&A% }% \def\XINT:NE:branch_a\romannumeral`&&@#1#2&&A% {% \expandafter{\detokenize{\expandafter#1\expanded}{#2}}% }% \def\XINT:NE:branch_b#1{% \def\XINT:NE:branch_b\romannumeral`&&@##1##2##3&&A% {% \expandafter{\romannumeral`&&@% \if0\XINT:NE:hastilde ##2~!\relax \XINT:NE:hashash ##2#1!\relax 0\else \expandafter\string\fi ##1{##2}##3}% }}\expandafter\XINT:NE:branch_b\string#% \def\XINT:NE:seqx#1{% \def\XINT:NE:seqx\XINT_allexpr_seqx##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:seqx:p \fi \XINT_allexpr_seqx{##1}{##2}% }}\expandafter\XINT:NE:seqx\string#% \def\XINT:NE:seqx:p\XINT_allexpr_seqx #1#2#3#4% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded {\xint_noxpd{\XINT_expr_seq:_b{#1#4\relax $XINT_expr_exclam #3}}% #2$XINT_expr_caret}% }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:opx#1{% \def\XINT:NE:opx\XINT_allexpr_opx ##1##2##3##4%##5##6##7##8% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##4}~!\relax \expandafter\XINT:NE:hashash \detokenize{##4}#1!\relax 0% \else \expandafter\XINT:NE:opx:p \fi \XINT_allexpr_opx ##1{##2}{##3}{##4}% en fait ##2 = \xint_c_, ##3 = \relax }}\expandafter\XINT:NE:opx\string#% \def\XINT:NE:opx:p\XINT_allexpr_opx #1#2#3#4#5#6#7#8% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{\xint_noxpd{\XINT_expr_iter:_b {#1\expandafter\XINT_allexpr_opx_ifnotomitted \romannumeral0#1#6\relax#7@\relax $XINT_expr_exclam #5}}% #4$XINT_expr_caret$XINT_expr_tilde{{#8}}}%$ }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:iter{\expandafter\XINT:NE:itery\expandafter}% \def\XINT:NE:itery#1{% \def\XINT:NE:itery\XINT_expr_itery##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:itery:p \fi \XINT_expr_itery{##1}{##2}% }}\expandafter\XINT:NE:itery\string#% \def\XINT:NE:itery:p\XINT_expr_itery #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{\xint_noxpd{\XINT_expr_iter:_b {#5#4\relax $XINT_expr_exclam #3}}% #1$XINT_expr_caret$XINT_expr_tilde{#2}}%$ }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:rseq{\expandafter\XINT:NE:rseqy\expandafter}% \def\XINT:NE:rseqy#1{% \def\XINT:NE:rseqy\XINT_expr_rseqy##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:rseqy:p \fi \XINT_expr_rseqy{##1}{##2}% }}\expandafter\XINT:NE:rseqy\string#% \def\XINT:NE:rseqy:p\XINT_expr_rseqy #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{#2\xint_noxpd{\XINT_expr_rseq:_b {#5#4\relax $XINT_expr_exclam #3}}% #1$XINT_expr_caret$XINT_expr_tilde{#2}}%$ }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:iterr{\expandafter\XINT:NE:iterry\expandafter}% \def\XINT:NE:iterry#1{% \def\XINT:NE:iterry\XINT_expr_iterry##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:iterry:p \fi \XINT_expr_iterry{##1}{##2}% }}\expandafter\XINT:NE:iterry\string#% \def\XINT:NE:iterry:p\XINT_expr_iterry #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{\xint_noxpd{\XINT_expr_iterr:_b {#5#4\relax $XINT_expr_exclam #3}}% #1$XINT_expr_caret$XINT_expr_tilde #20$XINT_expr_qmark}% }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:rrseq{\expandafter\XINT:NE:rrseqy\expandafter}% \def\XINT:NE:rrseqy#1{% \def\XINT:NE:rrseqy\XINT_expr_rrseqy##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:rrseqy:p \fi \XINT_expr_rrseqy{##1}{##2}% }}\expandafter\XINT:NE:rrseqy\string#% \def\XINT:NE:rrseqy:p\XINT_expr_rrseqy #1#2#3#4#5#6% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{#2\xint_noxpd{\XINT_expr_rrseq:_b {#6#5\relax $XINT_expr_exclam #4}}% #1$XINT_expr_caret$XINT_expr_tilde #30$XINT_expr_qmark}% }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:x:toblist#1{% \def\XINT:NE:x:toblist\XINT:expr:toblistwith##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:toblist:p \fi \XINT:expr:toblistwith{##1}{##2}% }}\expandafter\XINT:NE:x:toblist\string#% \def\XINT:NE:x:toblist:p\XINT:expr:toblistwith #1#2{{\XINTfstop.{#2}}}% \def\XINT:NE:x:flatten#1{% \def\XINT:NE:x:flatten\XINT:expr:flatten##1% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:x:flatten:p \fi \XINT:expr:flatten{##1}% }}\expandafter\XINT:NE:x:flatten\string#% \def\XINT:NE:x:flatten:p\XINT:expr:flatten #1% {% {{% \detokenize {% \expandafter\XINT:expr:flatten_checkempty \detokenize\expandafter{\expanded{#1}}$XINT_expr_caret%$ }% }}% }% \def\XINT:NE:x:zip#1{% \def\XINT:NE:x:zip\XINT:expr:zip##1% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:x:zip:p \fi \XINT:expr:zip{##1}% }}\expandafter\XINT:NE:x:zip\string#% \def\XINT:NE:x:zip:p\XINT:expr:zip #1% {% \expandafter{% \detokenize {% \expanded\expandafter\XINT_zip_A\expanded{#1}\xint_bye\xint_bye }% }% }% \def\XINT:NE:x:mapwithin#1{% \def\XINT:NE:x:mapwithin\XINT:expr:mapwithin ##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:mapwithin:p \fi \XINT:expr:mapwithin {##1}{##2}% }}\expandafter\XINT:NE:x:mapwithin\string#% \def\XINT:NE:x:mapwithin:p \XINT:expr:mapwithin #1#2% {% {{% \detokenize {% % \end{macrocode} % Attention (2022/06/10) I do not remember why I left these two commented % lines which docstrip will not remove, I hope this is not a forgotten % left=over from some debugging session. % \begin{macrocode} %% \expanded %% {% \expandafter\XINT:expr:mapwithin_checkempty \expanded{\noexpand#1$XINT_expr_exclam\expandafter}%$ \detokenize\expandafter{\expanded{#2}}$XINT_expr_caret%$ % \end{macrocode} % This is is the matching one. % \begin{macrocode} %% }% }% }}% }% \def\XINT:NE:x:ndmapx#1{% \def\XINT:NE:x:ndmapx\XINT_allexpr_ndmapx_a ##1##2^% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:ndmapx:p \fi \XINT_allexpr_ndmapx_a ##1##2^% }}\expandafter\XINT:NE:x:ndmapx\string#% \def\XINT:NE:x:ndmapx:p #1#2#3^\relax {% \detokenize {% \expanded{% \expandafter#1\expandafter#2\expanded{#3}$XINT_expr_caret\relax %$ }% }% }% % \end{macrocode} %\begin{lverb} % Attention here that user function % names may contain digits, so we don't use a \detokenize or ~ approach. % % This syntax means that a function defined by \xintdeffunc never expands % when used in another definition, so it can implement recursive definitions. % % \XINT:NE:userefunc et al. added at 1.3e. % % I added at \xintdefefunc, \xintdefiiefunc, \xintdeffloatefunc at 1.3e to on % the contrary expand if possible (i.e. if used only with numeric arguments) % in another definition. % % The \XINTusefunc % uses \expanded. Its ancestor \xintExpandArgs (xinttools 1.3) % had some more primitive f-expansion technique. %\end{lverb} % \begin{macrocode} \def\XINTusenoargfunc #1% {% 0\csname #1\endcsname }% \def\XINT:NE:usernoargfunc\csname #1\endcsname {% ~romannumeral~XINTusenoargfunc{#1}% }% \def\XINTusefunc #1% {% 0\csname #1\expandafter\endcsname\expanded }% \def\XINT:NE:usefunc #1#2#3% {% ~romannumeral~XINTusefunc{#1}{#3}\iffalse{{\fi}}% }% \def\XINTuseufunc #1% {% \expanded\expandafter\XINT:expr:mapwithin\csname #1\expandafter\endcsname\expanded }% \def\XINT:NE:useufunc #1#2#3% {% {{~expanded~XINTuseufunc{#1}{#3}}}% }% \def\XINT:NE:userfunc #1{% \def\XINT:NE:userfunc ##1##2##3% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##3}~!\relax \expandafter\XINT:NE:hashash\detokenize{##3}#1!\relax 0% \expandafter\XINT:NE:userfunc_x \else \expandafter\XINT:NE:usefunc \fi {##1}{##2}{##3}% }}\expandafter\XINT:NE:userfunc\string#% \def\XINT:NE:userfunc_x #1#2#3{#2#3\iffalse{{\fi}}}% \def\XINT:NE:userufunc #1{% \def\XINT:NE:userufunc ##1##2##3% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##3}~!\relax \expandafter\XINT:NE:hashash\detokenize{##3}#1!\relax 0% \expandafter\XINT:NE:userufunc_x \else \expandafter\XINT:NE:useufunc \fi {##1}{##2}{##3}% }}\expandafter\XINT:NE:userufunc\string#% \def\XINT:NE:userufunc_x #1{\XINT:expr:mapwithin}% \def\XINT:NE:macrofunc #1#2% {\expandafter\XINT:NE:macrofunc:a\string#1#2\empty&}% \def\XINT:NE:macrofunc:a#1\csname #2\endcsname#3&% {{~XINTusemacrofunc{#1}{#2}{#3}}}% \def\XINTusemacrofunc #1#2#3% {% \romannumeral0\expandafter\xint_stop_atfirstofone \romannumeral0#1\csname #2\endcsname#3\relax }% % \end{macrocode} % \subsubsection{\csh{XINT_expr_redefinemacros}} %\begin{lverb} % Completely refactored at 1.3. % % Again refactored at 1.4. The availability of \expanded allows more powerful % mechanisms and more importantly I better thought out the root problems % caused by the handling of list operations in this context and this helped % simplify considerably the code. %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }^^A % \begin{macrocode} \catcode`- 11 \catcode0 11 \catcode2 11 \catcode3 11 \def\XINT_expr_redefinemacros {% \let\XINT:NEhook:unpack \XINT:NE:unpack \let\XINT:NEhook:f:one:from:one \XINT:NE:f:one:from:one \let\XINT:NEhook:f:one:from:one:direct \XINT:NE:f:one:from:one:direct \let\XINT:NEhook:f:one:from:two \XINT:NE:f:one:from:two \let\XINT:NEhook:f:one:from:two:direct \XINT:NE:f:one:from:two:direct \let\XINT:NEhook:x:one:from:two \XINT:NE:x:one:from:two \let\XINT:NEhook:f:one:and:opt:direct \XINT:NE:f:one:and:opt:direct \let\XINT:NEhook:f:tacitzeroifone:direct \XINT:NE:f:tacitzeroifone:direct \let\XINT:NEhook:f:iitacitzeroifone:direct \XINT:NE:f:iitacitzeroifone:direct \let\XINT:NEhook:x:listsel \XINT:NE:x:listsel \let\XINT:NEhook:f:reverse \XINT:NE:f:reverse \let\XINT:NEhook:f:from:delim:u \XINT:NE:f:from:delim:u \let\XINT:NEhook:f:LFL \XINT:NE:f:LFL \let\XINT:NEhook:r:check \XINT:NE:r:check \let\XINT:NEhook:branch \XINT:NE:branch \let\XINT:NEhook:seqx \XINT:NE:seqx \let\XINT:NEhook:opx \XINT:NE:opx \let\XINT:NEhook:rseq \XINT:NE:rseq \let\XINT:NEhook:iter \XINT:NE:iter \let\XINT:NEhook:rrseq \XINT:NE:rrseq \let\XINT:NEhook:iterr \XINT:NE:iterr \let\XINT:NEhook:x:toblist \XINT:NE:x:toblist \let\XINT:NEhook:x:flatten \XINT:NE:x:flatten \let\XINT:NEhook:x:zip \XINT:NE:x:zip \let\XINT:NEhook:x:mapwithin \XINT:NE:x:mapwithin \let\XINT:NEhook:x:ndmapx \XINT:NE:x:ndmapx \let\XINT:NEhook:userfunc \XINT:NE:userfunc \let\XINT:NEhook:userufunc \XINT:NE:userufunc \let\XINT:NEhook:usernoargfunc \XINT:NE:usernoargfunc \let\XINT:NEhook:macrofunc \XINT:NE:macrofunc \def\XINTinRandomFloatSdigits{~XINTinRandomFloatSdigits }% \def\XINTinRandomFloatSixteen{~XINTinRandomFloatSixteen }% \def\calxFpRandomSdigits{~calxFpRandomSdigits }% \def\calxFpRandomSixteen{~calxFpRandomSixteen }% \def\calxintRandRange{~calxintRandRange }% \def\calxintRandRangeAtoB{~calxintRandRangeAtoB }% \def\xintRandBit{~xintRandBit }% \let\XINT_expr_exec_? \XINT:NE:exec_? \let\XINT_expr_exec_?? \XINT:NE:exec_?? \def\XINT_expr_op_? {\XINT_expr_op__?{\XINT_expr_op_-xii\XINT_expr_oparen}}% \def\XINT_flexpr_op_?{\XINT_expr_op__?{\XINT_flexpr_op_-xii\XINT_flexpr_oparen}}% \def\XINT_iiexpr_op_?{\XINT_expr_op__?{\XINT_iiexpr_op_-xii\XINT_iiexpr_oparen}}% % \end{macrocode} %\begin{lverb} % calx: \xintiieval literals stay raw in compiled functions and macros: % their meaning is detokenized and rescanned, where native M values would % come back with a catcode 11 tag; the ii operations convert raw integers % on entry. The fake operators &&@, &&B, &&C of \xintiieval put the % literal as it is (&&C as in \xintfloateval). %\end{lverb} % \begin{macrocode} \def\XINT_iiexpr_op_&&@ ##1##2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\CALX_rawE##1{\xint_zapspaces ##2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_iiexpr_op_&&B ##1% {% \expandafter\XINT_expr_put_op_first \expanded{{{\xint_noxpd##1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% \let\XINT_iiexpr_op_&&C\XINT_flexpr_op_&&C }% \catcode`- 12 \catcode0 12 \catcode2 12 \catcode3 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsubsection{Still more mysterious} % \label{\xintimplabelprefix XINT_NewExpr} % \label{\xintimplabelprefix XINT_NewExpr_a} % \changed{2.0a1} % % |\XINT_NewExpr| is the kernel underlying both \csbxint{deffunc} and % \csbxint{NewExpr}. Actually we declare here only \csbxint{deffloatfunc} and % \csbxint{defiifunc}. All user level definitions, including all "NewExpr" % variants are in \xintexprnameimp.sty. Nothing was changed at release % |2.0a1|. Only the split into \calxnameimp.sty/\xintexprnameimp.sty kept % here only \csbxint{deffloatfunc} and \csbxint{defiifunc}. % %\begin{lverb} % 1.2c for \xintdeffunc, \xintdefiifunc, \xintdeffloatfunc. % % At 1.3, NewFunc does not use anymore a comma delimited pattern for the % arguments to the macro being defined. % % At 1.4 we use \xintthebareeval, whose meaning now does not mean unlock % from csname but firstofone to remove a level of braces % This is involved in functioning of expr:userfunc and expr:userefunc %\end{lverb} % \begin{macrocode} \def\XINT_NewFloatFunc{\XINT_NewExpr\xint_gobble_i\xintthebarefloateval\XINT_newfunc_clean}% \def\XINT_NewIIFunc {\XINT_NewExpr\xint_gobble_i\xintthebareiieval\XINT_newfunc_clean}% \def\XINT_newfunc_clean #1>{}% \ifdefined\notexpanded\let\XINT_newfunc_clean\xint_gobble_vi\fi% % \end{macrocode} %\begin{lverb} % 1.2c adds optional logging. For this needed to pass to _NewExpr_a the % macro name as parameter. % % Up to and including 1.2c the definition was global. Starting with 1.2d it is % done locally. % % The \xintexprSafeCatcodes inserted here by \xintNewExpr % is not paired with an \xintexprRestoreCatcodes, % but this happens within a scope limiting group so does not matter. % At 1.3c, \XINT_NewFunc et al. do not even execute the % \xintexprSafeCatcodes, as it gets already done by \xintdeffunc prior % to arriving here. % %\end{lverb} % \begin{macrocode} \def\XINT_NewExpr {\begingroup\XINT_NewExpr_a}% \def\XINT_NewExpr_a #1#2#3#4#5[#6]% {% \ifcase #6\relax \toks0 {\endgroup\XINT_global\def#4}% \or \toks0 {\endgroup\XINT_global\def#4##1}% \or \toks0 {\endgroup\XINT_global\def#4##1##2}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6##7}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6##7##8}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6##7##8##9}% \fi #1\xintexprSafeCatcodes \XINT_expr_redefinemacros \XINT_NewExpr_b #1#2#3#4% }% % \end{macrocode} %\begin{lverb} % $catcode38 12 % % 1.2d's \xintNewExpr makes a local definition. In earlier releases, the % definition was global. % % \the\toks0 inserts the \endgroup, but this will happen % after \XINT_tmpa has already been expanded... % % The $%1 is \xint_firstofone for \xintNewExpr, \xint_gobble_i % for \xintdeffunc. % % Attention that at 1.4, there might be entire sub-xintexpressions embedded in % detokenized form. They are re-tokenized and the main thing is that the % parser should not mis-interpret catcode 11 characters as starting variable % names. As some macros use : in their names, the retokenization must be done % with : having catcode 11. To not break embedded non-evaluated % sub-expressions, the \XINT_expr_getop was extended to intercept the : % (alternative would have been to never inject any macro with : in its name... % too late now). On the other hand the ! is not used in the macro names % potentially kept as is non expanded by the \xintNewExpr/\xintdeffunc % process; it can thus be retokenized with catcode 12. But the «hooks» of % seq(), iter(), etc... if deciding they can't evaluate immediately will % inject a full sub-expression (possibly arbitrarily complicated) and append % to it for its delayed expansion a catcode 11 ! character (as well as % possibly catcode 3 ~ and ? and catcode 11 caret ^ and even catcode 7 $&). % The macros \XINT_expr_tilde etc... below serve for this injection (there are % *two* successive \scantokens using different catcode regimes and these % macros remain detokenized during the first pass!) and as consequence the % final meaning may have characters such as ! or & present with both standard % and special catcodes depending on where they are located. It may thus not be % possible to (easily) retokenize the meaning as printed in the log file if % \xintverbosetrue was issued. % % If a defined function is used in another expression it would thus break % things if its meaning was included pre-expanded ; a mechanism exists which % keeps only the name of the macro associated to the function (this name may % contain digits by the way), when the macro can not be immediately fully % expanded. Thus its meaning (with its possibly funny catcodes) is not % exposed. And this gives opportunity to pre-expand its arguments before % actually expanding the macro. % % There is a problem with xetex -8bit which will convert ^^@ possibly present % in the meaning written to log if \xintverbosetrue into a null byte. It % surprises at first, but perhaps because I am too much used to pdftex and luatex % converting the zero byte perhaps produced meaning internally to ^^@ notation % at the "output" stage. % % I observed that ConTeXt will spit out such null byte "as is", as does xetex % -8bit. This is a bit annoying because contrarily to xetex no option is % needed, and such output lets some software consider the output file is a % binary one (for example git diff). %\end{lverb} % \begin{macrocode} \catcode`~ 3 \catcode`? 3 \def\XINT_expr_tilde{~}\def\XINT_expr_qmark{?}% catcode 3 \def\XINT_expr_caret{^}\def\XINT_expr_exclam{!}% catcode 11 \def\XINT_expr_tab{&}% catcode 7 \def\XINT_expr_null{&&@}% % \end{macrocode} % \added{1.4n} Add \cs{xintmeaning} for matters of package test suite. % At user level, a priori simply expands to \cs{meaning}. It gets % redefined during execution of the test suite to keep logged expectations % the same also with LMTX engine. % \begin{macrocode} \ifdefined\xintmeaning\else\def\xintmeaning{\meaning}\fi % \end{macrocode} % \added{1.4n} %\begin{lverb} % Add \XINT_expr_set_tilde to address LuaMeta$TeX$ specifics. % We won't need to restore because we will be in a group and \toks0 will % bring the \endgroup. %\end{lverb} % % When I observed that the whole \csbxint{deffunc} thing was broken with % Con\TeX t due to what appeared to be some weirdness during expansion, I % realized much to my surprise that the active tilde was not expanding inside % \cs{edef}! I got lucky I could quickly find a then recent discussion % precisely about this on % \href{https://tex.stackexchange.com/q/749050}{tex.sx}, from which I picked % up the \cs{amcode} workaround. Such a trick is quite hidden in Con\TeX t % documentation, from which it is a long shot to deduce it behaves as it % actually does. % % Replacing about 130 occurrences of |~| in this file which are a core part of % the mysterious dealings underpinning \csbxint{deffunc} is not really an % option. I don't have that many available ascii characters and I do not want % to go into mass replacements and have to update unit tests sometimes % checking internals. What a relief there is the \cs{amcode} way! (and seemingly % no other way...). % \begin{macrocode} \catcode`~ 13 \catcode`$ 11 %$ \def\XINT_NewExpr_set_tilde{\def~{$noexpand$}}% \ifdefined\contextversion \ifdefined\amcode \def\XINT_NewExpr_set_tilde{\amcode`\~0\def~{$noexpand$}}% \else \xintMessage{xintexpr}{Error}{This ConTeXt is incompatible.}% \errhelp{xintexpr requires ConTeXt-LMTX to have its \string\amcode.}% \errmessage{The \noexpand\amcode primitive does not exist.}% \fi \fi \catcode`@ 14 \catcode`\% 6 \catcode`# 12 \def\XINT_NewExpr_b %1%2%3%4%5@ {@ \def\XINT_tmpa %%1%%2%%3%%4%%5%%6%%7%%8%%9{%5}@ \XINT_NewExpr_set_tilde \catcode`: 11 \catcode`_ 11 \catcode`\@ 11 \catcode`# 12 \catcode`~ 13 \escapechar 126 \endlinechar -1 \everyeof {\noexpand }@ \edef\XINT_tmpb {\scantokens\expandafter{\romannumeral`&&@\expandafter %2\XINT_tmpa{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}@ }@ \escapechar 92 \catcode`# 6 \catcode`$ 0 @ $ \edef\XINT_tmpa %%1%%2%%3%%4%%5%%6%%7%%8%%9@ {\scantokens\expandafter{\expandafter%3\meaning\XINT_tmpb}}@ \the\toks0\expandafter {\XINT_tmpa{%%1}{%%2}{%%3}{%%4}{%%5}{%%6}{%%7}{%%8}{%%9}}@ %1{\ifxintverbose \xintMessage{xintexpr}{Info}@ {\string%4\space now with @ \ifxintglobaldefs global \fi meaning \xintmeaning%4}@ \fi}@ }@ \catcode`% 14 \XINTsetcatcodes % clean up to avoid surprises if something changes % \end{macrocode} % \subsubsection{\csh{xintexprSafeCatcodes}, \csh{xintexprRestoreCatcodes}} % \changed[2018/06/17]{1.3c} %\begin{lverb} % Added \ifxintexprsafecatcodes to allow nesting %\end{lverb} % \changed[2022/05/15]{1.4k} %\begin{lverb} % The "allow nesting" from the 2018 comment was strange, because % the behaviour, as correctly documented in user manual, was that % in case of a series of \xintexprSafeCatcodes, the \xintexprRestoreCatcodes % would set catcodes to what they were before the *first* sanitization. % But as \xintdefvar and \xintdeffunc used such a pair this meant % that they would incomprehensibly for user reset catcodes to what % they were before a possible user \xintexprSafeCatcodes located before... % very lame situation. Anyway. I finally % fix at 1.4k that by removing the silly \ifxintexprsafecatcodes thing % and replace it by some stack-like method, avoiding extra macros % thanks to the help of \unexpanded. %\end{lverb} % \changed{1.4m} Use |\protected| rather than |\unexpanded| mechanism, % for lisibility. % \begin{macrocode} \protected\def\xintexprRestoreCatcodes{}% \def\xintexprSafeCatcodes {% \protected\edef\xintexprRestoreCatcodes{% \endlinechar=\the\endlinechar \catcode59=\the\catcode59 % ; \catcode34=\the\catcode34 % " \catcode63=\the\catcode63 % ? \catcode124=\the\catcode124 % | \catcode38=\the\catcode38 % & \catcode33=\the\catcode33 % ! \catcode93=\the\catcode93 % ] \catcode91=\the\catcode91 % [ \catcode94=\the\catcode94 % ^ \catcode95=\the\catcode95 % _ \catcode47=\the\catcode47 % / \catcode41=\the\catcode41 % ) \catcode40=\the\catcode40 % ( \catcode42=\the\catcode42 % * \catcode43=\the\catcode43 % + \catcode62=\the\catcode62 % > \catcode60=\the\catcode60 % < \catcode58=\the\catcode58 % : \catcode46=\the\catcode46 % . \catcode45=\the\catcode45 % - \catcode44=\the\catcode44 % , \catcode61=\the\catcode61 % = \catcode96=\the\catcode96 % ` \catcode32=\the\catcode32\relax % space \protected\odef\xintexprRestoreCatcodes{\xintexprRestoreCatcodes}% }% \endlinechar=13 % \catcode59=12 % ; \catcode34=12 % " \catcode63=12 % ? \catcode124=12 % | \catcode38=4 % & \catcode33=12 % ! \catcode93=12 % ] \catcode91=12 % [ \catcode94=7 % ^ \catcode95=8 % _ \catcode47=12 % / \catcode41=12 % ) \catcode40=12 % ( \catcode42=12 % * \catcode43=12 % + \catcode62=12 % > \catcode60=12 % < \catcode58=12 % : \catcode46=12 % . \catcode45=12 % - \catcode44=12 % , \catcode61=12 % = \catcode96=12 % ` \catcode32=10 % space }% \let\XINT_tmpa\undefined \let\XINT_tmpb\undefined \let\XINT_tmpc\undefined \let\XINT_tmpd\undefined \let\XINT_tmpe\undefined % \end{macrocode} %\subsection{The calx layer} %\begin{lverb} % calx: native float operators (wip). % ATTENTION: the ! has catcode 12 here due to prior \XINTsetcatcodes. % % ATTENTION: we do NOT set catcode of M (or N, or F) to 12 here. % They only appear in \if tests, and are needed in macro % names. % % Operator-level macros (letter-only names, frozen in user functions): % two arguments (one for Sqr, Opp), precision \XINTdigits at run time. % % Syntax (all f-expandable; arguments f-expanded, F, I or raw values; P = % \XINTdigits unless given; results F or I values, without leading space): %( % \calxFpAdd{X}{Y}, \calxFpSub, \calxFpMul, \calxFpDiv -> round_P(X op Y) %: \calxFpMulExact{X}{Y} -> X Y exact (X, Y finite F) %: \calxFpDivFloor{X}{Y} -> floor(X'/Y') exact (X' = round_P(X)) %: \calxFpMod{X}{Y} -> round_P(X' - Y' floor(X'/Y')) %: \calxFpDivMod{X}{Y} -> {floor(X'/Y')}{round_P(X' mod Y')} %: \calxFpInv{X} -> round_P(1/X) (X exact) %: \calxFpE{X}{n} -> round_P(X) 10^n (raw A[N]) %: \calxFpSum{X1}...{Xn}^, \calxFpPrd -> (((X1 op X2) op X3) ...), each op %: rounded (+(), *(); empty: 0, 1) %: \calxFpSqr{X}, \calxFpSqrtdigits{X} -> round_P(X^2), round_P(sqrt X) %: \calxFpSqrt[P]{X} -> round_P(sqrt X) %: \calxFpOpp{X}, \calxFpAbs{X} -> -X, |X| (exact) %: \calxSgn{X} -> -1, 0 or 1 (any value) %: \calxFpLt{X}{Y}, \calxFpGt, \calxFpLtorEq, \calxFpGtorEq, %: \calxFpEq, \calxFpNotEq -> 1 or 0 (exact comparison) %: \calxFpMaxof{X1}...{Xn}^, \calxFpMinof -> the largest (smallest) Xi %: \calxFpTrunc{X}, \calxFpFloor{X}, \calxFpCeil{X}, \calxFpFrac{X} %: -> F (raw input: raw result) %: \calxFpITrunc{k}{X}, \calxFpIRound{k}{X} -> trunc(X), round(X) %: \calxFpToNum{X} -> digits of trunc(X) %) % Internal helpers used by other files: \CALX_fcmp{X}{Y} (in \ifcase: 0 % equal, 1 greater, 2 less, 3 unordered), \CALX_fonec (native 1), % \CALX_fopp_a (sign flip), \CALX_ti_f (calxfp: trunc of an F value % followed by \xint:), \CALX_fcnan (InvalidOperation signal of a comparison). %\end{lverb} % \begin{macrocode} \def\calxFpAdd #1#2% {\romannumeral0\expandafter\CALX_fadd_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.}% \def\calxFpSub #1#2% {\romannumeral0\expandafter\CALX_fsub_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.}% \def\calxFpMul #1#2% {\romannumeral0\expandafter\CALX_fmul_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.}% \def\calxFpMulExact #1#2% {\romannumeral0\expandafter\CALX_fmulxs_in\expanded{#1\xint:#2\xint:}}% \def\calxFpDiv #1#2% {\romannumeral0\expandafter\CALX_fdiv_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.}% \def\calxFpDivFloor #1#2% {\romannumeral0\expandafter\CALX_fdq_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.\CALX_fdq_q}% \def\calxFpMod #1#2% {\romannumeral0\expandafter\CALX_fdq_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.\CALX_fdq_r}% \def\calxFpDivMod #1#2% {\romannumeral0\expandafter\CALX_fdq_in\expanded{#1\xint:#2\xint:}\the\XINTdigits.\CALX_fdq_p}% \def\calxFpInv #1% {\romannumeral0\expandafter\CALX_finv_in\romannumeral`&&@#1\xint:\the\XINTdigits.}% \def\calxFpE #1% {\romannumeral0\expandafter\CALX_fe_in\romannumeral`&&@#1\xint:\the\XINTdigits.}% % \end{macrocode} %\begin{lverb} % calx: `+`(), `*`() of \xintfloateval: Burnol's 1.4p \XINT_sum/\XINT_prd % loops (xintfrac), \xintadd/\xintmul replaced by \CALX_fsumop/\CALX_fprdop % (rounded to P at each step, unlike 1.4p's exact \XINT_Sum); empty: 0[0], % 1[0]; one item: returned as it is (f-expanded). %\end{lverb} % \begin{macrocode} \def\calxFpSum {\romannumeral0\CALX_fpsum}% \def\CALX_fpsum #1% {% \xint_gob_til_^ #1\CALX_fpsum_empty ^% \expandafter\CALX_fpsum_loop\romannumeral`&&@#1\xint: }% \def\CALX_fpsum_empty ^#1\xint:{ 0[0]}% \def\CALX_fpsum_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_fpsum_end ^% \expandafter\CALX_fpsum_loop \romannumeral0\CALX_fsumop{#1}{#2}\xint: }% \def\CALX_fpsum_end ^#1\CALX_fsumop #2#3\xint:{ #2}% \def\calxFpPrd {\romannumeral0\CALX_fpprd}% \def\CALX_fpprd #1% {% \xint_gob_til_^ #1\CALX_fpprd_empty ^% \expandafter\CALX_fpprd_loop\romannumeral`&&@#1\xint: }% \def\CALX_fpprd_empty ^#1\xint:{ 1[0]}% \def\CALX_fpprd_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_fpprd_end ^% \expandafter\CALX_fpprd_loop \romannumeral0\CALX_fprdop{#1}{#2}\xint: }% \def\CALX_fpprd_end ^#1\CALX_fprdop #2#3\xint:{ #2}% \def\CALX_fsumop {\CALX_fadd\XINTdigits}% \def\CALX_fprdop {\CALX_fmul\XINTdigits}% \def\calxFpSqr #1% {\romannumeral0\expandafter\CALX_fsqr_in\romannumeral`&&@#1\xint:\the\XINTdigits.}% \def\calxFpSqrtdigits #1% {\romannumeral0\expandafter\CALX_fsqrt_in\romannumeral`&&@#1\xint:\the\XINTdigits.}% \def\calxFpSqrt [#1]#2% {\romannumeral0\expandafter\CALX_fsqrt_in\romannumeral`&&@#2\xint:\the\numexpr#1.}% % \end{macrocode} %\begin{lverb} % \calxFpToNum{X}: explicit digits of trunc(X), where X is a parser % value (possibly still expandable). The ordinary entry takes one brace % level. \calxListItemToNum{X} is for the legacy list selectors, whose % items carry an additional brace level; it strips that level explicitly. % Both paths enter the same conversion kernel, \CALX_fnum, with an % already f-expanded input followed by \xint:. %\end{lverb} % \begin{macrocode} \def\calxFpToNum #1% {\romannumeral0\expandafter\CALX_fnum\romannumeral`&&@#1\xint:}% \def\calxListItemToNum #1% {\romannumeral0\expandafter\CALX_fnum\romannumeral`&&@\xint_firstofone#1% \xint:}% % \end{macrocode} %\begin{lverb} % \calxFpOpp: sign flip, the tag token kept; F+0.0., M+0.0. and I? % unchanged. F, M and I: \CALX_fopp_a. %\end{lverb} % \begin{macrocode} \def\calxFpOpp #1% {\romannumeral0\expandafter\CALX_fopp_e\romannumeral`&&@#1\xint:}% % \end{macrocode} %\begin{lverb} % raw input (strict A[N], A/B[N]): \CALX_fopp_x on the first token, a % leading - removed, a leading 0 (zero) kept, else - prepended. %\end{lverb} % \begin{macrocode} \def\CALX_fopp_e #1% {\if F#1\else\if I#1\else\if M#1\else\CALX_fopp_r\fi\fi\fi \CALX_fopp_a #1}% \def\CALX_fopp_r #1\fi\fi\fi\CALX_fopp_a #2\xint:{\fi\fi\fi\CALX_fopp_x #2\xint:}% \def\CALX_fopp_x #1#2\xint:% {\if-#1\xint_dothis{ #2}\fi\if0#1\xint_dothis{ #1#2}\fi\xint_orthat{ -#1#2}}% \def\CALX_fopp_a #1#2#3\xint:% {% \if#2-\xint_dothis{ #1+#3}\fi \if#2?\xint_dothis{ #1?}\fi \if0\CALX_fopp_b#3?\xint:\xint_dothis{ #1+#3}\fi \xint_orthat{ #1-#3}% }% \def\CALX_fopp_b #1#2\xint:{#1}% % \end{macrocode} %\begin{lverb} % Syntax (f-expandable; X a value of any parser, f-expanded; k a value % with \CALX_mr digits, i.e. M or raw integer): %( % \calxiiRound{k}{X}, \calxiiTrunc{k}{X} -> M (X 10^k rounded, truncated) %: \calxiiFloor{X}, \calxiiCeil{X} -> M %: \calxCeilToNum{X} -> explicit digits of ceil(X) %) % round(x, k), trunc(x, k), floor(), ceil() of \xintiieval, the start % value of n++. X 10^k as raw A/B[N + k] (M by \CALX_mtoraw_t, F by % \CALX_ftoraw), then calxfp's \CALX_fintn with the kind \CALX_fintk_r, % \CALX_fintk_t; floor, ceil: M (and I) values as they are, others % \CALX_fintn with \CALX_fintk_f, \CALX_fintk_c; result \CALX_ntom. I % values unchanged. \calxCeilToNum: \CALX_fint and \CALX_seq_k (I: % \CALX_fnum, InvalidOperation, 0). \string on the tag of X after its % f-expansion (values from compiled functions). %\end{lverb} % \begin{macrocode} \def\calxiiRound #1#2% {\romannumeral0\expandafter\CALX_iirt_s\romannumeral`&&@#2\xint:{#1}% \CALX_fintk_r}% \def\calxiiTrunc #1#2% {\romannumeral0\expandafter\CALX_iirt_s\romannumeral`&&@#2\xint:{#1}% \CALX_fintk_t}% \def\calxiiFloor #1% {\romannumeral0\expandafter\CALX_iifl_s\romannumeral`&&@#1\xint:% \CALX_fintk_f}% \def\calxiiCeil #1% {\romannumeral0\expandafter\CALX_iifl_s\romannumeral`&&@#1\xint:% \CALX_fintk_c}% \def\CALX_iirt_s{\expandafter\CALX_iirt_a\string}% \def\CALX_iirt_a #1% {% \if I#1\xint_dothis{\CALX_iirt_i#1}\fi \if M#1\xint_dothis{\CALX_iirt_m#1}\fi \if F#1\xint_dothis{\CALX_iirt_f#1}\fi \xint_orthat{\CALX_iirt_r#1}% }% \def\CALX_iirt_i #1#2\xint:#3#4{ #1#2}% \def\CALX_iirt_m #1#2\xint:#3% {\expandafter\CALX_iirt_b \romannumeral0\CALX_mtoraw_t#1#2\xint:[0]\xint:{#3}}% \def\CALX_iirt_f #1#2\xint:#3% {\expandafter\CALX_iirt_b \romannumeral0\CALX_ftoraw{#1#2}[0]\xint:{#3}}% \def\CALX_iirt_r #1#2\xint:#3{\CALX_iirt_b#1#2[0]\xint:{#3}}% \def\CALX_iirt_b #1[#2]#3\xint:#4% {\expandafter\CALX_iirt_c\the\numexpr#2+\CALX_mr{#4}.{#1}}% \def\CALX_iirt_c #1.#2#3% {\expandafter\CALX_ntom\romannumeral0\CALX_fintn#3#2[#1]\xint:}% \def\CALX_iifl_s{\expandafter\CALX_iifl_a\string}% \def\CALX_iifl_a #1% {% \if I#1\xint_dothis{\CALX_iifl_copy#1}\fi \if M#1\xint_dothis{\CALX_iifl_copy#1}\fi \xint_orthat{\CALX_iifl_calc#1}% }% \def\CALX_iifl_copy #1#2\xint:#3{ #1#2}% \def\CALX_iifl_calc #1#2\xint:#3% {\expandafter\CALX_ntom\romannumeral0\CALX_fintn#3#1#2\xint:}% \def\calxCeilToNum #1% {\romannumeral0\expandafter\CALX_ctn_s\romannumeral`&&@#1\xint:}% \def\CALX_ctn_s{\expandafter\CALX_ctn_a\string}% \def\CALX_ctn_a #1#2\xint:% {% \if I#1\xint_dothis{\CALX_fnum#1#2\xint:}\fi \xint_orthat{\expandafter\CALX_ctn_b\the\numexpr\expandafter\CALX_seq_k \romannumeral0\CALX_fint#1#2\xint:\CALX_fintk_c.}% }% \def\CALX_ctn_b #1.{ #1}% % \end{macrocode} %\begin{lverb} % calx: sign and zero tests on the values of the three parsers, by % calxcore's \CALX_ifsgn and \CALX_ifnz (first tokens only, no xintfrac % parsing). One macro token each, f-expandable, for the parser tables and % the \xintNewExpr hooks: %( % \calxSgn{X} -> -1, 0 or 1 %: \calxIsZero{X}, \calxIsNotZero{X} -> 1 or 0 %: \calxifNotZero{X}{A}{B} -> A (X <> 0) or B %: \calxifSgn{X}{A}{B}{C} -> A, B or C (X < 0, = 0, > 0) %: \calxAND{X}{Y}, \calxOR{X}{Y}, \calxXOR{X}{Y} -> 1 or 0 %: \CALX_ANDof{X}{Y}...^, \CALX_ORof..., \CALX_XORof... -> 1 or 0 %) % I? is non-zero for the truth tests; \calxSgn and \calxifSgn signal % InvalidOperation on it, then count it as 0. \calxAND, \calxOR, \calxXOR % and the loops of the lists use \CALX_ifnz_a with \xint_firstoftwo, % \xint_secondoftwo, which add no space (\CALX_xorof counts the non-zero % items as signs in a \numexpr, as xint's \XINT_xorof). %\end{lverb} % \begin{macrocode} \def\calxSgn #1% {\romannumeral0\expandafter\CALX_ifsgn_a\romannumeral`&&@#1\xint:{-1}{0}{1}}% \def\calxIsZero #1% {\romannumeral0\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_stop_atfirstoftwo\xint_stop_atsecondoftwo{0}{1}}% \def\calxIsNotZero #1% {\romannumeral0\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_stop_atfirstoftwo\xint_stop_atsecondoftwo{1}{0}}% \def\calxifNotZero #1% {\romannumeral0\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_stop_atfirstoftwo\xint_stop_atsecondoftwo}% \def\calxifSgn #1% {\romannumeral0\expandafter\CALX_ifsgn_a\romannumeral`&&@#1\xint:}% \def\calxAND #1#2% {\romannumeral0\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_firstoftwo\xint_secondoftwo{\CALX_ifnz{#2}{1}{0}}{ 0}}% \def\calxOR #1#2% {\romannumeral0\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_firstoftwo\xint_secondoftwo{ 1}{\CALX_ifnz{#2}{1}{0}}}% \def\calxXOR #1#2% {\romannumeral0\expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_firstoftwo\xint_secondoftwo{\CALX_ifnz{#2}{0}{1}}% {\CALX_ifnz{#2}{1}{0}}}% \def\CALX_ANDof {\romannumeral0\CALX_andof}% \def\CALX_andof #1% {\xint_gob_til_^ #1\CALX_andof_e ^% \expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_firstoftwo\xint_secondoftwo\CALX_andof\CALX_andof_n}% \def\CALX_andof_n #1^{ 0}% \def\CALX_andof_e ^#1\CALX_andof_n{ 1}% \def\CALX_ORof {\romannumeral0\CALX_orof}% \def\CALX_orof #1% {\xint_gob_til_^ #1\CALX_orof_e ^% \expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_firstoftwo\xint_secondoftwo\CALX_orof_y\CALX_orof}% \def\CALX_orof_y #1^{ 1}% \def\CALX_orof_e ^#1\CALX_orof{ 0}% \def\CALX_XORof {\romannumeral0\CALX_xorof}% \def\CALX_xorof {\if1\the\numexpr\CALX_xorof_a}% \def\CALX_xorof_a #1% {\xint_gob_til_^ #1\CALX_xorof_e ^% \expandafter\CALX_ifnz_a\romannumeral`&&@#1\xint:% \xint_firstoftwo\xint_secondoftwo{-}{}\CALX_xorof_a}% \def\CALX_xorof_e ^#1\CALX_xorof_a {1\relax\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% % \end{macrocode} %\begin{lverb} % calx: the same tests for \xintfloateval, with native F results (1, 0, % -1): the values of \xintfloateval are F, M, I or raw with [N], never a % bare integer. \CALX_fpone, \CALX_fpzero: F+1.0.100000001!, % F+0.0. (written where F has catcode 12); \CALX_fpb <0 or 1>: the % F value; the entries apply it to the digit of the general macros. %( % \calxFpSgn{X} -> F -1, 0 or 1 %: \calxFpIsZero{X}, \calxFpIsNotZero{X} -> F 1 or 0 %: \calxFpAND{X}{Y}, \calxFpOR, \calxFpXOR -> F 1 or 0 %: \calxFpANDof{X}{Y}...^, \calxFpORof, \calxFpXORof -> F 1 or 0 %: \calxFpEven{X}, \calxFpOdd, \calxFpIsOne, \calxFpIsInt -> F 1 or 0 %: \calxFpLength{L} -> raw A[0] %: \calxFpiLogTendigits{X}, \calxFpiLogTen[P]{X} -> F %) % ilog10(): X rounded to P digits (\CALX_fround; F, M, I, raw), then % from the header F..: 8e + D - 1 (\CALX_filt_f), as an F value % (\CALX_ffromraw); zero: -"7FFF8000 as xint; I: InvalidOperation, I?. %\end{lverb} % \begin{macrocode} \catcode`F=12 \def\CALX_fpone{ F+1.0.100000001!}% \def\CALX_fpzero{ F+0.0.}% \def\CALX_fpsgn #1% {\romannumeral0\CALX_ifsgn{#1}{F-1.0.100000001!}{F+0.0.}{F+1.0.100000001!}}% \catcode`F=11 \let\calxFpSgn\CALX_fpsgn \def\CALX_fpb #1{\if1#1\expandafter\CALX_fpone\else\expandafter\CALX_fpzero\fi}% \def\calxFpIsZero{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\calxIsZero}% \def\calxFpIsNotZero {\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\calxIsNotZero}% \def\calxFpAND{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\calxAND}% \def\calxFpOR{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\calxOR}% \def\calxFpXOR{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\calxXOR}% \def\calxFpANDof{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\CALX_ANDof}% \def\calxFpORof{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\CALX_ORof}% \def\calxFpXORof{\romannumeral0\expandafter\CALX_fpb\romannumeral`&&@\CALX_XORof}% % \end{macrocode} %\begin{lverb} % even(), odd(): parity of the truncation of X (exact, as xintfrac's % \xintNum). \CALX_fpar{X} -> 1 if odd, else 0. F: e > 0 or % zero: even; e = 0: the lowest block; e < 0: the block of index -e % (\CALX_nskip), if D > -8e, else the truncation is 0. M: e > 0 or zero: % even, else the lowest block. Raw (also bare A, A/B) and I: calxfp's % \CALX_fnum (I: InvalidOperation, 0), \CALX_nfromraw, the lowest block. % isone(): \CALX_fcmp with 1 (exact; I: 0). isint(): X rounded to P digits % (\CALX_fround, as xintfrac's \xintFloatIsInt), then zero or e >= 0: 1; % e < 0: 1 iff D > -8e and the -e lowest blocks are zero (\CALX_fii_z); I: % 0. ifint() (\calxFpifInt): the same test, first or second branch % (\CALX_ifb). ifone() (\calxFpifOne): \CALX_fcmp with 1 (no rounding), I: % second branch, no signal. ifint() of \xintiieval (calxint's % \calxiiifInt): its values are integers, first branch; I: InvalidOperation, % second branch (as \calxiiifOne). %\end{lverb} % \begin{macrocode} \def\calxFpEven{\romannumeral0\expandafter\CALX_fpe\romannumeral0\CALX_fpar}% \def\calxFpOdd{\romannumeral0\expandafter\CALX_fpb\romannumeral0\CALX_fpar}% \def\CALX_fpe #1{\if1#1\expandafter\CALX_fpzero\else\expandafter\CALX_fpone\fi}% \def\CALX_fpar #1{\expandafter\CALX_fpar_a\romannumeral`&&@#1\xint:}% \def\CALX_fpar_a #1% {% \if F#1\xint_dothis\CALX_fpar_f\fi \if M#1\xint_dothis\CALX_fpar_m\fi \xint_orthat\CALX_fpar_x #1% }% \def\CALX_fpar_f #1#2#3.#4.% {% \ifnum#4>\xint_c_ \xint_dothis\CALX_fpar_zero\fi \ifnum#3=\xint_c_ \xint_dothis\CALX_fpar_zero\fi \ifnum#4=\xint_c_ \xint_dothis\CALX_fpar_g\fi \ifnum#3>\numexpr-\xint_c_viii*(#4)\relax \xint_dothis{\CALX_nskip\CALX_fpar_g -#4.}\fi \xint_orthat\CALX_fpar_zero }% \def\CALX_fpar_m #1#2#3.#4.% {% \ifnum#3=\xint_c_ \xint_dothis\CALX_fpar_zero\fi \ifnum#4>\xint_c_ \xint_dothis\CALX_fpar_zero\fi \xint_orthat\CALX_fpar_g }% \def\CALX_fpar_zero #1\xint:{ 0}% \def\CALX_fpar_g 1#1!#2\xint:{\ifodd#1 \xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% \def\CALX_fpar_x #1\xint:% {\expandafter\CALX_fpar_n\romannumeral0\CALX_nfromraw {\romannumeral0\CALX_fnum#1\xint:}\xint:}% \catcode`N=12 \def\CALX_fpar_n N#1#2.#3\xint:% {\ifnum#2=\xint_c_ \xint_dothis{ 0}\fi\xint_orthat{\CALX_fpar_g#3\xint:}}% \catcode`N=11 \def\calxFpIsOne #1% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint: \CALX_fpone\xint:} \xint_afterfi\CALX_fpone \else\xint_afterfi\CALX_fpzero\fi}% \def\calxFpIsInt% {\romannumeral0\expandafter\CALX_fpb\romannumeral0\expandafter\CALX_fii \romannumeral0\CALX_fround{\XINTdigits}}% \def\CALX_fii #1{\if I#1\expandafter\CALX_fii_i\else\expandafter\CALX_fii_f\fi}% \def\CALX_fii_i #1\xint:{ 0}% \def\CALX_fii_f #1#2.#3.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_fii_yes\fi \ifnum#3<\xint_c_ \xint_dothis{\CALX_fii_n#2.#3.}\fi \xint_orthat\CALX_fii_yes }% \def\CALX_fii_n #1.#2.#3\xint:% {% \ifnum#1>\numexpr-\xint_c_viii*(#2)\relax \xint_dothis{\expandafter\CALX_fii_z\the\numexpr-#2.#3\xint:}\fi \xint_orthat{ 0}% }% \def\CALX_fii_z #1.1#2!% {% \ifnum#2>\xint_c_ \xint_dothis\CALX_fii_no\fi \ifnum#1=\xint_c_i \xint_dothis\CALX_fii_yes\fi \xint_orthat{\expandafter\CALX_fii_z\the\numexpr#1-\xint_c_i.}% }% \def\CALX_fii_no #1\xint:{ 0}% \def\CALX_fii_yes #1\xint:{ 1}% \def\calxFpifInt% {\romannumeral0\expandafter\CALX_ifb\romannumeral0\expandafter\CALX_fii \romannumeral0\CALX_fround{\XINTdigits}}% \def\CALX_ifb #1% {\if1#1\expandafter\xint_stop_atfirstoftwo\else \expandafter\xint_stop_atsecondoftwo\fi}% \def\calxFpifOne #1% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint: \CALX_fpone\xint:} % \expandafter\xint_stop_atfirstoftwo\else \expandafter\xint_stop_atsecondoftwo\fi}% \def\calxFpLength #1{\expanded{\xintLength{#1}[0]}}% \def\calxFpiLogTendigits% {\romannumeral0\expandafter\CALX_filt\romannumeral0\CALX_fround{\XINTdigits}}% \def\calxFpiLogTen [#1]% {\romannumeral0\expandafter\CALX_filt\romannumeral0\CALX_fround{#1}}% \def\CALX_filt #1% {\if I#1\expandafter\CALX_filt_i\else\expandafter\CALX_filt_f\fi #1}% \def\CALX_filt_i #1\xint:{\CALX_nsig{InvalidOperation}{ilog10 of I}{}}% \def\CALX_filt_f #1#2#3.#4.#5\xint:% {% \ifnum#3=\xint_c_ \expandafter\CALX_filt_z\fi \CALX_ffromraw{\the\numexpr\xint_c_viii*(#4)+#3-\xint_c_i[0]}% }% \def\CALX_filt_z #1#2{\CALX_ffromraw{-2147450880[0]}}% % \end{macrocode} %\begin{lverb} % calx: native comparisons and abs() of \xintfloateval. % % \CALX_fcmp{X}{Y} (use in \ifcase): 0 if X = Y, 1 if X > Y, 2 if X < Y, % 3 if unordered (an I?). Exact (no rounding). Two F values: the signs % (0 for zero), then the orders 8e + D, then the sign of the exact % difference \CALX_fsubx. I+, I- compare as infinities. Other inputs % (\CALX_fc_x): each operand as an exact pair {p}{q} of F values % (\CALX_fcq; q empty for 1): F itself; M: \CALX_fmx_c of calxfp (the % digit count from the top block), zero F+0.0.; raw strict A[N] (or bare % A, A/B as in compiled functions: [0] appended, ignored if [N] present): p by % \CALX_ffromraw; A/B[N]: p of A[N], q of B[0] (B > 0). X = p/q, Y = r/s: % p and r compared if q, s are empty, else p s and r q (\CALX_fmulx, % exact), by \CALX_fc_n. % % \calxFpLt, \calxFpGt, \calxFpLtorEq, \calxFpGtorEq: 1 or 0, an I? % operand signals InvalidOperation (value 0), as Python's Decimal; % \calxFpEq, \calxFpNotEq: I? is unequal to everything, no signal. % % The operands come from the parsers: their tag may have catcode 11 % (values stored in the meaning of a compiled function, read from a % file). \CALX_fc_as and \CALX_fc_bs apply \string to the first token of % each operand after its f-expansion: the copies handed to \CALX_fsubx, % whose patterns contain F of catcode 12, then have a catcode 12 tag. % % Expanded-operand entry: X\xint:Y\xint:, both input values are % already f-expanded. The first token of each is normalized by \string % before entering the common comparison kernel. %\end{lverb} % \begin{macrocode} \def\CALX_fcmp #1% {\romannumeral0\expandafter\CALX_fc_as\romannumeral`&&@#1\xint:}% \def\CALX_fcmp_in #1\xint:#2\xint:% {\expandafter\CALX_fc_ai\string#1\xint:#2\xint:}% \def\CALX_fc_ai #1\xint:#2\xint:% {\expandafter\CALX_fc_bs\romannumeral`&&@#2\xint:#1\xint:}% \def\CALX_fc_as{\expandafter\CALX_fc_a\string}% \def\CALX_fc_a #1\xint:#2% {\expandafter\CALX_fc_bs\romannumeral`&&@#2\xint:#1\xint:}% \def\CALX_fc_bs{\expandafter\CALX_fc_b\string}% \def\CALX_fc_b #1#2\xint:#3% {% \if I#3\xint_dothis{\CALX_fc_bi #1{#2}}\fi \if I#1\xint_dothis{\CALX_fc_bj #1{#2}#3}\fi \if F\if F#1#3\else Z\fi \xint_dothis{\CALX_fc_bn #1{#2}#3}\fi \xint_orthat{\CALX_fc_bx #1{#2}#3}% }% \def\CALX_fc_bi #1#2#3\xint:{\CALX_fc_i#3\xint:#1#2\xint:}% \def\CALX_fc_bj #1#2#3#4\xint:{\CALX_fc_j#2\xint:#3#4\xint:}% \def\CALX_fc_bn #1#2#3#4\xint:% {\CALX_fc_n{#3#4}{#1#2}#3#4\xint:#1#2\xint:}% \def\CALX_fc_bx #1#2#3#4\xint:{\CALX_fc_x{#3#4}{#1#2}}% \def\CALX_fc_x #1#2% {\expandafter\CALX_fc_xa\expanded{\CALX_fcq{#1}\CALX_fcq{#2}}}% \def\CALX_fc_xa #1#2#3#4% {% \if\relax\detokenize{#2#4}\relax \xint_dothis{\CALX_fc_n{#1}{#3}#1\xint:#3\xint:}\fi \xint_orthat{\expandafter\CALX_fc_xb\expanded {{\CALX_fcmul{#1}{#4}}{\CALX_fcmul{#3}{#2}}}}% }% \def\CALX_fc_xb #1#2{\CALX_fc_n{#1}{#2}#1\xint:#2\xint:}% \def\CALX_fcmul #1#2% {\if\relax\detokenize{#2}\relax\xint_dothis{#1}\fi \xint_orthat{\romannumeral0\CALX_fmulx{#1}{#2}}}% \def\CALX_fcq #1{\CALX_fcq_a #1\xint:}% \def\CALX_fcq_a #1#2\xint:% {% \if F#1\xint_dothis{{#1#2}{}}\fi \if M#1\xint_dothis{{\CALX_fcq_m #2\xint:}{}}\fi \xint_orthat{\CALX_fcq_r #1#2[0]\xint:}% }% \catcode`F=12 \catcode`N=12 \def\CALX_fcq_m #1#2.#3.#4\xint:% {\ifnum#2=\xint_c_ \xint_dothis{F+0.0.}\fi \xint_orthat{\romannumeral0\CALX_fmx_c N#1#2.#4\xint:{#3}}}% \catcode`F=11 \catcode`N=11 \def\CALX_fcq_r #1[#2]#3\xint:{\CALX_fcq_s #1/1/\xint:{#2}}% \def\CALX_fcq_s #1/#2/#3\xint:#4% {{\romannumeral0\CALX_ffromraw{#1[#4]}}% {\if\relax\detokenize{#3}\relax\else \romannumeral0\CALX_ffromraw{#2[0]}\fi}}% % \end{macrocode} %\begin{lverb} % X = I#1, Y any: I? unordered; I+ = I+, I+ > Y; I- = I-, I- < Y. %\end{lverb} % \begin{macrocode} \def\CALX_fc_i #1\xint:#2#3\xint:% {% \if ?#1\xint_dothis{ 3}\fi \if I#2\xint_dothis{\CALX_fc_ii #1#3\xint:}\fi \if -#1\xint_dothis{ 2}\fi \xint_orthat{ 1}% }% \def\CALX_fc_ii #1#2#3\xint:% {% \if ?#2\xint_dothis{ 3}\fi \if #1#2\xint_dothis{ 0}\fi \if -#1\xint_dothis{ 2}\fi \xint_orthat{ 1}% }% % \end{macrocode} %\begin{lverb} % Y = I#1, X not I. %\end{lverb} % \begin{macrocode} \def\CALX_fc_j #1\xint:#2\xint:% {% \if ?#1\xint_dothis{ 3}\fi \if -#1\xint_dothis{ 1}\fi \xint_orthat{ 2}% }% % \end{macrocode} %\begin{lverb} % {X}{Y}X\xint:Y\xint:, X = F.., Y the same: the % headers are read, Y's blocks are gobbled by \CALX_fc_o. %\end{lverb} % \begin{macrocode} \def\CALX_fc_n #1#2#3#4#5.#6.#7\xint:{\CALX_fc_m{#1}{#2}#4{#5}{#6}}% \def\CALX_fc_m #1#2#3#4#5#6#7#8.#9.% {% \expandafter\CALX_fc_o\the\numexpr \ifnum#4=\xint_c_ 0\else#31\fi-(\ifnum#8=\xint_c_ 0\else#71\fi)% \expandafter.\the\numexpr\xint_c_viii*(#5-#9)+#4-#8.#3{#1}{#2}% }% \def\CALX_fc_o #1.#2.#3#4#5#6\xint:% {% \ifnum#1>\xint_c_ \xint_dothis{ 1}\fi \ifnum#1<\xint_c_ \xint_dothis{ 2}\fi \ifnum#2>\xint_c_ \xint_dothis{\CALX_fc_t#3{ 2}{ 1}}\fi \ifnum#2<\xint_c_ \xint_dothis{\CALX_fc_t#3{ 1}{ 2}}\fi \xint_orthat {\expandafter\CALX_fc_s\romannumeral0\CALX_fsubx{#4}{#5}\xint:}% }% \def\CALX_fc_t #1% {\if-#1\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi}% \def\CALX_fc_s #1#2#3.#4\xint:% {\ifnum#3=\xint_c_ \xint_dothis{ 0}\fi\if-#2\xint_dothis{ 2}\fi \xint_orthat{ 1}}% \def\calxFpLt #1#2% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint:#2\xint:} \xint_afterfi\CALX_fpzero\or \xint_afterfi\CALX_fpzero\or\xint_afterfi\CALX_fpone\else\xint_afterfi\CALX_fpcnan\fi}% \def\calxFpGt #1#2% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint:#2\xint:} \xint_afterfi\CALX_fpzero\or \xint_afterfi\CALX_fpone\or\xint_afterfi\CALX_fpzero\else\xint_afterfi\CALX_fpcnan\fi}% \def\calxFpLtorEq #1#2% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint:#2\xint:} \xint_afterfi\CALX_fpone\or \xint_afterfi\CALX_fpzero\or\xint_afterfi\CALX_fpone\else\xint_afterfi\CALX_fpcnan\fi}% \def\calxFpGtorEq #1#2% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint:#2\xint:} \xint_afterfi\CALX_fpone\or \xint_afterfi\CALX_fpone\or\xint_afterfi\CALX_fpzero \else\xint_afterfi\CALX_fpcnan\fi}% \def\calxFpEq #1#2% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint:#2\xint:} \xint_afterfi\CALX_fpone\else \xint_afterfi\CALX_fpzero\fi}% \def\calxFpNotEq #1#2% {\romannumeral0\ifcase\expandafter\CALX_fcmp_in\expanded{#1\xint:#2\xint:} \xint_afterfi\CALX_fpzero\else \xint_afterfi\CALX_fpone\fi}% \def\CALX_fpcnan{\expandafter\CALX_fpb\romannumeral`&&@\CALX_fcnan}% % \end{macrocode} %\begin{lverb} % \calxFpAbs: F, M, I+, I-, I? or raw (strict A[N], A/B[N]: a leading - % removed, \CALX_fabs_r); the tag token kept. %\end{lverb} % \begin{macrocode} \def\calxFpAbs #1% {\romannumeral0\expandafter\CALX_fabs\romannumeral`&&@#1\xint:}% \def\CALX_fabs #1% {\if F#1\expandafter\CALX_fabs_f\else\expandafter\CALX_fabs_x\fi #1}% \def\CALX_fabs_f #1#2#3\xint:{ #1+#3}% \def\CALX_fabs_x #1#2\xint:% {\if I#1\xint_dothis{\CALX_fabs_i#1#2}\fi \if M#1\xint_dothis{\CALX_fabs_f#1#2\xint:}\fi \xint_orthat{\CALX_fabs_r#1#2}}% \def\CALX_fabs_r #1% {\if-#1\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo \fi{ }{ #1}}% \def\CALX_fabs_i #1#2% {\if ?#2\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo \fi{ #1#2}{ #1+}}% % \end{macrocode} %\begin{lverb} % calx: max(), min() of \xintfloateval: \calxFpMaxof, \calxFpMinof % {X1}{X2}...^: Burnol's 1.4p \XINT_maxof/\XINT_minof loops (xintfrac), % \xintmax/\xintmin replaced by \CALX_fmax/\CALX_fmin (selection by % \CALX_fcmp, no rounding); each item is f-expanded once and the value % returned is expanded; empty list: 0/1[0]. An unordered comparison (I?) % signals InvalidOperation and keeps the current value. %\end{lverb} % \begin{macrocode} \def\calxFpMaxof {\romannumeral0\CALX_maxof}% \def\CALX_maxof#1% {% \xint_gob_til_^ #1\CALX_maxof_empty ^% \expandafter\CALX_maxof_loop\romannumeral`&&@#1\xint: }% \def\CALX_maxof_empty ^#1\xint:{ 0/1[0]}% \def\CALX_maxof_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_maxof_e ^% \expandafter\CALX_maxof_loop\romannumeral0\CALX_fmax{#1}{#2}\xint: }% \def\CALX_maxof_e ^#1\CALX_fmax #2#3\xint:{ #2}% \def\calxFpMinof {\romannumeral0\CALX_minof}% \def\CALX_minof#1% {% \xint_gob_til_^ #1\CALX_minof_empty ^% \expandafter\CALX_minof_loop\romannumeral`&&@#1\xint: }% \def\CALX_minof_empty ^#1\xint:{ 0/1[0]}% \def\CALX_minof_loop #1\xint:#2% {% \xint_gob_til_^ #2\CALX_minof_e ^% \expandafter\CALX_minof_loop\romannumeral0\CALX_fmin{#1}{#2}\xint: }% \def\CALX_minof_e ^#1\CALX_fmin #2#3\xint:{ #2}% \def\CALX_fmax #1#2{\expandafter\CALX_fmax_a\expandafter1\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fmin #1#2{\expandafter\CALX_fmax_a\expandafter2\romannumeral`&&@#2\xint:{#1}}% \def\CALX_fmax_a #1#2\xint:#3% {\expandafter\CALX_mx_d\expandafter#1\romannumeral`&&@\CALX_fcmp{#2}{#3}.{#3}{#2}}% \def\CALX_mx_d #1#2.#3#4% {% \if 3#2\xint_dothis{\CALX_mx_sig{#3}}\fi \if #1#2\xint_dothis{ #4}\fi \xint_orthat{ #3}% }% \def\CALX_mx_sig #1% {\XINT_signalcondition{InvalidOperation}{max/min with I?}{}{ #1}}% % \end{macrocode} %\begin{lverb} % calx: floor(), ceil(), trunc(), round() (one argument) and frac() of % \xintfloateval, exact (no rounding to P). I+, I-, I? unchanged; % frac(I+-) = 0. % % F values: trunc by \CALX_ti_f (calxfp). floor, ceil: trunc, then -1 % (+1) by \CALX_fsubx (\CALX_faddx) if the result differs from X and % X < 0 (X > 0). round: trunc of X + 1/2 (X - 1/2 if X < 0). frac: % X - trunc(X). % % Raw values (A, A[N], A/B, A/B[N]) and M values: calxfp's \CALX_fintn % with the kind macro (\CALX_fintk_f floor, \CALX_fintk_c ceil, % \CALX_fintk_r round, \CALX_fintk_t trunc), result \CALX_fx_c 0.N. % frac (\CALX_fl_kq) of a raw value: B = 1, the exact F value of A[N] % goes to the F path; B > 1, the raw R/B[min(N,0)], with R the remainder % of the truncated division (\CALX_nmodtrunc) of A 10^max(N,0) by B % 10^max(-N,0); M values: 0. The kind macros, and \CALX_fl_kq for frac, % also serve as markers (\ifx) in the F path. % % The entries apply \string to the first token of X after its % f-expansion (\CALX_ti_s, \CALX_fl_s): X is handed on to \CALX_fsubx, % \CALX_faddx and \CALX_fcmp, and its tag may have catcode 11 when it % comes from the meaning of a compiled function or from a file. %\end{lverb} % \begin{macrocode} \edef\CALX_fonec{\romannumeral0\CALX_ffromraw{1[0]}}% \edef\CALX_fhalfc{\romannumeral0\CALX_ffromraw{5[-1]}}% \def\CALX_fl_kq {q}% \def\calxFpTrunc #1% {\romannumeral0\expandafter\CALX_ti_s\romannumeral`&&@#1\xint:}% \def\calxFpToM #1% {\romannumeral0\expandafter\CALX_ftom_a\romannumeral`&&@#1\xint:}% \def\CALX_ti_s{\expandafter\CALX_ti_a\string}% \def\calxFpITrunc #1{\calxFpTrunc}% \def\CALX_ti_a #1% {\if F#1\expandafter\CALX_ti_f\else\expandafter\CALX_ti_x\fi #1}% \def\CALX_ti_x #1% {\if I#1\expandafter\CALX_ti_xi\else\expandafter\CALX_ti_xn\fi #1}% \def\CALX_ti_xi #1#2\xint:{ #1#2}% \def\CALX_ti_xn #1#2\xint:% {\expandafter\CALX_fx_c\expandafter0\expandafter.% \romannumeral0\CALX_fintn\CALX_fintk_t#1#2\xint:\xint:}% % \end{macrocode} %\begin{lverb} % floor, ceil, round, frac: the trunc of F values, then a correction; % the last token is the kind macro. %\end{lverb} % \begin{macrocode} \def\calxFpFloor #1% {\romannumeral0\expandafter\CALX_fl_s\romannumeral`&&@#1\xint:% \CALX_fintk_f}% \def\calxFpCeil #1% {\romannumeral0\expandafter\CALX_fl_s\romannumeral`&&@#1\xint:% \CALX_fintk_c}% \def\calxFpIRound #1#2% {\romannumeral0\expandafter\CALX_fl_s\romannumeral`&&@#2\xint:% \CALX_fintk_r}% \def\calxFpFrac #1% {\romannumeral0\expandafter\CALX_fl_s\romannumeral`&&@#1\xint:\CALX_fl_kq}% \def\CALX_fl_s{\expandafter\CALX_fl_a\string}% \def\CALX_fl_a #1% {\if F#1\expandafter\CALX_fl_f\else\expandafter\CALX_fl_x\fi #1}% \def\CALX_fl_x #1#2\xint:#3% {% \if I#1\xint_dothis{\CALX_fl_i#3#1#2}\fi \ifx#3\CALX_fl_kq\xint_dothis{\CALX_fl_fr #1#2\xint:}\fi \xint_orthat{\expandafter\CALX_fx_c\expandafter0\expandafter.% \romannumeral0\CALX_fintn#3#1#2\xint:\xint:}% }% \def\CALX_fl_fr #1#2\xint:% {\if M#1\xint_dothis{\CALX_ffr_a 0[0]\xint:}\fi \xint_orthat{\CALX_fl_fa #1#2[0]\xint:}}% \def\CALX_fl_fa #1[#2]#3\xint:{\CALX_fl_fb #1/1/\xint:{#2}}% \def\CALX_fl_fb #1/#2/#3\xint:{\CALX_fl_fd #2\xint:{#1}{#2}}% \def\CALX_fl_fd #1#2\xint:#3#4#5% {\if1#1\if\relax\detokenize{#2}\relax\CALX_fl_fj\fi\fi \expandafter\CALX_fl_fc\romannumeral0\CALX_nmodtrunc {\CALX_nshl{#5}{\CALX_nfromraw{#3}}}% {\CALX_nshl{-#5}{\CALX_nfromraw{#4}}}\xint:{#4}{#5}{#3}}% \def\CALX_fl_fj #1\xint:#2#3#4% {\fi\fi\expandafter\CALX_fl_f\romannumeral0\CALX_ffr_a#4[#3]\xint:\xint:% \CALX_fl_kq}% \def\CALX_fl_fc #1\xint:#2#3#4% {\expanded{ \romannumeral0\CALX_ntoraw{#1}/#2% [\ifnum#3<\xint_c_ #3\else0\fi]}}% \def\CALX_fl_i #1% {\ifx#1\CALX_fl_kq\expandafter\CALX_fl_ii\else\expandafter\space\fi}% \def\CALX_fl_ii #1#2{\if ?#2\xint_dothis{ #1#2}\fi\xint_orthat\CALX_fpzero}% \def\CALX_fl_f #1#2#3\xint:#4% {% \ifx#4\CALX_fintk_r\xint_dothis{\CALX_fl_r#2{#1#2#3}}\fi \ifx#4\CALX_fl_kq\xint_dothis {\expandafter\CALX_fl_q\romannumeral0\CALX_ti_a#1#2#3\xint:\xint:% {#1#2#3}}\fi \xint_orthat {\expandafter\CALX_fl_b\romannumeral0\CALX_ti_a#1#2#3\xint:\xint:% #2#4{#1#2#3}}% }% \def\CALX_fl_q #1\xint:#2{\CALX_fsubx{#2}{#1}}% \def\CALX_fl_r #1#2% {\expandafter\CALX_ti_a\romannumeral0% \if-#1\expandafter\CALX_fsubx\else\expandafter\CALX_faddx\fi {#2}\CALX_fhalfc\xint:}% % floor: X < 0 and trunc(X) != X: trunc - 1; ceil: X > 0, != X: + 1. \def\CALX_fl_b #1\xint:#2#3#4% {% \ifx#3\CALX_fintk_f\if-#2\CALX_fl_c\fi\else\if-#2\else\CALX_fl_c\fi\fi \CALX_fl_e{#1}{#4}#3% }% \def\CALX_fl_e #1#2#3{ #1}% \def\CALX_fl_c #1\CALX_fl_e #2#3#4% {% \fi\fi \ifcase\CALX_fcmp{#2}{#3} \xint_afterfi{ #2}% \else\xint_afterfi{\ifx#4\CALX_fintk_f\expandafter\CALX_fsubx\else \expandafter\CALX_faddx\fi{#2}\CALX_fonec}\fi }% % \end{macrocode} % \subsection{Loading libraries} %\begin{lverb} % calx: calxtrig is loaded instead of xinttrig, calxlog (log function) % instead of xintlog. The \xinteval hooks and the constants Pi, ... are % defined at the end of calxtrig.tex (s50), the log family's in calxlog.tex. % Due to \XINTsetcatcodes done a bit earlier the ! is catcode 12. % % Formerly xintexpr loaded xintlog which loaded poormanlog which % defines \@namedef. Backporting it here, it is a short name and is % provided by LaTeX which will be used by vast majority of xint users. %\end{lverb} % \begin{macrocode} \if1\ifx\@namedef\JFBUundefined1\else\ifx\@namedef\relax1\else0\fi\fi \def\@namedef#1{\expandafter\def\csname #1\endcsname}% \def\@nameuse#1{\csname #1\endcsname}% \fi \input calxtrig.tex\relax \input calxlog.tex\relax \CALX_restorecc\let\CALX_restorecc\undefined % \end{macrocode} % \subsection{\csh{xintreloadxintlog}, \csh{xintreloadxinttrig}, \csh{xintreloadscilibs}} % Only for backward compatibility. TODO: make them emit messages to inform user % they are no-opts. % \begin{macrocode} \let\xintreloadxinttrig\empty \let\xintreloadxintlog\empty \let\xintreloadscilibs\empty % \end{macrocode} % \subsection{\csh{calxeval}, \csh{calxinteval}} % \begin{macrocode} \let\calxeval\xintfloateval \let\calxinteval\xintiieval \XINTrestorecatcodesendinput% % \end{macrocode} % \setcounter{xintMacroCnt}{\the\numexpr452+\value{xintMacroCnt}\relax} % \StoreCodelineNo {calx} % \etocsettocdepth{subsubsection} % \cleardoublepage\let\calxnameUp\undefined %\gardesactifs %\let\relax %\let<*calxlog>\gardesinactifs %------------------------------------------------------ %<*calxlog>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxlognameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Library \calxlognameimp implementation} % \RaisedLabel{sec:calxlogimp} % \addedcalx{2.0a1} % % \localtableofcontents % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code of this subsection is copied over from the xint packages, with % the package names changed. % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \catcode35=6 % # \catcode33=12 % ! \def\empty{}\def\space{ }\newlinechar10 \expandafter\let\expandafter\l\csname ver@calxlog.tex\endcsname \expandafter\let\expandafter\c\csname ver@calx.sty\endcsname \expandafter \ifx\csname PackageWarningNoLine\endcsname\relax \def\y#1#2{\immediate\write128{^^JPackage #1 Warning:^^J% \space\space\space\space#2.^^J}}% \else \def\y#1#2{\PackageWarningNoLine{#1}{#2}}% \fi % attention that in this file \z by default does \endinput. \def\z{\endgroup\endinput}% \expandafter\ifx\csname numexpr\endcsname\relax \y{calx}{\numexpr not available, aborting input}% \else % \end{macrocode} % BEWARE: on 2026/10/09 I hit a problem I knew about from years ago but % forgot. It is known that TeX executes all macros on the line where % |\endinput| is found. But imagine |\endinput\input foo.tex\relax|, % then what will happen is that only the first line of foo.tex % (if its EOL is not hidden by a comment char) is executed, so basically % foo.tex is not read beyond that. I will put |\endinput| last in both % situations, as is logical anyhow. % \begin{macrocode} \ifx\c\relax % calx.sty not yet loaded. \ifx\PackageWarningNoLine\relax \y{calx}{% Loading of calxlog.tex should happen via \string\input\space calx.sty\relax^^J\space\space\space\space Will try that now% }% \def\z{\endgroup \input calx.sty\relax\endinput}% \else \y{calx}{% Bad move! Inputting calxlog.tex directly in a LaTeX\MessageBreak document is forbidden! Simply use \string\usepackage{calx}\MessageBreak in the preamble, as every obedient LaTeX user does!\MessageBreak Trying to recover now, hoping to be in the preamble% }% \def\z{\endgroup \RequirePackage{calx}\endinput}% \fi \else % either calx.sty is trying to load us, or a second loading is % attempted on us by \input. Abort if the latter. \ifx\l\relax \def\z{\endgroup}% \else \y{calx}{calxlog.tex already loaded! Aborting this input}% \fi \fi \fi \z% % \end{macrocode} %\begin{lverb} % We arrive here only after a \XINTsetcatcodes which is done (near its tail) % in calx.sty. In particular ! has its normal catcode 12. But attention: % the \XINTsetcatcode does nothing with the letters F, I, N so we have to % be careful whenever we set them to be of catcode "other" (=12). % % There appears to be a problem with miniltx which provides \ProvidesFile % but does not let it define \ver@calxlog.tex. So we define it always. %\end{lverb} % \subsection{Package identification} % \begin{macrocode} \ifdefined\ProvidesFile \ProvidesFile{calxlog.tex}% [2026/11/01 v2.0a1 log, exp, etc for xintexpr/calx (JFB)]% \fi \expandafter\def\csname ver@calxlog.tex\endcsname {2026/11/01 v2.0a1 calx log library}% % \end{macrocode} % \subsection{Loading data tables} % \begin{macrocode} \catcode`\_ 11\catcode`\: 11 % \end{macrocode} %\begin{lverb} % Natural logarithm, P1..P8: tables (records in calxlogdata.tex): % \CALX_lgUT (ab = 10..99) #1 -> % #1c.t3.t2.t1.t0., c = floor(10^4/(ab+1)), round(10^12 ln(10^3/c)) in % limbs; \CALX_lgUV (j = 0..101) -> e2.e1.e0., round(10^12 ln(1+j/10^3)). %\end{lverb} % \begin{macrocode} \def\CALX_lgULoadT #1.#2.#3.#4.#5.#6,% {% \ifnum#1=\xint_c_ \expandafter\xint_gobble_i\else \expandafter\def\csname CALX_lgUT#1\endcsname##1{##1#2.#3.#4.#5.#6.}\fi \CALX_lgULoadT }% \def\CALX_lgULoadV #1.#2.#3.#4,% {% \ifnum#1<\xint_c_ \expandafter\xint_gobble_i\else \expandafter\def\csname CALX_lgUV#1\endcsname{#2.#3.#4.}\fi \CALX_lgULoadV }% \input calxlogdata.tex\relax % \end{macrocode} % \subsection{\csh{calxFpLog}, \csh{calxRawLog}} %\begin{lverb} % Syntax of the public macros of this file (f-expandable; X, A, B % f-expanded F, I or raw values; P = \XINTdigits; results F or I values % rounded to P digits; the \calxRaw variants give the same value as % xint raw A[N]): %( % \calxFpLog{X}, \calxFpLogOnePlus{X}, \calxFpLogTen{X} ln, ln(1+X), log10 %: \calxFpExp{X}, \calxFpPowTen{X}, \calxFpExpMinusOne{X} e^X, 10^X, e^X-1 %: \calxFpPow{A}{B} A^B %: \calxFpSinh{X}, \calxFpCosh, \calxFpTanh, \calxFpCoth, \calxFpSech, %: \calxFpCsch, \calxFpAsinh, \calxFpAcosh, \calxFpAtanh, \calxFpAcoth, %: \calxFpAsech, \calxFpAcsch hyperbolic %) % Internal entries (use with \romannumeral0; Y an F value rounded by % \CALX_fround, followed by its \xint:): %( % \CALX_lga Y\xint: -> ln Y (dispatch by P) %: \CALX_lpa Y\xint: -> ln(1 + Y) %: \CALX_exa Y\xint: -> e^Y (Y rounded at P + 14 digits) %) % and, f-expanded by its callers (\CALX_fnround, \CALX_fmulx), %( % \CALX_lpLP P.+..\xint: -> ln, F value at precision P %) % (internal log of a positive F value, not rounded to P digits; P <= 112). %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_lgHsF-\endcsname#1\xint: {\CALX_nsig{InvalidOperation}{log(x), x < 0}{}}% \expandafter\def\csname CALX_lgHsI+\endcsname#1\xint:{ I+}% \expandafter\def\csname CALX_lgHsI-\endcsname#1\xint: {\CALX_nsig{InvalidOperation}{log(-inf)}{}}% \expandafter\def\csname CALX_lgHsI?\endcsname#1\xint:{ I?}% \def\calxFpLog{\romannumeral0\expandafter\CALX_lga \romannumeral0\CALX_fround{\XINTdigits}}% \def\calxRawLog #1{\romannumeral0\CALX_ftoraw{\calxFpLog{#1}}}% \def\CALX_lgnfl #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpLog#3}}% }% \def\CALX_lgnex #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxRawLog#3}}% }% \let\XINT_flexpr_func_log\CALX_lgnfl \let\XINT_expr_func_log\CALX_lgnex % \end{macrocode} % \subsection{Natural logarithm, P1..P8} %\begin{lverb} % P1..P8 entry (\CALX_lga): the input is already rounded to P <= 8 digits, % F+..\xint:, D <= 16. E = D - 1 + 8e; |E| >= 4000: the P16 % code; else M = the 8 leading digits (\CALX_Lin of P16, padded). %\end{lverb} % \begin{macrocode} \expandafter\let\csname CALX_lgUtagF-\expandafter\endcsname \csname CALX_lgHsF-\endcsname \expandafter\let\csname CALX_lgUtagI+\expandafter\endcsname \csname CALX_lgHsI+\endcsname \expandafter\let\csname CALX_lgUtagI-\expandafter\endcsname \csname CALX_lgHsI-\endcsname \expandafter\let\csname CALX_lgUtagI?\expandafter\endcsname \csname CALX_lgHsI?\endcsname \expandafter\def\csname CALX_lgUtagF+\endcsname #1.#2.#3\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{log(0)}{-}}\fi \xint_orthat{\expandafter\CALX_lgUb \the\numexpr#1-\xint_c_i+\xint_c_viii*#2.#1.#2.#3\xint:}% }% \def\CALX_lgUb #1.#2.#3.% {% \ifnum\ifnum#1<\xint_c_ -\fi#1>3999 \xint_dothis\CALX_lgUb_large\fi \xint_orthat\CALX_lgUb_regular #1.#2.#3.% }% \def\CALX_lgUb_large #1.#2.#3.#4\xint:% {\csname CALX_LtagF+\endcsname#2.#3.#4\xint:}% \def\CALX_lgUb_regular #1.#2.#3.#4\xint:% {\csname CALX_Lin\ifnum#2>\xint_c_viii ii\else i\fi\endcsname \CALX_lgUa#4\xint:#1.#2.}% \def\CALX_lgUa #1#2#3#4#5#6#7#8#9\relax{\CALX_lgUc #1#2.#1#2#3#4.#5#6#7#8.}% % \end{macrocode} %\begin{lverb} % \CALX_lgUc ab.Mh.Ml.E.: classes by E: -1 (cm), 0 (cz), > 0 (cp), < -1 (cn) %\end{lverb} % \begin{macrocode} \def\CALX_lgUc #1.#2.#3.#4.% {% \csname CALX_lgUc\ifcase\numexpr#4+\xint_c_i\relax m\or z\else \ifnum#4>\xint_c_ p\else n\fi\fi\endcsname #1.#2.#3.#4.% }% \def\CALX_lgUcp{\CALX_lgUo\CALX_lgUfp}% \def\CALX_lgUcn{\CALX_lgUo\CALX_lgUfn}% % \end{macrocode} %\begin{lverb} % near 1: x < 1.011 (E = 0), x >= 0.989 (E = -1) %\end{lverb} % \begin{macrocode} \def\CALX_lgUcz #1.#2.% {% \ifnum#2>1010 \expandafter\CALX_lgUo\expandafter\CALX_lgUfp \else\expandafter\CALX_lgUzz\fi #1.#2.% }% \def\CALX_lgUcm #1.#2.#3.% {% \ifnum#2#3<98900000 \expandafter\CALX_lgUo\expandafter\CALX_lgUfn \else\expandafter\CALX_lgUzm\fi #1.#2.#3.% }% % \end{macrocode} %\begin{lverb} % Ordinary path, fixed point 10^-12. \CALX_lgUo ab.Mh.Ml.E. % A = 10^6 - c Mh, B = c Ml (u = (10^4 A - B) 10^-10); j; W = 10^12 u'; % S12 = 10^12 (u' + u'^2/2 + u'^3/3); the chain (\CALX_lgUfp$empty: E >= 0, % \CALX_lgUfn$empty: E < 0) gets S12.e2.e1.e0.E.t3.t2.t1.t0. %\end{lverb} % \begin{macrocode} \def\CALX_lgUo #1#2.{\csname CALX_lgUT#2\endcsname\CALX_lgUoa#1}% \def\CALX_lgUoa #1.#2.#3.#4.#5.#6#7.#8.#9.% {% \expandafter\CALX_lgUob\the\numexpr1000000-#1*#7\expandafter.% \the\numexpr#1*#8.#6#9.#2.#3.#4.#5.% }% \def\CALX_lgUob #1.#2.% {% \expandafter\CALX_lgUoc \the\numexpr(#1*10000-#2)/(10000000-10*#1+#2/1000).#1.#2.% }% \def\CALX_lgUoc #1.#2.#3.% {% \expandafter\CALX_lgUod \the\numexpr(#2*(1000+#1)-1000000*#1)*1000-#3*(1000+#1)/10.#1.% }% \def\CALX_lgUod #1.#2.#3% {% \expandafter#3\the\numexpr#1+(#1/1000)*(#1/1000)/2000000 +((#1/1000)*(#1/1000)/2000000)*(#1/1000)/1500000000\expandafter.% \romannumeral`&&@\csname CALX_lgUV#2\endcsname }% % \end{macrocode} %\begin{lverb} % |y| 10^12 = s(E ln10 + ln m) 10^12, ln10 10^12 = 2|3025|8509|2994 + 0.045684 %\end{lverb} % \begin{macrocode} \def\CALX_lgUfp #1.#2.#3.#4.#5.#6.#7.#8.#9.% {% \expandafter\CALX_lgUw\the\numexpr#6+2*#5% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#7-#2+3025*#5% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#8-#3-#1/10000+8509*#5% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#9-#4-#1+#1/10000*10000 +2994*#5+#5*45684/1000000\relax!+-12.% }% \def\CALX_lgUfn #1.#2.#3.#4.#5.#6.#7.#8.#9.% {% \expandafter\CALX_lgUw\the\numexpr-#6-2*#5% \expandafter\CALX_LR\the\numexpr\CALX_Loff-#7+#2-3025*#5% \expandafter\CALX_LR\the\numexpr\CALX_Loff-#8+#3+#1/10000-8509*#5% \expandafter\CALX_LR\the\numexpr\CALX_Loff-#9+#4+#1-#1/10000*10000 -2994*#5-#5*45684/1000000\relax!--12.% }% % \end{macrocode} %\begin{lverb} % Near-1 path: delta = d 10^-k, y = delta (1 + delta H'), Q = round(10^10 % delta H'); |y| = a (10^10 + Q) 10^-(k+10), a = |d| = a1 10^4 + a0. % \CALX_lgUzh a1.d.a0.10^k.10^(k-1).. %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \gdef\CALX_lgUzz #1.#2.#3.#4.% {% \ifnum#2#3=10000000 \xint_dothis{ F+0.0.}\fi \xint_orthat{\expandafter\CALX_lgUzh\the\numexpr#2-1000\expandafter.% \the\numexpr#2#3-10000000.#3.10000000.1000000.+-17.}% }% \endgroup \def\CALX_lgUzm #1.#2.#3.#4.% {% \expandafter\CALX_lgUzh\the\numexpr9999-#2\expandafter.% \the\numexpr#2#3-100000000\expandafter.% \the\numexpr10000-#3.100000000.10000000.--18.% }% \def\CALX_lgUzh #1.#2.#3.#4.#5.% {% \expandafter\CALX_lgUzb\the\numexpr #2*(-500000000+#2*(333333333+#2*(-250000000 +#2*200000000/#4)/#4)/#4)/#5.#1.#3.% }% % \end{macrocode} %\begin{lverb} % exact a (10^10 + Q): columns 100 a1 | 100 a0 + a1 Q1 | a1 Q0 + a0 Q1 | a0 Q0 %\end{lverb} % \begin{macrocode} \def\CALX_lgUzb #1.#2.#3.% {% \expandafter\CALX_lgUw\the\numexpr100*#2% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#2*(#1/10000)+100*#3% \expandafter\CALX_LR\the\numexpr \CALX_Loff+#2*(#1-#1/10000*10000)+#3*(#1/10000)% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#3*(#1-#1/10000*10000)\relax!% }% % \end{macrocode} %\begin{lverb} % Writer: T!l2!l1!l0!. (|y| = T l2 l1 l0 10^z0): H = T l2, L = l1 % l0, % n = digits of H (<= 9), v = n - P; M = round(H 10^8 + L)/10^(8+v)); % g = z0 + 8 + v; calxtrig's \CALX_dgoc M.b.g. writes the native. %\end{lverb} % \begin{macrocode} \def\CALX_lgUw #1!#2!#3!#4!#5#6.% {% \expandafter\CALX_lgUwa\the\numexpr\expandafter\CALX_nd_c \the\numexpr#1#2\relax{10}987654321\xint:-\XINTdigits.#1#2.#3#4.#6.#5% }% \def\CALX_lgUwa #1.#2.#3.#4.% {% \expandafter\CALX_dgoc\the\numexpr\ifnum#1>\xint_c_ #2/\CALX_pten{#1}\else #2*\CALX_pten{-#1}+#3/\CALX_pten{8+#1}\fi \expandafter.\the\numexpr(2*(#4+8+#1)-7)/16\expandafter.% \the\numexpr#4+8+#1.% }% % \end{macrocode} % \subsection{Natural logarithm, P9..P16} %\begin{lverb} % Natural logarithm, P9..P16. % x = 10^E m, m = M 10^-15, M the 16-digit mantissa as limbs m1!m2!m3!m4!. % Grid W = 24: V = 10^24 (1+t) as limbs v0!..v6! (v0 units limb, 0 or 1). % Bootstrap 1+t0 = c m/10^4, c = nint(200000/(2a+1)), a = first two digits % (unity zone: c = 10^4 if E = 0, 10^3 if E = -1, no constant at all). % Stages k = 2,4,6 (classes B, C) or 2,4,6,8 (class A = [1.1,1.2) and the % unity zone): 1+t <- (1+t)(1+j 10^-k), j = nint(-10R/(10^4+T)). % Constants: tables for c, k=2, k=4 (calxlogdata.tex, \CALX_Lb, % \CALX_Ls<100j>, \CALX_Lt); k=6,8 on the fly; ln(1+t) = t - t^2/2. % Final sum in 8-digit pairs, one carry chain with E ln10 (|E| < 10^4); % 10^4 <= |E|: exact native addition of E floor(10^24 ln10) 10^-24. % Unity zone with |x-1| < 10^-4: direct series y = delta (1 - Q). %\end{lverb} % \begin{macrocode} \csname newcount\endcsname\CALX_Loff \CALX_Loff=1200000000 \csname newcount\endcsname\CALX_Lob \CALX_Lob=1000000000 \let\CALX_LQ\relax \def\CALX_LR #1#2#3#4#5#6{+#1#2#3#4#5#6-120000!}% \def\CALX_LRb #1#2#3#4#5#6{+#1#2#3#4#5#6-100000!}% \def\CALX_LRz #1#2#3#4#5#6#7#8#9{+#1#2#3#4#5#6-120000\xint_gobble_i}% \let\CALX_Lfr\CALX_fnround % \end{macrocode} %\begin{lverb} % entry: F+..\xint: ; n = ceil(D/8) blocks, E = D-1+8e %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_LtagF+\endcsname #1.#2.#3\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{log(0)}{-}}\fi \xint_orthat{\expandafter\CALX_Ltb \the\numexpr(#1+\xint_c_iii)/\xint_c_viii \expandafter.\the\numexpr#1-\xint_c_i+\xint_c_viii*#2.#1.#3\xint:}% }% \def\CALX_Ltb #1.#2.#3.#4\xint:% {\CALX_Lfr\XINTdigits{\csname CALX_Lin% \romannumeral#1\endcsname\CALX_LM#4\xint:#2.#3.}}% % \end{macrocode} %\begin{lverb} % digits of M (MS first), padded with zeros; #1 continuation (shared % with the generic path): n = 1..5 blocks, z = 8n - D leading zeros %\end{lverb} % \begin{macrocode} \def\CALX_Lini #11#2!\xint:#3.#4.% {\csname CALX_Lgz\the\numexpr8-#4\endcsname #1#200000000000000000000000000000000\relax#3.}% \def\CALX_Linii #11#2!1#3!\xint:#4.#5.% {\csname CALX_Lgz\the\numexpr16-#5\endcsname #1#3#200000000000000000000000000000000\relax#4.}% \def\CALX_Liniii #11#2!1#3!1#4!\xint:#5.#6.% {\csname CALX_Lgz\the\numexpr24-#6\endcsname #1#4#3#200000000000000000000000000000000\relax#5.}% \def\CALX_Liniv #11#2!1#3!1#4!1#5!\xint:#6.#7.% {\csname CALX_Lgz\the\numexpr32-#7\endcsname #1#5#4#3#200000000000000000000000000000000\relax#6.}% \def\CALX_Linv #11#2!1#3!1#4!1#5!1#6!\xint:#7.#8.% {\csname CALX_Lgz\the\numexpr40-#8\endcsname #1#6#5#4#3#200000000000000000000000000000000\relax#7.}% \expandafter\def\csname CALX_Lgz0\endcsname#1{#1}% \expandafter\def\csname CALX_Lgz1\endcsname#1#2{#1}% \expandafter\def\csname CALX_Lgz2\endcsname#1#2#3{#1}% \expandafter\def\csname CALX_Lgz3\endcsname#1#2#3#4{#1}% \expandafter\def\csname CALX_Lgz4\endcsname#1#2#3#4#5{#1}% \expandafter\def\csname CALX_Lgz5\endcsname#1#2#3#4#5#6{#1}% \expandafter\def\csname CALX_Lgz6\endcsname#1#2#3#4#5#6#7{#1}% \expandafter\def\csname CALX_Lgz7\endcsname#1#2#3#4#5#6#7#8{#1}% % \end{macrocode} %\begin{lverb} % a = the first two digits, read as tokens %\end{lverb} % \begin{macrocode} \def\CALX_LM #1#2#3#4#5#6#7#8{\CALX_LMb{#1#2.#1#2#3#4!#5#6#7#8!}}% \def\CALX_LMb #1#2#3#4#5#6#7#8#9{\CALX_LMc{#1#2#3#4#5!#6#7#8#9!}}% \def\CALX_LMc #1#2\relax{\CALX_Lclb#1}% % \end{macrocode} %\begin{lverb} % classification: a.m1!m2!m3!m4!E. %\end{lverb} % \begin{macrocode} \def\CALX_Lclb #1.#2!#3!#4!#5!#6.% {% \ifnum#6=\xint_c_ \xint_dothis{\CALX_LcZ#1.#2!#3!#4!#5!}\fi \ifnum#6=-\xint_c_i \xint_dothis{\CALX_LcM#1.#2!#3!#4!#5!}\fi \ifnum\ifnum#6<\xint_c_ -\fi#6>9999 \xint_dothis{\CALX_LcE#1.#2!#3!#4!#5!#6.}\fi \xint_orthat{\expandafter\CALX_LB\the\numexpr10*(200000/(2*#1+1));% #2!#3!#4!#5!\CALX_LsBa#1;#6;}% }% % \end{macrocode} %\begin{lverb} % E = 0: a = 10 is the unity zone [1,1.1): x = 1 exact zero; x < 1.0001 % direct series (\CALX_LUz); else stages 2..8 with c = 10^4. a = 11: % class A. E = -1: a >= 90 (x <> 0.9) is the unity zone [0.9,1): % x > 0.9999 direct series (\CALX_LUm); else stages 2..8 with c = 10^3. %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \gdef\CALX_LcZ #1.% {% \ifnum#1>11 \xint_dothis\CALX_LcZ_high\fi \ifnum#1=11 \xint_dothis\CALX_LcZ_oneone\fi \xint_orthat\CALX_LcZ_unity #1.% }% \gdef\CALX_LcZ_high #1.#2!#3!#4!#5!% {% \expandafter\CALX_LB \the\numexpr10*(200000/(2*#1+1));#2!#3!#4!#5!\CALX_LsBa#1;0;% }% \gdef\CALX_LcZ_oneone #1.#2!#3!#4!#5!% {% \expandafter\CALX_LB \the\numexpr10*(200000/(2*#1+1));#2!#3!#4!#5!\CALX_LsAa#1;0;% }% \gdef\CALX_LcZ_unity #1.#2!#3!#4!#5!% {% \ifnum\numexpr#2#3-10000000+#4#5\relax=\xint_c_ \xint_dothis{F+0.0.}\fi \ifnum#2#3<10001000 \xint_dothis{\CALX_LUz#2!#3!#4!#5!}\fi \xint_orthat{\CALX_LB100000;#2!#3!#4!#5!\CALX_LsAa0;0;}% }% \gdef\CALX_LcM #1.% {% \ifnum#1<90 \xint_dothis\CALX_LcM_low\fi \xint_orthat\CALX_LcM_regular #1.% }% \gdef\CALX_LcM_low #1.#2!#3!#4!#5!% {% \expandafter\CALX_LB \the\numexpr10*(200000/(2*#1+1));#2!#3!#4!#5!\CALX_LsBa#1;-1;% }% \gdef\CALX_LcM_regular #1.#2!#3!#4!#5!% {% \ifnum\numexpr#2#3-90000000+#4#5\relax =\xint_c_ \xint_dothis{\expandafter\CALX_LB \the\numexpr10*(200000/(2*#1+1));#2!#3!#4!#5!\CALX_LsBa#1;-1;}\fi \ifnum#2#3<99990000 \xint_dothis{\CALX_LB10000;#2!#3!#4!#5!\CALX_LsAa0;0;}\fi \ifnum\numexpr#2#3-99990000+#4#5\relax=\xint_c_ \xint_dothis{\CALX_LB10000;#2!#3!#4!#5!\CALX_LsAa0;0;}\fi \xint_orthat{\CALX_LUm#2!#3!#4!#5!}% }% \endgroup \def\CALX_LcE #1.#2!#3!#4!#5!#6.% {% \CALX_faddx{\expandafter\CALX_LB\the\numexpr10*(200000/(2*#1+1));% #2!#3!#4!#5!\CALX_LsBa#1;0;}% {\CALX_fmulx{\romannumeral0\CALX_ffromraw{#6[0]}}{\CALX_Lzeta}}% }% \edef\CALX_Lzeta{\romannumeral0\CALX_ffromraw {2302585092994045684017991[-24]}}% % \end{macrocode} %\begin{lverb} % bootstrap: J;m1!m2!m3!m4! -> v0!...!v6! %\end{lverb} % \begin{macrocode} \def\CALX_LB #1;#2!#3!#4!#5!#6% {% \expandafter#6\the\numexpr\xint_c_\expandafter\CALX_LRb \the\numexpr\CALX_Lob\expandafter\CALX_LRb \the\numexpr\CALX_Lob+#1*#2\expandafter\CALX_LRb \the\numexpr\CALX_Lob+#1*#3\expandafter\CALX_LRb \the\numexpr\CALX_Lob+#1*#4\expandafter\CALX_LRb \the\numexpr\CALX_Lob+#1*#5\relax!0000!% }% % \end{macrocode} %\begin{lverb} % stage kernels: J;v0!..v6! -> v0'!..v6'!J; % V' = V + floor(J V'/10^(4a)), a = 1 (\CALX_LKa) or 2 (\CALX_LKb); the % lowest column only gives its carry. %\end{lverb} % \begin{macrocode} \def\CALX_LKa #1#2;#3!#4!#5!#6!#7!#8!#9!% {% \expandafter#1\the\numexpr#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4+#2*#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#5+#2*#4\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6+#2*#5\expandafter\CALX_LR \the\numexpr\CALX_Loff+#7+#2*#6\expandafter\CALX_LR \the\numexpr\CALX_Loff+#8+#2*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#9+#2*#8\expandafter\CALX_LRz \the\numexpr\CALX_Loff+#2*#9\relax!#2;% }% \def\CALX_LKb #1#2;#3!#4!#5!#6!#7!#8!#9!% {% \expandafter#1\the\numexpr#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4\expandafter\CALX_LR \the\numexpr\CALX_Loff+#5+#2*#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6+#2*#4\expandafter\CALX_LR \the\numexpr\CALX_Loff+#7+#2*#5\expandafter\CALX_LR \the\numexpr\CALX_Loff+#8+#2*#6\expandafter\CALX_LR \the\numexpr\CALX_Loff+#9+#2*#7\expandafter\CALX_LRz \the\numexpr\CALX_Loff+#2*#8\relax!#2;% }% \def\CALX_LKz #1#2;#3!#4!#5!#6!#7!#8!#9!{#1#3!#4!#5!#6!#7!#8!#9!0;}% % \end{macrocode} %\begin{lverb} % selectors: y = (v0-1)10^4 + v1 = floor(10^4 t) is T % \CALX_Ldef {}{} %\end{lverb} % \begin{macrocode} \def\CALX_Lsel #1#2#3#4;% {\ifnum#4=\xint_c_ \expandafter#2\else\expandafter#1\fi#3#4;}% \def\CALX_Ldef #1#2#3#4#5#6% {\def#1##1!##2!##3!##4!{\expandafter\CALX_Lsel \expandafter#3\expandafter#4% \expandafter#2\the\numexpr#5(#6);##1!##2!##3!##4!}}% % \end{macrocode} %\begin{lverb} % stages k = 2,4,6: names #1,#2,#3, next #4, kernels shift 1 (#5), % shift 2 (#6), skip (#7); stage k = 8: name, next, kernel, skip. % Shared by P9..P16 and P17..P32. %\end{lverb} % \begin{macrocode} \def\CALX_Lsdef #1#2#3#4#5#6#7% {% \CALX_Ldef#1#2#5#7{100*}% {-10*(((##1-1)*10000+##2)*10+##3/1000)/((##1-1)*10000+##2+10000)}% \CALX_Ldef#2#3#5#7{}% {-10*(((##1-1)*10000+##2)*1000+##3/10)/((##1-1)*10000+##2+10000)}% \CALX_Ldef#3#4#6#7{100*}% {-10*((((##1-1)*10000+##2)*10000+##3)*10+##4/1000)/% ((##1-1)*10000+##2+10000)}% }% \def\CALX_Lsdefd #1#2#3#4% {% \CALX_Ldef#1#2#3#4{}% {-10*((((##1-1)*10000+##2)*10000+##3)*1000+##4/10)/% ((##1-1)*10000+##2+10000)}% }% \CALX_Lsdef\CALX_LsBa\CALX_LsBb\CALX_LsBc\CALX_LfB\CALX_LKa\CALX_LKb\CALX_LKz \CALX_Lsdef\CALX_LsAa\CALX_LsAb\CALX_LsAc\CALX_LsAd\CALX_LKa\CALX_LKb\CALX_LKz \CALX_Lsdefd\CALX_LsAd\CALX_LfA\CALX_LKb\CALX_LKz % \end{macrocode} %\begin{lverb} % final, stages 2,4,6: v0!..v6!J6; (then J4;J2;a;E;) % w = floor(10^14 t); pairs P1 = v1v2, P2 = v3v4, P3 = v5v6; % j6 terms (series of -ln(1+j 10^-6)): -100j at limb 2, 5000j^2 at limb 4, % -100j^3/3 at limb 5 (+ remainder at limb 6), j^4/4 - j^5/(5 10^6) at % limb 6; -t^2/2 = -w^2/(2 10^8) at limb 5. %\end{lverb} % \begin{macrocode} \def\CALX_LfB #1!#2!#3!#4!#5!#6!#7!#8;% {% \expandafter\CALX_LfBb\the\numexpr#8/100\expandafter;\the\numexpr (((#1-1)*10000+#2)*10000+#3)*1000000+% #4*100+#5/100;#8;#1!#2#3!#4#5!#6#7!% }% \def\CALX_LfBb #1;#2;#3;#4!#5!#6!#7!% {% \expandafter\CALX_LTa\the\numexpr#4#5-100000000-#3\expandafter!% \the\numexpr#6+#3*#3/2\expandafter!% \the\numexpr#7-(100*#1*#1*#1-3*(100*#1*#1*#1/3))*3333+#1*#1*#1*#1/4% -#1*#1*#1*#1*#1/5000000\expandafter!% \the\numexpr0-100*#1*#1*#1/3-#2*#2/200000000;% }% % \end{macrocode} %\begin{lverb} % final, stages 2,4,6,8: v0!..v6!J8;J6; w = floor(10^16 t) %\end{lverb} % \begin{macrocode} \def\CALX_LfA #1!#2!#3!#4!#5!#6!#7!#8;#9;% {% \expandafter\CALX_LfAb\the\numexpr#9/100\expandafter;\the\numexpr ((((#1-1)*10000+#2)*10000+#3)*10000+#4)*10000+#5;#8;#9;% #1!#2#3!#4#5!#6#7!% }% \def\CALX_LfAb #1;#2;#3;#4;#5!#6!#7!#8!% {% \expandafter\CALX_LTa\the\numexpr#5#6-100000000-#4-#3\expandafter!% \the\numexpr#7+#4*#4/2\expandafter!% \the\numexpr#8-(100*#1*#1*#1-3*(100*#1*#1*#1/3))*3333+#1*#1*#1*#1/4% -#1*#1*#1*#1*#1/5000000-#3*#3*#3/3-#2*#2/200000000\expandafter!% \the\numexpr5000*#3*#3-100*#1*#1*#1/3;% }% % \end{macrocode} %\begin{lverb} % add the tables (8-digit pairs, no carry): A!P2!P3!S5;key; % A = floor(10^8 y), P2, P3 the next pairs (entries: F1!c2!c3!...) %\end{lverb} % \begin{macrocode} \def\CALX_LT #1#2#3;#4;% {\expandafter\expandafter\expandafter#1\csname#2#4\endcsname\CALX_LQ#3;}% \def\CALX_LTa{\CALX_LT\CALX_LCAa{CALX_Lt}}% \def\CALX_LTb{\CALX_LT\CALX_LCAb{CALX_Ls}}% \def\CALX_LTc{\CALX_LT\CALX_LCAc{CALX_Lb}}% \def\CALX_Ltmp #1#2% {\def#1##1!##2!##3!##4\CALX_LQ##5!##6!##7!% {\expandafter#2\the\numexpr##1+##5\expandafter!\the\numexpr##2+##6% \expandafter!\the\numexpr##3+##7!}}% \CALX_Ltmp\CALX_LCAa\CALX_LTb \CALX_Ltmp\CALX_LCAb\CALX_LTc \CALX_Ltmp\CALX_LCAc\CALX_LTd \let\CALX_Ltmp\relax % \end{macrocode} %\begin{lverb} % carry chain with E ln10 (limbs of floor(10^24 ln 10) written in). % Template, shared with exp: \CALX_LTdef {} % {}{}; params ##1 A (10^-8), ##2 P2 (10^-16), % ##3 P3 (10^-24), ##4 S5 (10^-20), ##5 E; output I!l1!..!l6!. %\end{lverb} % \begin{macrocode} \def\CALX_LTdef #1#2#3#4#5% {% \def#1#3% {% \expandafter#2\the\numexpr#4 2*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+3025*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##1+8509*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+2994*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##2+456*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##4+8401*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##3+7991*##5\relax!#5% }% }% \CALX_LTdef\CALX_LTd\CALX_LNat{#1!#2!#3!#4;#5;}{}{}% % \end{macrocode} %\begin{lverb} % floor form I!l1!..!l6! -> native float, blocks written directly % (value I + 0.l1...l6; negative: complement, |y| - 10^-24); D from % calxcore's \CALX_ndig. Only |y| < 10^-8 (large-E path) uses \CALX_rsa. % Template (shared with P24): \CALX_LNdef

{}{} % {}{}{}{}; e = number of 8-digit % pairs after I (D = 8e + ndig). %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \gdef\CALX_LNdef #1#2#3#4#5#6#7#8#9% {% \def#1##1!{\ifnum##1<\xint_c_ \expandafter#3\else\expandafter#2\fi##1!}% \def#2#4% {% \ifnum##1>\xint_c_ \xint_dothis{\expanded{F+\the\numexpr#5*8+% \CALX_ndig{##1}.-#5.#61\expandafter\xint_gobble_i \the\numexpr\xint_c_e_viii+##1!}}\fi \ifnum##2##3>\xint_c_ \xint_dothis{\expanded{F+\the\numexpr#5*8-8+% \CALX_ndig{##2##3}.-#5.#6}}\fi \xint_orthat{\expanded{\CALX_rsa#9\CALX_bp+!\expandafter\xint_gobble_i \the\numexpr\xint_c_e_viii+##1!#8}}% }% \def#3#4% {% \ifnum##1<-\xint_c_i \xint_dothis{\expanded{F-\the\numexpr#5*8+% \CALX_ndig{-##1-1}.-#5.#7% 1\expandafter\xint_gobble_i\the\numexpr\xint_c_e_viii-##1-1!}}\fi \ifnum##2##3<99999999 \xint_dothis{\expanded{F-\the\numexpr#5*8-8+% \CALX_ndig{99999999-##2##3}.-#5.#7}}\fi \xint_orthat{\expanded{\CALX_rsa#9\CALX_bn-!\the\numexpr \xint_c_e_viii+##1!#8}}% }% }% \endgroup \CALX_LNdef\CALX_LNat\CALX_LNp\CALX_LNn{#1!#2!#3!#4!#5!#6!#7!}{3}% {1#6#7!1#4#5!1#2#3!}% {\the\numexpr199999999-#6#7!\the\numexpr199999999-#4#5!% \the\numexpr199999999-#2#3!}% {#2!#3!#4!#5!#6!#7!}{4.3.}% % \end{macrocode} %\begin{lverb} % unity zone, |x-1| < 10^-4: delta = s D 10^-16, D < 10^12 as limbs % a!b!c! (c <= 10^4). Horner G_n = 1/n - delta G_(n+1) on 6 fixed limbs % (\CALX_LH), from G_5 (|x-1| >= 10^-5), G_4 (>= 10^-7), % G_3 (>= 10^-10) or G_2; Q = delta G_2; y = s D (1 - Q) 10^-16 with % D (1 - Q) computed exactly (\CALX_LY). Relative error of y below % 3.4 10^-21 (remainder), budget 5 10^-20. %\end{lverb} % \begin{macrocode} \csname newcount\endcsname\CALX_Loffh \CALX_Loffh=1400000000 \def\CALX_LRh #1#2#3#4#5#6{+#1#2#3#4#5#6-140000!}% \def\CALX_LRhz #1#2#3#4#5#6#7#8#9{+#1#2#3#4#5#6-140000\xint_gobble_i}% \def\CALX_LUz #1!#2!#3!#4!% {% \expandafter\CALX_LUs\expandafter P\the\numexpr10*#2+(2*#3-999)/2000% \expandafter!\the\numexpr10*(#3-1000*((2*#3-999)/2000))+(2*#4-999)/2000% \expandafter!\the\numexpr10*(#4-1000*((2*#4-999)/2000))!% }% \def\CALX_LUm #1!#2!#3!#4!% {% \expandafter\CALX_LUs\expandafter M\the\numexpr9999-#2\expandafter!% \the\numexpr9999-#3\expandafter!\the\numexpr10000-#4!% }% \def\CALX_LUs #1#2!#3!% {% \ifnum#2>999 \xint_dothis{\csname CALX_LHd#1\endcsname 2000!0000!0000!0000!0000!0000!}\fi \ifnum#2>9 \xint_dothis{\csname CALX_LHc#1\endcsname 2500!0000!0000!0000!0000!0000!}\fi \ifnum\numexpr#2*10000+#3>99 \xint_dothis{\csname CALX_LHb#1\endcsname 3333!3333!3333!3333!3333!3333!}\fi \xint_orthat{\csname CALX_LHq#1\endcsname 5000!0000!0000!0000!0000!0000!}#2!#3!% }% % \end{macrocode} %\begin{lverb} % G' = C D 10^-16 G: g1..g6, a, b, c; C literal (floor of 1/n) %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1#2#3#4#5#6#7#8#9% {% \def#1##1!##2!##3!##4!##5!##6!##7!##8!##9!% {% \expandafter#2\the\numexpr#4\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#5\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#6#3##7*##1\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#7#3(##7*##2+##8*##1)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#8#3(##7*##3+##8*##2+##9*##1)% \expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#9#3(##7*##4+##8*##3+##9*##2)% \expandafter\CALX_LRhz \the\numexpr\CALX_Loffh#3(##7*##5+##8*##4+##9*##3)\relax!##7!##8!##9!% }% }% \CALX_Ltmp\CALX_LHdP\CALX_LHcP-{2500}{0000}{0000}{0000}{0000}{0000}% \CALX_Ltmp\CALX_LHcP\CALX_LHbP-{3333}{3333}{3333}{3333}{3333}{3333}% \CALX_Ltmp\CALX_LHbP\CALX_LHqP-{5000}{0000}{0000}{0000}{0000}{0000}% \CALX_Ltmp\CALX_LHqP\CALX_LYP+{0}{0}{0}{0}{0}{0}% \CALX_Ltmp\CALX_LHdM\CALX_LHcM+{2500}{0000}{0000}{0000}{0000}{0000}% \CALX_Ltmp\CALX_LHcM\CALX_LHbM+{3333}{3333}{3333}{3333}{3333}{3333}% \CALX_Ltmp\CALX_LHbM\CALX_LHqM+{5000}{0000}{0000}{0000}{0000}{0000}% \CALX_Ltmp\CALX_LHqM\CALX_LYM+{0}{0}{0}{0}{0}{0}% % \end{macrocode} %\begin{lverb} % D (1 |Q|), exact: q1..q6, a, b, c -> 1<8 digits>!y1!y0!f1!..!f6! %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1#2#3% {% \def#1##1!##2!##3!##4!##5!##6!##7!##8!##9!% {% \expandafter#3\the\numexpr\xint_c_e_viii+##7\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+##8#2##7*##1\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+##9#2(##7*##2+##8*##1)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh#2(##7*##3+##8*##2+##9*##1)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh#2(##7*##4+##8*##3+##9*##2)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh#2(##7*##5+##8*##4+##9*##3)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh#2(##7*##6+##8*##5+##9*##4)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh#2(##8*##6+##9*##5)\expandafter\CALX_LRh \the\numexpr\CALX_Loffh#2##9*##6\relax!% }% }% \CALX_Ltmp\CALX_LYP-\CALX_LUop \CALX_Ltmp\CALX_LYM+\CALX_LUom \let\CALX_Ltmp\relax % \end{macrocode} %\begin{lverb} % y = s Z 10^-40, Z the integer of the five blocks %\end{lverb} % \begin{macrocode} \def\CALX_LUop 1#1!#2!#3!#4!#5!#6!#7!#8!#9!% {\expanded{\CALX_rsa5.5.\CALX_bp+!#1!#2!#3!#4!#5!#6!#7!#8!#9!}}% \def\CALX_LUom 1#1!#2!#3!#4!#5!#6!#7!#8!#9!% {\expanded{\CALX_rsa5.5.\CALX_bp-!#1!#2!#3!#4!#5!#6!#7!#8!#9!}}% % \end{macrocode} %\begin{lverb} % special values (tags F-, I+, I-, I?) %\end{lverb} % \begin{macrocode} \expandafter\let\csname CALX_LtagF-\expandafter\endcsname \csname CALX_lgHsF-\endcsname \expandafter\let\csname CALX_LtagI+\expandafter\endcsname \csname CALX_lgHsI+\endcsname \expandafter\let\csname CALX_LtagI-\expandafter\endcsname \csname CALX_lgHsI-\endcsname \expandafter\let\csname CALX_LtagI?\expandafter\endcsname \csname CALX_lgHsI?\endcsname % \end{macrocode} %\begin{lverb} % (dispatch \CALX_lga$empty: at the end of the P17..P32 code) %\end{lverb} % \subsection{Natural logarithm, P17..P32} %\begin{lverb} % Layout L = 8 ceil(P/8) (24 or 32), % grid W = L + 8, V = 10^W (1+t) as v0!v1!..!vn! (n = W/4 = 8 or 10), % followed by the sentinel pair \CALX_LQ!\CALX_LQ!. Stages k = 2,4,6,8 with % tables for every class; series t - t^2/2 + t^3/3 (- t^4/4 for L = 32). % |x - 1| < 10^-4: y = delta G by the series kernel \CALX_Z (calxtrig). % entry: F+..\xint: %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \expandafter\gdef\csname CALX_LGtagF+\endcsname #1.#2.#3\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{log(0)}{-}}\fi \xint_orthat{\expandafter\CALX_LGtb\the\numexpr(#1+\xint_c_iii)/\xint_c_viii \expandafter.\the\numexpr#1-\xint_c_i+\xint_c_viii*#2.#1.#3\xint:}% }% \endgroup \def\CALX_LGtb #1.#2.#3.#4\xint:% {\CALX_Lfr\XINTdigits{\CALX_LGL\XINTdigits.#1.#2.#3.#4\xint:}}% % \end{macrocode} %\begin{lverb} % Internal log at precision P (#1: the token \XINTdigits, or digits % delimited by the dot), n blocks, E, D, blocks: digits by \CALX_Lin % (P <= 32) or \CALX_LGin, continuation \CALX_LGh (g = (P-5)/8 groups % more), then {P} in the slot read by \CALX_LGcl (#6). %\end{lverb} % \begin{macrocode} \def\CALX_LGL #1.#2.#3.#4.#5\xint:% {\csname CALX_\ifnum#1>32 LGin\else Lin\romannumeral#2\fi\expandafter \endcsname\csname CALX_LGh\the\numexpr(#1-5)/8\endcsname#5\xint:#3.#4.{#1}}% % \end{macrocode} %\begin{lverb} % P > 32: blocks (LS first) reversed by a loop, leading zeros of the top % block removed (\CALX_Lgz), 112 zeros of padding (P <= 112) %\end{lverb} % \begin{macrocode} \def\CALX_LGin #1{\CALX_LGir{#1}{}}% \def\CALX_LGir #1#2#3{\xint_gob_til_xint: #3\CALX_LGie\xint:\CALX_LGis{#1}{#2}#3}% \def\CALX_LGis #1#2#3#4!{\CALX_LGir{#1}{#4#2}}% \def\CALX_LGie\xint:\CALX_LGis#1#2\xint:#3.#4.% {% \csname CALX_Lgz\the\numexpr8*((#4+3)/8)-#4\endcsname#1#2% 00000000000000000000000000000000000000000000000000000% 00000000000000000000000000000000000000000000000000000000000\relax#3.% }% % \end{macrocode} %\begin{lverb} % digits -> a.m1!m2!..., 8 digits per call (g = (P-5)/8 more calls): % first call \CALX_LGh (g baked, g = 2..13) %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1#2% {\expandafter\edef\csname CALX_LGg#1\endcsname##1##2##3##4##5##6##7##8##9% {\expandafter\noexpand\csname CALX_LGg#2\endcsname {##1##2##3##4##5!##6##7##8##9!}}}% \CALX_Ltmp{1}{0}\CALX_Ltmp{2}{1}\CALX_Ltmp{3}{2}\CALX_Ltmp{4}{3}% \CALX_Ltmp{5}{4}\CALX_Ltmp{6}{5}\CALX_Ltmp{7}{6}\CALX_Ltmp{8}{7}% \CALX_Ltmp{9}{8}\CALX_Ltmp{10}{9}\CALX_Ltmp{11}{10}\CALX_Ltmp{12}{11}% \CALX_Ltmp{13}{12}% \def\CALX_Ltmp #1% {\expandafter\edef\csname CALX_LGh#1\endcsname##1##2##3##4##5##6##7##8% {\expandafter\noexpand\csname CALX_LGg#1\endcsname {##1##2.##1##2##3##4!##5##6##7##8!}}}% \CALX_Ltmp{2}\CALX_Ltmp{3}\CALX_Ltmp{4}\CALX_Ltmp{5}\CALX_Ltmp{6}\CALX_Ltmp{7}% \CALX_Ltmp{8}\CALX_Ltmp{9}\CALX_Ltmp{10}\CALX_Ltmp{11}\CALX_Ltmp{12}% \CALX_Ltmp{13}% \expandafter\def\csname CALX_LGg0\endcsname #1#2\relax#3.% {\CALX_LGcl#3.#1\CALX_LQ!\CALX_LQ!}% % \end{macrocode} %\begin{lverb} % classification: E.a.m1!m2!...\CALX_LQ!\CALX_LQ!{P} (P: the token % \XINTdigits or digits; stages \CALX_LGsa, g = (P-5)/8; P. appended at % the end of the tail J8;J6;J4;J2;a;E; for \CALX_LGo / absorbed by L24) % "#1#2" (E then a) is 10 iff E = 0, a = 10; in [-199,-191] iff E = -1, % a >= 91 (a = 90 stays ordinary: x = 0.9 is not in the unity zone). %\end{lverb} % \begin{macrocode} \def\CALX_LGcl #1.#2.% {% \ifnum\ifnum#1<\xint_c_ -\fi#1>9999 \xint_dothis\CALX_LGcl_large\fi \xint_orthat\CALX_LGcl_regular #1.#2.% }% \def\CALX_LGcl_large #1.#2.#3!#4!#5\CALX_LQ!\CALX_LQ!#6% {% \CALX_faddx{\expandafter\CALX_LGB \csname CALX_LGsa\the\numexpr(#6-5)/8\expandafter\endcsname \the\numexpr10*(200000/(2*#2+1));#3!#4!#5\CALX_LQ!\CALX_LQ!#2;0;#6.}% {\CALX_fmulx{\romannumeral0\CALX_ffromraw{#1[0]}}{\CALX_LzetaL}}% }% \def\CALX_LGcl_regular #1.#2.#3!#4!#5\CALX_LQ!\CALX_LQ!#6% {% \ifnum\ifnum#1#2=10 #3#4\else999999999\fi<10001000 \xint_dothis{\CALX_LWs#4!#5\CALX_LQ!{#6}}\fi \ifnum#1#2=10 \xint_dothis{\expandafter\CALX_LGB \csname CALX_LGsa\the\numexpr(#6-5)/8\endcsname 100000;#3!#4!#5\CALX_LQ!\CALX_LQ!0;0;#6.}\fi \ifnum\ifnum#1#2<-199 \xint_c_\else\ifnum#1#2<-190 #3#4\else\xint_c_\fi\fi >99989999 \xint_dothis{\expandafter\CALX_LWt \the\numexpr#4-10000!#5\CALX_LQ!{#6}}\fi \ifnum\ifnum#1#2<-199 \xint_c_\else#1#2\fi<-190 \xint_dothis{\expandafter\CALX_LGB \csname CALX_LGsa\the\numexpr(#6-5)/8\endcsname 10000;#3!#4!#5\CALX_LQ!\CALX_LQ!0;0;#6.}\fi \xint_orthat{\expandafter\CALX_LGB \csname CALX_LGsa\the\numexpr(#6-5)/8\expandafter\endcsname \the\numexpr10*(200000/(2*#2+1));#3!#4!#5\CALX_LQ!\CALX_LQ!#2;#1;#6.}% }% \edef\CALX_LzetaL{\romannumeral0\CALX_ffromraw{\CALX_Lzraw}}% % \end{macrocode} %\begin{lverb} % end test on the sentinel pair (gob-til) %\end{lverb} % \begin{macrocode} \def\CALX_LGgt #1\CALX_LQ{}% % \end{macrocode} %\begin{lverb} % bootstrap: J;m1!..!\CALX_LQ!\CALX_LQ! -> v0!..!vn!sentinel % V = J M 10^4, J = 10c (unity zone: 10^5 if E = 0, 10^4 if E = -1) %\end{lverb} % \begin{macrocode} \def\CALX_LGB #1#2;% {\expandafter#1\the\numexpr\xint_c_\expandafter\CALX_LRb \the\numexpr\CALX_Lob\CALX_LGBp#2;}% \def\CALX_LGBp #1;#2!#3!% {% \CALX_LGgt#2\CALX_LGBe\CALX_LQ\expandafter\CALX_LRb \the\numexpr\CALX_Lob+#1*#2\expandafter\CALX_LRb \the\numexpr\CALX_Lob+#1*#3\CALX_LGBp#1;% }% \def\CALX_LGBe\CALX_LQ#1\CALX_LGBp#2;{\relax!0000!\CALX_LQ!\CALX_LQ!}% % \end{macrocode} %\begin{lverb} % stage kernels: J;v0!..!vn!sentinel -> v0'!..!vn'!sentinel J; % V' = V + floor(J V/10^(4s)), s = 1 (\CALX_LGKa), 2 (\CALX_LGKb); the % dropped column only gives its carry (\CALX_LRz). %\end{lverb} % \begin{macrocode} \def\CALX_LGKa #1#2;#3!{\expandafter#1\the\numexpr#3\CALX_LGPa#2;#3!}% \def\CALX_LGPa #1;#2!#3!#4!% {% \CALX_LGgt#3\CALX_LGPe\CALX_LQ\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1*#2+#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1*#3+#4\CALX_LGPa#1;#4!% }% \def\CALX_LGPe\CALX_LQ\expandafter\CALX_LR\the\numexpr\CALX_Loff+#1*#2+#3% \CALX_LQ!% {\expandafter\CALX_LRz\the\numexpr\CALX_Loff+#1*#2\relax!\CALX_LQ!\CALX_LQ!#1;}% \def\CALX_LGKb #1#2;#3!{\expandafter#1\the\numexpr#3\CALX_LGPb#2;0!#3!}% \def\CALX_LGPb #1;#2!#3!#4!#5!% {% \CALX_LGgt#4\CALX_LGPf\CALX_LQ\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1*#2+#4\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1*#3+#5\CALX_LGPb#1;#4!#5!% }% \def\CALX_LGPf\CALX_LQ\expandafter\CALX_LR\the\numexpr\CALX_Loff+#1*#2+#3% \CALX_LQ!\CALX_LQ!% {\expandafter\CALX_LRz\the\numexpr\CALX_Loff+#1*#2\relax!\CALX_LQ!\CALX_LQ!#1;}% \def\CALX_LGKz #1#2;#3\CALX_LQ!\CALX_LQ!{#1#3\CALX_LQ!\CALX_LQ!0;}% % \end{macrocode} %\begin{lverb} % selectors (templates of P9..P16): one set per layout g = 2..13 % (\CALX_LGsa..\CALX_LGsd, final \CALX_LGf): the layout reaches % the final through the selectors' continuations. % final: layout g and sign by v0 (|t| < 5.061e-9: v1 = v2 = 0000 if % v0 = 1, 9999 if v0 = 0) %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1% {\expandafter\CALX_Ltmpc\csname CALX_LGsa#1\expandafter\endcsname \csname CALX_LGsb#1\expandafter\endcsname\csname CALX_LGsc#1\expandafter \endcsname\csname CALX_LGsd#1\expandafter\endcsname \csname CALX_LGf#1\endcsname{#1}}% \def\CALX_Ltmpc #1#2#3#4#5#6% {% \CALX_Lsdef#1#2#3#4\CALX_LGKa\CALX_LGKb\CALX_LGKz \CALX_Lsdefd#4#5\CALX_LGKb\CALX_LGKz \def#5##1!{\csname CALX_LGf\ifnum##1=\xint_c_ n\else p\fi#6\endcsname}% }% \CALX_Ltmp{2}\CALX_Ltmp{3}\CALX_Ltmp{4}\CALX_Ltmp{5}\CALX_Ltmp{6}\CALX_Ltmp{7}% \CALX_Ltmp{8}\CALX_Ltmp{9}\CALX_Ltmp{10}\CALX_Ltmp{11}\CALX_Ltmp{12}% \CALX_Ltmp{13}% \let\CALX_Ltmpc\relax % \end{macrocode} %\begin{lverb} % L = 24 (W = 32): v3..v8 -> P4!P3!P2!A; tau = |t| limbs (n: 9999-v, % |t| - 10^-32), s = tau3tau4, rho = tau5tau6; pairs P2 (10^-16), P3 % (10^-24), P4 (10^-32). y = t - t^2/2 + t^3/3. % #1 suffix, #2 v1!v2!, #3 limb complement prefix, #4 pair complement % prefix, #5 A, #6 sign of the cubic %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1#2#3#4#5#6% {% \expandafter\def\csname CALX_LGf#1\endcsname#2##1!##2!##3!##4!##5!##6!% \CALX_LQ!\CALX_LQ!% {% \expandafter\CALX_LGTva\the\numexpr##5##6% -((#3##1)*(#3##1)-2*((#3##1)*(#3##1)/2))*50000000% -((#3##1)*(#3##2)-10000*((#3##1)*(#3##2)/10000))*10000% -(#3##2)*(#3##2)/2-(#4##1##2)*(#4##3##4)/100000000% #6(#4##1##2)*(#4##1##2)/100000000*(#4##1##2)/300000000% \expandafter!\the\numexpr##3##4-(#3##1)*(#3##1)/2% -(#3##1)*(#3##2)/10000!##1##2!#5;% }% }% \CALX_Ltmp{p2}{0000!0000!}{}{}{0}+% \CALX_Ltmp{n2}{9999!9999!}{9999-}{99999999-}{-1}-% % \end{macrocode} %\begin{lverb} % L = 32 (W = 40): step 1 -> Hs!Ls!u!w!tau5!tau6!lambda!mu! % (s^2 = Hs 10^8 + Ls exactly, u = tau3, w = tau4); n: complements. %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_LGfp3\endcsname 0000!0000!#1!#2!#3!#4!#5!#6!#7!#8!% \CALX_LQ!\CALX_LQ!% {% \expandafter\CALX_LGgp\the\numexpr#1*#1+2*#1*#2/10000\expandafter!% \the\numexpr(2*#1*#2-10000*(2*#1*#2/10000))*10000+#2*#2!% #1!#2!#3!#4!#5#6!#7#8!% }% \expandafter\def\csname CALX_LGfn3\endcsname 9999!9999!#1!#2!#3!#4!#5!#6!#7!#8!% \CALX_LQ!\CALX_LQ!% {% \expandafter\CALX_LGgn\the\numexpr(9999-#1)*(9999-#1)% +2*(9999-#1)*(9999-#2)/10000\expandafter!% \the\numexpr(2*(9999-#1)*(9999-#2)-10000*(2*(9999-#1)*(9999-#2)/10000))% *10000+(9999-#2)*(9999-#2)\expandafter!% \the\numexpr9999-#1\expandafter!\the\numexpr9999-#2\expandafter!% \the\numexpr9999-#3\expandafter!\the\numexpr9999-#4\expandafter!% \the\numexpr99999999-#5#6\expandafter!\the\numexpr99999999-#7#8!% }% % \end{macrocode} %\begin{lverb} % step 2: Hs!Ls!u!w!tau5!tau6!lambda!mu! -> P4!P3!P2!A!P5; % #1 name, #2 pair complement prefix, #3 tokens writing A, #4 sign of t %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1#2#3#4% {% \def#1##1!##2!##3!##4!##5!##6!##7!##8!% {% \expandafter\CALX_LGTvb\the\numexpr#2##7% -(##1-2*(##1/2))*50000000-##2/2-##3*##5% -(##3*##6+##4*##5+##4*##6/10000)/10000% #4(##3*(##1/10000)/3% +(##3*(##1-10000*(##1/10000))+##4*(##1/10000))/30000)% \expandafter!\the\numexpr#2(##5*10000+##6)-##1/2% \expandafter!\the\numexpr#2(##3*10000+##4)% #3\the\numexpr#2##8% -(##2-2*(##2/2))*50000000% -((##3*##6+##4*##5-10000*((##3*##6+##4*##5+##4*##6/10000)/10000))% *10000+##4*##6)% -(##3*10000+##4)*##7/100000000% -(##5*10000+##6)*(##5*10000+##6)/200000000% -(##3*10000+##4)*##8/100000000/100000000% -(##5*10000+##6)*##7/100000000/100000000% #4((##3*(##1/10000)-3*(##3*(##1/10000)/3))*33333333% +((##3*(##1-10000*(##1/10000))+##4*(##1/10000))-30000*% ((##3*(##1-10000*(##1/10000))+##4*(##1/10000))/30000))*10000/3% +##4*(##1-10000*(##1/10000))/3% +(##3*10000+##4)*##2/300000000% +##1*(##5*10000+##6)/100000000% +##2*(##5*10000+##6)/100000000/100000000)% -##1*##1/400000000;% }% }% \CALX_Ltmp\CALX_LGgp{}{\expandafter!\expandafter0\expandafter!}+% \CALX_Ltmp\CALX_LGgn{99999999-}% {\expandafter!\expandafter-\expandafter1\expandafter!}-% % \end{macrocode} %\begin{lverb} % tables: fetch + add, order Lv, Lu, Lt, Ls, Lb. Templates (shared % with exp P17..P32): \CALX_LGTdef , % \CALX_LGAdef (L = 24), \CALX_LGBdef (L = 32) % fetch: ;; -> \CALX_LQ; %\end{lverb} % \begin{macrocode} \def\CALX_LGTdef #1#2#3% {\def#1##1;##2;{\expandafter\expandafter\expandafter#3% \csname#2##2\endcsname\CALX_LQ##1;}}% % \end{macrocode} %\begin{lverb} % add, L = 24: F1!c2!c3!c4!rest\CALX_LQ P4!P3!P2!A; %\end{lverb} % \begin{macrocode} \def\CALX_LGAdef #1#2% {\def#1##1!##2!##3!##4!##5\CALX_LQ##6!##7!##8!##9;% {\expandafter#2\the\numexpr##6+##4\expandafter!\the\numexpr##7+##3% \expandafter!\the\numexpr##8+##2\expandafter!\the\numexpr##9+##1;}}% % \end{macrocode} %\begin{lverb} % add, L = 32: accs P4!P3!P2!A!P5; (c5 + P5 by \CALX_LGCe) %\end{lverb} % \begin{macrocode} \def\CALX_LGBdef #1#2% {\def#1##1!##2!##3!##4!##5\CALX_LQ##6!##7!##8!##9!% {\expandafter#2\the\numexpr##6+##4\expandafter!\the\numexpr##7+##3% \expandafter!\the\numexpr##8+##2\expandafter!\the\numexpr##9+##1% \expandafter!\the\numexpr\CALX_LGCe##5\CALX_LQ}}% \def\CALX_LGCe #1!#2\CALX_LQ#3;{#1+#3;}% \CALX_LGTdef\CALX_LGTva{CALX_Lv}\CALX_LGAva \CALX_LGAdef\CALX_LGAva\CALX_LGTua \CALX_LGTdef\CALX_LGTua{CALX_Lu}\CALX_LGAua \CALX_LGAdef\CALX_LGAua\CALX_LGTta \CALX_LGTdef\CALX_LGTta{CALX_Lt}\CALX_LGAta \CALX_LGAdef\CALX_LGAta\CALX_LGTsa \CALX_LGTdef\CALX_LGTsa{CALX_Ls}\CALX_LGAsa \CALX_LGAdef\CALX_LGAsa\CALX_LGTba \CALX_LGTdef\CALX_LGTba{CALX_Lb}\CALX_LGAba \CALX_LGAdef\CALX_LGAba\CALX_LGca \CALX_LGTdef\CALX_LGTvb{CALX_Lv}\CALX_LGAvb \CALX_LGBdef\CALX_LGAvb\CALX_LGTub \CALX_LGTdef\CALX_LGTub{CALX_Lu}\CALX_LGAub \CALX_LGBdef\CALX_LGAub\CALX_LGTtb \CALX_LGTdef\CALX_LGTtb{CALX_Lt}\CALX_LGAtb \CALX_LGBdef\CALX_LGAtb\CALX_LGTsb \CALX_LGTdef\CALX_LGTsb{CALX_Ls}\CALX_LGAsb \CALX_LGBdef\CALX_LGAsb\CALX_LGTbb \CALX_LGTdef\CALX_LGTbb{CALX_Lb}\CALX_LGAbb \CALX_LGBdef\CALX_LGAbb\CALX_LGcb % \end{macrocode} %\begin{lverb} % carry chains with E ln10 (limbs of floor(10^40 ln10)); the last pair % is split (its column could leave the 10-digit range). Templates % (shared with exp): \CALX_LGcadef / \CALX_LGcbdef {} % {}; params ##1..##4 P4!P3!P2!A (L24), ##1..##5 % P4!P3!P2!A!P5 (L32), then E (##5 / ##6); output I!l1!..!ln! % (L24: + tail #5; L32: + \CALX_LQ) %\end{lverb} % \begin{macrocode} \def\CALX_LGcadef #1#2#3#4#5% {% \def#1#3% {% \expandafter#2\the\numexpr#4 2*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+3025*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##4+8509*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+2994*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##3+456*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+8401*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+##2+7991*##5\expandafter\CALX_LR \the\numexpr\CALX_Loff+4546*##5+##1/10000\expandafter\CALX_LR \the\numexpr\CALX_Loff+8436*##5+##1-##1/10000*10000\relax!#5% }% }% \CALX_LGcadef\CALX_LGca\CALX_LNaat{#1!#2!#3!#4;#5;#6.}{}{}% P4!P3!P2!A;E;P. \def\CALX_LGcbdef #1#2#3#4% {% \def#1#3% {% \expandafter#2\the\numexpr#4 2*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+3025*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+##4+8509*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+2994*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+##3+456*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+8401*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+##2+7991*##6\expandafter\CALX_LR \the\numexpr\CALX_Loff+4546*##6+##1/10000\expandafter\CALX_LR \the\numexpr\CALX_Loff+8436*##6+##1-##1/10000*10000\expandafter\CALX_LR \the\numexpr\CALX_Loff+4207*##6+##5/10000\expandafter\CALX_LR \the\numexpr\CALX_Loff+6011*##6+##5-##5/10000*10000\relax!\CALX_LQ }% }% \CALX_LGcbdef\CALX_LGcb\CALX_LGo{#1!#2!#3!#4!#5;#6;}{}% P4!P3!P2!A!P5;E; (P. -> LGo) % \end{macrocode} %\begin{lverb} % output: L = 24 by the P16 template, L = 32 by calxtrig's \CALX_rsa %\end{lverb} % \begin{macrocode} \CALX_LNdef\CALX_LNaat\CALX_LNap\CALX_LNan{#1!#2!#3!#4!#5!#6!#7!#8!#9!}{4}% {1#8#9!1#6#7!1#4#5!1#2#3!}% {\the\numexpr199999999-#8#9!\the\numexpr199999999-#6#7!% \the\numexpr199999999-#4#5!\the\numexpr199999999-#2#3!}% {#2!#3!#4!#5!#6!#7!#8!#9!}{5.4.}% % \end{macrocode} %\begin{lverb} % generic (P > 24): I!l1!..!ln!\CALX_LQ P. (P from the tail), % m = W/8 = ceil(P/8) + 1 pairs %\end{lverb} % \begin{macrocode} \def\CALX_LGo #1!#2\CALX_LQ#3.% {\expandafter\CALX_LGoq\the\numexpr(#3+3)/8+2\expandafter.% \the\numexpr(#3+3)/8+1.#1!#2\CALX_LQ}% \def\CALX_LGoq #1.#2.#3!#4\CALX_LQ% {% \ifnum#3<\xint_c_ \xint_dothis{\expanded{\CALX_rsa#1.#2.\CALX_bn-!% \the\numexpr\xint_c_e_viii+#3!#4}}\fi \xint_orthat{\expanded{\CALX_rsa#1.#2.\CALX_bp+!\expandafter\xint_gobble_i \the\numexpr\xint_c_e_viii+#3!#4}}% }% % \end{macrocode} %\begin{lverb} % unity zone |x - 1| < 10^-4: y = delta G, G = sum_k (-delta)^k/(k+1), % Horner by the series kernel \CALX_Z (calxtrig), decreasing widths: level % k has scale 10^(4(A-k)), T_k = C_k - U' T_(k+1) 10^(-4b), U' = 10^4 delta % (b_0 = M - 1 limbs, U_k its top b_k = min(b_0, A-k-1) limbs), C_k = % floor(10^(4(A-k))/(k+1)) (\CALX_cdl), T_(A-1) = C_(A-1) (one limb), % levels k = A-2..1 (b_k, m = A-k-1, n = A-k), level 0 with C_0 = 10^(4A) % (n = A+1 limbs, output negated), then the exact product level % (\CALX_Zlevp$empty: b_0 by A+1 limbs, all columns, floor carries). % A = ceil((P+4)/4) up to P = 64, ceil((P+5)/4) above; error of T_0 at % most 3A - 4 + 1/(A+1) units 10^(-4A) (each % level: |err| < 0.503). % y = (x - 1) T_0 10^(-4A): exact product by one more kernel level, one % rounding. % Schedule \CALX_Zul

(P = 17..112): {C_(A-1)}{\CALX_LWk}. %\end{lverb} % \begin{macrocode} \def\CALX_LWrv #1\relax{\CALX_LWrw#1\relax\relax}% reverse l!..l! (load time) \def\CALX_LWrw #1!#2\relax#3\relax% {\if\relax\detokenize{#2}\relax#1!#3\else\CALX_LWrw#2\relax#1!#3\relax\fi}% \def\CALX_LWzr #1.{\ifnum#1>\xint_c_ 0!\expandafter\CALX_LWzr \the\numexpr#1-1\expandafter.\fi}% \def\CALX_LWmin #1#2{\ifnum#1<\numexpr#2\relax#1\else#2\fi}% \def\CALX_LWlev #1.#2.#3.#4{\CALX_Zlev{#1}{#2}{#3}{#4}}% % \end{macrocode} %\begin{lverb} % coefficient hook: log, log1p: 1/(k+1); expm1 sets it to % exp's \CALX_exgK (1/(k+1)!) while building its schedules %\end{lverb} % \begin{macrocode} \def\CALX_LWco{\CALX_tcoef{l}}% \def\CALX_LWbl #1.% {% \ifnum#1>\xint_c_ \expandafter\CALX_LWlev\the\numexpr\CALX_LWmin\CALX_LWm{\CALX_LWa-#1-1}% \expandafter.\the\numexpr\CALX_LWa-#1-1\expandafter.% \the\numexpr\CALX_LWa-#1.% {\expandafter\CALX_LWrv\expanded{\CALX_LWco{#1}{\CALX_LWa-#1}% {\CALX_LWa-#1}\CALX_tq}\relax}\CALX_Zu \expandafter\CALX_LWbl\the\numexpr#1-1.% \else \expandafter\CALX_LWlev\the\numexpr\CALX_LWmin\CALX_LWm{\CALX_LWa-1}% \expandafter.\the\numexpr\CALX_LWa-1\expandafter.% \the\numexpr\CALX_LWa+1.% {1!\expandafter\CALX_LWzr\CALX_LWa.}\CALX_Zun \CALX_LWfin \fi }% \def\CALX_Ltmp #1% {% \edef\CALX_LWa{\the\numexpr(#1+\ifnum#1>64 6\else5\fi)/4}% \edef\CALX_LWm{\the\numexpr2*((#1+3)/8)-1}% \expandafter\edef\csname CALX_Zul#1\endcsname {% {\expandafter\CALX_Zhd\expanded{\CALX_tcoef{l}{\CALX_LWa-1}{1}{1}% \CALX_tq}\relax}% {\expandafter\CALX_LWbl\the\numexpr\CALX_LWa-2.}% }% }% % \end{macrocode} %\begin{lverb} % after level 0 (a hook; log1p builds its levels without it) %\end{lverb} % \begin{macrocode} \def\CALX_LWfin{\CALX_Zlevp\CALX_LWm{\the\numexpr\CALX_LWa+1}\CALX_Zuf \noexpand\CALX_LWk}% \def\CALX_Ltmpb #1{\ifnum#1<113 \CALX_Ltmp{#1}% \expandafter\CALX_Ltmpb\expandafter{\the\numexpr#1+1\expandafter}\fi}% \CALX_Ltmpb{17}% \let\CALX_LWa\relax \let\CALX_LWm\relax \let\CALX_LWfin\relax % \end{macrocode} %\begin{lverb} % U' = 10^4 (x - 1), limbs MS first. E = 0 (x = 1.0000ddd..): limb j = % digits 2-4 of m_j and digit 1 of m_(j+1), j = 2..M (\CALX_LWsh); % E = -1 (x = 0.9999ddd..): m_2 - 10^4, m_3, .., m_M. Then the kernel's U % list (\CALX_Zbt$empty: negated, balanced, top limb kept whole). %\end{lverb} % \begin{macrocode} \def\CALX_LWsh #1#2#3#4!#5% {\CALX_Zgob#5\CALX_LWse\CALX_Zq#2#3#4#5!\CALX_LWsh#5}% \def\CALX_LWse\CALX_Zq#1#2#3\CALX_Zq!\CALX_LWsh\CALX_Zq!{#1#2#30!\CALX_Zq!}% \def\CALX_LWs #1\CALX_LQ!#2% {\expandafter\CALX_LWu\expanded{\CALX_LWsh#1\CALX_Zq!}{#2}}% \def\CALX_LWt #1\CALX_LQ!{\CALX_LWu#1\CALX_Zq!}% \def\CALX_LWu #1\CALX_Zq!#2% {% \expandafter\expandafter\expandafter\CALX_Zst \csname CALX_Zul\the\numexpr#2\expandafter\endcsname \expandafter{\expanded{\CALX_Zbt#1\CALX_Zq!}}{#2}% }% % \end{macrocode} %\begin{lverb} % final: {U}x_top.\CALX_Zq{P}: the exact product % N = U'_int T_0,int on K = b_0 + A + 1 limbs (floor form, x_top = top % limb, negative iff delta < 0), y = N 10^(-4K): \CALX_rsa (calxtrig) with % pairs MS first, a zero limb appended if K (i.e. A) is odd, complement % conversion for N < 0 (|N| - 1 unit, harmless). N = 0 (x = 1): \CALX_rsa % returns F+1.<..>, impossible otherwise (|y| > 10^(-4K)): F+0.0. % #4 = P (\XINTdigits or digits); A = (P + 5 or 6)/4, c = (2 ((P+3)/8) % + A)/2 computed here. %\end{lverb} % \begin{macrocode} \def\CALX_LWk #1#2.#3\CALX_Zq#4% {\expandafter\CALX_LWkk\the\numexpr(2*((#4+3)/8)+(#4+\ifnum#4>64 6\else 5\fi)/4)/2\expandafter.\expanded{\ifnum#2<\xint_c_ \the\numexpr10000+#2\else \expandafter\xint_gobble_i\the\numexpr10000+#2\fi!% #3\ifodd\numexpr(#4+\ifnum#4>64 6\else5\fi)/4\relax 0000!\fi}\relax#2.}% \def\CALX_LWkk #1.#2\relax#3.% {% \expandafter\CALX_LWz\expanded{% \ifnum#3<\xint_c_ \expandafter\CALX_LWkn\else\expandafter\CALX_LWkp\fi #3.#1.#2}% }% \def\CALX_LWkp #1.#2.{\CALX_rsa#2.#2.\CALX_bp+}% \def\CALX_LWkn #1.#2.{\CALX_rsa#2.#2.\CALX_bn-}% \begingroup\catcode`F=12 \gdef\CALX_LWz F#1#2.% {\ifnum#2=\xint_c_i \expandafter\CALX_LWzz\fi F#1#2.}% \gdef\CALX_LWzz F#1#2.#3.#4!{F+0.0.}% \endgroup % \end{macrocode} % \subsection{Natural logarithm, P33 and above} %\begin{lverb} % L = 8 ceil(P/8) <= 112, W = L + 8 <= 120, n = W/4 limbs, m = n/2 pairs. % After stage 8, |t| < 5.061e-9: y_s = ln(1+t) = t G(t), G = sum % (-t)^k/(k+1), by the series kernel \CALX_Z (calxtrig) with U'' = 10^8 t % (n-2 limbs v3..vn; t < 0: v3 - 10^4, v4, ..): level k has scale % 10^(4(n-2-2k)), T_k = C_k - U'' T_(k+1) 10^(-4b), b = m = n-4-2k (two % limbs less per level), levels k = (n-6)/2..1 from T = C_((n-4)/2) (two % limbs); level 0: T_0 = G (C_0 = 10^(4(n-2)), n-1 limbs, output negated); % final level: y_s 10^W = 0 + U'' T_0 10^(-4(n-2)) (b = n-2, m = n-1, % n limbs, floor carries), written A!P2!..!Pm! with A = floor(10^8 y_s) % (0 or -1). Error: per level |err| < 0.503 unit (total % within ~4.1 units of 10^-W). % Schedules \CALX_Zlg (keyed by the layout g = (P-5)/8 = 4..13): % {c1.\CALX_Zn c2}{\CALX_LGFk}. %\end{lverb} % \begin{macrocode} \def\CALX_LGt #1!#2!{#2.\noexpand\CALX_Zn#1}% LS first pair -> T items \def\CALX_LGsl #1.% {% \ifnum#1>\xint_c_ \expandafter\CALX_LWlev\the\numexpr\CALX_LWa-4-2*#1\expandafter.% \the\numexpr\CALX_LWa-4-2*#1\expandafter.% \the\numexpr\CALX_LWa-2-2*#1.% {\expandafter\CALX_LWrv\expanded{\CALX_tcoef{l}{#1}{\CALX_LWa-2-2*#1}% {\CALX_LWa-2-2*#1}\CALX_tq}\relax}\CALX_Zu \expandafter\CALX_LGsl\the\numexpr#1-1.% \else \expandafter\CALX_LWlev\the\numexpr\CALX_LWa-4\expandafter.% \the\numexpr\CALX_LWa-4\expandafter.\the\numexpr\CALX_LWa-1.% {1!\expandafter\CALX_LWzr\the\numexpr\CALX_LWa-2.}\CALX_Zun \expandafter\CALX_LGsv\the\numexpr\CALX_LWa-2\expandafter.% \the\numexpr\CALX_LWa-1\expandafter.\CALX_LWa.% {\expandafter\CALX_LWzr\CALX_LWa.}\CALX_Zuf \noexpand\CALX_LGFk \fi }% \def\CALX_LGsv #1.#2.#3.#4{\CALX_Zlevx\CALX_Zvn{#1}{#2}{#3}{#4}}% \def\CALX_Ltmp #1% {% \edef\CALX_LWa{\the\numexpr2*#1+4}% n \expandafter\edef\csname CALX_Zlg#1\endcsname {% {\expandafter\CALX_LGt\expanded{\CALX_tcoef{l}{(\CALX_LWa-4)/2}{2}{2}% \CALX_tq}}% {\expandafter\CALX_LGsl\the\numexpr(\CALX_LWa-6)/2.}% }% }% \def\CALX_Ltmpb #1{\ifnum#1<14 \CALX_Ltmp{#1}% \expandafter\CALX_Ltmpb\expandafter{\the\numexpr#1+1\expandafter}\fi}% \CALX_Ltmpb{4}% \let\CALX_LWa\relax \let\CALX_Ltmp\relax \let\CALX_Ltmpb\relax % \end{macrocode} %\begin{lverb} % final, after \CALX_LGf (v0 read): % v1!..!vn!\CALX_LQ!\CALX_LQ!J8;..;key;E;P. % U'' limbs MS first (t < 0: top v3 - 10^4), then the kernel with the % schedule \CALX_Zlg (g baked in \CALX_LGfp, \CALX_LGfn) %\end{lverb} % \begin{macrocode} \def\CALX_LGFs #1\CALX_Zq!#2.% {% \expandafter\expandafter\expandafter\CALX_Zst \csname CALX_Zlg#2\expandafter\endcsname \expandafter{\expanded{\CALX_Zbt#1\CALX_Zq!}}% }% % \end{macrocode} %\begin{lverb} % {U}x_top.\CALX_Zq -> \CALX_LGTv A!P2!..!Pm!; %\end{lverb} % \begin{macrocode} \def\CALX_LGFk #1#2.#3\CALX_Zq% {\expandafter\CALX_LGFa\expanded{{#2}#3}\CALX_Zq!\CALX_Zq!}% \def\CALX_LGFa #1#2!#3\CALX_Zq!\CALX_Zq!% {% \expandafter\CALX_LGTv\the\numexpr#1*10000+#2\expandafter!% \expanded{\CALX_LGFb#3\CALX_Zq!\CALX_Zq!};% }% \def\CALX_LGFb #1!#2!{\CALX_Zgob#1\CALX_LGFc\CALX_Zq#1#2!\CALX_LGFb}% \def\CALX_LGFc\CALX_Zq#1\CALX_LGFb{}% % \end{macrocode} %\begin{lverb} % tables: A!P2!..!Pm!;key; -> sums (zip with the entry, m <= 14 items; % a dummy item 0! lets the sentinel step read past the 14th) %\end{lverb} % \begin{macrocode} \def\CALX_LGTx #1#2#3;#4;% {\expandafter\expandafter\expandafter\CALX_LGTw\csname#2#4\endcsname \relax#1{#3}}% \def\CALX_LGTw #1\relax#2#3% {\expandafter#2\expanded{\CALX_LGad#3\CALX_LQ!;#10!\relax};}% \def\CALX_LGad #1!#2;#3!% {\CALX_LGgt#1\CALX_LGae\CALX_LQ\the\numexpr#1+#3!\CALX_LGad#2;}% \def\CALX_LGae\CALX_LQ#1\relax{}% \def\CALX_LGTv{\CALX_LGTx\CALX_LGTu{CALX_Lv}}% \def\CALX_LGTu{\CALX_LGTx\CALX_LGTt{CALX_Lu}}% \def\CALX_LGTt{\CALX_LGTx\CALX_LGTs{CALX_Lt}}% \def\CALX_LGTs{\CALX_LGTx\CALX_LGTb{CALX_Ls}}% \def\CALX_LGTb{\CALX_LGTx\CALX_LGch{CALX_Lb}}% % \end{macrocode} %\begin{lverb} % carry chain with E ln10: A!P2!..!Pm!;E; ; ln10 = 2.3025 8509 then the % limbs of \CALX_Lzl; pair P_i whole in its low limb column %\end{lverb} % \begin{macrocode} \def\CALX_LGch{\expandafter\CALX_LGci\CALX_Lzl\relax}% % \end{macrocode} %\begin{lverb} % template (shared with exp): \CALX_LGcidef {} % {}; params ##1 ln10 limbs, ##2 A, ##3 pairs, ##4 E %\end{lverb} % \begin{macrocode} \def\CALX_LGcidef #1#2#3#4% {% \def#1#3% {% \expandafter#2\the\numexpr#4 2*##4\expandafter\CALX_LR \the\numexpr\CALX_Loff+3025*##4\expandafter\CALX_LR \the\numexpr\CALX_Loff+##2+8509*##4\CALX_LGcy##3\CALX_LQ!;##4;##10!0!\relax }% }% \CALX_LGcidef\CALX_LGci\CALX_LGo{#1\relax#2!#3;#4;}{}% \def\CALX_LGcy #1!#2;#3;#4!#5!% {% \CALX_LGgt#1\CALX_LGce\CALX_LQ\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4*#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1+#5*#3\CALX_LGcy#2;#3;% }% \def\CALX_LGce\CALX_LQ#1\relax{\relax!\CALX_LQ}% \def\CALX_Ltmp #1% {% \expandafter\def\csname CALX_LGfp#1\endcsname 0000!0000!##1\CALX_LQ!\CALX_LQ!% {\CALX_LGFs##1\CALX_Zq!#1.}% \expandafter\def\csname CALX_LGfn#1\endcsname 9999!9999!##1!##2\CALX_LQ!\CALX_LQ!% {\expandafter\CALX_LGFs\the\numexpr##1-10000!##2\CALX_Zq!#1.}% }% \CALX_Ltmp4\CALX_Ltmp5\CALX_Ltmp6\CALX_Ltmp7\CALX_Ltmp8\CALX_Ltmp9% \CALX_Ltmp{10}\CALX_Ltmp{11}\CALX_Ltmp{12}\CALX_Ltmp{13}% \let\CALX_Ltmp\relax % \end{macrocode} %\begin{lverb} % dispatch: P17..P100 (LG), P1..P8 as before, P9..P16 by the P16 code % (16-digit grid, input padded with zeros, one rounding to P digits) %\end{lverb} % \begin{macrocode} \expandafter\let\csname CALX_LGtagF-\expandafter\endcsname \csname CALX_lgHsF-\endcsname \expandafter\let\csname CALX_LGtagI+\expandafter\endcsname \csname CALX_lgHsI+\endcsname \expandafter\let\csname CALX_LGtagI-\expandafter\endcsname \csname CALX_lgHsI-\endcsname \expandafter\let\csname CALX_LGtagI?\expandafter\endcsname \csname CALX_lgHsI?\endcsname \def\CALX_lga #1#2% {% \ifnum\XINTdigits>16 \xint_dothis{\csname CALX_LGtag#1#2\endcsname}\fi \ifnum\XINTdigits<9 \xint_dothis{\csname CALX_lgUtag#1#2\endcsname}\fi \xint_orthat{\csname CALX_Ltag#1#2\endcsname}% }% % \end{macrocode} % \subsection{\csh{calxFpLogOnePlus}, \csh{calxRawLogOnePlus}} %\begin{lverb} % log1p(x) = log(1 + x). % Input rounded to P digits; x <= -1: errors as log; x = 0: 0. %( A. |x| >= 0.1: r = round_P(1+x), d = (1+x) - r (exact, one digit), y = %: L(r) + d/r, L(r) the UNROUNDED internal log (P16 code for P <= 16), %: d/r by \CALX_fdiv at 9 digits, exact sum, one rounding. %: B. 10^-4 <= |x| < 0.1: V = 10^W (1+x) exact (W = 24, or 8 ceil(P/8) + 8 %: for P > 16), the staged unity path of log (\CALX_LsAa, \CALX_LGsa). %: C. |x| < 10^-4: x G(x) by the kernel (\CALX_lpC below). %) %\end{lverb} % \begin{macrocode} \def\calxFpLogOnePlus{\romannumeral0\expandafter\CALX_lpa \romannumeral0\CALX_fround{\XINTdigits}}% \def\calxRawLogOnePlus #1{\romannumeral0\CALX_ftoraw{\calxFpLogOnePlus{#1}}}% \def\CALX_lpnfl #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpLogOnePlus#3}}% }% \def\CALX_lpnex #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxRawLogOnePlus#3}}% }% % \end{macrocode} %\begin{lverb} % expression function log1p: the only names with log1p (a digit: \csname) %\end{lverb} % \begin{macrocode} \expandafter\let\csname XINT_flexpr_func_log1p\endcsname\CALX_lpnfl \expandafter\let\csname XINT_expr_func_log1p\endcsname\CALX_lpnex \def\CALX_lpa #1#2{\csname CALX_lptag#1#2\endcsname}% \expandafter\let\csname CALX_lptagI+\expandafter\endcsname \csname CALX_lgHsI+\endcsname \expandafter\let\csname CALX_lptagI?\expandafter\endcsname \csname CALX_lgHsI?\endcsname \expandafter\def\csname CALX_lptagI-\endcsname#1\xint:% {\CALX_nsig{InvalidOperation}{log1p(-inf)}{}}% \begingroup\catcode`F=12 \expandafter\gdef\csname CALX_lptagF+\endcsname #1.#2.#3\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{ F+0.0.}\fi \xint_orthat{\expandafter\CALX_lpb \the\numexpr#1-\xint_c_i+\xint_c_viii*#2.+#1.#2.#3\xint:}% }% % \end{macrocode} %\begin{lverb} % x < 0: E >= 0 means x <= -1 (\CALX_lpm$empty: 1 + x = 0 or < 0) %\end{lverb} % \begin{macrocode} \expandafter\gdef\csname CALX_lptagF-\endcsname #1.#2.% {% \ifnum\numexpr#1-\xint_c_i+\xint_c_viii*#2>-\xint_c_i \xint_dothis\CALX_lptag_negative_domain\fi \xint_orthat\CALX_lptag_negative_regular #1.#2.% }% \gdef\CALX_lptag_negative_domain #1.#2.#3\xint:% {\expandafter\CALX_lpm\romannumeral0\CALX_faddx {F+1.0.100000001!}{F-#1.#2.#3}\xint:}% \gdef\CALX_lptag_negative_regular #1.#2.#3\xint:% {\expandafter\CALX_lpb \the\numexpr#1-\xint_c_i+\xint_c_viii*#2.-#1.#2.#3\xint:}% \gdef\CALX_lpm F#1#2.#3\xint:% {% \ifnum#2=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{log1p(-1)}{-}}\fi \xint_orthat{\CALX_nsig{InvalidOperation}{log1p(x), x < -1}{}}% }% % \end{macrocode} %\begin{lverb} % classes by the decimal exponent E of x: E >= -1, E <= -5, else B %\end{lverb} % \begin{macrocode} \gdef\CALX_lpb #1.#2#3.% {% \ifnum#1>-\xint_c_ii \xint_dothis\CALX_lpb_large\fi \ifnum#1<-\xint_c_iv \xint_dothis\CALX_lpb_small\fi \xint_orthat\CALX_lpb_regular #1.#2#3.% }% \gdef\CALX_lpb_large #1.#2#3.#4.#5\xint:{\CALX_lpA#2#3.#4.#5\xint:}% \gdef\CALX_lpb_small #1.#2#3.#4.#5\xint:{\CALX_lpC lps;#2#3.#4.#5\xint:}% \gdef\CALX_lpb_regular #1.#2#3.#4.#5\xint:{\CALX_lpB#2#3.#4.#5\xint:}% % \end{macrocode} %\begin{lverb} % A: |x| >= 0.1 %\end{lverb} % \begin{macrocode} \gdef\CALX_lpA #1\xint:% {\expandafter\CALX_lpAa \romannumeral0\CALX_faddx{F+1.0.100000001!}{F#1}\xint:}% \gdef\CALX_lpAa #1\xint:% {\expandafter\CALX_lpAb\romannumeral0\CALX_fround{\XINTdigits}{#1}#1\xint:}% \gdef\CALX_lpAb #1\xint:#2\xint:% {\expandafter\CALX_lpAc\romannumeral0\CALX_fsubx{#2}{#1}\xint:#1\xint:}% \gdef\CALX_lpAc F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_lpAc_zero\fi \xint_orthat\CALX_lpAc_regular F#1#2.% }% \gdef\CALX_lpAc_zero F#1#2.#3\xint:F#4\xint:% {\CALX_fnround{\XINTdigits}{\CALX_lpL#4\xint:}}% \gdef\CALX_lpAc_regular F#1#2.#3\xint:F#4\xint:% {\CALX_fnround{\XINTdigits}{\CALX_faddx{\CALX_lpL#4\xint:}% {\CALX_fdiv{9}{F#1#2.#3}{F#4}}}}% \endgroup % \end{macrocode} %\begin{lverb} % unrounded internal log of r = +.. (bodies of \CALX_Ltb, % \CALX_LGtb without the rounding) % \CALX_lpLP P.+..\xint: at precision P (\XINTdigits or % digits; P <= 112; P <= 16: the P16 code), shared with pow %\end{lverb} % \begin{macrocode} \def\CALX_lpL{\CALX_lpLP\XINTdigits.}% \def\CALX_lpLP #1.+#2.#3.#4\xint:% {% \expandafter\CALX_lpLb\the\numexpr#1\expandafter.% \the\numexpr(#2+\xint_c_iii)/\xint_c_viii \expandafter.\the\numexpr#2-\xint_c_i+\xint_c_viii*#3.#2.#4\xint:% }% \def\CALX_lpLb #1.% {\ifnum#1>16 \expandafter\CALX_LGL\else\expandafter\CALX_lpLd\fi#1.}% \def\CALX_lpLd #1.{\CALX_lpLs}% \def\CALX_lpLs #1.#2.#3.#4\xint:% {\csname CALX_Lin\romannumeral#1\endcsname\CALX_LM#4\xint:#2.#3.}% % \end{macrocode} %\begin{lverb} % B: 10^-4 <= |x| < 0.1; Bw = W/8 blocks, nb blocks of N %\end{lverb} % \begin{macrocode} \def\CALX_lpB #1#2.#3.#4\xint:% {% \expandafter\CALX_lpBa\the\numexpr\ifnum\XINTdigits>16 (\XINTdigits+\xint_c_iii)/\xint_c_viii+\xint_c_i\else\xint_c_iii\fi \expandafter.\the\numexpr(#2+\xint_c_iii)/\xint_c_viii.#1#3.#4\xint:% }% \def\CALX_lpBa #1.#2.#3#4.#5\xint:% {% \CALX_Lfr\XINTdigits{\csname CALX_lpB\ifnum\XINTdigits>16 g\else s\fi#3% \endcsname{\expandafter\CALX_lpzb\the\numexpr#1+#4.#5% \expandafter\CALX_lpzb\the\numexpr-#4-#2.}}% }% \def\CALX_lpzb #1.{\ifnum#1>\xint_c_ 100000000!\expandafter\CALX_lpzb \the\numexpr#1-1\expandafter.\fi}% % \end{macrocode} %\begin{lverb} % the selectors receive V = v0!v1!..: v0 = 1, x 10^W; v0 = 0, 10^W - |x| 10^W %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_lpBs+\endcsname #1% {\expandafter\CALX_LsAa\expandafter1\expandafter!\expanded {\expandafter\CALX_shr\expanded{#1}\CALX_Zq!\relax}0;0;}% \expandafter\def\csname CALX_lpBs-\endcsname #1% {\expandafter\CALX_LsAa\expandafter0\expandafter!\expanded {\expandafter\CALX_shr\expanded{\expandafter\CALX_lpcz\expanded{#1}% \CALX_Zq!}\CALX_Zq!\relax}0;0;}% \expandafter\def\csname CALX_lpBg+\endcsname #1% {\csname CALX_LGsa\the\numexpr(\XINTdigits-5)/8\expandafter\endcsname \expandafter1\expandafter!\expanded {\expandafter\CALX_shr\expanded{#1}% \CALX_Zq!\relax}\CALX_LQ!\CALX_LQ!0;0;\XINTdigits.}% \expandafter\def\csname CALX_lpBg-\endcsname #1% {\csname CALX_LGsa\the\numexpr(\XINTdigits-5)/8\expandafter\endcsname \expandafter0\expandafter!\expanded {\expandafter\CALX_shr\expanded{\expandafter\CALX_lpcz\expanded{#1}% \CALX_Zq!}\CALX_Zq!\relax}\CALX_LQ!\CALX_LQ!0;0;\XINTdigits.}% % \end{macrocode} %\begin{lverb} % 10^(8k) - X on blocks 1<8 digits>! LS first (inside \expanded): zero % blocks stay (\CALX_lpcz), the first nonzero one gives 10^8 - b, the % others 10^8 - 1 - b (\CALX_lpco) %\end{lverb} % \begin{macrocode} \def\CALX_lpcz #1#2!{\CALX_Zgob#1\CALX_lpce\CALX_Zq\CALX_lpcy#2!}% \def\CALX_lpcy #1!{\ifnum#1=\xint_c_ 100000000!\expandafter\CALX_lpcz\else \the\numexpr200000000-#1!\expandafter\CALX_lpco\fi}% \def\CALX_lpco #1#2!{\CALX_Zgob#1\CALX_lpce\CALX_Zq\CALX_lpcb#2!}% \def\CALX_lpcb #1!{\the\numexpr199999999-#1!\CALX_lpco}% \def\CALX_lpce\CALX_Zq#1!{}% % \end{macrocode} %\begin{lverb} % C: |x| < 10^-4: y = x G(x), G = sum (-x)^k/(k+1), by the kernel with % the levels of log's unity zone for P' = max(P,17) but b_k = A-k-1 % (\CALX_lpS: U' = 10^4 x may have more limbs than log's delta), then % an exact product level on X' (x = X' 10^(-8z), as calxtrig's sin) and % calxtrig's finisher \CALX_shx (kind s: one rounding to P digits). % U' list: x > 0: limbs of x (2z zero limbs, then those of N) without the % first one (0000); x < 0: limbs of 1 + x, 9999 dropped, the next one % minus 10^4 (as log's E = -1 unity entry); a zero limb appended (\CALX_Zbt % needs two items); z > 14: U' = 0; then A zero limbs (the levels read up % to A+1 items). % kind;s D.e.blocks, kind lp (log1p) or em (expm1: schedules % \CALX_emS, U lists \CALX_emU = \CALX_lpU<-s>) %\end{lverb} % \begin{macrocode} \def\CALX_lpC #1;#2#3.#4.#5\xint:% {% \expandafter\CALX_lpCa\the\numexpr-#4-(#3+\xint_c_iii)/\xint_c_viii \expandafter.\the\numexpr\ifnum\XINTdigits<17 17\else \XINTdigits\fi.#1;#2{#5}% }% \def\CALX_lpCa #1.#2.#3#4#5;#6#7% {% \csname CALX_#3#4S#2\expandafter\endcsname\expanded{{\ifnum#1>14 0!0!0!0!% \else\csname CALX_#3#4U#6\endcsname#1.{#7}\fi \expandafter\CALX_Zzr\the\numexpr(#2+\ifnum#2>64 6\else5\fi)/4.}% \expandafter\noexpand\csname CALX_lpF#2\endcsname {\expandafter\CALX_Zbt\expanded{\CALX_shr#7\CALX_Zq!\relax \expandafter\CALX_Zzr\the\numexpr2*((#2+10)/8).}\CALX_Zq!}}#1.#6#5% }% \expandafter\def\csname CALX_lpU+\endcsname #1.#2% {% \expandafter\CALX_Zbt\expanded{\expandafter\CALX_lpdr\expanded {\expandafter\CALX_Zzr \the\numexpr2*#1.\CALX_shr#2\CALX_Zq!\relax}0!}\CALX_Zq!% }% \expandafter\def\csname CALX_lpU-\endcsname #1.#2% {% \expandafter\CALX_Zbt\expanded{\expandafter\CALX_lpdn\expanded {\expandafter\CALX_shr\expanded{\expandafter\CALX_lpcz\expanded {#2\CALX_lpzb#1.}\CALX_Zq!}\CALX_Zq!\relax}0!}\CALX_Zq!% }% \def\CALX_lpdr #1!{}% \def\CALX_lpdn #1!#2!{\the\numexpr#2-10000!}% % \end{macrocode} %\begin{lverb} % load time, P' = 17..100: \CALX_lpS{U list} (C_(A-1), levels A-2..0, % level 0 negated), \CALX_lpF{U}\CALX_Zq{X' list}: exact product % level X'_int T_0 (b_p = 2 ceil((P'+7)/8) limbs of X', A+1 of T_0), then % \CALX_shx with ..{0000!}{post} (b_p + A fractional limbs) %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1% {% \edef\CALX_LWa{\the\numexpr(#1+\ifnum#1>64 6\else5\fi)/4}% \edef\CALX_LWm{\the\numexpr\CALX_LWa-1}% \edef\CALX_LWp{\the\numexpr2*((#1+10)/8)}% \expandafter\edef\csname CALX_lpS#1\endcsname##1% {% \noexpand\CALX_Zd\expandafter\CALX_Zhd\expanded{\CALX_tcoef{l}% {\CALX_LWa-1}{1}{1}\CALX_tq}\relax.\noexpand\CALX_Zq{##1}% \expandafter\CALX_LWbl\the\numexpr\CALX_LWa-2.% }% \expandafter\edef\csname CALX_lpF#1\endcsname##1##2\CALX_Zq##3% {% \noexpand\CALX_Zd##2\noexpand\CALX_Zq{##3}% \CALX_Zlevp{\CALX_LWp}{\the\numexpr\CALX_LWa+1\relax}\CALX_Zuf \noexpand\CALX_shx{\ifodd\CALX_LWa\space \the\numexpr(\CALX_LWp+\CALX_LWa+3)/2.% \the\numexpr(\CALX_LWp+\CALX_LWa+1)/2.% {0000!}{0000!}\else \the\numexpr(\CALX_LWp+\CALX_LWa+2)/2.% \the\numexpr(\CALX_LWp+\CALX_LWa)/2.% {0000!}{}\fi}% }% }% \let\CALX_LWfin\empty \def\CALX_Ltmpb #1{\ifnum#1<101 \CALX_Ltmp{#1}% \expandafter\CALX_Ltmpb\expandafter{\the\numexpr#1+1\expandafter}\fi}% \CALX_Ltmpb{17}% \let\CALX_LWa\relax \let\CALX_LWm\relax \let\CALX_LWp\relax \let\CALX_LWfin\relax \let\CALX_Ltmp\relax \let\CALX_Ltmpb\relax % \end{macrocode} % \subsection{\csh{calxFpLogTen}, \csh{calxRawLogTen}} %\begin{lverb} % log10(x). % y = L(x) k_P, L(x) the unrounded internal ln (\CALX_lpL of log1p: the % P16 code for P <= 16), k_P = round_(P+12)(1/ln10) (\CALX_ltk

, load % time), exact product (\CALX_fmulx), one rounding. x = 1: 0; x = 10^k: k. %\end{lverb} % \begin{macrocode} \def\calxFpLogTen{\romannumeral0\expandafter\CALX_lta \romannumeral0\CALX_fround{\XINTdigits}}% \def\calxRawLogTen #1{\romannumeral0\CALX_ftoraw{\calxFpLogTen{#1}}}% \def\CALX_ltnfl #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpLogTen#3}}% }% \def\CALX_ltnex #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxRawLogTen#3}}% }% % \end{macrocode} %\begin{lverb} % expression function log10: the only names with log10 (a digit: \csname) %\end{lverb} % \begin{macrocode} \expandafter\let\csname XINT_flexpr_func_log10\endcsname\CALX_ltnfl \expandafter\let\csname XINT_expr_func_log10\endcsname\CALX_ltnex \def\CALX_lta #1#2{\csname CALX_ltt#1#2\endcsname}% \expandafter\let\csname CALX_lttI+\expandafter\endcsname \csname CALX_lgHsI+\endcsname \expandafter\let\csname CALX_lttI?\expandafter\endcsname \csname CALX_lgHsI?\endcsname \expandafter\def\csname CALX_lttI-\endcsname#1\xint:% {\CALX_nsig{InvalidOperation}{log10(-inf)}{}}% \expandafter\def\csname CALX_lttF-\endcsname#1\xint:% {\CALX_nsig{InvalidOperation}{log10(x), x < 0}{}}% \expandafter\def\csname CALX_lttF+\endcsname #1.#2.#3\xint:% {% \ifnum#1=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{log10(0)}{-}}\fi \xint_orthat{\CALX_fnround{\XINTdigits}% {\CALX_fmulx{\CALX_lpL+#1.#2.#3\xint:}% {\csname CALX_ltk\the\numexpr\XINTdigits\endcsname}}}% }% % \end{macrocode} %\begin{lverb} % k_P, P = 1..100, from 1/ln10 truncated to 130 digits (calxlogdata.tex) %\end{lverb} % \begin{macrocode} \edef\CALX_Ltmpb{\romannumeral0\CALX_ffromraw{\CALX_Lzinvraw}}% \def\CALX_Ltmp #1.% {% \expandafter\edef\csname CALX_ltk#1\endcsname {\romannumeral0\CALX_fnround{#1+12}{\CALX_Ltmpb}}% \ifnum#1<100 \expandafter\CALX_Ltmp\the\numexpr#1+1\expandafter.\fi }% \CALX_Ltmp 1.\let\CALX_Ltmp\relax \let\CALX_Ltmpb\relax % \end{macrocode} % \subsection{\csh{calxFpExp}, \csh{calxRawExp}} %\begin{lverb} % Exponential, P9..P16. x rounded to P+14 digits on entry, sliced at 10^-24. % k = ceil(Z/10^5), Z = nint(10^5 |x|/ln10) (approximate), bucket i of % -r0 = k ln10 - x; buckets 1..98: a = A[i], c = nint(200000/(2a+1)), % constant ln(10^4/c); bucket 0: c = 10^4, no constant; bucket 99: c = 1000, % constant ln10 (equivalent to k = nint(x/ln10)): r1 = x - k ln10 + constant, % |r1| < 0.0488, R1 = 10^10 r1 in one \numexpr; stages k = 2, 4, 6, 8 on the % short residual R (tables Ls, Lt, Lu, Lv: -ln(1 + j 10^-k)); t on the grid % 10^-24 (|t| < 5.5e-9), U = 10^24 (e^t - 1), G = c (100+j2)(10^4+j4) % (10^6+j6)(10^8+j8) exact, Y' = G + G U 10^-24: exp x = 10^(k-24) Y', one % rounding to P digits. %\end{lverb} % \begin{macrocode} \let\CALX_exQ\relax \def\calxFpExp{\romannumeral0\expandafter\CALX_exa \romannumeral0\CALX_fround{\XINTdigits+14}}% \def\calxRawExp #1{\romannumeral0\CALX_ftoraw{\calxFpExp{#1}}}% \def\CALX_exnfl #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpExp#3}}% }% \def\CALX_exnex #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxRawExp#3}}% }% \let\XINT_flexpr_func_exp\CALX_exnfl \let\XINT_expr_func_exp\CALX_exnex \def\CALX_exa #1#2{\csname CALX_ext#1#2\endcsname}% \begingroup\catcode`F=12 \expandafter\gdef\csname CALX_extI+\endcsname#1\xint:{ I+}% \expandafter\gdef\csname CALX_extI-\endcsname#1\xint:{ F+0.0.}% \expandafter\gdef\csname CALX_extI?\endcsname#1\xint:{ I?}% \expandafter\gdef\csname CALX_extF+\endcsname{\CALX_exb ex;+}% \expandafter\gdef\csname CALX_extF-\endcsname{\CALX_exb ex;-}% % \end{macrocode} %\begin{lverb} % kind;s D, e, blocks (kind: ex = exp, pw = pow10, em = expm1: the readers % \CALX_G, hG, gG, Ja); x = 0 -> 1; p = e + ceil(D/8) % - 1 (top block position) %\end{lverb} % \begin{macrocode} \gdef\CALX_exb #1;#2#3.% {% \ifnum\XINTdigits>16 \xint_dothis\CALX_exb_big\fi \ifnum#3=\xint_c_ \xint_dothis\CALX_exb_zero\fi \xint_orthat\CALX_exb_regular #1;#2#3.% }% \gdef\CALX_exb_big #1;#2#3.#4.#5\xint:{\CALX_exgb#1;#2#3.#4.#5\xint:}% \gdef\CALX_exb_zero #1;#2#3.#4.#5\xint:{ F+1.0.100000001!}% \gdef\CALX_exb_regular #1;#2#3.#4.#5\xint:% {% \expandafter\CALX_exc \the\numexpr#4+(#3+\xint_c_iii)/\xint_c_viii-\xint_c_i\expandafter.% \the\numexpr#4\expandafter.% \csname CALX_#1\ifnum\XINTdigits<9 h\fi G\endcsname#2#5\xint:% }% % \end{macrocode} %\begin{lverb} % p < -3: |x| < 10^-24, result 1; p >= 2: |x| >= 10^16, over/underflow; % #3 the layout reader (\CALX_exG, or \CALX_exhG for P <= 8) %\end{lverb} % \begin{macrocode} \gdef\CALX_exc #1.#2.% {% \ifnum#1>\xint_c_i \xint_dothis\CALX_exc_over\fi \ifnum#1<-\xint_c_iii \xint_dothis\CALX_exc_small\fi \xint_orthat\CALX_exc_regular #1.#2.% }% \gdef\CALX_exc_over #1.#2.#3#4#5\xint:{\CALX_exO#4}% \gdef\CALX_exc_small #1.#2.#3#4#5\xint:{ F+1.0.100000001!}% \gdef\CALX_exc_regular #1.#2.#3#4#5\xint:% {% \csname CALX_exL\the\numexpr#2+\xint_c_iii\endcsname #3#5100000000!100000000!100000000!100000000!\xint:#4% }% \endgroup % \end{macrocode} %\begin{lverb} % grid layout (e = -7..1, D <= P+21): drop -(e+3) low blocks or prepend % e+3 zero blocks, then % \CALX_exG reads f3 (10^-24), f2, f1, I (integer block) and the sign %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_exL-4\endcsname#1#2!#3!#4!#5!{#1}% \expandafter\def\csname CALX_exL-3\endcsname#1#2!#3!#4!{#1}% \expandafter\def\csname CALX_exL-2\endcsname#1#2!#3!{#1}% \expandafter\def\csname CALX_exL-1\endcsname#1#2!{#1}% \expandafter\let\csname CALX_exL0\endcsname\xint_firstofone \expandafter\def\csname CALX_exL4\endcsname #1{#1100000000!100000000!100000000!100000000!}% \expandafter\def\csname CALX_exL1\endcsname#1{#1100000000!}% \expandafter\def\csname CALX_exL2\endcsname#1{#1100000000!100000000!}% \expandafter\def\csname CALX_exL3\endcsname#1{#1100000000!100000000!100000000!}% % \end{macrocode} %\begin{lverb} % Z = nint(X5*434294482/10^9) ~ 10^5 |x|/ln10, X5 = nint(10^5 |x|); data % for the table macro: s x12, s x34, s x56 (8-digit pairs), s xI. Rare % path if the integer block xI >= 10^4 or the block at 10^8 (first of #5) % is not zero. %\end{lverb} % \begin{macrocode} \def\CALX_exGt #1!#2\xint:{#1}% % \end{macrocode} %\begin{lverb} % normal branch (shared): f3.f2.f1.xI.s; the % marker (\CALX_exMk exp's writer, \CALX_emMk expm1's finisher, empty for % the P <= 8 path) ends the stream and is read by the writers after k. %\end{lverb} % \begin{macrocode} \def\CALX_exGn #1.#2.#3.#4.#5#6#7% {% \expandafter\CALX_exK\the\numexpr(#4*100000+#3/1000)*434294482/1000000000.% #5#6#5#3.#5#2.#5#1.#5#4.#7% }% \def\CALX_exG 1#1!1#2!1#3!1#4!#5\xint:#6% {% \ifnum#4>9999 \xint_dothis{\CALX_exHa#5\xint:#6#4.#3.#2.#1.}\fi \ifnum\CALX_exGt#5\xint:>100000000 \xint_dothis{\CALX_exHa#5\xint:#6#4.#3.#2.#1.}\fi \xint_orthat{\CALX_exGn#1.#2.#3.#4.#6A\CALX_exMk}% }% % \end{macrocode} %\begin{lverb} % P <= 8: as \CALX_exG with the table macros \CALX_exC %\end{lverb} % \begin{macrocode} \def\CALX_exhG 1#1!1#2!1#3!1#4!#5\xint:#6% {% \ifnum#4>9999 \xint_dothis{\CALX_exHa#5\xint:#6#4.#3.#2.#1.}\fi \ifnum\CALX_exGt#5\xint:>100000000 \xint_dothis{\CALX_exHa#5\xint:#6#4.#3.#2.#1.}\fi \xint_orthat{\CALX_exGn#1.#2.#3.#4.#6C\CALX_exMk}% }% % \end{macrocode} %\begin{lverb} % k = ceil(s Z/10^5) (floor(a/b) = (2a-b+1)/(2b), a >= 0); #3 table letter % (A: P <= 16, B: P > 16) %\end{lverb} % \begin{macrocode} \def\CALX_exK #1.#2#3% {% \expandafter\CALX_exKa\the\numexpr\if-#2 0-(2*#1-99999)/200000\else (2*#1+99999)/200000\fi.#1.#2#3% }% % \end{macrocode} %\begin{lverb} % i = floor(m/1000), m = k 10^5 - s Z in [0, 10^5): table macro % \CALX_ex %\end{lverb} % \begin{macrocode} \def\CALX_exKa #1.#2.#3#4% {% \csname CALX_ex#4\the\numexpr(2*(#1*100000\if-#3+\else-\fi#2)-999)/2000% \endcsname#1.% }% % \end{macrocode} %\begin{lverb} % the ln10 chain (template of log P9..P16): A!P2!P3!0;-k.sxI. %\end{lverb} % \begin{macrocode} \CALX_LTdef\CALX_exC\CALX_exW{#1!#2!#3!#4;#5.#6.#7\CALX_exQ}{#6+}{#7}% % \end{macrocode} %\begin{lverb} % state R.S2.S4.S6.| (R1 and the Lb items from the table macro); % stages: \CALX_exTmp {}{}{} % S: fetch F1!c2!c3!j. (load-time short tables); R: R, sums, J list %\end{lverb} % \begin{macrocode} \def\CALX_exTmp #1#2#3#4#5#6% {% \def#1##1.{\expandafter\expandafter\expandafter#2% \csname#4\the\numexpr#5\endcsname##1.}% \def#2##1!##2!##3!##4.##5.##6.##7.##8.##9|% {% \expandafter#3#6\the\numexpr##6+##1\expandafter.\the\numexpr##7+##2% \expandafter.\the\numexpr##8+##3.##4;##9|% }% }% \CALX_exTmp\CALX_exSa\CALX_exRa\CALX_exSb{CALX_exu}% {(#1+#1*#1/1000000000/20)/100000000}% {\the\numexpr#5+100*#1+#2/1000000\expandafter.}% \CALX_exTmp\CALX_exSb\CALX_exRb\CALX_exSc{CALX_exv}% {(#1+#1*#1/1000000000/20)/1000000}% {\the\numexpr#5+100*#1+#2/1000000\expandafter.}% \CALX_exTmp\CALX_exSc\CALX_exRc\CALX_exSd{CALX_exw}% {#1/10000}% {\the\numexpr#5+100*#1+#2/1000000\expandafter.}% \CALX_exTmp\CALX_exSd\CALX_exRd\CALX_exV{CALX_exz}% {#1/100}{}% \let\CALX_exTmp\relax % \end{macrocode} %\begin{lverb} % chain 2: t = s x - k ln10 + Lb + Ls + Lt + Lu + Lv %\end{lverb} % \begin{macrocode} \def\CALX_exV #1.#2.#3.#4|#5.#6.#7.#8.#9.% {\CALX_exC#5+#1!#6+#2!#7+#3!0;-#8.#9.#4|\CALX_exQ}% % \end{macrocode} %\begin{lverb} % t = T0!t1!..!t6! (|t| < 5.5e-9: t1 = t2 = 0000 or 9999), s = % floor(10^16 t) = T0 10^8 + t3t4, rho = t5t6: U = 10^24 (e^t - 1) = s 10^8 % + rho + s^2/2e8 (dropped s rho/1e16 + t^3/6 < 0.6 units 10^-24), ONE chain, % floor limbs u3 (signed)!u2!u1!u0!; then G (\CALX_exEc) and \CALX_exPS %\end{lverb} % \begin{macrocode} \def\CALX_exW #1!#2!#3!#4!#5!#6!#7!% {% \expandafter\CALX_exWj\expandafter{\the\numexpr 0\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1*100000000+#4#5\expandafter\CALX_LR \the\numexpr\CALX_Loff\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6#7+(#1*100000000+#4#5)*(#1*100000000+#4#5)% /200000000\relax!}% }% \def\CALX_exWj #1#2;#3;#4;#5;#6;|{\CALX_exEc\CALX_exPS{#1}#6.#5.#4.#3.#2.}% % \end{macrocode} %\begin{lverb} % Y' = G + G U 10^-24 (G = g5..g0 ~ 10^24, U = u3..u0): columns c = i + m % >= 6, guard c = 5 (its u0 term by \CALX_exPT), dropped columns and guard % floor < 6 units of Y'; output T!y1!..!y5! (stream k.) %\end{lverb} % \begin{macrocode} \def\CALX_exPS #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \expandafter\CALX_exY\the\numexpr#1\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2\expandafter\CALX_LR \the\numexpr\CALX_Loff+#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4+#1*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#5+#1*#8+#2*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6+#1*#9+#2*#8+#3*#7\expandafter\CALX_LRz \the\numexpr\CALX_Loff+#2*#9+#3*#8+#4*#7\CALX_exPT#1!% }% \def\CALX_exPT #1!#2!{+#1*#2\relax!}% % \end{macrocode} %\begin{lverb} % writer: exp x = 10^(k-24) Y', Y' = T!y1!..!y5!, then k.. expm1 % marker: \CALX_emF; frequent: P9..P16 and 1000 <= T <= 9999 ((2T - 10999)^2 % <= 8999^2); else generic (\CALX_ffromraw, \CALX_fround). %\end{lverb} % \begin{macrocode} \def\CALX_exY #1!#2!#3!#4!#5!#6!#7.#8% {% \ifx#8\CALX_exMk\else\xint_dothis{\CALX_emF#1#2#3#4#5#6.#7.24.#8}\fi \ifnum\XINTdigits<9 \xint_dothis{\CALX_exYg#1#2#3#4#5#6.#7.}\fi \ifnum\numexpr(2*#1-10999)*(2*#1-10999)>80982001 \xint_dothis{\CALX_exYg#1#2#3#4#5#6.#7.}\fi \xint_orthat{\expandafter\expandafter\expandafter\CALX_exYa \csname CALX_exq\the\numexpr\XINTdigits\endcsname#1#2.#3#4.#5.#7.}% }% \def\CALX_exYg #1.#2.{\expandafter\CALX_exYgg\the\numexpr#2-24.#1.}% \def\CALX_exYgg #1.#2.% {\CALX_fnround{\XINTdigits}{\CALX_ffromraw{#2[#1]}}}% % \end{macrocode} %\begin{lverb} % Q = 10^(16-P), C = 10^(P-8), Z = 1 if P = 16 (\CALX_exq

); H = T y1, % L = y2 y3: M = round(Y'/10^(24-P)) = Mh 10^8 + Ml, Mh = floor(H/Q), % Ml = (H - Q Mh) C + nint(L/Q) (+ nint(y4/10^4) if P = 16; for P < 16 the % rounding boundaries are integers: the lower limbs are irrelevant) %\end{lverb} % \begin{macrocode} \def\CALX_exYa #1.#2.#3.#4.#5.#6.% {% \expandafter\CALX_exYb\the\numexpr(2*#4-#1+1)/(2*#1)\expandafter.% \the\numexpr(#4-(2*#4-#1+1)/(2*#1)*#1)*#2+#5/#1+(2*#6+1)/20000*#3.% }% % \end{macrocode} %\begin{lverb} % Mh.Ml.k. : carries (Ml = 10^8; M = 10^P -> 10^(P-1), k+1) %\end{lverb} % \begin{macrocode} \def\CALX_exYb #1.#2.#3.% {% \ifnum#2>99999999 \xint_dothis{\expandafter\CALX_exYe\the\numexpr#1+1.#3.}\fi \xint_orthat{\CALX_exYh#1.#2.#3.}% }% \def\CALX_exYe #1.#2.% {% \ifnum#1=\CALX_pten{\XINTdigits-8} \xint_dothis{\expandafter\CALX_exYh \the\numexpr#1/10\expandafter.\expandafter0\expandafter.% \the\numexpr#2+1.}\fi \xint_orthat{\CALX_exYh#1.0.#2.}% }% % \end{macrocode} %\begin{lverb} % g = k - P, e = floor(g/8), h = g - 8e (\CALX_exh = h.10^h.10^(8-h).), % D = P + h; blocks of M 10^h: A = floor(Ml/V), B = floor(Mh/V), V = 10^(8-h) %\end{lverb} % \begin{macrocode} \def\CALX_exYh #1.#2.#3.% {\expandafter\CALX_exYi\the\numexpr(2*(#3-\XINTdigits)-7)/16.#3.#1.#2.}% \def\CALX_exYi #1.#2.% {% \expandafter\expandafter\expandafter\CALX_exYk \csname CALX_exh\the\numexpr#2-\XINTdigits-8*#1\endcsname#1.% }% \begingroup\catcode`F=12 \gdef\CALX_exYk #1.#2.#3.#4.#5.#6.% {% \expanded{ F+\the\numexpr\XINTdigits+#1.#4.% \the\numexpr100000000+(#6-(2*#6-#3+1)/(2*#3)*#3)*#2!% \the\numexpr100000000+(2*#6-#3+1)/(2*#3)+(#5-(2*#5-#3+1)/(2*#3)*#3)*#2!% \ifnum#5<#3 \else\the\numexpr100000000+(2*#5-#3+1)/(2*#3)!\fi}% }% \endgroup \def\CALX_Ltmp #1.% {% \expandafter\edef \csname CALX_exq#1\endcsname{\the\numexpr\CALX_pten{16-#1}.% \CALX_pten{#1-8}.\ifnum#1=16 1\else0\fi.}% \ifnum#1<16 \expandafter\CALX_Ltmp\the\numexpr#1+1\expandafter.\fi }% \CALX_Ltmp 9.% \def\CALX_Ltmp #1.% {% \expandafter\edef\csname CALX_exh#1\endcsname{#1.\CALX_pten{#1}.% \CALX_pten{8-#1}.}% \ifnum#1<7 \expandafter\CALX_Ltmp\the\numexpr#1+1\expandafter.\fi }% \CALX_Ltmp 0.\let\CALX_Ltmp\relax % \end{macrocode} % \subsection{Exponential, P1..P8} %\begin{lverb} % Front, k, i and R1 as P16 (table macros \CALX_exC); stages k = 2, 4 on % the short residual R (scale 10^-10, keys only, P > 16 receivers); t = R4 % 10^-10, U = 10^10 (e^t - 1) = R4 + R4^2/(2 10^10) (t^3/6 < 2.2e-14); % A = c(100+j2) = a1 10^4 + a0, G = A (10^4+j4) = H 10^4 + g0, H = A + a1 j4, % g0 = a0 j4; Z' = 10^12 e^r0 = G (10^10+U)/10^8 = H 10^6 + L', % L' = 100 g0 + H U/10^4 + g0 U/10^8; normalized H', L'' (0 <= L'' < 10^6); % M = round(Z'/10^(12-P)), exp x = M 10^(k-P): calxtrig's \CALX_dgoc. P >= 6: % M = H' 10^(P-6) + round(L''/10^(12-P)); P <= 5: M = round(H'/10^(6-P)) % exactly (the rounding boundaries are multiples of 10^6: L'' irrelevant). % Relative error < 2.2e-10 (R1 0.52, tables 2 x 0.5, U 0.5 units 10^-10): % 0.022 ulp_8. % R4.j4;j2;c;|k. %\end{lverb} % \begin{macrocode} \def\CALX_exhV #1.#2;#3;#4;|% {% \expandafter\CALX_exhW\the\numexpr#1+#1*#1/1000000000/20\expandafter.% \the\numexpr(2*#4*(100+#3)-9999)/20000\expandafter.% \the\numexpr#4*(100+#3).#2.% }% % \end{macrocode} %\begin{lverb} % U, a1, A, j4: H = A + a1 j4, g0 = (A - 10^4 a1) j4 %\end{lverb} % \begin{macrocode} \def\CALX_exhW #1.#2.#3.#4.% {% \expandafter\CALX_exhX\the\numexpr#3+#2*#4\expandafter.% \the\numexpr(#3-10000*#2)*#4.#1.% }% % \end{macrocode} %\begin{lverb} % H, g0, U: L' -> H', L'' %\end{lverb} % \begin{macrocode} \def\CALX_exhX #1.#2.#3.% {% \expandafter\CALX_exhY\the\numexpr100*#2+#1*#3/10000+#2*#3/100000000.#1.% }% \def\CALX_exhY #1.#2.% {% \expandafter\CALX_exhZ\the\numexpr#2+(2*#1-999999)/2000000\expandafter.% \the\numexpr#1-1000000*((2*#1-999999)/2000000).% }% % \end{macrocode} %\begin{lverb} % H', L'', k: frequent 10^5 <= H' < 10^6; M by P >= 6 / P <= 5 %\end{lverb} % \begin{macrocode} \def\CALX_exhZ #1.#2.#3.#4% {% \ifx#4\CALX_exMk\else\xint_dothis{#4}\fi \ifnum#1<100000 \xint_dothis\CALX_exhR\fi \ifnum#1>999999 \xint_dothis\CALX_exhR\fi \ifnum\XINTdigits>5 \xint_dothis\CALX_exhP\fi \xint_orthat\CALX_exhQ#1.#2.#3.% }% \def\CALX_exhP #1.#2.#3.% {% \expandafter\CALX_exhO\the\numexpr#1*\CALX_pten{\XINTdigits-6}% +#2/\CALX_pten{12-\XINTdigits}\expandafter.\the\numexpr#3-\XINTdigits.% }% \def\CALX_exhQ #1.#2.#3.% {% \expandafter\CALX_exhO\the\numexpr#1/\CALX_pten{6-\XINTdigits}% \expandafter.\the\numexpr#3-\XINTdigits.% }% \def\CALX_exhO #1.#2.{\expandafter\CALX_dgoc\the\numexpr#1\expandafter.% \the\numexpr(2*#2-7)/16.#2.+}% \def\CALX_exhR #1.#2.#3.% {% \expandafter\CALX_exhRr\expanded{\the\numexpr#3-12.% #1\expandafter\xint_gobble_i\the\numexpr1000000+#2.}% }% \def\CALX_exhRr #1.#2.{\CALX_fnround{\XINTdigits}{\CALX_ffromraw{#2[#1]}}}% % \end{macrocode} %\begin{lverb} % rare path 10^4 <= |x| < 10^16: D = |x| - |K| ln10 % with |K| = 8 K8, K8 = floor(Ze/8) - 25, Ze ~ |x|/ln10 (8 leading digits): % D in (290, 650) exactly on the grid (ln10 floored at 10^-36, |K| < 2^31); % the fast path on x' = s D, then e <- e + s K8 (K = s |K|). % |x| >= 4944763850 (approx.): overflow (x > 0), underflow (x < 0). %\end{lverb} % \begin{macrocode} \def\CALX_exHa 1#1!#2\xint:#3#4.% {% \ifnum#1>49 \xint_dothis{\CALX_exOd#3}\fi \ifnum\numexpr#1*1000000+#4/100>49447638 \xint_dothis{\CALX_exOd#3}\fi \xint_orthat{\expandafter\CALX_exHb\the\numexpr (\ifnum#1>\xint_c_ (#1*1000000+#4/100)*434294482/1000000000*100\else #4*434294482/1000000000\fi-4)/8-25.#3#1.#4.}% }% \def\CALX_exOd #1#2.#3.#4.{\CALX_exO#1}% % \end{macrocode} %\begin{lverb} % K8, s, I1, I0, f1, f2, f3; |K| = k2 10^8 + k1 10^4 + k0; tail s K8. %\end{lverb} % \begin{macrocode} \def\CALX_exHb #1.#2#3.#4.% {\expandafter\CALX_exHc\the\numexpr(2*#1-12499999)/25000000.#1.#2#3.#4.}% \def\CALX_exHc #1.#2.#3#4.#5.#6.#7.#8.% {\expandafter\CALX_exHd\the\numexpr8*#2-100000000*#1.#1.#4.#5.#6.#7.#8.#3#2.}% \def\CALX_exHd #1.#2.#3.#4.#5.#6.#7.% {% \expandafter\CALX_exHe\the\numexpr(2*#1-9999)/20000\expandafter.% \the\numexpr#1-10000*((2*#1-9999)/20000).#2.#3.#4.#5.#6.#7.% }% % \end{macrocode} %\begin{lverb} % k1, k0, k2, I1, I0, f1, f2, f3: D = |x| - |K| ln10, ln10 limbs 2|3025|8509| % 2994|0456|8401|7991|4546|8436|4207 (floor 10^-36); pairs I0 (w=0), f1 % (w=-2), f2 (w=-4), f3 (w=-6), I1 (10^8); columns w >= 0 merged (they % cancel to D's integer part); w=-7 (+ w=-8) carry only %\end{lverb} % \begin{macrocode} \def\CALX_exHe #1.#2.#3.#4.#5.#6.#7.#8.% {% \expandafter\CALX_exHf\the\numexpr((#4-2*#3)*10000-2*#1-3025*#3)*10000% +#5-2*#2-3025*#1-8509*#3\expandafter\CALX_LRh \the\numexpr\CALX_Loffh-3025*#2-8509*#1-2994*#3\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#6-8509*#2-2994*#1-456*#3\expandafter\CALX_LRh \the\numexpr\CALX_Loffh-2994*#2-456*#1-8401*#3\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#7-456*#2-8401*#1-7991*#3\expandafter\CALX_LRh \the\numexpr\CALX_Loffh-8401*#2-7991*#1-4546*#3\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#8-7991*#2-4546*#1-8436*#3\expandafter\CALX_LRhz \the\numexpr\CALX_Loffh-4546*#2-8436*#1-4207*#3% +(-8436*#2-4207*#1)/10000\relax!% }% % \end{macrocode} %\begin{lverb} % Dint, m1..m6, s, K8: the fast path on x' = s D, then the exponent % (P <= 8 reader \CALX_exhG; also used by pow10) %\end{lverb} % \begin{macrocode} \def\CALX_exHf #1!#2!#3!#4!#5!#6!#7!#8#9.% {% \expandafter\CALX_exHz\romannumeral0% \csname CALX_ex\ifnum\XINTdigits<9 h\fi G\expandafter\endcsname\expanded {1#6#7!1#4#5!1#2#3!\the\numexpr100000000+#1!100000000!}\xint:#8% \xint:#8#9.% }% % \end{macrocode} %\begin{lverb} % E = 8e + D - 1: Overflow if E > 2^31 - 9 (the xint printer % fails at E = 2^31 - 1), Underflow if E < -(2^31-1) + P + 7 %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \gdef\CALX_exHz F#1#2.#3.#4\xint:#5.% {% \expandafter\CALX_exHy\the\numexpr#3#5.#2.#4\xint:% }% \gdef\CALX_exHy #1.#2.#3\xint:% {% \ifnum\ifnum#1>268435440 \numexpr8*(#1-268435455)+#2\relax\else0\fi>\xint_c_ \xint_dothis{\CALX_exO+}\fi \ifnum\ifnum#1<-268435440 \numexpr8*(#1+268435455)+#2-\XINTdigits\relax \else1\fi<\xint_c_i \xint_dothis{\CALX_exO-}\fi \xint_orthat{ F+#2.#1.#3}% }% \gdef\CALX_exO #1% {% \if-#1\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expandafter\CALX_sp\romannumeral`&&@% \CALX_signalcondition{Underflow}{exp(x) underflow}{F+0.0.}{F+0.0.}}% {\CALX_nsig{Overflow}{exp(x)}{+}}% }% \endgroup % \end{macrocode} % \subsection{Exponential, P17..P100} %\begin{lverb} % Exponential, P17..P100. Grid % W = 8m, m = ceil(P/8) + 1 pairs, n = 2m limbs. x: integer block and m % pairs MS first (signed); k, i, R1 as P16 (table macros \CALX_exB); % stages k = 2, 4, 6, 8 on R (keys only); t = x + Lv + Lu + Lt + Ls + Lb - % k ln10 by log's zip adder \CALX_LGTx and ln10 chain template \CALX_LGcidef; % e^t: P17..P32 an explicit series and product by fixed chains (below); % P > 32: e^t = 1 + t E1(t), E1 = sum t^k/(k+1)!, by the kernel (schedules % \CALX_exS

: all levels negate their output, \CALX_Zun / \CALX_Zvn); % Y = G e^t, G = c (100+j2)(10^4+j4)(10^6+j6)(10^8+j8) exact (6 limbs), one % kernel level (\CALX_exT

); exp x = 10^(k-W) Y, \CALX_ffromraw + fround. %\end{lverb} % \begin{macrocode} \def\CALX_exgm{\numexpr(\XINTdigits+3)/8+1\relax}% m (internal integer) % \end{macrocode} %\begin{lverb} % s, D, e, blocks: p = top block position; p >= 2 over/underflow; p < -m: % |x| < 10^-W, result 1; p = 1 or integer block >= 10^4: rare path %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \gdef\CALX_exgb #1;#2#3.% {% \ifnum#3=\xint_c_ \xint_dothis\CALX_exgb_zero\fi \xint_orthat\CALX_exgb_regular #1;#2#3.% }% \gdef\CALX_exgb_zero #1;#2#3.#4.#5\xint:{ F+1.0.100000001!}% \gdef\CALX_exgb_regular #1;#2#3.#4.#5\xint:% {% \expandafter\CALX_exgc \the\numexpr#4+(#3+\xint_c_iii)/\xint_c_viii-\xint_c_i.#4.#1;#2#5\xint:% }% \gdef\CALX_exgc #1.% {% \ifnum#1>\xint_c_i \xint_dothis\CALX_exgc_over\fi \ifnum#1<-\CALX_exgm \xint_dothis\CALX_exgc_small\fi \xint_orthat\CALX_exgc_regular #1.% }% \gdef\CALX_exgc_over #1.#2.#3;#4#5\xint:{\CALX_exO#4}% \gdef\CALX_exgc_small #1.#2.#3;#4#5\xint:{ F+1.0.100000001!}% \gdef\CALX_exgc_regular #1.#2.#3;#4#5\xint:% {% \csname CALX_#3\ifnum#1>\xint_c_ Ja\else gG\fi \expandafter\endcsname\expanded{#4% \csname CALX_exgz\ifnum#1>\xint_c_ 0\else\the\numexpr-#1\fi\endcsname \expandafter\CALX_exgDp\the\numexpr-\CALX_exgm-#2.#4#5\xint:!% \csname CALX_exgz\ifnum#2>-\CALX_exgm\the\numexpr#2+\CALX_exgm\else0\fi \endcsname \noexpand\CALX_exQ\expandafter\noexpand\csname CALX_#3Mk\endcsname}% }% \endgroup % \end{macrocode} %\begin{lverb} % drop d low blocks, then reverse into signed items s<8 digits>! (MS first) %\end{lverb} % \begin{macrocode} \def\CALX_exgDp #1.% {\ifnum#1>\xint_c_ \expandafter\CALX_exgDq\else\expandafter\CALX_exgDr\fi#1.}% \def\CALX_exgDq #1.#2#3!{\expandafter\CALX_exgDp\the\numexpr#1-1.#2}% \def\CALX_exgDr #1.#2{\CALX_exgRw#2{}}% \def\CALX_exgRw #1#2#3#4!% {\xint_gob_til_xint: #3\CALX_exgRe\xint:\CALX_exgRw#1{#1#4!#2}}% \def\CALX_exgRe\xint:\CALX_exgRw#1#2{\CALX_exgRf#2}% \def\CALX_exgRf #1!{}% % \end{macrocode} %\begin{lverb} % s, s xI, s f1, s f2 (rest s f3!..!s fm!\CALX_exQ): Z, then k, i as P16 %\end{lverb} % \begin{macrocode} \def\CALX_exgG #1#2!% {% \ifnum#1#2>9999 \xint_dothis\CALX_exgG_large\fi \xint_orthat\CALX_exgG_regular #1#2!% }% \def\CALX_exgG_large #1#2!#3!#4!{\CALX_exJa#1+00000000!#2!#3!#4!}% \def\CALX_exgG_regular #1#2!#3!#4!% {% \expandafter\CALX_exK\the\numexpr (0#1(#2*100000+#3/1000))*434294482/1000000000.#1B#2!#3!#4!% }% % \end{macrocode} %\begin{lverb} % stages (keys only): \CALX_exgTmp {}{}{} %\end{lverb} % \begin{macrocode} \def\CALX_exgTmp #1#2#3#4#5#6% {% \def#1##1.{\expandafter\expandafter\expandafter#2% \csname#4\the\numexpr#5\endcsname##1.}% \def#2##1!##2!##3!##4.##5.##6|{#6##4;##6|}% }% \CALX_exgTmp\CALX_exgSa\CALX_exgRa\CALX_exgSb{CALX_exu}% {(#1+#1*#1/1000000000/20)/100000000}% {\expandafter\CALX_exgSb\the\numexpr#5+100*#1+#2/1000000.}% \CALX_exgTmp\CALX_exgSb\CALX_exgRb\CALX_exgSc{CALX_exv}% {(#1+#1*#1/1000000000/20)/1000000}% {\expandafter\CALX_exgSc\the\numexpr#5+100*#1+#2/1000000.}% \CALX_exgTmp\CALX_exgSc\CALX_exgRc\CALX_exgSd{CALX_exw}% {#1/10000}% {\expandafter\CALX_exgSd\the\numexpr#5+100*#1+#2/1000000.}% \CALX_exgTmp\CALX_exgSd\CALX_exgRd\CALX_exgV{CALX_exz}% {#1/100}{\CALX_exgV}% \CALX_exgTmp\CALX_exhSa\CALX_exhRa\CALX_exhSb{CALX_exu}% {(#1+#1*#1/1000000000/20)/100000000}% {\expandafter\CALX_exhSb\the\numexpr#5+100*#1+#2/1000000.}% \CALX_exgTmp\CALX_exhSb\CALX_exhRb\CALX_exhV{CALX_exv}% {(#1+#1*#1/1000000000/20)/1000000}% {\expandafter\CALX_exhV\the\numexpr#5+100*#1+#2/1000000.}% \let\CALX_exgTmp\relax % \end{macrocode} %\begin{lverb} % j8;j6;j4;j2;a;c;|k.sxI! then s f1!..!s fm!\CALX_exQ$empty: the adder stream; % keys j8;100j6;j4;100j2;a;-k;sxI. then c.j2.j4.j6.j8.k.; P > 32: log's % generic zip adder (\CALX_exgVb), P <= 32: log's fixed-arity adders % (templates \CALX_LGTdef, \CALX_LGAdef, \CALX_LGBdef, chains \CALX_LGcadef, % \CALX_LGcbdef), accs LS first: L24 f4!f3!f2!f1; L32 f4!f3!f2!f1!f5; %\end{lverb} % \begin{macrocode} \def\CALX_exgV #1;#2;#3;#4;#5;#6;|#7.#8!% {% \csname CALX_exgV% \ifnum\XINTdigits>32 b\else\ifnum\XINTdigits>24 q\else p\fi\fi \expandafter\endcsname\expanded{{#1;\the\numexpr100*#2\relax;#3;% \the\numexpr100*#4\relax;#5;-#7;#8.}{#6.#4.#3.#2.#1.#7.}}% }% \def\CALX_exgVb #1#2#3\CALX_exQ{\CALX_exTv#3;#1#2}% \def\CALX_exgVp #1#2#3!#4!#5!#6!\CALX_exQ{\CALX_exNva#6!#5!#4!#3;#1#2}% \def\CALX_exgVq #1#2#3!#4!#5!#6!#7!\CALX_exQ{\CALX_exNvb#6!#5!#4!#3!#7;#1#2}% \CALX_LGTdef\CALX_exNva{CALX_Lv}\CALX_exUva \CALX_LGAdef\CALX_exUva\CALX_exNua \CALX_LGTdef\CALX_exNua{CALX_Lu}\CALX_exUua \CALX_LGAdef\CALX_exUua\CALX_exNta \CALX_LGTdef\CALX_exNta{CALX_Lt}\CALX_exUta \CALX_LGAdef\CALX_exUta\CALX_exNsa \CALX_LGTdef\CALX_exNsa{CALX_Ls}\CALX_exUsa \CALX_LGAdef\CALX_exUsa\CALX_exNba \CALX_LGTdef\CALX_exNba{CALX_Lb}\CALX_exUba \CALX_LGAdef\CALX_exUba\CALX_exNca \CALX_LGTdef\CALX_exNvb{CALX_Lv}\CALX_exUvb \CALX_LGBdef\CALX_exUvb\CALX_exNub \CALX_LGTdef\CALX_exNub{CALX_Lu}\CALX_exUub \CALX_LGBdef\CALX_exUub\CALX_exNtb \CALX_LGTdef\CALX_exNtb{CALX_Lt}\CALX_exUtb \CALX_LGBdef\CALX_exUtb\CALX_exNsb \CALX_LGTdef\CALX_exNsb{CALX_Ls}\CALX_exUsb \CALX_LGBdef\CALX_exUsb\CALX_exNbb \CALX_LGTdef\CALX_exNbb{CALX_Lb}\CALX_exUbb \CALX_LGBdef\CALX_exUbb\CALX_exNcb \CALX_LGcadef\CALX_exNca\CALX_exgW{#1!#2!#3!#4;#5;#6.}{#6+}{\CALX_LQ}% \CALX_LGcbdef\CALX_exNcb\CALX_exgW{#1!#2!#3!#4!#5;#6;#7.}{#7+}% \def\CALX_exTv{\CALX_LGTx\CALX_exTu{CALX_Lv}}% \def\CALX_exTu{\CALX_LGTx\CALX_exTt{CALX_Lu}}% \def\CALX_exTt{\CALX_LGTx\CALX_exTs{CALX_Lt}}% \def\CALX_exTs{\CALX_LGTx\CALX_exTb{CALX_Ls}}% \def\CALX_exTb{\CALX_LGTx\CALX_exch{CALX_Lb}}% \def\CALX_exch{\expandafter\CALX_exci\CALX_Lzl\relax}% \CALX_LGcidef\CALX_exci\CALX_exgW{#1\relax#2!#3;#4;#5.}{#5+}% % \end{macrocode} %\begin{lverb} % t = I!l1!..!ln!\CALX_LQ (|t| < 5.5e-9): P <= 32 the explicit back end % (\CALX_exE, sign of t, layout L = 24 or 32), P > 32 the kernel %\end{lverb} % \begin{macrocode} \def\CALX_exgW #1!% {% \csname CALX_ex\ifnum\XINTdigits>32 gWk\else E\ifnum#1<\xint_c_ n\else p\fi \ifnum\XINTdigits>24 b\else a\fi\fi\endcsname#1!% }% % \end{macrocode} %\begin{lverb} % P > 32: U'' = 10^8 t (l3..ln, t < 0: top l3 - 10^4), kernel U list, % schedule \CALX_exS

%\end{lverb} % \begin{macrocode} \def\CALX_exgWk #1!#2!#3!#4\CALX_LQ% {% \ifnum#1<\xint_c_ \expandafter\CALX_exgWn\else\expandafter\CALX_exgWs\fi #4\CALX_Zq!% }% \def\CALX_exgWn #1!{\expandafter\CALX_exgWs\the\numexpr#1-10000!}% \def\CALX_exgWs #1\CALX_Zq!% {% \expandafter\expandafter\expandafter\CALX_Zst \csname CALX_exS\the\numexpr\XINTdigits\expandafter\endcsname \expandafter{\expanded{\CALX_Zbt#1\CALX_Zq!}}% }% % \end{macrocode} %\begin{lverb} % {U}x_top.\CALX_Zq c.j2.j4.j6.j8. (then k.): a = c(100+j2) % = a1 10^4 + a0; T items -(e^t 10^W) %\end{lverb} % \begin{macrocode} \def\CALX_exgF #1#2.#3\CALX_Zq{\expandafter\CALX_exgFb\expanded{#2.#3}\CALX_Zq}% \def\CALX_exgFb #1.#2\CALX_Zq#3.#4.#5.#6.#7.% {% \expandafter\CALX_exgGa\expanded{\the\numexpr(2*#3*(100+#4)-9999)/20000.% \the\numexpr#3*(100+#4)-10000*((2*#3*(100+#4)-9999)/20000).#5.#6.#7.% \noexpand\CALX_exgGc{-#1.\CALX_exgTn#2\CALX_Zq!}}% }% \def\CALX_exgTn #1!% {\CALX_Zgob#1\CALX_exgTe\CALX_Zq\noexpand\CALX_Zn-#1.\CALX_exgTn}% \def\CALX_exgTe\CALX_Zq#1\CALX_exgTn{}% % \end{macrocode} %\begin{lverb} % a1.a0.j4.j6.j8.: a b = p3!p2!p1!p0!, b = 100 10^8 + (100 j4 + j6) % 10^4 + j4 j6 (shared by P17..P100; = \CALX_exgGc (kernel path), % \CALX_exPA, \CALX_exPB) %\end{lverb} % \begin{macrocode} \def\CALX_exgGa #1.#2.#3.#4.#5.% {% \expandafter\CALX_exgGb\the\numexpr100*#1\expandafter\CALX_LR \the\numexpr\CALX_Loff+100*#2+#1*(100*#3+#4)\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2*(100*#3+#4)+#1*#3*#4\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2*#3*#4\relax!#5.% }% % \end{macrocode} %\begin{lverb} % G = a b (10^8 + j8): g5!..!g0! (6 limbs, top not normalized) %\end{lverb} % \begin{macrocode} \def\CALX_exgGb #1!#2!#3!#4!#5.#6% {% \expandafter#6\the\numexpr#1\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2\expandafter\CALX_LR \the\numexpr\CALX_Loff+#3+#1*#5\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4+#2*#5\expandafter\CALX_LR \the\numexpr\CALX_Loff+#3*#5\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4*#5\relax!% }% \def\CALX_exgGc #1!#2!#3!#4!#5!#6!#7% {% \csname CALX_exT\the\numexpr\XINTdigits\expandafter\endcsname\expandafter {\expanded{\CALX_Zbt#1!#2!#3!#4!#5!#6!\CALX_Zq!}}{#7}% }% % \end{macrocode} %\begin{lverb} % {U}x_top.\CALX_Zq k. : exp x = 10^(k-W) Y %\end{lverb} % \begin{macrocode} \def\CALX_exgY #1#2.#3\CALX_Zq {\expandafter\CALX_exgYb\expanded{#2.#3}\CALX_Zq}% \def\CALX_exgYb #1.#2\CALX_Zq#3.% {% \expandafter\CALX_exgYd\expanded{\ifnum#1>\xint_c_ #1\fi \CALX_exgYs#2\CALX_Zq!}#3.% }% % \end{macrocode} %\begin{lverb} % digits.k.: expm1 -> \CALX_emF, else \CALX_exgYa %\end{lverb} % \begin{macrocode} \def\CALX_exgYd #1.#2.#3{\ifx#3\CALX_exMk\expandafter\xint_firstoftwo \else\expandafter\xint_secondoftwo\fi {\CALX_exgYe#1.#2.8*\CALX_exgm.}{\CALX_emF#1.#2.8*\CALX_exgm.#3}}% \def\CALX_exgYe #1.#2.#3.{\expandafter\CALX_exgYa\the\numexpr#2-#3.#1.}% \def\CALX_exgYs #1!{\CALX_Zgob#1\CALX_exgYt\CALX_Zq#1\CALX_exgYs}% \def\CALX_exgYt\CALX_Zq#1\CALX_exgYs{.}% \def\CALX_exgYa #1.#2.% {\CALX_fnround{\XINTdigits}{\CALX_ffromraw{#2[#1]}}}% % \end{macrocode} %\begin{lverb} % P17..P32: explicit back end, no kernel. % t = I!0000!0000!l3!..!ln!\CALX_LQ (I = 0) or -1!9999!9999!..; s = % floor(10^16 t) = u 10^4 + w (u = l3 or l3 - 10^4, w = l4); U = 10^W % (e^t - 1) by ONE carry chain (floor limbs, signed top), braced; then G % (\CALX_exgGa), Y' = G 10^(W-24) + G U 10^-24 (\CALX_exPA, \CALX_exPB), % exp x = 10^(k-W) Y' (writer \CALX_exXa, \CALX_exXb). % L = 24 (W = 32): u.s.w!l5!l6!l7!l8!\CALX_LQ (rho = l5l6, lambda = l7l8); % U = s 1e16 + rho 1e8 + lambda + s^2/2 + s rho/1e8 + s^3/6e16, s^2/2 = % (u^2/2) 1e8 + u w 1e4 + w^2/2 %\end{lverb} % \begin{macrocode} \def\CALX_exEpa 0!0000!0000!#1!#2!{\CALX_exEa#1.#1#2.#2!}% \def\CALX_exEna -1!9999!9999!#1!#2!% {\expandafter\CALX_exEa \the\numexpr#1-10000\expandafter.\the\numexpr#1#2-100000000.#2!}% \def\CALX_exEa #1.#2.#3!#4!#5!#6!#7!\CALX_LQ% {% \expandafter\CALX_exEc\expandafter\CALX_exPA\expandafter{\the\numexpr 0\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2\expandafter\CALX_LR \the\numexpr\CALX_Loff\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4#5+#1*#1/2\expandafter\CALX_LR \the\numexpr\CALX_Loff+(#1*#1-2*(#1*#1/2))*5000+#1*#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6#7+#3*#3/2+#2*#4#5/100000000% +(#2*#2/100000000)*#2/600000000\relax!}% }% % \end{macrocode} %\begin{lverb} % L = 32 (W = 40): u.w!l5!..!l10!\CALX_LQ -> h1.h0.Ls.u.w!r1!r0!lambda!mu! % (s^2 = Hs 1e8 + Ls exactly, Hs = h1 1e4 + h0) %\end{lverb} % \begin{macrocode} \def\CALX_exEpb 0!0000!0000!#1!#2!{\CALX_exEh#1.#2!}% \def\CALX_exEnb -1!9999!9999!#1!#2!% {\expandafter\CALX_exEh\the\numexpr#1-10000.#2!}% \def\CALX_exEh #1.#2!#3!#4!#5!#6!#7!#8!\CALX_LQ% {% \expandafter\CALX_exEb \the\numexpr(#1*#1+2*#1*#2/10000)/10000\expandafter.% \the\numexpr#1*#1+2*#1*#2/10000-10000*((#1*#1+2*#1*#2/10000)/10000)% \expandafter.\the\numexpr(2*#1*#2-10000*(2*#1*#2/10000))*10000+#2*#2.% #1.#2!#3!#4!#5#6!#7#8!% }% % \end{macrocode} %\begin{lverb} % U = s 1e24 + rho 1e16 + lambda 1e8 + mu + t^2/2 + t^3/6 + t^4/24 (units % 10^-40): s rho = u r1 1e8 + (u r0 + w r1) 1e4 + w r0; s^3/6e8 = s Hs/6 + % s Ls/6e8, s Hs/6 = (u h1/6) 1e8 + ((u h0 + w h1)/6) 1e4 + w h0/6 %\end{lverb} % \begin{macrocode} \def\CALX_exEb #1.#2.#3.#4.#5!#6!#7!#8!#9!% {% \expandafter\CALX_exEc\expandafter\CALX_exPB\expandafter{\the\numexpr 0\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4*10000+#5\expandafter\CALX_LR \the\numexpr\CALX_Loff\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6#7+#4*#4/2\expandafter\CALX_LR \the\numexpr\CALX_Loff+(#4*#4-2*(#4*#4/2))*5000+#4*#5\expandafter\CALX_LR \the\numexpr\CALX_Loff+#8+#5*#5/2+#4*#6+#4*#1/6\expandafter\CALX_LR \the\numexpr\CALX_Loff+(#5*#5-2*(#5*#5/2))*5000+#4*#7+#5*#6% +(#4*#2+#5*#1)/6\expandafter\CALX_LR \the\numexpr\CALX_Loff+#9+#5*#7+#6#7*#6#7/200000000% +(#4*10000+#5)*#8/100000000+(#4*10000+#5)*#3/600000000% +(#4*#1-6*(#4*#1/6))*50000000/3% +(#4*#2+#5*#1-6*((#4*#2+#5*#1)/6))*5000/3+#5*#2/6% +(#1*10000+#2)*#6#7/200000000% +(#1*10000+#2)*(#1*10000+#2)/1200000000/2\relax!}% }% % \end{macrocode} %\begin{lverb} % {U limbs}c.j2.j4.j6.j8. : a = c (100 + j2) = a1 10^4 + a0, then G %\end{lverb} % \begin{macrocode} \def\CALX_exEc #1#2#3.#4.#5.#6.#7.% {% \expandafter\CALX_exgGa\the\numexpr(2*#3*(100+#4)-9999)/20000\expandafter.% \the\numexpr#3*(100+#4)-10000*((2*#3*(100+#4)-9999)/20000).#5.#6.#7.#1#2% }% % \end{macrocode} %\begin{lverb} % Y' = G 10^(W-24) + G U 10^-24: columns c = i + m (g_i u_m) >= W/4 - 2, % c = W/4 - 3 guard (carry only); later partial sums passed as expression % TEXT. L = 24: g5..g0, u5, u4, u3 (stream u2!u1!u0!k.) %\end{lverb} % \begin{macrocode} \def\CALX_exPA #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \expandafter\CALX_exXe\the\numexpr#1\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2\expandafter\CALX_LR \the\numexpr\CALX_Loff+#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4+#1*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#5+#1*#8+#2*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6+#1*#9+#2*#8+#3*#7% \CALX_exPAb#2*#9+#3*#8+#4*#7!#3*#9+#4*#8+#5*#7!#4*#9+#5*#8+#6*#7!% #1!#2!#3!% }% % \end{macrocode} %\begin{lverb} % S1, S0, Sg (texts), g5, g4, g3, u2, u1, u0 %\end{lverb} % \begin{macrocode} \def\CALX_exPAb #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#4*#7+#1% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#4*#8+#5*#7+#2% \expandafter\CALX_LRz\the\numexpr\CALX_Loff+#4*#9+#5*#8+#6*#7+#3\relax!% }% % \end{macrocode} %\begin{lverb} % L = 32: g5..g0, u7, u6, u5 (stream u4!..!u0!k.); column 9 left open %\end{lverb} % \begin{macrocode} \def\CALX_exPB #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \expandafter\CALX_exXf\the\numexpr#1\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2\expandafter\CALX_LR \the\numexpr\CALX_Loff+#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+#4+#1*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#5+#1*#8+#2*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#6+#1*#9+#2*#8+#3*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#2*#9+#3*#8+#4*#7% \CALX_exPBb#3*#9+#4*#8+#5*#7!#4*#9+#5*#8+#6*#7\CALX_exPBc#6*#9!#5!% #5*#9+#6*#8\CALX_exPm#1!#2!#3!#4!% }% \let\CALX_exPm\relax % \end{macrocode} %\begin{lverb} % S8, bundle (S7, \CALX_exPBc, A5, g1, A6), g5..g2, u4, u3, u2: closes % column 9; column 7 ends with S7 and \CALX_exPBc (A6 + B6 one parameter) %\end{lverb} % \begin{macrocode} \def\CALX_exPBb #1!#2\CALX_exPm#3!#4!#5!#6!#7!#8!#9!% {% +#3*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#1+#3*#8+#4*#7\expandafter\CALX_LR \the\numexpr\CALX_Loff+#3*#9+#4*#8+#5*#7+#2+#4*#9+#5*#8+#6*#7!% #5*#9+#6*#8!#3!#4!#7!% }% % \end{macrocode} %\begin{lverb} % A5, g1, A6 + B6, B5, g5, g4, u4, u1, u0 %\end{lverb} % \begin{macrocode} \def\CALX_exPBc #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \expandafter\CALX_LR\the\numexpr\CALX_Loff+#5*#8+#3% \expandafter\CALX_LRz\the\numexpr\CALX_Loff+#5*#9+#6*#8+#2*#7+#4+#1\relax!% }% % \end{macrocode} %\begin{lverb} % writer: T!q..!q0!k.: \CALX_exXe (L24), \CALX_exXf (L32) dispatch % (expm1: \CALX_emXa, \CALX_emXb) %\end{lverb} % \begin{macrocode} \def\CALX_exXe #1.#2{\ifx#2\CALX_exMk\CALX_exXj\fi\CALX_emXa#1.#2}% \def\CALX_exXf #1.#2{\ifx#2\CALX_exMk\CALX_exXk\fi\CALX_emXb#1.#2}% \def\CALX_exXj\fi\CALX_emXa#1.#2{\fi\CALX_exXa#1.}% \def\CALX_exXk\fi\CALX_emXb#1.#2{\fi\CALX_exXb#1.}% % \end{macrocode} %\begin{lverb} % T!q..!q0!k. ; frequent 1000 <= T <= 9999 (Y' has W digits): % pairs MS first P!..!P0!k. ; else \CALX_ffromraw (\CALX_exgYa) %\end{lverb} % \begin{macrocode} \def\CALX_exXa #1!#2!#3!#4!#5!#6!#7!% {% \ifnum\numexpr(2*#1-10999)*(2*#1-10999)>80982001 \xint_dothis{\CALX_exXg32.#1#2#3#4#5#6#7}\fi \xint_orthat{\CALX_exXca#1#2!#3#4!#5#6!#7}% }% \def\CALX_exXb #1!#2!#3!#4!#5!#6!#7!#8!#9!% {% \ifnum\numexpr(2*#1-10999)*(2*#1-10999)>80982001 \xint_dothis{\CALX_exXg40.#1#2#3#4#5#6#7#8#9}\fi \xint_orthat{\CALX_exXcb#1#2!#3#4!#5#6!#7#8!#9}% }% \def\CALX_exXg #1.#2!#3.{\expandafter\CALX_exgYa\the\numexpr#3-#1.#2.}% % \end{macrocode} %\begin{lverb} % f = floor(k/8), h = k - 8f %\end{lverb} % \begin{macrocode} \def\CALX_exXca #1!#2!#3!#4!#5.% {% \expandafter\CALX_exXd\the\numexpr(2*#5-7)/16\expandafter.% \the\numexpr#5-8*((2*#5-7)/16).#1!#2!#3!#4!% }% \def\CALX_exXcb #1!#2!#3!#4!#5!#6.% {% \expandafter\CALX_exXd\the\numexpr(2*#6-7)/16\expandafter.% \the\numexpr#6-8*((2*#6-7)/16).#1!#2!#3!#4!#5!% }% % \end{macrocode} %\begin{lverb} % f.h. -> \CALX_exX h.10^h.V.f. (V = 10^(8-h), \CALX_exh): % P = L (24, 32): v (h = 0), u (h > 0) direct; other P: z, s (\CALX_fround) %\end{lverb} % \begin{macrocode} \def\CALX_exXd #1.#2.% {% \csname CALX_exX\ifnum\numexpr\XINTdigits-8*((\XINTdigits+3)/8)\relax =\xint_c_ \ifnum#2=\xint_c_ v\else u\fi\else\ifnum#2=\xint_c_ z\else s\fi\fi \ifnum\XINTdigits>24 b\else a\fi \expandafter\expandafter\expandafter\endcsname\csname CALX_exh#2\endcsname#1.% }% % \end{macrocode} %\begin{lverb} % blocks of N = Y' 10^h (LS first), D = W + h, e = f - W/8; one rounding. % floor(P/V) = (2P-V+1)/(2V) %\end{lverb} % \begin{macrocode} \begingroup\catcode`F=12 \gdef\CALX_exXza #1.#2.#3.#4.#5!#6!#7!#8!% {\CALX_fnround\XINTdigits {\expanded{F+32.\the\numexpr#4-4.1#8!1#7!1#6!1#5!}}}% \gdef\CALX_exXzb #1.#2.#3.#4.#5!#6!#7!#8!#9!% {\CALX_fnround\XINTdigits {\expanded{F+40.\the\numexpr#4-5.1#9!1#8!1#7!1#6!1#5!}}}% \gdef\CALX_exXsa #1.#2.#3.#4.#5!#6!#7!#8!% {% \CALX_fnround\XINTdigits{\expanded{F+\the\numexpr32+#1.\the\numexpr#4-4.% \the\numexpr100000000+(#8-(2*#8-#3+1)/(2*#3)*#3)*#2!% \the\numexpr100000000+(#7-(2*#7-#3+1)/(2*#3)*#3)*#2+(2*#8-#3+1)/(2*#3)!% \the\numexpr100000000+(#6-(2*#6-#3+1)/(2*#3)*#3)*#2+(2*#7-#3+1)/(2*#3)!% \the\numexpr100000000+(#5-(2*#5-#3+1)/(2*#3)*#3)*#2+(2*#6-#3+1)/(2*#3)!% \the\numexpr100000000+(2*#5-#3+1)/(2*#3)!}}% }% \gdef\CALX_exXsb #1.#2.#3.#4.#5!#6!#7!#8!#9!% {% \CALX_fnround\XINTdigits{\expanded{F+\the\numexpr40+#1.\the\numexpr#4-5.% \the\numexpr100000000+(#9-(2*#9-#3+1)/(2*#3)*#3)*#2!% \the\numexpr100000000+(#8-(2*#8-#3+1)/(2*#3)*#3)*#2+(2*#9-#3+1)/(2*#3)!% \the\numexpr100000000+(#7-(2*#7-#3+1)/(2*#3)*#3)*#2+(2*#8-#3+1)/(2*#3)!% \the\numexpr100000000+(#6-(2*#6-#3+1)/(2*#3)*#3)*#2+(2*#7-#3+1)/(2*#3)!% \the\numexpr100000000+(#5-(2*#5-#3+1)/(2*#3)*#3)*#2+(2*#6-#3+1)/(2*#3)!% \the\numexpr100000000+(2*#5-#3+1)/(2*#3)!}}% }% % \end{macrocode} %\begin{lverb} % P = L: M = (pairs above P0) + [P0 >= 5e7] (= round(Y'/10^8)), blocks of % M 10^h, D = P + h, e = f - P/8; M1 + [P0 >= 5e7] = 10^8: the fround path %\end{lverb} % \begin{macrocode} \gdef\CALX_exXva #1.#2.#3.#4.#5!#6!#7!#8!% {% \ifnum\numexpr#7+#8/100000000>99999999 \xint_dothis{\CALX_exXza#1.#2.#3.#4.#5!#6!#7!#8!}\fi \xint_orthat{\expanded{ F+24.\the\numexpr#4-3.% \the\numexpr1#7+#8/100000000!1#6!1#5!}}% }% \gdef\CALX_exXvb #1.#2.#3.#4.#5!#6!#7!#8!#9!% {% \ifnum\numexpr#8+#9/100000000>99999999 \xint_dothis{\CALX_exXzb#1.#2.#3.#4.#5!#6!#7!#8!#9!}\fi \xint_orthat{\expanded{ F+32.\the\numexpr#4-4.% \the\numexpr1#8+#9/100000000!1#7!1#6!1#5!}}% }% \gdef\CALX_exXua #1.#2.#3.#4.#5!#6!#7!#8!% {% \ifnum\numexpr#7+#8/100000000>99999999 \xint_dothis{\CALX_exXsa#1.#2.#3.#4.#5!#6!#7!#8!}\fi \xint_orthat {\expandafter\CALX_exXw\the\numexpr#7+#8/100000000.#1.#2.#3.#4.#5!#6!}% }% \gdef\CALX_exXw #1.#2.#3.#4.#5.#6!#7!% {% \expanded{ F+\the\numexpr24+#2.\the\numexpr#5-3.% \the\numexpr100000000+(#1-(2*#1-#4+1)/(2*#4)*#4)*#3!% \the\numexpr100000000+(#7-(2*#7-#4+1)/(2*#4)*#4)*#3+(2*#1-#4+1)/(2*#4)!% \the\numexpr100000000+(#6-(2*#6-#4+1)/(2*#4)*#4)*#3+(2*#7-#4+1)/(2*#4)!% \the\numexpr100000000+(2*#6-#4+1)/(2*#4)!}% }% \gdef\CALX_exXub #1.#2.#3.#4.#5!#6!#7!#8!#9!% {% \ifnum\numexpr#8+#9/100000000>99999999 \xint_dothis{\CALX_exXsb#1.#2.#3.#4.#5!#6!#7!#8!#9!}\fi \xint_orthat{\expandafter\CALX_exXx\the\numexpr#8+#9/100000000.% #1.#2.#3.#4.#5!#6!#7!}% }% \gdef\CALX_exXx #1.#2.#3.#4.#5.#6!#7!#8!% {% \expanded{ F+\the\numexpr32+#2.\the\numexpr#5-4.% \the\numexpr100000000+(#1-(2*#1-#4+1)/(2*#4)*#4)*#3!% \the\numexpr100000000+(#8-(2*#8-#4+1)/(2*#4)*#4)*#3+(2*#1-#4+1)/(2*#4)!% \the\numexpr100000000+(#7-(2*#7-#4+1)/(2*#4)*#4)*#3+(2*#8-#4+1)/(2*#4)!% \the\numexpr100000000+(#6-(2*#6-#4+1)/(2*#4)*#4)*#3+(2*#7-#4+1)/(2*#4)!% \the\numexpr100000000+(2*#6-#4+1)/(2*#4)!}% }% \endgroup % \end{macrocode} %\begin{lverb} % rare path P > 16, 10^4 <= |x| < 10^16 (as P16: K = s 8 K8, D = |x| - % |K| ln10 in (290, 650), the fast path on s D, e <- e + s K8): s, s I1 % (block 10^8), s I0, then s f1!..!s fm!\CALX_exQ. D by one chain: columns % w = 2..-(n+1), X_w - k0 l_(-w) - k1 l_(1-w) - k2 l_(2-w) (ln10 limbs l_j, % \CALX_exLx$empty: j = 3..31, floor 10^-124); the last column only for the % carry. %\end{lverb} % \begin{macrocode} \def\CALX_exJa #1#2!#3!% {% \ifnum#1#2>49 \xint_dothis\CALX_exJa_over\fi \ifnum\numexpr(#1#2)*1000000+(#1#3)/100>49447638 \xint_dothis\CALX_exJa_over\fi \xint_orthat\CALX_exJa_regular #1#2!#3!% }% \def\CALX_exJa_over #1#2!#3!#4\CALX_exQ#5{\CALX_exO#1}% \def\CALX_exJa_regular #1#2!#3!#4\CALX_exQ#5% {% \expandafter\CALX_exJb\the\numexpr (\ifnum#1#2>\xint_c_ ((#1#2)*1000000+(#1#3)/100)*434294482/1000000000*100% \else(#1#3)*434294482/1000000000\fi-4)/8-25.#1#2!#3!#4\CALX_exQ#5% }% % \end{macrocode} %\begin{lverb} % K8, s, s I1, s I0, pairs: k2 = floor(8 K8/10^8), rem, k1, k0; X limbs %\end{lverb} % \begin{macrocode} \def\CALX_exJb #1.#2#3!#4!#5\CALX_exQ% {% \expandafter\CALX_exJc\expanded{\the\numexpr(2*#1-12499999)/25000000.% \the\numexpr8*#1-100000000*((2*#1-12499999)/25000000).% \the\numexpr#2#3!\CALX_exJs#4!\CALX_exJl#5\CALX_exQ!}0!\CALX_LQ!#2#1.% }% \def\CALX_exJs #1#2#3#4#5#6#7#8#9!{#2#3#4#5!#6#7#8#9!}% \def\CALX_exJl #1#2!% {\ifx\CALX_exQ#1\else\CALX_exJs#1#2!\expandafter\CALX_exJl\fi}% \def\CALX_exJc #1.#2.% {% \expandafter\CALX_exJd\the\numexpr(2*#2-9999)/20000\expandafter.% \the\numexpr#2-10000*((2*#2-9999)/20000).#1.% }% % \end{macrocode} %\begin{lverb} % k1, k0, k2, X2, X1, X0, rest X (\CALX_LQ!): the chain %\end{lverb} % \begin{macrocode} \def\CALX_exJd{\expandafter\CALX_exJe\CALX_exLx\relax}% \def\CALX_exJe #1\relax#2.#3.#4.#5!#6!#7!#8\CALX_LQ!% {% \expandafter\CALX_exJf\the\numexpr#5-2*#4\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#6-2*#2-3025*#4\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#7-2*#3-3025*#2-8509*#4% \CALX_exJw#8\CALX_LQ!;3025.8509.#3.#2.#4.#10!0!\relax }% % \end{macrocode} %\begin{lverb} % X_w, rest X, l_(-w), l_(1-w), k0, k1, k2, l_(2-w) (stream) %\end{lverb} % \begin{macrocode} \def\CALX_exJw #1!#2;#3.#4.#5.#6.#7.#8!% {% \CALX_LGgt#1\CALX_exJz\CALX_LQ\expandafter\CALX_LRh \the\numexpr\CALX_Loffh+#1-#5*#3-#6*#4-#7*#8\CALX_exJw#2;#4.#8.#5.#6.#7.% }% \def\CALX_exJz\CALX_LQ#1\relax{\relax!\CALX_LQ}% % \end{macrocode} %\begin{lverb} % c2!l1!l0!m1!..m_(n+1)!\CALX_LQ s K8. : the fast path on s D (the % marker passed to it), then e + s K8 %\end{lverb} % \begin{macrocode} \def\CALX_exJf #1!#2!#3!#4\CALX_LQ#5#6.#7% {% \expandafter\CALX_exHz\romannumeral0\expandafter\CALX_exgG\expanded {#5#5#2#3!\CALX_exJp#5#4\CALX_LQ!}\CALX_exQ#7\xint:#5#6.% }% \def\CALX_exJp #1#2!#3!% {\ifx\CALX_LQ#3\else#1#2#3!\expandafter\CALX_exJp\expandafter#1\fi}% % \end{macrocode} %\begin{lverb} % load time: short tables F1!c2!c3!j. keyed by j: \CALX_exu = Ls<100j>, % \CALX_exv = Lt, \CALX_exw = Lu<100j> %\end{lverb} % \begin{macrocode} \def\CALX_exMs #1!#2!#3!#4\CALX_LQ#5#6{\expandafter\def\csname#5#6\endcsname {#1!#2!#3!#6.}}% \def\CALX_exMt #1.#2.#3.#4.#5.% {% \edef\CALX_Ltmpb{\the\numexpr#3*#4}% \expandafter\expandafter\expandafter \CALX_exMs\csname#2\CALX_Ltmpb\endcsname \CALX_LQ{#1}{#4}% \ifnum#4>#5 \xint_afterfi{\expandafter\CALX_exMt\expanded{#1.#2.#3.% \the\numexpr#4-1.#5.}}\fi }% \CALX_exMt CALX_exu.CALX_Ls.100.11.-11.% \CALX_exMt CALX_exv.CALX_Lt.1.56.-56.% \CALX_exMt CALX_exw.CALX_Lu.100.51.-51.% \CALX_exMt CALX_exz.CALX_Lv.1.51.-51.% % \end{macrocode} %\begin{lverb} % table macros \CALX_exA (i = 0..99) from \CALX_exAlist (calxlogdata.tex) % and the entries \CALX_Lb: #1 k, #2 s x12, #3 s x34, #4 s x56, #5 s xI. % R1 = 100 A2 + (-2994k + (s x34 + c2 - 456k)/10^4)/100, A2 = A1 10^4 + s x12 % + F1 - 8509k, A1 = (s xI - 2k) 10^4 - 3025k (|A1| < 3.7e4, |A2| < 5e6). % list entries i.key.c. (key of \CALX_Lb: 0 = zero entry, 1 = % \CALX_Lz (ln10), else a; c the bootstrap multiplier) %\end{lverb} % \begin{macrocode} \expandafter\let\csname CALX_Lb1\endcsname\CALX_Lz \def\CALX_exMa #1!#2!#3!#4\CALX_LQ#5.#6.#7.% {% \expandafter\edef\csname CALX_exA#5\endcsname##1.##2.##3.##4.##5.% {% \noexpand\expandafter\noexpand\CALX_exSa\noexpand\the\noexpand\numexpr (((##5-2*##1)*10000-3025*##1)*10000+##2+#1-8509*##1)*100% +(-2994*##1+(##3+#2-456*##1)/10000)/100.#1.#2.#3.% #7;|##2.##3.##4.##1.##5.##1.% }% }% \def\CALX_exLd #1.#2.#3.% {% \ifnum#1<\xint_c_ \expandafter\xint_gobble_i\else \expandafter\expandafter\expandafter\CALX_exMa\csname CALX_Lb#2\endcsname \CALX_LQ#1.#2.#3.\fi \CALX_exLd }% \expandafter\CALX_exLd\CALX_exAlist % \end{macrocode} %\begin{lverb} % P > 16 table macros \CALX_exB: #1 k, #2 s xI, #3 s f1, #4 s f2 (R1 as % P16) %\end{lverb} % \begin{macrocode} \def\CALX_exMa #1!#2!#3!#4\CALX_LQ#5.#6.#7.% {% \expandafter\edef\csname CALX_exB#5\endcsname##1.##2!##3!##4!% {% \noexpand\expandafter\noexpand\CALX_exgSa\noexpand\the\noexpand\numexpr (((##2-2*##1)*10000-3025*##1)*10000+##3+#1-8509*##1)*100% +(-2994*##1+(##4+#2-456*##1)/10000)/100.#6;% #7;|##1.##2!##3!##4!% }% }% \expandafter\CALX_exLd\CALX_exAlist % \end{macrocode} %\begin{lverb} % P <= 8 table macros \CALX_exC: as \CALX_exA, state R1.c;|k. %\end{lverb} % \begin{macrocode} \def\CALX_exMa #1!#2!#3!#4\CALX_LQ#5.#6.#7.% {% \expandafter\edef\csname CALX_exC#5\endcsname##1.##2.##3.##4.##5.% {% \noexpand\expandafter\noexpand\CALX_exhSa\noexpand\the\noexpand\numexpr (((##5-2*##1)*10000-3025*##1)*10000+##2+#1-8509*##1)*100% +(-2994*##1+(##3+#2-456*##1)/10000)/100.% #7;|##1.% }% }% \expandafter\CALX_exLd\CALX_exAlist % \end{macrocode} %\begin{lverb} % zero items +00000000! (k = 0..16) for the P > 16 layout %\end{lverb} % \begin{macrocode} \def\CALX_Ltmp #1.#2% {% \expandafter\def\csname CALX_exgz#1\endcsname{#2}% \ifnum#1<16 \xint_afterfi{\expandafter\CALX_Ltmp\the\numexpr#1+1.% {#2+00000000!}}\fi }% \CALX_Ltmp0.{}% % \end{macrocode} %\begin{lverb} % schedules, P = 33..100 (P17..P32: explicit back end): n = 2m, K = % (n-4)/2; start -C_K (scale 10^8); % levels k = K-1..1 (b = m = n-4-2k, n_k = n-2-2k, C_k = 1/(k+1)!), level 0 % (C_0 = 1, n-1 limbs), e^t level (C = 10^W, n+1 limbs, floor carries); % \CALX_exT

: Y = G e^t 10^-24 (U = G, 6 limbs; T = -e^t, n+1 items) %\end{lverb} % \begin{macrocode} \def\CALX_exgK #1#2{\CALX_tcoef{\ifodd\numexpr#1+1\relax s\else c\fi}% {\ifodd\numexpr#1+1\relax(#1)/2\else(#1+1)/2\fi}{#2}}% % \end{macrocode} %\begin{lverb} % #1 b, #2 m; the following braced n goes directly to \CALX_tcoef. % The coefficient continuation follows n. %\end{lverb} % \begin{macrocode} \def\CALX_exgLv #1.#2.#3.#4.#5#6% {\ifnum#4=\xint_c_i\CALX_Zlevx\CALX_Zv{#1}{#2}{#3}{#5}#6\else \CALX_Zlevx\CALX_Zvn{#1}{#2}{#3}{#5}#6\fi}% \def\CALX_exgSl #1.% {% \ifnum#1>\xint_c_ \expandafter\CALX_exgLv\the\numexpr\CALX_LWa-4-2*#1\expandafter.% \the\numexpr\CALX_LWa-4-2*#1\expandafter.\the\numexpr\CALX_LWa-2-2*#1% \expandafter.% \the\numexpr\ifnum\numexpr#1-\CALX_LWb\relax=\xint_c_ 1\else0\fi.% {\expandafter\CALX_LWrv\expanded{\CALX_exgK{#1}{\CALX_LWa-2-2*#1}% {\CALX_LWa-2-2*#1}\CALX_tq}\relax}\CALX_Zun \expandafter\CALX_exgSl\the\numexpr#1-1.% \else \expandafter\CALX_exgLv\the\numexpr\CALX_LWa-4\expandafter.% \the\numexpr\CALX_LWa-4\expandafter.% \the\numexpr\CALX_LWa-1\expandafter.% \the\numexpr\ifnum\CALX_LWb=\xint_c_ 1\else0\fi.% {1!\expandafter\CALX_LWzr\the\numexpr\CALX_LWa-2.}\CALX_Zun \expandafter\CALX_exgLv\the\numexpr\CALX_LWa-2\expandafter.% \the\numexpr\CALX_LWa-1\expandafter.\the\numexpr\CALX_LWa+1.0.% {1!\expandafter\CALX_LWzr\CALX_LWa.}\CALX_Zuf \noexpand\CALX_exgF \fi }% \def\CALX_exgSt #1!#2!{-#2.\noexpand\CALX_Zn-#1}% \def\CALX_Ltmp #1% {% \edef\CALX_LWa{\the\numexpr2*((#1+3)/8)+2}% n \edef\CALX_LWb{\the\numexpr(\CALX_LWa-4)/2-1}% first level \expandafter\edef\csname CALX_exS#1\endcsname {% {\expandafter\CALX_exgSt\expanded{\CALX_exgK{\CALX_LWb+1}{2}{2}% \CALX_tq}}% {\expandafter\CALX_exgSl\CALX_LWb.}% }% \expandafter\edef\csname CALX_exT#1\endcsname##1##2% {% \noexpand\CALX_Zd##2\noexpand\CALX_Zq {##1\expandafter\CALX_LWzr\the\numexpr\CALX_LWa-6.}% U pad \expandafter\CALX_exgLv\expandafter6\expandafter.\the\numexpr \CALX_LWa+1\expandafter.\the\numexpr\CALX_LWa+1.1.% {\expandafter\CALX_LWzr\the\numexpr\CALX_LWa+1.}\CALX_Zuf \noexpand\CALX_exgY }% \ifnum#1<100 \expandafter\CALX_Ltmp\expandafter{\the\numexpr#1+1\expandafter}\fi }% \CALX_Ltmp{33}% \let\CALX_Ltmp\relax \let\CALX_LWa\relax \let\CALX_LWb\relax % \end{macrocode} % \subsection{\csh{calxFpPowTen}, \csh{calxRawPowTen}} %\begin{lverb} % pow10(x). x rounded as exp (P+14 digits, sliced at the % grid); |x| = 8K + y, K = floor(n/8) (n integer part of |x|), y = d + phi, % d = n mod 8 = (block I0) mod 8; 10^x = 10^(8sK) exp(s y ln10): x' = y ln10 % (< 18.43) on exp's grid by one short product, then exp's fast path and % e <- e + sK (\CALX_exHf / \CALX_exJf -> \CALX_exHz$empty: Overflow, % Underflow). % Integer x (P <= 16 path): 10^(s n) written directly (\CALX_exHy). %\end{lverb} % \begin{macrocode} \def\calxFpPowTen{\romannumeral0\expandafter\CALX_pwa \romannumeral0\CALX_fround{\XINTdigits+14}}% \def\calxRawPowTen #1{\romannumeral0\CALX_ftoraw{\calxFpPowTen{#1}}}% \def\CALX_pwnfl #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpPowTen#3}}% }% \def\CALX_pwnex #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxRawPowTen#3}}% }% \expandafter\let\csname XINT_flexpr_func_pow10\endcsname\CALX_pwnfl \expandafter\let\csname XINT_expr_func_pow10\endcsname\CALX_pwnex \def\CALX_pwa #1#2{\csname CALX_pwt#1#2\endcsname}% \expandafter\let \csname CALX_pwtI+\expandafter\endcsname\csname CALX_extI+\endcsname \expandafter\let \csname CALX_pwtI-\expandafter\endcsname\csname CALX_extI-\endcsname \expandafter\let \csname CALX_pwtI?\expandafter\endcsname\csname CALX_extI?\endcsname \expandafter\def \csname CALX_pwtF+\endcsname{\CALX_exb pw;+}% \expandafter\def \csname CALX_pwtF-\endcsname{\CALX_exb pw;-}% % \end{macrocode} %\begin{lverb} % P <= 16 reader (layout of \CALX_exc): f3, f2, f1, I0, I1, rest, s; % I1 > 21: |x| > 2.2e9, over/underflow; floor(I0/8) = (2 I0 - 7)/16 %\end{lverb} % \begin{macrocode} \def\CALX_pwG 1#1!1#2!1#3!1#4!1#5!% {% \ifnum#5>21 \xint_dothis\CALX_pwG_over\fi \ifnum\numexpr#1+#2+#3\relax=\xint_c_ \xint_dothis\CALX_pwG_int\fi \xint_orthat\CALX_pwG_regular 1#1!1#2!1#3!1#4!1#5!% }% \def\CALX_pwG_over 1#1!1#2!1#3!1#4!1#5!#6\xint:#7{\CALX_exO#7}% \def\CALX_pwG_int 1#1!1#2!1#3!1#4!1#5!#6\xint:#7% {% \expandafter\CALX_pwI\the\numexpr#4-8*((2*#4-7)/16)\expandafter.% \the\numexpr#5*12500000+(2*#4-7)/16.#7% }% \def\CALX_pwG_regular 1#1!1#2!1#3!1#4!1#5!#6\xint:#7% {% \expandafter\CALX_pwP\expanded{\the\numexpr#4-8*((2*#4-7)/16)!% \CALX_pwh#3\CALX_pwh#2\CALX_pwh#1#7\the\numexpr#5*12500000+(2*#4-7)/16.}% }% \let\CALX_pwhG\CALX_pwG \def\CALX_pwh #1#2#3#4#5#6#7#8{#1#2#3#4!#5#6#7#8!}% % \end{macrocode} %\begin{lverb} % d, y1..y6 (stream s K.): x' 10^24 = y 10^24 ln10, columns c0..c6, guard % c7 (ln10 limbs 2|3025|8509|2994|0456|8401|7991|4546; dropped columns < 5 % units 10^-24) -> \CALX_exHf X!l1!..!l6!sK. %\end{lverb} % \begin{macrocode} \def\CALX_pwP #1!#2!#3!#4!#5!#6!#7!% {% \expandafter\CALX_exHf\the\numexpr2*#1\expandafter\CALX_LR \the\numexpr\CALX_Loff+3025*#1+2*#2\expandafter\CALX_LR \the\numexpr\CALX_Loff+8509*#1+3025*#2+2*#3\expandafter\CALX_LR \the\numexpr\CALX_Loff+2994*#1+8509*#2+3025*#3+2*#4\expandafter\CALX_LR \the\numexpr\CALX_Loff+456*#1+2994*#2+8509*#3+3025*#4+2*#5% \expandafter\CALX_LR \the\numexpr\CALX_Loff+8401*#1+456*#2+2994*#3+8509*#4+3025*#5+2*#6% \expandafter\CALX_LR \the\numexpr\CALX_Loff+7991*#1+8401*#2+456*#3+2994*#4+8509*#5+3025*#6% +2*#7\expandafter\CALX_LRz \the\numexpr\CALX_Loff+4546*#1+7991*#2+8401*#3+456*#4+2994*#5+8509*#6% +3025*#7\relax!% }% % \end{macrocode} %\begin{lverb} % integer x = s n, n = 8K + d: 10^(s n) as e.D.block for \CALX_exHy %\end{lverb} % \begin{macrocode} \def\CALX_pwI #1.#2.#3% {% \expandafter\CALX_exHy\expanded{\if-#3% \ifnum#1=\xint_c_ \the\numexpr-#2.1.100000001!% \else\the\numexpr-#2-1.\the\numexpr9-#1.% \the\numexpr100000000+\CALX_pten{8-#1}!\fi \else\the\numexpr#2.\the\numexpr#1+1.\the\numexpr100000000+\CALX_pten{#1}!% \fi}\xint:% }% % \end{macrocode} %\begin{lverb} % P > 16 readers (layout of \CALX_exgc$empty: s, signed items MS first, % \CALX_exQ): p <= 0 (I0 first), p = 1 (I1, I0) %\end{lverb} % \begin{macrocode} \def\CALX_pwgG #1#2#3!{\CALX_pwS#1.00000000.#3.}% \def\CALX_pwJa #1#2#3!#4#5!#6\CALX_exQ#7% {\ifnum#3>21 \xint_dothis{\CALX_exO#1}\fi \xint_orthat{\CALX_pwS#1.#3.#5.#6\CALX_exQ#7}}% \def\CALX_pwS #1.#2.#3.% {% \expandafter\CALX_pwV\the\numexpr#2*12500000+(2*#3-7)/16\expandafter.% \the\numexpr#3-8*((2*#3-7)/16).#1% }% % \end{macrocode} %\begin{lverb} % K.d.s f-items\CALX_exQ$empty: U list (d, limbs of the fraction items), % kernel % level \CALX_pwT

(U = y, T = -ln10, C = 0, floor carries); stream s K. %\end{lverb} % \begin{macrocode} \def\CALX_pwV #1.#2.#3#4\CALX_exQ% {% \csname CALX_pwT\the\numexpr\XINTdigits\expandafter\endcsname\expandafter {\expanded{\expandafter\CALX_Zbt \expanded{#2!\CALX_pwL#4\CALX_exQ}\CALX_Zq!}}% #3#1.% }% \def\CALX_pwL #1{\ifx\CALX_exQ#1\else\expandafter\CALX_pwLs\fi}% \def\CALX_pwLs #1#2#3#4#5#6#7#8!{#1#2#3#4!#5#6#7#8!\CALX_pwL}% % \end{macrocode} %\begin{lverb} % {U}0.\CALX_Zq s K. -> \CALX_exJf 0!0000!0000! %\end{lverb} % \begin{macrocode} \def\CALX_pwF #1#2.#3\CALX_Zq{\expandafter\CALX_exJf\expanded{0!0000!#3}0000!\CALX_LQ}% % \end{macrocode} %\begin{lverb} % load time: \CALX_pwT

#1 (U list), P = 17..100, n = W/4: T = -ln10 on % n+2 limbs (2, 3025, 8509, \CALX_exLx), level b = n+1, m = n+2, n+2 limbs % (the kernel's top output column must be >= b+m-1: top limb 0) %\end{lverb} % \begin{macrocode} \edef\CALX_pwlx{3025!8509!\CALX_exLx}% \def\CALX_pwk #1.#2!{\ifnum#1>\xint_c_ \noexpand\CALX_Zn-#2.\expandafter\CALX_pwk \the\numexpr#1-1\expandafter.\else\expandafter\CALX_pwz\fi}% \def\CALX_pwz #1\relax{}% \def\CALX_Ltmp #1% {% \edef\CALX_LWa{\the\numexpr2*((#1+3)/8)+2}% n \expandafter\edef\csname CALX_pwT#1\endcsname##1% {% \noexpand\CALX_Zd-2.\expandafter\CALX_pwk\the\numexpr\CALX_LWa+1% \expandafter.\CALX_pwlx\relax\noexpand\CALX_Zq{##1}% \expandafter\CALX_exgLv\the\numexpr\CALX_LWa+1\expandafter.\the\numexpr \CALX_LWa+2\expandafter.\the\numexpr\CALX_LWa+2.1.% {\expandafter\CALX_LWzr\the\numexpr\CALX_LWa+2.}\CALX_Zuf \noexpand\CALX_pwF }% \ifnum#1<100 \expandafter\CALX_Ltmp \expandafter{\the\numexpr#1+1\expandafter}\fi }% \CALX_Ltmp{17}% \let\CALX_Ltmp\relax \let\CALX_LWa\relax \let\CALX_pwlx\relax \let\CALX_pwk\relax \let\CALX_pwz\relax % \end{macrocode} % \subsection{\csh{calxFpExpMinusOne}, \csh{calxRawExpMinusOne}} %\begin{lverb} % expm1(x) = exp(x) - 1. x rounded to P digits. E = decimal exponent: % E <= -5: x E1(x), E1 = sum x^k/(k+1)!, log1p's C machinery (kind em); % E >= 3: exp(x) (x > 0) or -1; else exp's front with kind em: readers % \CALX_emG (P <= 16), \CALX_emgG (P > 16): |x| >= T_P = (P+4) ln10 (up): % exp (x > 0) or -1; 0 < x < 0.04: bucket-0 table macro with k = 0; else % exp's normal branch; the writers then call \CALX_emF (marker \CALX_emMk): % N = Y' - 10^(W'-k) exact, ONE rounding. %\end{lverb} % \begin{macrocode} \chardef\CALX_exMk=1 \chardef\CALX_emMk=2 \let\CALX_pwMk\CALX_exMk \chardef\CALX_euMk=3 \chardef\CALX_xuMk=4 % unrounded expm1, exp \def\calxFpExpMinusOne{\romannumeral0\expandafter\CALX_ema \romannumeral0\CALX_fround{\XINTdigits}}% \def\calxRawExpMinusOne #1{\romannumeral0\CALX_ftoraw{\calxFpExpMinusOne{#1}}}% \def\CALX_emnfl #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpExpMinusOne#3}}% }% \def\CALX_emnex #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxRawExpMinusOne#3}}% }% \expandafter\let\csname XINT_flexpr_func_expm1\endcsname\CALX_emnfl \expandafter\let\csname XINT_expr_func_expm1\endcsname\CALX_emnex \def\CALX_ema #1#2{\csname CALX_emt#1#2\endcsname}% \def\CALX_emT{\numexpr(\XINTdigits+4)*23026/10000+1\relax}% T_P \begingroup\catcode`F=12 \expandafter\gdef\csname CALX_emtI+\endcsname#1\xint:{ I+}% \expandafter\gdef\csname CALX_emtI-\endcsname#1\xint:{ F-1.0.100000001!}% \expandafter\gdef\csname CALX_emtI?\endcsname#1\xint:{ I?}% \expandafter\gdef\csname CALX_emtF+\endcsname{\CALX_emb+}% \expandafter\gdef\csname CALX_emtF-\endcsname{\CALX_emb-}% % \end{macrocode} %\begin{lverb} % s D.e.blocks; D + 8e = E + 1 %\end{lverb} % \begin{macrocode} \gdef\CALX_emb #1#2.#3.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_emb_zero\fi \ifnum\numexpr#2+8*#3\relax<-\xint_c_iii \xint_dothis\CALX_emb_small\fi \ifnum\numexpr#2+8*#3\relax>\xint_c_iii \xint_dothis\CALX_emb_large\fi \xint_orthat\CALX_emb_regular #1#2.#3.% }% \gdef\CALX_emb_zero #1#2.#3.#4\xint:{ F+0.0.}% \gdef\CALX_emb_small #1#2.#3.#4\xint:{\CALX_lpC ems;#1#2.#3.#4\xint:}% \gdef\CALX_emb_large #1#2.#3.#4\xint: {\CALX_emL#1{\CALX_exb ex;#1#2.#3.#4\xint:}}% \gdef\CALX_emb_regular #1#2.#3.#4\xint:{\CALX_exb em;#1#2.#3.#4\xint:}% % \end{macrocode} %\begin{lverb} % s{exp's computation}: x > 0: the computation, x < 0: -1 %\end{lverb} % \begin{macrocode} \gdef\CALX_emL #1% {\if-#1\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\CALX_emM}{\xint_firstofone}}% \gdef\CALX_emM #1{ F-1.0.100000001!}% \endgroup % \end{macrocode} %\begin{lverb} % P <= 16 reader (layout of \CALX_exc, |x| < 1000): f3, f2, f1, xI, rest, s %\end{lverb} % \begin{macrocode} \def\CALX_emG 1#1!1#2!1#3!1#4!#5\xint:#6% {% \ifnum#4<\CALX_emT\else \xint_dothis{\CALX_emL#6{\CALX_exG1#1!1#2!1#3!1#4!#5\xint:#6}}\fi \ifnum\numexpr#61*(#4*100+#3/1000000)\relax<4 \xint_dothis{\if-#6\expandafter\CALX_exGn\else\expandafter\CALX_emA\fi #1.#2.#3.#4.#6A\CALX_emMk}\fi \xint_orthat{\CALX_exGn#1.#2.#3.#4.#6A\CALX_emMk}% }% \let\CALX_emhG\CALX_emG % \end{macrocode} %\begin{lverb} % 0 < x < 0.04: bucket 0 (c = 10^4, no constant) with k = 0 %\end{lverb} % \begin{macrocode} \def\CALX_emA #1.#2.#3.#4.#5#6% {\csname CALX_exA0\endcsname 0.#5#3.#5#2.#5#1.#5#4.}% % \end{macrocode} %\begin{lverb} % P > 16 reader (layout of \CALX_exgc): s, s xI, s f1, s f2, rest\CALX_exQ % \CALX_emMk %\end{lverb} % \begin{macrocode} \def\CALX_emgG #1#2!#3!% {% \ifnum#1#2<\CALX_emT\else\xint_dothis\CALX_emgG_large\fi \ifnum\numexpr#2*100+#3/1000000\relax<4 \xint_dothis\CALX_emgG_small\fi \xint_orthat\CALX_emgG_regular #1#2!#3!% }% \def\CALX_emgG_large #1#2!#3!#4!{\CALX_emgL#1#2!#3!#4!}% \def\CALX_emgG_small #1#2!#3!#4!% {% \if-#1\expandafter\CALX_exgG\else\expandafter\CALX_emgA\fi #1#2!#3!#4!% }% \def\CALX_emgG_regular #1#2!#3!#4!{\CALX_exgG#1#2!#3!#4!}% \def\CALX_emgA #1#2!#3!#4!{\csname CALX_exB0\endcsname 0.#2!#3!#4!}% % \end{macrocode} %\begin{lverb} % |x| >= T_P: x > 0 exp (marker of exp's writer), x < 0 -1 %\end{lverb} % \begin{macrocode} \def\CALX_emgL #1#2\CALX_exQ#3{\CALX_emL#1{\CALX_exgG#1#2\CALX_exQ\CALX_exMk}}% \let\CALX_emJa\CALX_emgL % \end{macrocode} %\begin{lverb} % finisher: digits of Y'.k.W'. -> exp x - 1 = round_P(Y' 10^(k-W') - 1), % the subtraction exact (\CALX_fsubx, native 1), ONE rounding %\end{lverb} % \begin{macrocode} \def\CALX_emF #1.#2.#3.{\expandafter\CALX_emZ\the\numexpr#2-#3.#1.}% \def\CALX_emZ #1.#2.#3% {% \ifcase#3\or\or\expandafter\CALX_emZr\or\expandafter\CALX_emZu \else\expandafter\CALX_emZx\fi{#2[#1]}% }% \begingroup\catcode`F=12 \gdef\CALX_emZr #1% {\CALX_fnround\XINTdigits{\CALX_fsubx{\CALX_ffromraw{#1}}{F+1.0.100000001!}}}% \gdef\CALX_emZu #1{\CALX_fsubx{\CALX_ffromraw{#1}}{F+1.0.100000001!}}% \endgroup \def\CALX_emZx{\CALX_ffromraw}% % \end{macrocode} %\begin{lverb} % P17..P32 writers: T!q..!q1! then q0!k. -> digits.k.W. %\end{lverb} % \begin{macrocode} \def\CALX_emXa #1!#2!#3!#4!#5!#6!#7!{\CALX_emXc#1#2#3#4#5#6#7}% \def\CALX_emXb #1!#2!#3!#4!#5!#6!#7!#8!#9!{\CALX_emXc#1#2#3#4#5#6#7#8#9}% \def\CALX_emXc #1!#2.#3{\CALX_emF#1.#2.8*\CALX_exgm.#3}% % \end{macrocode} %\begin{lverb} % series |x| < 10^-4: U = -10^4 x (lists of log1p, sign swapped), schedules % \CALX_emS (log's unity levels, C_k = 1/(k+1)! by \CALX_exgK) %\end{lverb} % \begin{macrocode} \expandafter\let\csname CALX_emU+% \expandafter\endcsname\csname CALX_lpU-\endcsname \expandafter\let\csname CALX_emU-% \expandafter\endcsname\csname CALX_lpU+\endcsname \def\CALX_Ltmp #1% {% \edef\CALX_LWa{\the\numexpr(#1+\ifnum#1>64 6\else5\fi)/4}% \edef\CALX_LWm{\the\numexpr\CALX_LWa-1}% \expandafter\edef\csname CALX_emS#1\endcsname##1% {% \noexpand\CALX_Zd\expandafter\CALX_Zhd\expanded{\CALX_exgK {\CALX_LWa-1}{1}{1}\CALX_tq}\relax.\noexpand\CALX_Zq{##1}% \expandafter\CALX_LWbl\the\numexpr\CALX_LWa-2.% }% \ifnum#1<100 \expandafter\CALX_Ltmp% \expandafter{\the\numexpr#1+1\expandafter}\fi }% \let\CALX_LWco\CALX_exgK \let\CALX_LWfin\empty \CALX_Ltmp{17}% \def\CALX_LWco{\CALX_tcoef{l}}% \let\CALX_Ltmp\relax \let\CALX_LWa\relax \let\CALX_LWm\relax \let\CALX_LWfin\relax \let\CALX_exgK\relax \let\CALX_exgSl\relax \let\CALX_exgSt\relax \let\CALX_exgLv\relax \let\CALX_exMs\relax \let\CALX_exMt\relax \let\CALX_exMa\relax \let\CALX_exLd\relax \let\CALX_Ltmpb\relax % \end{macrocode} % \subsection{\csh{calxFpPow}, \csh{calxRawPow}} %\begin{lverb} % Powers a**b, a^b, pow(a, b) of \xintfloateval. % y = exp(z), z = b' ln a': a' = a rounded to P digits, b' = b rounded to % P + 14 digits (|z| < 5e9 is the only range that matters: |z| rho_b <= % 2.5e-(P+4)); ln a' by the unrounded internal log at P' = P + 2 + g % (log1p's \CALX_lpLP), 10^g >= |z| (bound from the exponents, g <= 10); % z = b' ln a' exact (\CALX_fmulx), then exp's entry (x at P + 14 digits, % one rounding). No special algorithm for integer b: integer b only gives % the sign for a < 0. Specials: IEEE-754 pow table (a = 1 or b = 0: 1). %\end{lverb} % \begin{macrocode} \def\calxFpPow #1#2{\romannumeral0\expandafter\CALX_ppa \romannumeral0\CALX_fround{\XINTdigits+14}{#2}{#1}}% \def\calxRawPow #1#2{\romannumeral0\CALX_ftoraw{\calxFpPow{#1}{#2}}}% \let\XINTinFloatSciPow\calxFpPow \def\XINT_flexpr_func_pow #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpPow#3}}% }% % \end{macrocode} %\begin{lverb} % b'\xint:{a} -> a'\xint:b'\xint:, dispatch on %\end{lverb} % \begin{macrocode} \def\CALX_ppa #1\xint:#2% {\expandafter\CALX_ppb\romannumeral0\CALX_fround{\XINTdigits}{#2}#1\xint:}% \def\CALX_ppb #1#2#3\xint:#4{\csname CALX_ppt#1#2#4\endcsname#3\xint:}% % \end{macrocode} %\begin{lverb} % d = digits of 24 (|E_a| + 1) (|E_a| < 4166666, else 11): % |z| < 10^(E_b + 1) 2.303 (|E_a| + 1) < 10^(E_b + d); g = E_b + d in [0, 10] %\end{lverb} % \begin{macrocode} \def\CALX_ppc #1.#2.% {% \expandafter\CALX_ppd\the\numexpr\XINTdigits+\xint_c_ii+\expandafter\CALX_ppg \the\numexpr#2+\ifnum\ifnum#1<\xint_c_ -\fi#1<4166666 \CALX_ndig{24*(\ifnum#1<\xint_c_ -\fi#1+1)}\else 11\fi.% .% }% \def\CALX_ppg #1.{\ifnum#1<\xint_c_ 0\else\ifnum#1>10 10\else#1\fi\fi}% % \end{macrocode} %\begin{lverb} % P'.b'\xint:+\xint: -> exp(b' ln a') %\end{lverb} % \begin{macrocode} \def\CALX_ppd #1.#2\xint:#3\xint:% {% \expandafter\CALX_exa\romannumeral0\CALX_fround{\XINTdigits+14}% {\CALX_fmulx{#2}{\CALX_lpLP#1.#3\xint:}}% }% \def\CALX_ppz #1% {\if-#1\xint_dothis{\CALX_nsig{DivisionByZero}{0 ** b, b < 0}{+}}\fi \xint_orthat{ F+0.0.}}% % \end{macrocode} %\begin{lverb} % T\xint:b\xint:: T = trunc(b) (\CALX_ti_f), b an % integer iff T = b (\CALX_fcmp); parity from T's block at 10^0 %\end{lverb} % \begin{macrocode} \def\CALX_ppi #1\xint:#2\xint:#3#4#5% {\ifcase\CALX_fcmp{#1}{#2} \xint_afterfi{\CALX_ppj#1\xint:#3#4}% \else\xint_afterfi{#5}\fi}% % \end{macrocode} %\begin{lverb} % |a| ** b, negated (b odd); not an integer: InvalidOperation %\end{lverb} % \begin{macrocode} \def\CALX_ppE{\csname CALX_pptF+F\endcsname}% \def\CALX_ppO #1\xint:#2\xint:% {\expandafter\CALX_fopp_a\romannumeral0\csname CALX_pptF+F\endcsname #1\xint:#2\xint:\xint:}% \def\CALX_ppx #1\xint:#2\xint:% {\CALX_nsig{InvalidOperation}{a ** b, a < 0, b not an integer}{}}% \def\CALX_ppP{ I+}% \def\CALX_ppM{ I-}% % \end{macrocode} %\begin{lverb} % |a| vs 1, b = I+, I-, I? %\end{lverb} % \begin{macrocode} \def\CALX_ppy #1#2#3% {\if ?#1\xint_dothis{ I?}\fi\if#1#2\xint_dothis{ I+}\fi \xint_orthat{ F+0.0.}}% \begingroup\catcode`F=12 \gdef\CALX_ppj F#1#2.#3.#4!% {% \ifnum#3>\xint_c_ \xint_dothis\CALX_ppj_positive\fi \ifodd#4 \xint_dothis\CALX_ppj_odd\fi \xint_orthat\CALX_ppj_regular F#1#2.#3.#4!% }% \gdef\CALX_ppj_positive F#1#2.#3.#4!#5\xint:#6#7{#6}% \gdef\CALX_ppj_odd F#1#2.#3.#4!#5\xint:#6#7{#7}% \gdef\CALX_ppj_regular F#1#2.#3.#4!#5\xint:#6#7{#6}% % \end{macrocode} %\begin{lverb} % a >= 0, b finite: ..\xint:..\xint: %\end{lverb} % \begin{macrocode} \expandafter\gdef\csname CALX_pptF+F\endcsname #1.#2.#3\xint:#4#5.#6.#7\xint:% {% \ifnum#5=\xint_c_ \xint_dothis{ F+1.0.100000001!}\fi \ifnum#1=\xint_c_ \xint_dothis{\CALX_ppz#4}\fi \xint_orthat{\expandafter\CALX_ppc\the\numexpr#1-\xint_c_i+\xint_c_viii*#2% \expandafter.\the\numexpr#5-\xint_c_i+\xint_c_viii*#6.% F#4#5.#6.#7\xint:+#1.#2.#3\xint:}% }% \expandafter\gdef\csname CALX_pptF-F\endcsname #1.#2.#3\xint:#4#5.#6.#7\xint:% {% \ifnum#5=\xint_c_ \xint_dothis{ F+1.0.100000001!}\fi \xint_orthat {\expandafter\CALX_ppi\romannumeral0\CALX_ti_f F#4#5.#6.#7\xint:% \xint:F#4#5.#6.#7\xint:\CALX_ppE\CALX_ppO\CALX_ppx #1.#2.#3\xint:#4#5.#6.#7\xint:}% }% \expandafter\gdef\csname CALX_pptF+I\endcsname #1\xint:#2\xint:% {% \ifcase\CALX_fcmp{F+#1}{\CALX_fonec} \xint_afterfi{ F+1.0.100000001!}% \or\xint_afterfi{\CALX_ppy#2+-}% \else\xint_afterfi{\CALX_ppy#2-+}\fi }% \expandafter\gdef\csname CALX_pptI+F\endcsname\xint:#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_ppt_posinf_zero\fi \if-#1\xint_dothis\CALX_ppt_posinf_negative\fi \xint_orthat\CALX_ppt_posinf_positive #1#2.% }% \gdef\CALX_ppt_posinf_zero #1#2.#3\xint:{ F+1.0.100000001!}% \gdef\CALX_ppt_posinf_negative #1#2.#3\xint:{ F+0.0.}% \gdef\CALX_ppt_posinf_positive #1#2.#3\xint:{ I+}% \expandafter\gdef\csname CALX_pptI-F\endcsname\xint:#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_ppt_neginf_zero\fi \if-#1\xint_dothis\CALX_ppt_neginf_negative\fi \xint_orthat\CALX_ppt_neginf_regular #1#2.% }% \gdef\CALX_ppt_neginf_zero #1#2.#3.#4\xint:{ F+1.0.100000001!}% \gdef\CALX_ppt_neginf_negative #1#2.#3.#4\xint:{ F+0.0.}% \gdef\CALX_ppt_neginf_regular #1#2.#3.#4\xint:% {\expandafter\CALX_ppi\romannumeral0\CALX_ti_f F#1#2.#3.#4\xint:% \xint:F#1#2.#3.#4\xint:\CALX_ppP\CALX_ppM\CALX_ppP}% \expandafter\gdef\csname CALX_pptI?F\endcsname\xint:#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_ppt_nan_zero\fi \xint_orthat\CALX_ppt_nan_regular #1#2.% }% \gdef\CALX_ppt_nan_zero #1#2.#3\xint:{ F+1.0.100000001!}% \gdef\CALX_ppt_nan_regular #1#2.#3\xint:{ I?}% \expandafter\gdef\csname CALX_pptI+I\endcsname\xint:#1\xint:% {\if ?#1\xint_dothis{ I?}\fi\if-#1\xint_dothis{ F+0.0.}\fi \xint_orthat{ I+}}% \expandafter\gdef\csname CALX_pptI?I\endcsname\xint:#1\xint:{ I?}% \endgroup \expandafter\let\csname CALX_pptF-I\expandafter\endcsname \csname CALX_pptF+I\endcsname \expandafter\let\csname CALX_pptI-I\expandafter\endcsname \csname CALX_pptI+I\endcsname % \end{macrocode} %\begin{lverb} % Unrounded exp and expm1 (used by the hyperbolic functions): kinds xu % (exp, |x| < 10^4) and eu (expm1, |x| < 1000) of exp's front; the writers % pass the digits of Y' to \CALX_emF with the marker \CALX_xuMk or % \CALX_euMk, the finisher \CALX_emZ then gives Y' 10^(k-W') or % Y' 10^(k-W') - 1 exactly (no rounding); expm1 |x| < 10^-4: log1p's C % machinery with the output letter u (\CALX_shou: no rounding). %\end{lverb} % \begin{macrocode} \def\CALX_xuG 1#1!1#2!1#3!1#4!#5\xint:#6{\CALX_exGn#1.#2.#3.#4.#6A\CALX_xuMk}% \let\CALX_xuhG\CALX_xuG \let\CALX_xugG\CALX_exgG \let\CALX_xuJa\CALX_exJa \def\CALX_euG 1#1!1#2!1#3!1#4!#5\xint:#6% {% \ifnum#4<\CALX_emT\else \xint_dothis{\CALX_emL#6{\CALX_exG1#1!1#2!1#3!1#4!#5\xint:#6}}\fi \ifnum\numexpr#61*(#4*100+#3/1000000)\relax<4 \xint_dothis{\if-#6\expandafter\CALX_exGn\else\expandafter\CALX_emA\fi #1.#2.#3.#4.#6A\CALX_euMk}\fi \xint_orthat{\CALX_exGn#1.#2.#3.#4.#6A\CALX_euMk}% }% \let\CALX_euhG\CALX_euG \let\CALX_eugG\CALX_emgG \let\CALX_euJa\CALX_emJa \def\CALX_shou #1{\expandafter\space\romannumeral`&&@#1}% \begingroup\catcode`F=12 \gdef\CALX_hyX #1{\expandafter\CALX_hyXa\romannumeral`&&@#1\xint:}% \gdef\CALX_hyXa F#1#2.#3.#4\xint:{\CALX_exb xu;#1#2.#3.#4\xint:}% \gdef\CALX_hyU #1{\expandafter\CALX_hyUa\romannumeral`&&@#1\xint:}% \gdef\CALX_hyUa F#1#2.#3.% {% \ifnum\numexpr#2+\xint_c_viii*#3<-\xint_c_iii \xint_dothis\CALX_hyUa_small\fi \xint_orthat\CALX_hyUa_regular F#1#2.#3.% }% \gdef\CALX_hyUa_small F#1#2.#3.#4\xint:{\CALX_lpC emu;#1#2.#3.#4\xint:}% \gdef\CALX_hyUa_regular F#1#2.#3.#4\xint:{\CALX_exb eu;#1#2.#3.#4\xint:}% \endgroup \def\CALX_hyln{\CALX_lpLP\XINTdigits+\xint_c_viii.+1.0.100000002!\xint:}% % \end{macrocode} % \subsection{\csh{calxFpSinh}, \csh{calxFpCosh}, \csh{calxFpTanh}, % \csh{calxFpCoth}, \csh{calxFpSech}, \csh{calxFpCsch}, \csh{calxFpAsinh}, % \csh{calxFpAcosh}, \csh{calxFpAtanh}, \csh{calxFpAcoth}, % \csh{calxFpAsech}, \csh{calxFpAcsch}} %\begin{lverb} % Hyperbolic functions and their inverses (and the \calxRaw... variants, % expression functions sinh, cosh, ...), composed from exp, expm1, log1p, % the internal log and calxfp arithmetic at Q = P + 4 digits, with one final % rounding; formulas chosen to avoid cancellation. x is rounded to P digits, % a = |x|, E its decimal exponent, u = expm1(x), w = expm1(-x): %( %: sinh E < 0: (u - w)/2; E <= 2: (e^x - e^-x)/2; else sign e^(a-ln2) %: cosh (e^x + e^-x)/2; E > 2: e^(a-ln2) %: tanh (u - w)/(u + w + 2); E > 2: sign 1; coth the inverse ratio %: sech 2/(e^x + e^-x); csch 2/(u - w) or 2/(e^x - e^-x); E > 2: e^(ln2-a) %: asinh sign log1p(a + a^2/(1 + sqrt(1 + a^2))); E >= Q: log1p(2a) %: acosh log1p(t + sqrt(t(t+2))), t = x - 1; E >= Q: log1p(2x) %: atanh sign log1p(q/(1 + sqrt(1 + q))), q = 2a/(1 - a) %: acoth the same with q = 2/(a - 1) %: asech acosh(1/x) with t = (1 - x)/x; E < -Q/2: log1p((2 - x)/x) %: acsch asinh(1/a) with sign; E >= Q/2: 1/x; E < -Q/2: log1p((2-a)/a) %) % asinh, atanh: E < -Q/2 gives x. log1p is applied to its Q-digit % argument without rounding it to P digits (its three paths accept it). % Entry \CALX_hyd -> \csname CALX_hy % with Q. in front (Q = P + 4, P < 8 counts as 8); codes S C T K E H % (sinh .. csch), s c t k e h (asinh .. % acsch); the F macros of both signs come from the template \CALX_hyT. %\end{lverb} % \begin{macrocode} \edef\CALX_hytwo{\romannumeral0\CALX_ffromraw{2[0]}}% \edef\CALX_hyup{\romannumeral0\CALX_ffromraw{1[0]}}% \edef\CALX_hyum{\romannumeral0\CALX_ffromraw{-1[0]}}% \edef\CALX_hyzero{\romannumeral0\CALX_ffromraw{0[0]}}% \expandafter\let\csname CALX_hyu+\endcsname\CALX_hyup \expandafter\let\csname CALX_hyu-\endcsname\CALX_hyum \def\CALX_hyd #1#2#3% {\expandafter\CALX_hye\the\numexpr\ifnum\XINTdigits<\xint_c_viii \xint_c_viii\else\XINTdigits\fi+\xint_c_iv.#1#2#3}% \def\CALX_hye #1.#2#3#4% {\csname CALX_hy#2\ifnum\XINTdigits<9 w\fi#3#4\endcsname#1.#3#4}% % \end{macrocode} %\begin{lverb} % Infinities and NaN: \CALX_hyIp (the input), \CALX_hyIa (I+), \CALX_hyIo % (sign 1), \CALX_hyIz (0), \CALX_hyIn (InvalidOperation). %\end{lverb} % \begin{macrocode} \def\CALX_hyIp #1.#2#3\xint:{ #2#3}% \def\CALX_hyIa #1.#2#3\xint:{ #2+}% \def\CALX_hyIo #1.#2#3\xint:% {\expandafter\expandafter\expandafter\space\csname CALX_hyu#3\endcsname}% \def\CALX_hyIz #1\xint:{\expandafter\space\CALX_hyzero}% \def\CALX_hyIn #1\xint:% {\CALX_nsig{InvalidOperation}{inverse hyperbolic function of inf}{}}% \def\CALX_hyIs #1#2#3% {% \expandafter\let\csname CALX_hy#1I+\endcsname#2% \expandafter\let\csname CALX_hy#1I-\endcsname#3% \expandafter\let\csname CALX_hy#1I?\endcsname\CALX_hyIp \expandafter\let\csname CALX_hy#1wI+\endcsname#2% \expandafter\let\csname CALX_hy#1wI-\endcsname#3% \expandafter\let\csname CALX_hy#1wI?\endcsname\CALX_hyIp }% \CALX_hyIs S\CALX_hyIp\CALX_hyIp \CALX_hyIs C\CALX_hyIa\CALX_hyIa \CALX_hyIs T\CALX_hyIo\CALX_hyIo \CALX_hyIs K\CALX_hyIo\CALX_hyIo \CALX_hyIs E\CALX_hyIz\CALX_hyIz \CALX_hyIs H\CALX_hyIz\CALX_hyIz \CALX_hyIs s\CALX_hyIp\CALX_hyIp \CALX_hyIs c\CALX_hyIp\CALX_hyIn \CALX_hyIs t\CALX_hyIn\CALX_hyIn \CALX_hyIs k\CALX_hyIz\CALX_hyIz \CALX_hyIs e\CALX_hyIn\CALX_hyIn \CALX_hyIs h\CALX_hyIz\CALX_hyIz % \end{macrocode} %\begin{lverb} % Helpers (e^x, u, w: unrounded \CALX_hyX, \CALX_hyU; ln 2 \CALX_hyln at % P + 8). \CALX_hyNp, \CALX_hyNm: sign. \CALX_hyP{x1}{x2}: % f(x2)\xint:f(x1)\xint:. \CALX_hyLp{w}: log1p(w) (w >= 0.1: the % internal log at Q of round_Q(1 + w)); \CALX_hyLm{w}: -log1p(w). % \CALX_hyS{b}{Q}: of % b + b^2/(1 + sqrt(1 + b^2)). \CALX_hyq q\xint:Q.: of % q/(1 + sqrt(1 + q)). \CALX_hyW{t}{Q}: t + sqrt(t(t+2)). %\end{lverb} % \begin{macrocode} \let\CALX_hyNp\xint_firstofone \def\CALX_hyNm #1{\expandafter\CALX_fopp_a\romannumeral0#1\xint:}% \def\CALX_hyP #1#2#3#4% {\expandafter\CALX_hyPa\romannumeral0#1{#2}\xint:#1{#3}#4}% \def\CALX_hyPa #1\xint:#2#3#4% {\expandafter#4\romannumeral0#2{#3}\xint:#1\xint:}% \def\CALX_hyLp #1{\expandafter\CALX_hyLa\romannumeral`&&@#1\xint:}% \def\CALX_hyLa #1#2#3.#4.% {% \ifnum\numexpr#3+\xint_c_viii*#4>-\xint_c_i \xint_dothis\CALX_hyLa_large\fi \xint_orthat\CALX_hyLa_regular #1#2#3.#4.% }% \def\CALX_hyLa_large #1#2#3.#4.#5\xint:% {\expandafter\CALX_hyLc \the\numexpr\XINTdigits+\xint_c_iv.#1#2#3.#4.#5\xint:}% \def\CALX_hyLa_regular #1#2#3.#4.#5\xint:{\CALX_lpa#1#2#3.#4.#5\xint:}% \def\CALX_hyLc #1.#2\xint:% {\CALX_fnround{\XINTdigits}{\expandafter\CALX_hyLd \romannumeral0\CALX_fadd{#1}{\CALX_hyup}{#2}\xint:#1.}}% \begingroup\catcode`F=12 \gdef\CALX_hyLd F#1\xint:#2.{\CALX_lpLP#2.#1\xint:}% \endgroup \def\CALX_hyLm #1% {\expandafter\CALX_fopp_a\romannumeral0\CALX_hyLp{#1}\xint:}% \def\CALX_hyS #1#2% {\expandafter\CALX_hySa\romannumeral0\CALX_fmul{#2}{#1}{#1}\xint:% {#1}{#2}}% \def\CALX_hySa #1\xint:#2#3#4% {% #4{\CALX_fadd{#3}{#2}{\CALX_fdiv{#3}{#1}{\CALX_fadd{#3}{\CALX_fonec}% {\CALX_fsqrt{#3}{\CALX_fadd{#3}{\CALX_fonec}{#1}}}}}}% }% \def\CALX_hyb #1\xint:#2.{\CALX_hyS{#1}{#2}}% \def\CALX_hyq #1\xint:#2.#3% {% #3{\CALX_fdiv{#2}{#1}{\CALX_fadd{#2}{\CALX_fonec}{\CALX_fsqrt{#2}% {\CALX_fadd{#2}{\CALX_fonec}{#1}}}}}% }% \def\CALX_hyW #1#2% {\CALX_fadd{#2}{#1}{\CALX_fsqrt{#2}{\CALX_fmul{#2}{#1}% {\CALX_faddx{#1}{\CALX_hytwo}}}}}% % \end{macrocode} %\begin{lverb} % Final ratios: w\xint:u\xint:Q. (tanh, coth, csch), e^-x\xint:e^x\xint:Q. % (sech, csch). %\end{lverb} % \begin{macrocode} \def\CALX_hyTt #1\xint:#2\xint:#3.% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_fsubx{#2}{#1}}% {\CALX_faddx{\CALX_faddx{#2}{#1}}{\CALX_hytwo}}}}% \def\CALX_hyKt #1\xint:#2\xint:#3.% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}% {\CALX_faddx{\CALX_faddx{#2}{#1}}{\CALX_hytwo}}{\CALX_fsubx{#2}{#1}}}}% \def\CALX_hyEt #1\xint:#2\xint:#3.% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_hytwo}% {\CALX_faddx{#2}{#1}}}}% \def\CALX_hyHt #1\xint:#2\xint:#3.% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_hytwo}% {\CALX_fsubx{#2}{#1}}}}% % \end{macrocode} %\begin{lverb} % \CALX_hyT: the F macros. % Parameters: Q.FD.e.blocks\xint:, v = D + 8e = E + 1. %\end{lverb} % \begin{macrocode} \def\CALX_hyT #1#2#3#4#5% {% \expandafter\def\csname CALX_hySF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hySF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\xint_c_iii \xint_dothis{\csname CALX_hySF#1b\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_i \xint_dothis{\csname CALX_hySF#1c\endcsname}\fi \xint_orthat{\csname CALX_hySF#1d\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hySF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hySF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% #5{\calxFpExp{\CALX_fsubx{##2+##4.##5.##6}% {\CALX_hyln}}}% }% \expandafter\def\csname CALX_hySF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_fnround{\XINTdigits}{\CALX_fhalf{\CALX_fsubx {\CALX_hyU{##2#1##4.##5.##6}}{\CALX_hyU{##2#2##4.##5.##6}}}}% }% \expandafter\def\csname CALX_hySF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_fnround{\XINTdigits}{\CALX_fhalf{\CALX_fsubx {\CALX_hyX{##2#1##4.##5.##6}}{\CALX_hyX{##2#2##4.##5.##6}}}}% }% \expandafter\def\csname CALX_hyCF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyCF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\xint_c_iii \xint_dothis{\csname CALX_hyCF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyCF#1c\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyCF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space\CALX_hyup% }% \expandafter\def\csname CALX_hyCF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \calxFpExp{\CALX_fsubx{##2+##4.##5.##6}{\CALX_hyln}}% }% \expandafter\def\csname CALX_hyCF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_fnround{\XINTdigits}{\CALX_fhalf{\CALX_faddx {\CALX_hyX{##2#1##4.##5.##6}}{\CALX_hyX{##2#2##4.##5.##6}}}}% }% \expandafter\def\csname CALX_hyTF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyTF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\xint_c_iii \xint_dothis{\csname CALX_hyTF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyTF#1c\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyTF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hyTF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space#3% }% \expandafter\def\csname CALX_hyTF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_hyP\CALX_hyU{##2#1##4.##5.##6}% {##2#2##4.##5.##6}\CALX_hyTt##1.% }% \expandafter\def\csname CALX_hyKF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyKF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\xint_c_iii \xint_dothis{\csname CALX_hyKF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyKF#1c\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyKF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_nsig{DivisionByZero}{coth(0)}{+}% }% \expandafter\def\csname CALX_hyKF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space#3% }% \expandafter\def\csname CALX_hyKF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_hyP\CALX_hyU{##2#1##4.##5.##6}% {##2#2##4.##5.##6}\CALX_hyKt##1.% }% \expandafter\def\csname CALX_hyEF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyEF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\xint_c_iii \xint_dothis{\csname CALX_hyEF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyEF#1c\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyEF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space\CALX_hyup% }% \expandafter\def\csname CALX_hyEF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \calxFpExp{\CALX_fsubx{\CALX_hyln}{##2+##4.##5.##6}}% }% \expandafter\def\csname CALX_hyEF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_hyP\CALX_hyX{##2#1##4.##5.##6}% {##2#2##4.##5.##6}\CALX_hyEt##1.% }% \expandafter\def\csname CALX_hyHF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyHF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\xint_c_iii \xint_dothis{\csname CALX_hyHF#1b\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_i \xint_dothis{\csname CALX_hyHF#1c\endcsname}\fi \xint_orthat{\csname CALX_hyHF#1d\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyHF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_nsig{DivisionByZero}{csch(0)}{+}% }% \expandafter\def\csname CALX_hyHF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% #5{\calxFpExp{\CALX_fsubx{\CALX_hyln}% {##2+##4.##5.##6}}}% }% \expandafter\def\csname CALX_hyHF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_hyP\CALX_hyU{##2#1##4.##5.##6}% {##2#2##4.##5.##6}\CALX_hyHt##1.% }% \expandafter\def\csname CALX_hyHF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_hyP\CALX_hyX{##2#1##4.##5.##6}% {##2#2##4.##5.##6}\CALX_hyHt##1.% }% \expandafter\def\csname CALX_hysF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hysF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\numexpr\xint_c_i-##1/\xint_c_ii\relax \xint_dothis{\csname CALX_hysF#1b\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>##1 \xint_dothis{\csname CALX_hysF#1c\endcsname}\fi \xint_orthat{\csname CALX_hysF#1d\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hysF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hysF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2#1##4.##5.##6% }% \expandafter\def\csname CALX_hysF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% #4{\CALX_faddx{##2+##4.##5.##6}{##2+##4.##5.##6}}% }% \expandafter\def\csname CALX_hysF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_hyS{##2+##4.##5.##6}{##1}#4% }% \expandafter\def\csname CALX_hytF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hytF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\numexpr\xint_c_i-##1/\xint_c_ii\relax \xint_dothis{\csname CALX_hytF#1b\endcsname}\fi \xint_orthat{\csname CALX_hytF#1c\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hytF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hytF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2#1##4.##5.##6% }% \expandafter\def\csname CALX_hytF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hyta\romannumeral0\CALX_fsub{##1}% {\CALX_hyup}{##2+##4.##5.##6}\xint:{##2+##4.##5.##6}##1.#4#1% }% \expandafter\def\csname CALX_hykF#1\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hyka\romannumeral0\CALX_fsub{##1}% {##2+##4.##5.##6}{\CALX_hyup}\xint:##1.#4#1% }% \expandafter\def\csname CALX_hyhF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyhF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5>\numexpr##1/\xint_c_ii\relax \xint_dothis{\csname CALX_hyhF#1b\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\numexpr\xint_c_i-##1/\xint_c_ii\relax \xint_dothis{\csname CALX_hyhF#1c\endcsname}\fi \xint_orthat{\csname CALX_hyhF#1d\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyhF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_nsig{DivisionByZero}{acsch(0)}{+}% }% \expandafter\def\csname CALX_hyhF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_fdiv{\XINTdigits}{\CALX_hyup}% {##2#1##4.##5.##6}% }% \expandafter\def\csname CALX_hyhF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% #4{\CALX_fdiv{##1}{\CALX_fsub{##1}{\CALX_hytwo}% {##2+##4.##5.##6}}{##2+##4.##5.##6}}% }% \expandafter\def\csname CALX_hyhF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hyb\romannumeral0\CALX_fdiv{##1}% {\CALX_hyup}{##2+##4.##5.##6}\xint:##1.#4% }% }% \CALX_hyT+-\CALX_hyup\CALX_hyLp\CALX_hyNp \CALX_hyT-+\CALX_hyum\CALX_hyLm\CALX_hyNm % \end{macrocode} %\begin{lverb} % atanh, acoth: d = 1 - a, a - 1 (at Q digits, exact near |x| = 1); % \CALX_hyta d\xint:{a}Q., \CALX_hyka d\xint:Q.. %\end{lverb} % \begin{macrocode} \def\CALX_hyta #1#2#3.#4.#5\xint:#6#7.#8#9% {% \if-#2\xint_dothis {\CALX_nsig{InvalidOperation}{atanh(x), |x| > 1}{}}\fi \ifnum#3=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{atanh(+-1)}{#9}}\fi \xint_orthat{\expandafter\CALX_hyq\romannumeral0\CALX_fdiv{#7}% {\CALX_faddx{#6}{#6}}{#1#2#3.#4.#5}\xint:#7.#8}% }% \def\CALX_hyka #1#2#3.#4.#5\xint:#6.#7#8% {% \if-#2\xint_dothis {\CALX_nsig{InvalidOperation}{acoth(x), |x| < 1}{}}\fi \ifnum#3=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{acoth(+-1)}{#8}}\fi \xint_orthat{\expandafter\CALX_hyq\romannumeral0\CALX_fdiv{#6}% {\CALX_hytwo}{#1#2#3.#4.#5}\xint:#6.#7}% }% % \end{macrocode} %\begin{lverb} % acosh (x >= 1) and asech (0 < x <= 1): t = x - 1, t = (1 - x)/x. %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_hycF+\endcsname #1.#2#3#4.#5.#6\xint:% {% \ifnum\numexpr#4+\xint_c_viii*#5>#1 \xint_dothis{\CALX_hyLp{\CALX_faddx{#2+#4.#5.#6}{#2+#4.#5.#6}}}\fi \xint_orthat{\expandafter\CALX_hyca\romannumeral0\CALX_fsub{#1}% {#2+#4.#5.#6}{\CALX_hyup}\xint:#1.}% }% \expandafter\def\csname CALX_hycF-\endcsname #1\xint:% {\CALX_nsig{InvalidOperation}{acosh(x), x < 1}{}}% \def\CALX_hyca #1#2#3.#4.#5\xint:#6.% {% \if-#2\xint_dothis{\CALX_nsig{InvalidOperation}{acosh(x), x < 1}{}}\fi \ifnum#3=\xint_c_ \xint_dothis{ #1+0.0.}\fi \xint_orthat{\CALX_hyLp{\CALX_hyW{#1#2#3.#4.#5}{#6}}}% }% \expandafter\def\csname CALX_hyeF+\endcsname #1.#2#3#4.#5.#6\xint:% {% \ifnum#4=\xint_c_ \xint_dothis{\CALX_nsig{DivisionByZero}{asech(0)}{+}}\fi \ifnum\numexpr#4+\xint_c_viii*#5<\numexpr\xint_c_i-#1/\xint_c_ii\relax \xint_dothis{\CALX_hyLp{\CALX_fdiv{#1}{\CALX_fsub{#1}{\CALX_hytwo}% {#2+#4.#5.#6}}{#2+#4.#5.#6}}}\fi \xint_orthat{\expandafter\CALX_hyea\romannumeral0\CALX_fsub{#1}% {\CALX_hyup}{#2+#4.#5.#6}\xint:{#2+#4.#5.#6}#1.}% }% \expandafter\def\csname CALX_hyeF-\endcsname #1\xint:% {\CALX_nsig{InvalidOperation}{asech(x), x < 0}{}}% \def\CALX_hyea #1#2#3.#4.#5\xint:#6#7.% {% \if-#2\xint_dothis{\CALX_nsig{InvalidOperation}{asech(x), x > 1}{}}\fi \ifnum#3=\xint_c_ \xint_dothis{ #1+0.0.}\fi \xint_orthat{\expandafter\CALX_hyeb\romannumeral0\CALX_fdiv{#7}% {#1#2#3.#4.#5}{#6}\xint:#7.}% }% \def\CALX_hyeb #1\xint:#2.{\CALX_hyLp{\CALX_hyW{#1}{#2}}}% % \end{macrocode} %\begin{lverb} % P <= 8 (codes w, \CALX_hye adds w). x = X8 10^(E-7), X8 the 8 leading % digits (\CALX_hzx: one or two blocks, D <= P + 7); u = x^2 at scale 2e9: % U2 (\CALX_hzU, abs. error <= 0.5 unit). % Results built as V = |y| 10^-z (V >= 10^9, error a few units: 0.05 ulp is % >= 5 units) and written by \CALX_hyv + \CALX_hywb (log P <= 8 writer % \CALX_lgUw), or as a factor F = 1 +- t (two-part native, \CALX_hynb) and % one product/quotient at Q digits. %( %: |x| < 1 sinh x(1 + u A), A = 1/6 + u A' (A' at 2e11); %: cosh 1 + u/2 + u^2 B' (B' at 4e10); csch (1/x)(1 - (S-1)/S) %: |x| < 0.5 tanh x(1 - Delta), Delta = uK/C, K = 1/3 + u K' (K' at 5e10); %: coth (1/x)(1 + Delta/(1 - Delta)); sech 1 - Cm/(1 + Cm) %: |x| < 1000 otherwise: one call of the P <= 8 exp kernel (kind xw, %: marker \CALX_xwMk: e^a native from Z' = H' 10^6 + L'', relative %: error < 2.2e-10), then Q-digit operations on E = e^a, E^2 %: asinh, atanh |x| < 0.1: x(1 - u Ka), x(1 + u Kc) (series to u^4) %) % Other inputs, and acosh, acoth, asech, acsch: the general code. %\end{lverb} % \begin{macrocode} \def\CALX_hzx #1.1#2!#3\relax {\ifx\relax#3\relax#2*\CALX_pten{8-#1}\else\CALX_hzy#1.#2.#3\fi}% \def\CALX_hzy #1.#2.1#3!{#3*\CALX_pten{16-#1}+#2/\CALX_pten{#1-8}}% \def\CALX_hzU #1.#2.% {\ifnum#2>-3 #1*#1/(5*\CALX_pten{4-2*#2})\else #1*#1/500000000/\CALX_pten{-2*#2-4}\fi}% \def\CALX_hzAp #1{(1666666667+#1*(39682540+#1*(551146+#1*(5010% +#1*32/2000000000)/2000000000)/2000000000)/2000000000)}% \def\CALX_hzBp #1{(1666666667+#1*(55555556+#1*(992063+#1*(11023% +#1*84/2000000000)/2000000000)/2000000000)/2000000000)}% \def\CALX_hzKp #1{(1666666667+#1*(59523810+#1*(1102293+#1*(12526% +#1*96/2000000000)/2000000000)/2000000000)/2000000000)}% \def\CALX_hzKb #1{(1500000000-#1*(892857143-#1*607638889/2000000000)% /2000000000)}% \def\CALX_hzKc #1{(2000000000+#1*(1428571429+#1*1111111111/2000000000)% /2000000000)}% % \end{macrocode} %\begin{lverb} % \CALX_hyvR.H.: H 10^8 + R normalized (-10^8 < R < 2.09e9) -> % H'.1<8 digits>. ; \CALX_hywb: the writer (stream: sign z.), % \CALX_hynb: the native (stream: z.). %\end{lverb} % \begin{macrocode} \def\CALX_hyv #1#2.#3.% {\expandafter\CALX_hyva\the\numexpr(#2+50000000)/100000000-1.#3.#2.#1}% \def\CALX_hyva #1.#2.#3.#4% {\expandafter#4\the\numexpr#2+#1\expandafter.% \the\numexpr100000000+#3-100000000*#1.}% \def\CALX_hywb #1.1#2.{\CALX_lgUw#1!!#2!!}% \def\CALX_hynb #1.1#2.#3.{\CALX_ffromraw{#1#2[#3]}}% % \end{macrocode} %\begin{lverb} % series: \CALX_hzS X8.E. (sinh), \CALX_hzC U2. (cosh), % \CALX_hzE U2. (sech), \CALX_hzT U2..Q. (tanh, coth: = % \CALX_hzTt, \CALX_hzKt), \CALX_hzH U2..Q. (csch), \CALX_hzs, \CALX_hzt % (asinh, atanh: X8.E.) %\end{lverb} % \begin{macrocode} \def\CALX_hzS #1.#2.#3% {% \expandafter\CALX_hzSa\the\numexpr\CALX_hzU#1.#2.\relax.#1.#2.#3% }% \def\CALX_hzSa #1.#2.#3.#4% {% \expandafter\CALX_hzSb\the\numexpr#1*5/6% +#1*(#1*\CALX_hzAp{#1}/2000000000)/2000000000/20% \expandafter.\the\numexpr(#2-500000)/1000000\expandafter.% \the\numexpr#3-9.#2.#4% }% \def\CALX_hzSb #1.#2.#3.#4.#5% {% \expandafter\CALX_hyv\expandafter\CALX_hywb \the\numexpr100*(#4-1000000*#2)+#4*#1/100000000.#2.#5#3.% }% \def\CALX_hzC #1.% {% \expandafter\CALX_hyv\expandafter\CALX_hywb \the\numexpr#1/4+#1*(#1*\CALX_hzBp{#1}/2000000000)/2000000000/40.10.+-9.% }% \def\CALX_hzCm #1{#1*5/2+#1*(#1*\CALX_hzBp{#1}/2000000000)/2000000000/4}% \def\CALX_hzE #1.% {% \expandafter\CALX_hzEa\the\numexpr\CALX_hzCm{#1}.% }% \def\CALX_hzEa #1.% {% \expandafter\CALX_hyv\expandafter\CALX_hywb \the\numexpr2000000000-#1*1000000000/(1000000000+#1/10).80.+-10.% }% \def\CALX_hzT #1.% {% \expandafter\CALX_hzTa\the\numexpr\CALX_hzCm{#1}\expandafter.% \the\numexpr#1*5/3+#1*(#1*\CALX_hzKp{#1}/2000000000)/2000000000/5.% }% \def\CALX_hzTa #1.#2.% {% \expandafter\CALX_hzTb\the\numexpr#2-#2*#1/(1000000000+#1/10)/10.% }% \def\CALX_hzTb #1.#2#3.#4{#4#1.{#2}#3.}% \def\CALX_hzTt #1.#2#3.% {% \CALX_fnround{\XINTdigits}{\CALX_fmul{#3}{#2}% {\expandafter\CALX_hyv\expandafter\CALX_hynb \the\numexpr1000000000-#1.90.-10.}}% }% \def\CALX_hzKt #1.#2#3.% {% \CALX_fnround{\XINTdigits}{\CALX_fmul{#3}{\CALX_fdiv{#3}{\CALX_hyup}{#2}}% {\expandafter\CALX_hyv\expandafter\CALX_hynb\the\numexpr #1*1000000000/(1000000000-#1/10).100.-10.}}% }% \def\CALX_hzH #1.% {% \expandafter\CALX_hzHa\the\numexpr#1*5/6% +#1*(#1*\CALX_hzAp{#1}/2000000000)/2000000000/20.% }% \def\CALX_hzHa #1.#2#3.% {% \CALX_fnround{\XINTdigits}{\CALX_fmul{#3}{\CALX_fdiv{#3}{\CALX_hyup}{#2}}% {\expandafter\CALX_hyv\expandafter\CALX_hynb\the\numexpr 2000000000-#1*1000000000/(1000000000+#1/10).80.-10.}}% }% \def\CALX_hzs #1.#2.#3% {% \expandafter\CALX_hzsa\the\numexpr\CALX_hzU#1.#2.\relax.#1.#2.#3% }% \def\CALX_hzsa #1.#2.#3.#4% {% \expandafter\CALX_hzsb\the\numexpr#1*5/6% -#1*(#1*\CALX_hzKb{#1}/2000000000)/2000000000/2% \expandafter.\the\numexpr(#2-50000)/100000\expandafter.% \the\numexpr#3-10.#2.#4% }% \def\CALX_hzsb #1.#2.#3.#4.#5% {% \expandafter\CALX_hyv\expandafter\CALX_hywb \the\numexpr1000*(#4-100000*#2)+1000000000-#4*#1/10000000\expandafter.% \the\numexpr#2-10.#5#3.% }% \def\CALX_hzt #1.#2.#3% {% \expandafter\CALX_hzta\the\numexpr\CALX_hzU#1.#2.\relax.#1.#2.#3% }% \def\CALX_hzta #1.#2.#3.#4% {% \expandafter\CALX_hzSb\the\numexpr#1*5/3% +#1*(#1*\CALX_hzKc{#1}/2000000000)/2000000000% \expandafter.\the\numexpr(#2-500000)/1000000\expandafter.% \the\numexpr#3-9.#2.#4% }% % \end{macrocode} %\begin{lverb} % exp kernel P <= 8, kind xw: \CALX_xwMk H'.L''.k. -> E\xint: % (E = e^a native); continuations Q.: \CALX_hzXS (sinh, cosh: % ), \CALX_hzXT (tanh, coth, sech, csch: = 10^8>); E >= 10^8: E^-1 negligible. %\end{lverb} % \begin{macrocode} \def\CALX_xwhG 1#1!1#2!1#3!1#4!#5\xint:#6% {\CALX_exGn#1.#2.#3.#4.#6C\CALX_xwMk}% \def\CALX_xwMk #1.#2.#3.% {\expandafter\CALX_xwMa\the\numexpr#3-12\expandafter.% \the\numexpr1000000+#2.#1.}% \def\CALX_xwMa #1.1#2.#3.#4% {\expandafter#4\romannumeral0\CALX_ffromraw{#3#2[#1]}\xint:}% \begingroup\catcode`F=12 \gdef\CALX_hzXS F#1#2.#3.% {% \ifnum\numexpr#2+\xint_c_viii*#3>\xint_c_viii \xint_dothis\CALX_hzXS_large\fi \xint_orthat\CALX_hzXS_regular F#1#2.#3.% }% \gdef\CALX_hzXS_large F#1#2.#3.#4\xint:#5.#6#7% {#7{\CALX_fnround{\XINTdigits}{\CALX_fhalf{F#1#2.#3.#4}}}}% \gdef\CALX_hzXS_regular F#1#2.#3.#4\xint:#5.#6#7% {#7{\CALX_fnround{\XINTdigits}{\CALX_fhalf{#6{F#1#2.#3.#4}% {\CALX_fdiv{#5}{\CALX_hyup}{F#1#2.#3.#4}}}}}}% \gdef\CALX_hzXT F#1#2.#3.% {% \ifnum\numexpr#2+\xint_c_viii*#3>\xint_c_viii \xint_dothis\CALX_hzXT_large\fi \xint_orthat\CALX_hzXT_regular F#1#2.#3.% }% \gdef\CALX_hzXT_large F#1#2.#3.#4\xint:#5.#6#7#8% {#7{F#1#2.#3.#4}#8}% \gdef\CALX_hzXT_regular F#1#2.#3.#4\xint:#5.#6#7#8% {\expandafter#6\romannumeral0\CALX_fmul{#5}{F#1#2.#3.#4}% {F#1#2.#3.#4}\xint:{F#1#2.#3.#4}#5.#8}% \endgroup % \end{macrocode} %\begin{lverb} % finals: normal \xint:{E}Q. (c = sign 1 or 2), E >= 10^8: {E} %\end{lverb} % \begin{macrocode} \def\CALX_hzXTa #1\xint:#2#3.#4% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_fmulx{#4}% {\CALX_fsubx{#1}{\CALX_hyup}}}{\CALX_faddx{#1}{\CALX_hyup}}}}% \def\CALX_hzXKa #1\xint:#2#3.#4% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_fmulx{#4}% {\CALX_faddx{#1}{\CALX_hyup}}}{\CALX_fsubx{#1}{\CALX_hyup}}}}% \def\CALX_hzXTb #1{\expandafter\space}% \def\CALX_hzXEa #1\xint:#2#3.#4% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_fmulx{#4}{#2}}% {\CALX_faddx{#1}{\CALX_hyup}}}}% \def\CALX_hzXHa #1\xint:#2#3.#4% {\CALX_fnround{\XINTdigits}{\CALX_fdiv{#3}{\CALX_fmulx{#4}{#2}}% {\CALX_fsubx{#1}{\CALX_hyup}}}}% \def\CALX_hzXEb #1#2{\CALX_fnround{\XINTdigits}{\CALX_fdiv{12}{#2}{#1}}}% \def\CALX_hzu #1#2.#3.{\expandafter#1\the\numexpr\CALX_hzU#2.#3.\relax.}% % \end{macrocode} %\begin{lverb} % \CALX_hzW: the P <= 8 F % macros; v = D + 8e = E + 1. %\end{lverb} % \begin{macrocode} \edef\CALX_hymtwo{\romannumeral0\CALX_ffromraw{-2[0]}}% \def\CALX_hzW #1#2#3#4#5% {% \expandafter\def\csname CALX_hySwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hySwF#1a\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hySwF#1b\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_i \xint_dothis{\csname CALX_hySwF#1c\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_iv \xint_dothis{\csname CALX_hySwF#1d\endcsname ##1.##2##3##4.##5.}\fi \xint_orthat{\csname CALX_hySwF#1e\endcsname ##1.##2##3##4.##5.}% }% \expandafter\def\csname CALX_hySwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hySwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2#1##4.##5.##6% }% \expandafter\def\csname CALX_hySwF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hzS \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.#1% }% \expandafter\def\csname CALX_hySwF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_exb xw;+##4.##5.##6\xint:\CALX_hzXS##1.% \CALX_fsubx#4% }% \expandafter\def\csname CALX_hySwF#1e\endcsname ##1.##2##3##4.##5.##6\xint:% {% \csname CALX_hySF#1\endcsname##1.##2##3##4.##5.##6\xint:% }% % \expandafter\def\csname CALX_hyCwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyCwF#1a\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hyCwF#1b\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_i \xint_dothis{\csname CALX_hyCwF#1c\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_iv \xint_dothis{\csname CALX_hyCwF#1d\endcsname ##1.##2##3##4.##5.}\fi \xint_orthat{\csname CALX_hyCwF#1e\endcsname ##1.##2##3##4.##5.}% }% \expandafter\def\csname CALX_hyCwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space\CALX_hyup% }% \expandafter\def\csname CALX_hyCwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space\CALX_hyup% }% \expandafter\def\csname CALX_hyCwF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hzu\expandafter\CALX_hzC \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.% }% \expandafter\def\csname CALX_hyCwF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_exb xw;+##4.##5.##6\xint:\CALX_hzXS##1.% \CALX_faddx\CALX_hyNp% }% \expandafter\def\csname CALX_hyCwF#1e\endcsname ##1.##2##3##4.##5.##6\xint:% {% \csname CALX_hyCF#1\endcsname##1.##2##3##4.##5.##6\xint:% }% % \expandafter\def\csname CALX_hyTwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyTwF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hyTwF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyTwF#1r\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyTwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hyTwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2#1##4.##5.##6% }% \expandafter\def\csname CALX_hyTwF#1r\endcsname ##1.##2##3##4.##5.##6\xint:% {% \ifnum\numexpr(##4+\xint_c_viii*##5)*100000000% +\CALX_hzx##4.##6\relax<50000000 \xint_dothis{\expandafter\CALX_hzu\expandafter\CALX_hzT \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.% {##2#1##4.##5.##6}##1.\CALX_hzTt}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_iv \xint_dothis{\CALX_exb xw;+##4.##5.##6\xint:\CALX_hzXT##1.% \CALX_hzXTa\CALX_hzXTb#3}\fi \xint_orthat{\csname CALX_hyTF#1\endcsname##1.##2##3##4.##5.##6\xint:}% }% \expandafter\def\csname CALX_hyKwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyKwF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hyKwF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyKwF#1r\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyKwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_nsig{DivisionByZero}{coth(0)}{+}% }% \expandafter\def\csname CALX_hyKwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_fdiv{\XINTdigits}{\CALX_hyup}{##2#1##4.##5.##6}% }% \expandafter\def\csname CALX_hyKwF#1r\endcsname ##1.##2##3##4.##5.##6\xint:% {% \ifnum\numexpr(##4+\xint_c_viii*##5)*100000000% +\CALX_hzx##4.##6\relax<50000000 \xint_dothis{\expandafter\CALX_hzu\expandafter\CALX_hzT \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.% {##2#1##4.##5.##6}##1.\CALX_hzKt}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_iv \xint_dothis{\CALX_exb xw;+##4.##5.##6\xint:\CALX_hzXT##1.% \CALX_hzXKa\CALX_hzXTb#3}\fi \xint_orthat{\csname CALX_hyKF#1\endcsname##1.##2##3##4.##5.##6\xint:}% }% \expandafter\def\csname CALX_hyEwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyEwF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hyEwF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyEwF#1r\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyEwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space\CALX_hyup% }% \expandafter\def\csname CALX_hyEwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\space\CALX_hyup% }% \expandafter\def\csname CALX_hyEwF#1r\endcsname ##1.##2##3##4.##5.##6\xint:% {% \ifnum\numexpr(##4+\xint_c_viii*##5)*100000000% +\CALX_hzx##4.##6\relax<50000000 \xint_dothis{\expandafter\CALX_hzu\expandafter\CALX_hzE \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_iv \xint_dothis{\CALX_exb xw;+##4.##5.##6\xint:\CALX_hzXT##1.% \CALX_hzXEa\CALX_hzXEb\CALX_hytwo}\fi \xint_orthat{\csname CALX_hyEF#1\endcsname##1.##2##3##4.##5.##6\xint:}% }% \expandafter\def\csname CALX_hyHwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyHwF#1a\endcsname}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hyHwF#1b\endcsname}\fi \xint_orthat{\csname CALX_hyHwF#1r\endcsname}##1.##2##3##4.##5.% }% \expandafter\def\csname CALX_hyHwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_nsig{DivisionByZero}{csch(0)}{+}% }% \expandafter\def\csname CALX_hyHwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% \CALX_fdiv{\XINTdigits}{\CALX_hyup}{##2#1##4.##5.##6}% }% \expandafter\def\csname CALX_hyHwF#1r\endcsname ##1.##2##3##4.##5.##6\xint:% {% \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_i \xint_dothis{\expandafter\CALX_hzu\expandafter\CALX_hzH \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.% {##2#1##4.##5.##6}##1.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_iv \xint_dothis{\CALX_exb xw;+##4.##5.##6\xint:\CALX_hzXT##1.% \CALX_hzXHa\CALX_hzXEb#5}\fi \xint_orthat{\csname CALX_hyHF#1\endcsname##1.##2##3##4.##5.##6\xint:}% }% \expandafter\def\csname CALX_hyswF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hyswF#1a\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hyswF#1b\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_ \xint_dothis{\csname CALX_hyswF#1c\endcsname ##1.##2##3##4.##5.}\fi \xint_orthat{\csname CALX_hyswF#1d\endcsname ##1.##2##3##4.##5.}% }% \expandafter\def\csname CALX_hyswF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hyswF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2#1##4.##5.##6% }% \expandafter\def\csname CALX_hyswF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hzs \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.#1% }% \expandafter\def\csname CALX_hyswF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \csname CALX_hysF#1\endcsname##1.##2##3##4.##5.##6\xint:% }% % \expandafter\def\csname CALX_hytwF#1\endcsname ##1.##2##3##4.##5.% {% \ifnum##4=\xint_c_ \xint_dothis{\csname CALX_hytwF#1a\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<-\xint_c_iv \xint_dothis{\csname CALX_hytwF#1b\endcsname ##1.##2##3##4.##5.}\fi \ifnum\numexpr##4+\xint_c_viii*##5<\xint_c_ \xint_dothis{\csname CALX_hytwF#1c\endcsname ##1.##2##3##4.##5.}\fi \xint_orthat{\csname CALX_hytwF#1d\endcsname ##1.##2##3##4.##5.}% }% \expandafter\def\csname CALX_hytwF#1a\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2+0.0.% }% \expandafter\def\csname CALX_hytwF#1b\endcsname ##1.##2##3##4.##5.##6\xint:% {% ##2#1##4.##5.##6% }% \expandafter\def\csname CALX_hytwF#1c\endcsname ##1.##2##3##4.##5.##6\xint:% {% \expandafter\CALX_hzt \the\numexpr\CALX_hzx##4.##6\relax\expandafter.% \the\numexpr##4-\xint_c_i+\xint_c_viii*##5.#1% }% \expandafter\def\csname CALX_hytwF#1d\endcsname ##1.##2##3##4.##5.##6\xint:% {% \csname CALX_hytF#1\endcsname##1.##2##3##4.##5.##6\xint:% }% % }% \CALX_hzW+-\CALX_hyup\CALX_hyNp\CALX_hytwo \CALX_hzW-+\CALX_hyum\CALX_hyNm\CALX_hymtwo \def\CALX_hzL #1% {% \expandafter\let\csname CALX_hy#1wF+\expandafter\endcsname \csname CALX_hy#1F+\endcsname \expandafter\let\csname CALX_hy#1wF-\expandafter\endcsname \csname CALX_hy#1F-\endcsname }% \CALX_hzL c\CALX_hzL k\CALX_hzL e\CALX_hzL h% % \end{macrocode} %\begin{lverb} % Public macros and expression functions (\CALX_hymk ). %\end{lverb} % \begin{macrocode} \def\CALX_hymk #1#2#3% {% \expandafter\def\csname calxFp#1\endcsname##1% {\romannumeral0\expandafter\CALX_hyd\expandafter#2% \romannumeral0\CALX_fround{\XINTdigits}{##1}}% \expandafter\edef\csname calxRaw#1\endcsname##1% {\noexpand\romannumeral0\noexpand\CALX_ftoraw {\expandafter\noexpand\csname calxFp#1\endcsname{##1}}}% \expandafter\edef\csname XINT_flexpr_func_#3\endcsname##1##2##3% {\noexpand\expandafter##1\noexpand\expandafter##2% \noexpand\expandafter{\noexpand\romannumeral`&&@% \noexpand\XINT:NEhook:f:one:from:one{\noexpand\romannumeral`&&@% \expandafter\noexpand\csname calxFp#1\endcsname##3}}}% \expandafter\edef\csname XINT_expr_func_#3\endcsname##1##2##3% {\noexpand\expandafter##1\noexpand\expandafter##2% \noexpand\expandafter{\noexpand\romannumeral`&&@% \noexpand\XINT:NEhook:f:one:from:one{\noexpand\romannumeral`&&@% \expandafter\noexpand\csname calxRaw#1\endcsname##3}}}% }% \CALX_hymk{Sinh}S{sinh}\CALX_hymk{Cosh}C{cosh}\CALX_hymk{Tanh}T{tanh}% \CALX_hymk{Coth}K{coth}\CALX_hymk{Sech}E{sech}\CALX_hymk{Csch}H{csch}% \CALX_hymk{Asinh}s{asinh}\CALX_hymk{Acosh}c{acosh}% \CALX_hymk{Atanh}t{atanh}\CALX_hymk{Acoth}k{acoth}% \CALX_hymk{Asech}e{asech}\CALX_hymk{Acsch}h{acsch}% % \end{macrocode} % \subsection{Aliases} % \begin{macrocode} \let\XINT_flexpr_func_ln\XINT_flexpr_func_log \let\XINT_expr_func_ln\XINT_expr_func_log \let\XINT_flexpr_func_sh\XINT_flexpr_func_sinh \let\XINT_flexpr_func_ch\XINT_flexpr_func_cosh \let\XINT_flexpr_func_th\XINT_flexpr_func_tanh \let\XINT_flexpr_func_argsh\XINT_flexpr_func_asinh \let\XINT_flexpr_func_argch\XINT_flexpr_func_acosh \let\XINT_flexpr_func_argth\XINT_flexpr_func_atanh \let\XINT_flexpr_func_argcoth\XINT_flexpr_func_acoth \let\XINT_flexpr_func_argsech\XINT_flexpr_func_asech \let\XINT_flexpr_func_argcsch\XINT_flexpr_func_acsch \xintFor #1 in {sh, ch, th, argsh, argch, argth, argcoth, argsech, argcsch}\do{% \expandafter\let\csname XINT_expr_func_#1\expandafter\endcsname \csname XINT_expr_func_#1\endcsname }% % \end{macrocode} % \StoreCodelineNo {calxlog} % \cleardoublepage\let\calxlognameUp\undefined %\gardesactifs %\let\relax %\let<*calxlogdata>\gardesinactifs %------------------------------------------------------ %<*calxlogdata>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxlogdatanameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Library \calxlognameimp data tables} % \RaisedLabel{sec:calxlogdataimp} % \addedcalx{2.0a1} % %\begin{lverb} % calxlogdata.tex -- table constants shared by log and potential exp. % Full table: floor(log(factor)*10^112); native P16 cache: 24 places. % P1..P8 (s47): log tables at 10^-12, see calxlog.tex (\CALX_lgULoadT/V). % % This file is loaded from calxlog.tex in a context having done % \XINTsetcatcodes, in particular the exclamation mark has catcode 12. % % The definition of \ver@calxlogdata.tex control sequence done also under % existence of LaTeX \ProvidesFile is due to a miniltx feature (under % investigation). %\end{lverb} % \begin{macrocode} \ifdefined\ProvidesFile \ProvidesFile{calxlogdata.tex}[2026/11/01 v2.0a1 calx log data (JFB)]% \fi \expandafter\def\csname ver@calxlogdata.tex\endcsname {2026/11/01 v2.0a1 calx log data (JFB)}% \CALX_lgULoadT 10.909.0.954.1018.4805,11.833.0.1827.2163.6815,12.769.0.2626.6430.9476,% 13.714.0.3368.7231.6643,14.666.0.4064.6560.8442,15.625.0.4700.362.9246,% 16.588.0.5310.2833.1084,17.555.0.5887.8716.5236,18.526.0.6424.5406.6244,% 19.500.0.6931.4718.560,20.476.0.7423.3742.4751,21.454.0.7896.5808.941,% 22.434.0.8347.1074.4882,23.416.0.8770.7001.8721,24.400.0.9162.9073.1874,% 25.384.0.9571.1272.6394,26.370.0.9942.5227.3344,27.357.1.300.1949.7202,% 28.344.1.671.1362.1609,29.333.1.996.1278.9002,30.322.1.1332.373.3438,% 31.312.1.1647.5209.1173,32.303.1.1940.2247.3473,33.294.1.2241.7551.1643,% 34.285.1.2552.6609.8713,35.277.1.2837.3777.2795,36.270.1.3093.3331.9984,% 37.263.1.3356.124.6804,38.256.1.3625.7783.4503,39.250.1.3862.9436.1120,% 40.243.1.4146.9383.5642,41.238.1.4354.8460.5311,42.232.1.4610.1790.7316,% 43.227.1.4828.526.1501,44.222.1.5050.7789.7110,45.217.1.5278.5792.5442,% 46.212.1.5511.6900.4310,47.208.1.5702.1719.9281,48.204.1.5896.3528.5138,% 49.200.1.6094.3791.2434,50.196.1.6296.4061.9752,51.192.1.6502.5990.6954,% 52.188.1.6713.1331.6152,53.185.1.6873.9945.3904,54.181.1.7092.5824.7716,% 55.178.1.7259.7172.8690,56.175.1.7429.6930.5059,57.172.1.7602.6080.2169,% 58.169.1.7778.5656.4059,59.166.1.7957.6749.626,60.163.1.8140.507.8175,% 61.161.1.8263.5091.3998,62.158.1.8451.6024.5955,63.156.1.8578.9927.1733,% 64.153.1.8773.1735.7590,65.151.1.8904.7544.2167,66.149.1.9038.897.3037,% 67.147.1.9173.2269.2203,68.144.1.9379.4197.9406,69.142.1.9519.2822.1381,% 70.140.1.9661.1285.6373,71.138.1.9805.159.3825,72.136.1.9951.39.3246,% 73.135.2.24.8050.544,74.133.2.174.615.760,75.131.2.325.5795.5781,% 76.129.2.479.4287.4620,77.128.2.557.2501.5063,78.126.2.714.7337.2031,% 79.125.2.794.4154.1680,80.123.2.955.7092.3610,81.121.2.1119.6473.3385,% 82.120.2.1202.6353.6200,83.119.2.1286.3178.5871,84.117.2.1455.8134.4184,% 85.116.2.1541.6508.7876,86.114.2.1715.5683.588,87.113.2.1803.6746.270,% 88.112.2.1892.5640.7687,89.111.2.1982.2507.7670,90.109.2.2164.739.6753,% 91.108.2.2256.2405.1858,92.107.2.2349.2644.4520,93.106.2.2443.1618.4870,% 94.105.2.2537.9492.8825,95.104.2.2633.6437.9841,96.103.2.2730.2629.753,% 97.102.2.2827.8246.5698,98.101.2.2926.3476.2141,99.100.2.3025.8509.2994,% 0.0.0.0.0.0,% \CALX_lgULoadV 0.0.0.0,1.9.9950.333,2.19.9800.2663,3.29.9550.8980,4.39.9202.1270,% 5.49.8754.1511,6.59.8207.1678,7.69.7561.3736,8.79.6816.9649,9.89.5974.1371,% 10.99.5033.853,11.109.3994.38,12.119.2857.865,13.129.1622.5267,% 14.139.290.5169,15.148.8861.2494,16.158.7334.9156,17.168.5711.7066,% 18.178.3991.8128,19.188.2175.4241,20.198.262.7296,21.207.8253.9183,% 22.217.6149.1782,23.227.3948.6969,24.237.1652.6617,25.246.9261.2590,% 26.256.6774.6749,27.266.4193.946,28.276.1516.7033,29.285.8745.6852,% 30.295.5880.2242,31.305.2920.5035,32.314.9866.7059,33.324.6719.138,% 34.334.3477.6086,35.344.142.6717,36.353.6714.3837,37.363.3192.9247,% 38.372.9578.4744,39.382.5871.2117,40.392.2071.3153,41.401.8178.9633,% 42.411.4194.3331,43.421.117.6019,44.430.5948.9460,45.440.1688.5417,% 46.449.7336.5643,47.459.2893.1888,48.468.8358.5899,49.478.3732.9414,% 50.487.9016.4169,51.497.4209.1895,52.506.9311.4316,53.516.4323.3152,% 54.525.9245.119,55.535.4076.6928,56.544.8818.5284,57.554.3470.6888,% 58.563.8033.3436,59.573.2506.6619,60.582.6890.8124,61.592.1185.9632,% 62.601.5392.2820,63.610.9509.9360,64.620.3539.919,65.629.7479.9161,% 66.639.1332.5744,67.648.5097.2320,68.657.8774.538,69.667.2363.2043,% 70.676.5864.8474,71.685.9279.1466,72.695.2606.2649,73.704.5846.3649,% 74.713.8999.6087,75.723.2066.1580,76.732.5046.1740,77.741.7939.8174,% 78.751.747.2487,79.760.3468.6276,80.769.6104.1136,81.778.8653.8657,% 82.788.1118.424,83.797.3496.8019,84.806.5790.3017,85.815.7998.6992,% 86.825.122.1512,87.834.2160.8139,88.843.4114.8434,89.852.5984.3951,% 90.861.7769.6241,91.870.9470.6851,92.880.1087.7323,93.889.2620.9194,% 94.898.4070.4000,95.907.5436.3268,96.916.6718.8526,97.925.7918.1293,% 98.934.9034.3087,99.944.67.5421,100.953.1017.9804,101.962.1885.7741,% -1.0.0.0,% % log10 (s47): 1/ln10 truncated to 130 digits \def\CALX_Lzinvraw{43429448190325182765112891891660508229439700580366656% 61144537831658646492088707747292249493384317483187061% 067447663037336416792871[-130]}% % exp (s49): bucket table i.key.c. (gen_expdata.py, exp_bounds.py) \def\CALX_exAlist{% 0.0.10000.1.10.9524.2.10.9524.3.10.9524.4.11.8696.5.11.8696.6.11.8696.7.11.% 8696.% 8.12.8000.9.12.8000.10.12.8000.11.13.7407.12.13.7407.13.13.7407.14.13.7407.% 15.14.% 6897.16.14.6897.17.14.6897.18.15.6452.19.15.6452.20.16.6061.21.16.6061.22.16.% 6061.% 23.17.5714.24.17.5714.25.17.5714.26.18.5405.27.18.5405.28.19.5128.29.19.5128.% 30.20.% 4878.31.20.4878.32.21.4651.33.21.4651.34.22.4444.35.22.4444.36.23.4255.37.23.% 4255.% 38.24.4082.39.24.4082.40.25.3922.41.26.3774.42.26.3774.43.27.3636.44.27.3636.% 45.28.% 3509.46.29.3390.47.29.3390.48.30.3279.49.31.3175.50.31.3175.51.32.3077.52.33.% 2985.53.% 34.2899.54.35.2817.55.35.2817.56.36.2740.57.37.2667.58.38.2597.59.39.2532.60.% 40.2469.% 61.41.2410.62.42.2353.63.43.2299.64.44.2247.65.45.2198.66.46.2151.67.47.2105.% 68.48.2062.69.49.2020.70.50.1980.71.51.1942.72.53.1869.73.54.1835.74.55.1802.% 75.56.1770.76.58.1709.77.59.1681.78.60.1653.79.62.1600.80.63.1575.81.65.1527.% 82.66.1504.83.68.1460.84.69.1439.85.71.1399.86.73.1361.87.74.1342.88.76.1307.% 89.78.1274.90.80.1242.91.82.1212.92.84.1183.93.86.1156.94.88.1130.95.90.1105.% 96.92.1081.97.94.1058.98.96.1036.99.1.1000.-1.0.0.}% % ln10 limbs 3..31 (10^-12 .. 10^-124, floor), exp rare path P > 16 \def\CALX_exLx{2994!0456!8401!7991!4546!8436!4207!6011!0148!8628!7729!7603!% 3327!9009!6757!2609!6773!5248!0235!9972!0508!9598!2983!4196!7784!0422!8624!% 8633!4095!}% % calxlogdata_s50.tex -- generated by calx/t/s50/gen_logdata.py (s50: 128 places). % Floors at 10^-128: F1!c2!...!c16!, F1 = floor(10^8 value) (see generator). \@namedef{CALX_Lz}{230258509!29940456!84017991!45468436!42076011!01488628!% 77297603!33279009!67572609!67735248!02359972!05089598!29834196!77840422!% 86248633!40952546!}% \def\CALX_Lzraw{2302585092994045684017991454684364207601101488628772976033327% 90096757260967735248023599720508959829834196778404228624863340952546[-128]}% \@namedef{CALX_Lb0}{0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!}% \@namedef{CALX_Ls0}{0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!}% \@namedef{CALX_Lt0}{0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!}% \@namedef{CALX_Lu0}{0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!}% \@namedef{CALX_Lv0}{0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!0!}% \@namedef{CALX_Lb10}{4877016!43694293!36438707!09756716!44757540!30750384!% 86035967!62043359!32455608!94122546!68018852!73358077!49141346!88747895!% 70469625!61742890!}% \@namedef{CALX_Lb11}{13972194!31751373!64678175!44301696!52712039!97184836!% 45331971!42500516!42479531!64743535!51508681!01872546!03600091!89139520!% 03589419!21760533!}% \@namedef{CALX_Lb12}{22314355!13142097!55766295!09030983!45033746!01085548!% 00721367!12878724!87391743!76826833!34184072!24100342!23571596!33409805!% 74191432!35296475!}% \@namedef{CALX_Lb13}{30015959!39628935!41371602!37944702!72769808!91876679!% 20550559!77179025!65849303!27944414!71217655!17752346!84864281!78978044!% 07633012!93937294!}% \@namedef{CALX_Lb14}{37149855!85448914!96543805!99399681!89888761!22427518!% 37928342!35216155!62356195!60013023!92061052!65723651!62595342!90221061!% 60995397!73700552!}% \@namedef{CALX_Lb15}{43819493!27310832!55733785!23617541!65471959!89052525!% 87033936!52180080!48059180!90773175!48005880!42744461!37180218!14169936!% 47502086!74779789!}% \@namedef{CALX_Lb16}{50071029!00248977!04817722!77652256!23878508!06925355!% 80183145!51133066!87643331!59412358!58614086!13722162!08351011!51923350!% 90024935!80227559!}% \@namedef{CALX_Lb17}{55966578!91854643!54500117!66979777!15388453!04460706!% 78467197!45551708!20457419!05438256!30576210!61284747!03442015!02755367!% 29888029!74325560!}% \@namedef{CALX_Lb18}{61526064!19028740!83843502!98392889!93635403!73783385!% 91440702!15199881!06299991!51115278!55047640!96677472!78725725!60456750!% 81784009!02261093!}% \@namedef{CALX_Lb19}{66786937!33756767!67986862!91636132!69403096!71722039!% 36786625!96453530!54332445!52642539!67010711!99040292!36043514!69578056!% 66497065!89571724!}% \@namedef{CALX_Lb20}{71784979!32003171!43767373!15022836!68141283!92775092!% 81408601!40285319!06563729!45287167!16068233!53055328!44436231!53978467!% 64816121!21726166!}% \@namedef{CALX_Lb21}{76550284!27520857!22079452!35855135!97223254!86076623!% 03479508!91977063!29076333!22551495!29152721!67824181!56882994!97868036!% 88895202!88481475!}% \@namedef{CALX_Lb22}{81103022!12166621!22291359!73094298!52375408!16244659!% 55947074!21185140!50917687!25443990!51525273!51620964!26902069!12749814!% 46642489!12169377!}% \@namedef{CALX_Lb23}{85449033!09687082!26296357!98266962!59085363!46698238!% 50227657!71156537!20128458!02659279!27164323!16440050!10743189!86672852!% 03627352!27378869!}% \@namedef{CALX_Lb24}{89599802!86063926!33176801!01931048!64087813!94244530!% 97917766!54000859!81706601!01518340!81170410!67394256!72104538!72969006!% 54874881!45408646!}% \@namedef{CALX_Lb25}{93598336!52198911!48142168!88721877!53280688!50480075!% 98288331!95894431!65902435!80586428!14044440!15203884!61520194!68823765!% 87778395!83479224!}% \@namedef{CALX_Lb26}{97444964!60476872!10641858!17145218!08581931!34662578!% 70624733!57868416!64120200!72981389!21533933!36838570!80873774!24117445!% 33718380!40540525!}% \@namedef{CALX_Lb27}{101170091!66788132!83562812!83506306!31280675!41982951!% 47774249!12975559!06502724!73045868!44803505!49996134!88285946!69427376!% 68909526!64125448!}% \@namedef{CALX_Lb28}{104725399!63929676!20764806!63044528!66252664!79332717!% 51347477!45058339!66362409!74508416!15005122!89535267!18789244!00996677!% 02162762!56866023!}% \@namedef{CALX_Lb29}{108175517!16016867!92076597!63351454!52461264!83519360!% 57568162!49413339!21649630!25439840!29981857!57955190!72827527!02024514!% 46181009!88988077!}% \@namedef{CALX_Lb30}{111504659!51315344!84010607!67124674!69902575!43934652!% 50955719!23890832!90556597!96991184!30913325!65498134!15405297!64766107!% 66634102!11947625!}% \@namedef{CALX_Lb31}{114727746!06493907!13823006!34456878!91564792!94122051!% 97069740!07506130!64747201!55751901!39378259!44569530!63764548!84831726!% 37907428!82654800!}% \@namedef{CALX_Lb32}{117862999!66541409!08983344!16223132!13675758!70500426!% 86830325!33457619!77682025!65026056!28072227!16147167!61053562!13153719!% 62144607!72580399!}% \@namedef{CALX_Lb33}{120898534!61494802!74665839!95672020!62843402!08761854!% 35223157!95083908!14517952!40222728!93142549!13153263!44630582!89778697!% 78853610!08020156!}% \@namedef{CALX_Lb34}{123821924!30545272!41382373!16744899!81989005!09735283!% 89796460!38937306!08689493!94901281!04120082!55717158!20503389!78163285!% 02889390!06510058!}% \@namedef{CALX_Lb35}{126691260!40998101!36602710!03563519!50675363!25570532!% 32307251!55592916!33338911!22138741!68328657!88830543!13517080!21975014!% 11685930!40074170!}% \@namedef{CALX_Lb36}{129462717!25940668!27321552!11461505!06641646!69157481!% 49835892!90296523!79178828!19947837!83571288!43535953!29862341!55317854!% 20985311!81541225!}% \@namedef{CALX_Lb37}{132163084!77941684!66523927!03065545!90012459!21543184!% 39550103!19619124!38031021!00215630!85368194!47354286!24346438!93659442!% 60026574!18280197!}% \@namedef{CALX_Lb38}{134822816!03134342!91716791!19282203!96007702!58742440!% 15192416!64018339!77126079!26178152!68340118!78696728!90953963!39272763!% 51849691!85438726!}% \@namedef{CALX_Lb39}{137357558!87121159!30100300!07344429!78715647!56954390!% 16357346!94784516!39873148!59048283!97347590!76159433!01835517!39687333!% 96150110!71201216!}% \@namedef{CALX_Lb40}{139877188!26310032!32766847!61636955!29816283!82434501!% 95495733!24122362!03343596!49805311!39953812!72566078!93743078!79268703!% 65498755!30737716!}% \@namedef{CALX_Lb41}{142295834!54914820!56587563!04534227!68877860!44701870!% 07109042!85814416!91021317!12724799!40020678!20726813!92710829!51310055!% 31388185!09720306!}% \@namedef{CALX_Lb42}{144689398!32488202!53179391!33853912!92983588!05568252!% 40597413!15379891!96509934!12678166!43197429!20744181!06928471!13853263!% 86480267!59124234!}% \@namedef{CALX_Lb43}{147011084!72130011!87939051!23091934!46935236!12985341!% 12873515!82159491!99850488!81873920!60797210!20537383!71474139!90511721!% 18861140!10500975!}% \@namedef{CALX_Lb44}{149298909!97908535!66266969!02134847!43945566!84390979!% 07371037!91104010!48498913!20873902!97253958!63455178!92767582!31389494!% 73967503!00391652!}% \@namedef{CALX_Lb45}{151503723!70126160!64124935!71743262!52839495!77459709!% 32510562!50554467!07591405!58752431!97289572!32246874!68282158!37947875!% 66455601!26248869!}% \@namedef{CALX_Lb46}{153665224!27084526!86318311!75063049!63246716!20483066!% 62332989!49401207!86632178!93130952!81887638!12471197!08587090!59837126!% 70419048!28742588!}% \@namedef{CALX_Lb47}{155826962!58597009!43882490!25711417!17173572!62538271!% 91122294!42886071!55970564!69589149!67573865!96781458!56065725!06919422!% 86302648!10105522!}% \@namedef{CALX_Lb48}{157890870!73992775!01350328!59183507!78535211!75661349!% 24980374!68872363!47055382!48885874!40256082!25792261!37393118!12145128!% 13413328!94946192!}% \@namedef{CALX_Lb49}{159948758!15809322!91752543!97568192!68978369!21744328!% 45892404!80383317!07312323!46001885!35974481!81530419!44963544!06978478!% 69078111!65325770!}% \@namedef{CALX_Lb50}{161948824!82876018!15784308!19078473!53456111!16361943!% 14759529!13473170!03761996!71190807!82798420!70642277!23849324!60870862!% 34330159!55147854!}% \@namedef{CALX_Lb51}{163886672!31249125!15395120!34995610!28351694!36881376!% 84878173!06444447!68407021!24579761!56578073!10065298!56743717!34091876!% 56680847!78926947!}% \@namedef{CALX_Lb52}{165810308!44153813!97028520!44087245!10913574!04918497!% 73896757!87041709!01431896!04656781!16943440!67848978!15965748!47571283!% 95604586!18254900!}% \@namedef{CALX_Lb53}{167718156!45206199!01253552!29770190!21767151!70279977!% 52189983!25295430!07262389!95927543!98356510!15007313!83456955!12466705!% 54040736!44539503!}% \@namedef{CALX_Lb54}{169554061!14875120!89851774!54635284!00253491!38165233!% 44591823!54048941!18757216!44593294!48272102!05452390!59361022!04538374!% 22943678!67049218!}% \@namedef{CALX_Lb55}{171368793!38078995!12260729!94037709!59563807!25054657!% 87425966!72643864!76599606!99529406!58913706!80838550!32846540!75726202!% 96388490!21877870!}% \@namedef{CALX_Lb56}{173160554!64083079!10042678!75341086!92940924!67118733!% 11494685!32526722!06023421!54802099!64750359!00652429!03722748!94435050!% 15917874!80931506!}% \@namedef{CALX_Lb57}{174927485!76218997!04882919!47793383!59576082!77865327!% 23170728!78905758!70482478!21324778!29342775!33251478!55162961!06099772!% 31816418!82376550!}% \@namedef{CALX_Lb58}{176667668!88605918!46335612!62850485!39773479!65765923!% 50139270!04728098!60031668!44262357!34770563!89169342!32080871!69685376!% 85580947!33002611!}% \@namedef{CALX_Lb59}{178319623!85675671!28338439!07266264!16536515!85015716!% 48863689!47857833!50333205!89809490!90193545!37614419!57129189!01573783!% 96010840!13683953!}% \@namedef{CALX_Lb60}{179999327!41551585!57484421!11756516!59830250!23221470!% 46955493!89866821!80722662!28875133!20628475!66911064!78613686!08891572!% 70157715!68984053!}% \@namedef{CALX_Lb61}{181646208!18684268!35162618!38715089!25187758!83332915!% 56353774!87228655!44058022!67148063!84804391!07869060!53315028!54269127!% 22681863!58526588!}% \@namedef{CALX_Lb62}{183258146!37483101!30367054!42353602!21429002!02439816!% 52493558!39357639!61570731!47592609!80485411!02193521!84651592!96440022!% 89754332!07696998!}% \@namedef{CALX_Lb63}{184832982!07164492!98974603!93499685!04124211!37400750!% 69636837!92370037!09364014!10480719!01488310!55956698!26719893!67777879!% 46996337!73033069!}% \@namedef{CALX_Lb64}{186433016!20628904!31524050!70628454!77728277!64181137!% 20923443!06177389!53557424!72684844!38639929!05839528!65365296!01122161!% 03338185!63402795!}% \@namedef{CALX_Lb65}{187928006!67575503!01841856!72575517!24772303!90473260!% 64605536!13734764!02229259!99252497!30438216!21595652!73997553!80784825!% 62982486!13034382!}% \@namedef{CALX_Lb66}{189445686!74663976!02164854!54167440!02811308!54780693!% 59160032!94032095!96504115!35513527!03039824!31941553!77470141!21571652!% 74055136!17774361!}% \@namedef{CALX_Lb67}{190986755!77083839!53570139!14989848!80908592!03746305!% 45925035!16229688!25033728!87519070!57151978!29172962!39722056!07312348!% 03350001!27835472!}% \@namedef{CALX_Lb68}{192414865!72738006!13544633!38515637!34838230!51486654!% 46600938!36048362!47534231!14176543!18257989!65437517!31322987!04467048!% 96338424!42294755!}% \@namedef{CALX_Lb69}{193863666!50888149!19138665!25293717!68563035!71259310!% 42351320!04676252!70686728!93565631!16294057!13064676!22575966!27795162!% 61031650!02530424!}% \@namedef{CALX_Lb70}{195333766!48841099!27489536!64048005!71586763!21191471!% 10021240!06300090!37533107!80405339!49256313!54822299!74977656!69366366!% 20779413!97346582!}% \@namedef{CALX_Lb71}{196682739!73107015!60679395!44961500!51858743!19415587!% 53896986!34352903!38255138!98028203!09281764!04724256!83671038!05868014!% 90705742!82836563!}% \@namedef{CALX_Lb72}{198122649!41828809!24186815!74613144!61257586!77162575!% 19100987!53170820!17209199!90849169!64205729!67114909!76718689!44828525!% 34817616!52938461!}% \@namedef{CALX_Lb73}{199436536!93247166!64273124!04020619!38515242!26452886!% 22775015!90205837!64110671!35539244!81509061!98092420!95482760!53442981!% 89016134!94412265!}% \@namedef{CALX_Lb74}{200842405!44445556!33841401!01588853!62161915!17223136!% 15841185!66802388!26883385!98152976!10776415!79259235!94138768!10370178!% 03739679!73175263!}% \@namedef{CALX_Lb75}{202117263!35558601!52725978!01325602!37809932!25493066!% 83885725!98863509!03927829!35060453!31490611!19686112!74192582!47096446!% 23005715!85388132!}% \@namedef{CALX_Lb76}{203485065!83519607!88463612!11624558!09768982!89146829!% 99290864!76672804!55958873!60474397!28134285!59356431!55318073!90010046!% 44074731!52084082!}% \@namedef{CALX_Lb77}{204794287!46204649!37185886!61378471!98825966!77723182!% 01406117!36041043!42364361!94046203!52967838!62371065!51934042!76426928!% 04088610!10102178!}% \@namedef{CALX_Lb78}{206042353!58440740!80390540!76882760!21982494!68416230!% 90715667!48057838!38272423!91116649!03632338!32745741!96307048!80746441!% 09305344!97292261!}% \@namedef{CALX_Lb79}{207306193!47157969!02037103!40837470!65628406!25220401!% 45569907!04811753!01614493!94842285!90270090!91652302!89752571!24408104!% 91584122!77340948!}% \@namedef{CALX_Lb80}{208586210!94827586!61662245!15470150!70299440!53831846!% 15255280!99132159!81420691!09909000!65188771!36767783!42510776!23543793!% 70574676!98984031!}% \@namedef{CALX_Lb81}{209801292!72652712!98963198!37268654!50384441!24734283!% 38400714!52011167!73596759!27643308!57819172!88192813!35235675!48848520!% 17783255!79692704!}% \@namedef{CALX_Lb82}{211031320!53469229!74958058!07198558!88327150!32540774!% 22719422!59918895!43997017!94906765!13539663!04809866!97164743!69718036!% 26775269!00925870!}% \@namedef{CALX_Lb83}{212193159!33007880!77844534!52439782!35754053!95770282!% 15732657!34853939!82517877!91134229!88474823!57638899!66714230!97089347!% 05080886!31643606!}% \@namedef{CALX_Lb84}{213453150!79977959!58859638!19216363!98911567!85335412!% 81648283!58304326!05781241!30852029!43571809!94889542!68883629!30577777!% 68410358!85004061!}% \@namedef{CALX_Lb85}{214558134!41843809!33209996!44864272!26087030!55405480!% 61290821!15495249!64264575!27042932!75611854!42200841!22868070!51019021!% 80292783!96041345!}% \@namedef{CALX_Lb86}{215761932!27438599!56738432!34007485!06230769!99660623!% 09182129!74761091!18918043!16815792!79080724!30290549!92324717!16500336!% 29508483!47187570!}% \@namedef{CALX_Lb87}{216892870!81813720!80234034!53717611!30262355!15714943!% 50723775!66577287!38116590!53561660!94508621!91128425!68166948!10310841!% 53301743!53855000!}% \@namedef{CALX_Lb88}{218036746!02697964!83471842!87043707!09507739!74077183!% 32513335!96356675!59143923!47300736!98718015!12768922!81706324!02315174!% 04046752!25788500!}% \@namedef{CALX_Lb89}{219193857!29069820!27493883!97499206!69723337!00801332!% 75469147!44443730!59954865!06846106!48153008!13362001!82107236!06563598!% 46380387!81724787!}% \@namedef{CALX_Lb90}{220273975!80243295!45168184!42607282!40504853!33642900!% 62227850!43804638!50354207!87641069!60021854!10787221!14628029!83790074!% 79652710!98434929!}% \@namedef{CALX_Lb91}{221365888!37996441!75405852!90816927!26949050!34492475!% 25900892!70834169!28050891!18852080!99649483!20311866!24284094!65056767!% 24499844!48748048!}% \@namedef{CALX_Lb92}{222469855!43369744!58444262!31715508!70030659!75137654!% 43212893!41678795!80478979!21881055!01348979!74770652!39805722!23486967!% 97346908!74661616!}% \@namedef{CALX_Lb93}{223492644!45202308!78749575!54702981!56212401!58189754!% 91137453!98669836!56000459!50206478!41506729!11767184!24511488!70781789!% 96725523!68614754!}% \@namedef{CALX_Lb94}{224620475!95579380!45041228!03365888!80254441!45190473!% 96516601!53608394!10910324!77011860!89413233!09055984!87711747!52280059!% 14035008!23512435!}% \@namedef{CALX_Lb95}{225665616!11056458!81477239!05931629!14166080!30059231!% 98006317!22286710!15813007!94600701!88692497!11340940!57964497!87770411!% 20889925!46701023!}% \@namedef{CALX_Lb96}{226721794!91567543!67764053!16134647!68007162!43369045!% 08404378!76487537!52933585!02759015!65455821!34105515!63050899!75276312!% 56814768!76172983!}% \@namedef{CALX_Lb97}{227691734!62454678!92459970!55462384!96111490!54885387!% 45947627!05883570!55121235!01969101!60031198!45105038!34366491!89347299!% 50575223!82661515!}% \@namedef{CALX_Lb98}{228769648!05002950!29182581!70970617!78557472!06956741!% 96891483!96032108!15750807!11183055!52328293!28859485!63292884!35542164!% 11455995!63204106!}% \@namedef{CALX_Lb99}{229759755!14830066!10405889!25222502!07356643!81139201!% 92939334!81852479!83348652!25505629!28013249!99630456!00924597!26128168!% 11551694!55888592!}% \@namedef{CALX_Ls-1100}{11653381!62559515!29718167!36869887!91957975!% 42590124!58658795!99582246!47191326!57524871!40249308!58229720!85366664!% 74018577!90550123!71810058!}% \@namedef{CALX_Ls-1000}{10536051!56578263!01227500!98083931!27983061!% 20372983!27407256!39392336!92584023!24013454!64887656!95462134!12076602!% 77259103!70517148!67351701!}% \@namedef{CALX_Ls-900}{9431067!94712413!26877142!72436023!00807598!50302915!% 47764718!82201413!34100689!27822551!32847612!48150835!58092161!56817859!% 58634723!56314418!}% \@namedef{CALX_Ls-800}{8338160!89390510!58394765!83464217!91606088!22393696!% 59970182!66604054!65364729!43051723!10618666!64033364!40724573!53924721!% 00988903!58928182!}% \@namedef{CALX_Ls-700}{7257069!28348354!30711573!34790384!55001047!73488954!% 20452857!52433958!22669509!53854476!13845138!24029377!87732298!86021295!% 74786709!58050348!}% \@namedef{CALX_Ls-600}{6187540!37180874!71797800!11813837!81382306!52340877!% 06666474!54674456!34933383!87920917!22554413!29748031!92818548!25131629!% 84300804!10077363!}% \@namedef{CALX_Ls-500}{5129329!43875505!33426196!14425468!72384392!22361689!% 89941161!60476740!51673529!58284990!71277021!48270277!09008692!86318421!% 06798018!07309191!}% \@namedef{CALX_Ls-400}{4082199!45202551!29554577!06515531!98701772!11747633!% 52022972!85614208!30682816!28762241!55690620!20383371!07018595!81339157!% 61202856!02344552!}% \@namedef{CALX_Ls-300}{3045920!74847085!45919261!28766476!67013932!88074598!% 76459609!04214331!74967927!57651783!51297116!65144922!04675698!48874361!% 92790639!28105957!}% \@namedef{CALX_Ls-200}{2020270!73175194!48408045!30102419!23878525!33383733!% 56832102!71954925!66591871!88087170!92908140!86007034!85515581!06986522!% 99529709!68602617!}% \@namedef{CALX_Ls-100}{1005033!58535014!41183548!85755854!77060855!15007674!% 62987337!86994255!29583009!00425031!36497081!92549097!62769327!97840645!% 18767259!82747331!}% \@namedef{CALX_Ls100}{-995034!91468319!17151784!64245573!92583113!20390059!% 94120213!53904402!33133335!75236108!89673143!03437239!83883547!43948261!% 53515211!92925247!}% \@namedef{CALX_Ls200}{-1980263!27038202!86973970!93311489!96068910!09272488!% 79645891!40437209!21964728!36546999!70804204!60331542!87283561!57959508!% 56888499!36793362!}% \@namedef{CALX_Ls300}{-2955881!77584555!97267380!59431528!75945739!41868886!% 74278945!54248429!04614014!90691069!08802484!35127087!69109980!19646489!% 80605270!21838109!}% \@namedef{CALX_Ls400}{-3922072!68467187!03730799!10342888!01061704!34629416!% 57307328!55702627!91499686!12121063!42548297!65749451!04528867!29329300!% 97718434!23033573!}% \@namedef{CALX_Ls500}{-4879017!58305679!96934625!59577683!53413920!26335584!% 41758995!99234268!85892075!67636896!11805862!78684413!37010293!75417910!% 47927713!00328921!}% \@namedef{CALX_Ls600}{-5826891!18760242!24474281!64888149!40767667!25089986!% 07309489!78463224!23746963!44152038!63314711!38696856!67929982!02665829!% 10948514!79732061!}% \@namedef{CALX_Ls700}{-6765865!15261851!94731584!09234545!14136390!56701126!% 13839850!65390826!88427849!82471230!39146757!06677585!94677291!92941367!% 10476890!27662207!}% \@namedef{CALX_Ls800}{-7696105!88638716!75015782!95568479!81651087!31035068!% 78708862!12127820!35875095!75948862!86394204!91745162!95523602!25188455!% 57528572!34399778!}% \@namedef{CALX_Ls900}{-8617770!37589476!67658666!45715952!67641418!54093754!% 31479899!17822472!54241935!15954197!87279881!38217743!82418594!27066738!% 40537569!46152001!}% \@namedef{CALX_Ls1000}{-9531018!01956751!39956047!87671923!49077793!94634691!% 35580081!47601918!36998985!76411576!71609424!97086963!50692725!20581541!% 48250111!15395630!}% \@namedef{CALX_Ls1100}{-10436002!46757572!32272642!00141475!55466546!% 34832267!16033668!70487871!04661179!14573492!81993571!21693295!84711415!% 65867277!18964138!66946740!}% \@namedef{CALX_Lt-56}{561573!87856356!95176194!38278177!61543268!68308793!% 91517181!23558309!15962043!32803899!02151540!28866630!26136448!78466098!% 40239662!35528060!}% \@namedef{CALX_Lt-55}{551518!06881101!62377693!95222777!26411903!52527255!% 12337503!49917965!75365621!43919276!22549539!01159756!96870435!83208755!% 63921226!24834084!}% \@namedef{CALX_Lt-54}{541463!27014988!81751532!38194002!50357803!37572395!% 52091881!01998703!37911481!49929545!14766865!32887073!89481154!85422854!% 80851513!27678733!}% \@namedef{CALX_Lt-53}{531409!48237687!93572635!55604600!60359986!38851846!% 76425983!34708024!14770069!31534978!42876462!09776922!18974268!64688264!% 24737071!90854177!}% \@namedef{CALX_Lt-52}{521356!70528874!51252817!59905599!60052579!08234191!% 27590980!24162993!37232208!78419849!99636509!64942399!42008419!21184552!% 60647660!43171199!}% \@namedef{CALX_Lt-51}{511304!93868230!21094256!51909687!40372273!86760004!% 46098118!12426340!02334168!83498217!88869136!04398480!28982120!11152292!% 21295741!95803169!}% \@namedef{CALX_Lt-50}{501254!18235442!82043093!73895836!77813865!97831048!% 32870728!08748234!84439635!94348377!59518734!62877397!23675183!12228934!% 50470719!03868032!}% \@namedef{CALX_Lt-49}{491204!43610206!25443157!44024929!69137438!30190080!% 34292708!17824785!11097359!36325706!52991895!30706963!82409590!78962662!% 85263599!85712556!}% \@namedef{CALX_Lt-48}{481155!69972220!54789809!64601389!17139069!80870215!% 92875332!66702224!49820063!50782272!77144038!62242941!81171344!35693157!% 16342384!20459548!}% \@namedef{CALX_Lt-47}{471107!97301191!85483916!96721077!25486332!80256184!% 41812629!07977902!95200740!13361070!13829415!82355364!28532639!78654804!% 78962218!68965380!}% \@namedef{CALX_Lt-46}{461061!25576832!44585944!93850963!82012232!98750504!% 86693267!16816596!04522306!42599572!56572951!19372559!19461856!50853149!% 72783811!34580548!}% \@namedef{CALX_Lt-45}{451015!54778860!70570175!86891313!09638167!65304806!% 67819341!93678992!55221989!83029736!60141289!98088856!15583928!75485092!% 95640477!14382245!}% \@namedef{CALX_Lt-44}{440970!84887001!13079050!13276372!42639081!16419854!% 87160539!69958933!66674152!56921375!70707905!21785840!75481818!23234704!% 56638634!17006749!}% \@namedef{CALX_Lt-43}{430927!15880984!32677630!82674781!43653050!62767771!% 58885159!77371495!43641380!50362678!65687635!43863370!46212753!27236656!% 76466277!16222121!}% \@namedef{CALX_Lt-42}{420884!47740547!00608191!71856149!14053422!92737182!% 85186753!41060052!13655284!43883044!21125485!54812625!62870188!76381407!% 28906642!34145098!}% \@namedef{CALX_Lt-41}{410842!80445431!98544928!41295471!67424350!14335973!% 66300420!37155716!41114732!97677835!06367836!01264693!38324131!66866080!% 29643175!48122949!}% \@namedef{CALX_Lt-40}{400802!13975388!18348792!66092284!33289755!00582679!% 82259793!59858873!39857301!98506843!67842219!09491651!99692597!76229563!% 08879610!78730834!}% \@namedef{CALX_Lt-39}{390762!48310170!61822449!73786658!36320641!67674955!% 15626246!15291290!37953584!17202886!41515383!19551790!17064542!07265281!% 15109350!14779210!}% \@namedef{CALX_Lt-38}{380723!83429540!40465358!81659365!55365109!28149677!% 38291516!81454275!63412613!18422060!91908758!09066602!86527107!31799415!% 17033879!68443441!}% \@namedef{CALX_Lt-37}{370686!19313264!75228976!26108742!07187905!42696002!% 04301184!05770254!22840356!21070758!06135929!04917745!93839003!05014439!% 81173975!04744956!}% \@namedef{CALX_Lt-36}{360649!55941116!96272081!76701987!22149973!77430863!% 13975964!33137680!58680347!32072955!85869124!68444888!60748530!27797458!% 95249318!89809424!}% \@namedef{CALX_Lt-35}{350613!93292876!42716227!27503832!83580923!46839881!% 43818445!44063582!72070751!21036324!08603957!00615547!22507922!47510632!% 69760565!80389381!}% \@namedef{CALX_Lt-34}{340579!31348328!62401308!58290714!89676019!72015814!% 88014777!66755111!36389036!79454316!83260599!35220043!43432535!95136250!% 56476010!96416986!}% \@namedef{CALX_Lt-33}{330545!70087265!11641259!58263770!66761126!34161786!% 88978206!21939114!68640439!48115807!63797865!02533387!25840458!55739861!% 47534168!77040521!}% \@namedef{CALX_Lt-32}{320513!09489483!54979869!04879172!16090606!60300359!% 25033508!45038386!71182195!29910554!42858134!61835371!17318951!53516542!% 29163544!07131831!}% \@namedef{CALX_Lt-31}{310481!49534787!64946719!90419490!13350714!70069972!% 70046123!68877017!14752570!18367869!93807272!67321581!51788429!67088460!% 15076705!86315976!}% \@namedef{CALX_Lt-30}{300450!90202987!21813250!88934962!01110315!32002627!% 33817267!62979648!89868993!66290844!38843128!50075526!84354940!01172005!% 83374650!12888709!}% \@namedef{CALX_Lt-29}{290421!31473898!13348940!56188712!19967305!23275664!% 22314178!31838854!84160989!79516208!47854995!33674780!44681891!08724277!% 34588987!52253576!}% \@namedef{CALX_Lt-28}{280392!73327342!34577613!55245144!14457954!04622376!% 81157408!91188750!12722664!30153329!89215094!11820793!07547623!17958158!% 48720328!66984024!}% \@namedef{CALX_Lt-27}{270365!15743147!87533869!00345890!25302230!46900626!% 01373266!92832241!18745096!99073445!76671269!35352216!93812142!33923980!% 27930793!83865735!}% \@namedef{CALX_Lt-26}{260338!58701148!81019631!11722868!40625359!43290820!% 00880376!06955235!70411073!77110391!80622357!61997714!49874623!19979881!% 02407651!19212023!}% \@namedef{CALX_Lt-25}{250313!02181185!30360821!74003152!25798312!48697274!% 31700157!59711009!37565605!25921886!83082884!26954690!46018986!61736331!% 54725731!07638112!}% \@namedef{CALX_Lt-24}{240288!46163103!57164154!90865516!84851242!56452630!% 02664765!79159588!24469617!78948700!22954397!26467283!42119836!14280141!% 69311058!26368745!}% \@namedef{CALX_Lt-23}{230264!90626755!89074053!28613671!26407233!57318515!% 64123216!01201320!41416062!71215865!45134884!55843429!26555945!80371652!% 09301888!30521394!}% \@namedef{CALX_Lt-22}{220242!35552000!59529686!41336336!14131970!28416893!% 12851928!46283775!00775954!81340044!33676481!50474888!73255161!73903593!% 38947703!65108822!}% \@namedef{CALX_Lt-21}{210220!80918702!07522130!70329465!76170496!08663622!% 10073816!78025748!90545313!36748334!07145012!07006197!54615794!91684630!% 32228317!32253884!}% \@namedef{CALX_Lt-20}{200200!26706730!77351651!10461052!30317193!49408528!% 27793340!24730508!63971963!17752605!12137547!44880370!22030667!72305768!% 01438630!45568933!}% \@namedef{CALX_Lt-19}{190180!72895963!18385104!36164083!52111200!20700248!% 95563545!57034090!54648246!05987247!40125567!92808426!60770587!05723622!% 22559384!14077957!}% \@namedef{CALX_Lt-18}{180162!19466281!84813463!79748354!72037995!01845251!% 94774779!78879944!81342291!40529640!71382010!71285021!53390563!38104823!% 53186177!49955751!}% \@namedef{CALX_Lt-17}{170144!66397575!35409465!54726961!35919813!88280100!% 22941920!59873765!88050098!89352496!80392071!36836153!41598347!19813803!% 81826100!08120769!}% \@namedef{CALX_Lt-16}{160128!13669738!33285376!16858419!99763476!46377050!% 09330301!41316836!22182502!40883304!98238917!86132822!11547463!10668458!% 58921290!25378125!}% \@namedef{CALX_Lt-15}{150112!61262671!45650881!55610482!57174335!68336188!% 52621857!47726216!73561757!05045043!71389875!78527844!47645493!95402384!% 27322774!29225713!}% \@namedef{CALX_Lt-14}{140098!09156281!43571097!08756822!14309254!69878679!% 19847067!60134167!50571685!78790676!13223829!47993661!20146366!04847537!% 70142728!67509440!}% \@namedef{CALX_Lt-13}{130084!57330481!01724698!92822877!34599244!48395095!% 59953540!98869842!14475937!72285150!62547601!46981437!09977414!36750829!% 77554949!21715236!}% \@namedef{CALX_Lt-12}{120072!05765188!98162176!42102247!73492767!98912938!% 19071253!33295176!83794905!43346957!46954920!59069383!18716765!99137776!% 45447730!31723807!}% \@namedef{CALX_Lt-11}{110060!54440330!14064205!48970133!12622471!36903992!% 28432293!72379366!09777110!46844572!85860766!71512217!40100007!99981865!% 44220718!33447946!}% \@namedef{CALX_Lt-10}{100050!03335835!33500142!98225406!83449607!55205250!% 43440925!09880207!97245202!38586947!46881228!17155429!96788018!43126380!% 89481287!34298441!}% \@namedef{CALX_Lt-9}{90040!52431641!43186641!88198005!42959672!29943485!% 50738554!58462760!79581942!48342852!60099601!00272009!73785678!68520851!% 73395909!49944067!}% \@namedef{CALX_Lt-8}{80032!01707691!32246387!31363406!28737409!38810305!% 25378310!28346523!44014370!23745105!93984628!62872708!36340931!53335882!% 41562714!35592633!}% \@namedef{CALX_Lt-7}{70024!51143933!91966953!27211048!78106623!25063859!% 67262590!53728599!07061816!82540631!97990052!42185665!05230457!64343152!% 02267551!10920163!}% \@namedef{CALX_Lt-6}{60018!00720324!15559780!00118635!46347060!42718791!% 14255264!68385248!26403392!91744966!35038991!47359499!79100643!54240016!% 51001127!42376027!}% \@namedef{CALX_Lt-5}{50012!50416822!97919271!94989326!02663514!53209785!% 57440037!73996927!49289687!18964788!51259409!49714909!34584454!81481845!% 57016951!30941720!}% \@namedef{CALX_Lt-4}{40008!00213397!35382016!23413909!19947435!42656222!% 36477994!12392134!88556600!24634170!63712345!46338577!72799142!64946031!% 56418209!05395980!}% \@namedef{CALX_Lt-3}{30004!50090020!25486121!53125106!05804477!93944169!% 14731057!00846962!14359465!89361037!58760482!46256368!14043085!76980917!% 60140462!78953450!}% \@namedef{CALX_Lt-2}{20002!00026670!66730677!33516222!48188038!92655810!% 37182939!84597792!85285350!95568687!46570819!02951022!81908997!36091767!% 12775420!80131040!}% \@namedef{CALX_Lt-1}{10000!50003333!58335333!50001428!69643968!35397734!% 57107551!40898657!62716344!75661140!26170224!95986337!46652875!41788906!% 72282471!75672579!}% \@namedef{CALX_Lt1}{-10000!49996666!91664666!83331904!88689365!17935598!% 92892448!73387056!78355083!92592828!09226600!52787111!39025335!33724468!% 86197936!79034935!}% \@namedef{CALX_Lt2}{-19999!99973337!33269343!99817174!85145499!20678205!% 62819400!72553256!29029490!44218709!82064449!60207540!32632732!51802363!% 45109956!45229722!}% \@namedef{CALX_Lt3}{-29996!49910020!24514121!46876534!19207331!86144404!% 35952224!33105306!98330115!73603145!32634782!28501332!85217791!59380648!% 57100042!13598957!}% \@namedef{CALX_Lt4}{-39993!99786730!64619349!09935808!13595613!13473314!% 01869933!53050282!04084771!51941425!25845158!18893465!23422240!47924899!% 96560621!55117039!}% \@namedef{CALX_Lt5}{-49988!49583489!52085936!38441663!57622944!20813660!% 64490956!56636496!32843130!66049255!79484709!80480630!25677973!80057849!% 74594269!12906045!}% \@namedef{CALX_Lt6}{-59983!99280323!84455772!00301268!65746178!40078376!% 80628846!84751742!45454019!29060322!28105253!52043912!23177756!56808678!% 90567499!01260551!}% \@namedef{CALX_Lt7}{-69976!48857266!58072263!07563485!36721782!95151642!% 71789357!64401950!29442757!12716047!18127425!03588078!72079745!05686339!% 06763254!11903431!}% \@namedef{CALX_Lt8}{-79969!98294356!67840994!06164233!19344403!27775433!% 67332262!78044032!71866120!84302271!93521852!68433462!65442111!50513758!% 00644738!66374208!}% \@namedef{CALX_Lt9}{-89960!47571639!06990505!22563681!79397678!61678609!% 14785573!89058515!04544752!32860889!30026124!56112318!12228250!66734017!% 23744085!96255333!}% \@namedef{CALX_Lt10}{-99951!96669164!66833190!60107946!49885392!44937606!% 83344800!29803331!71099675!04234128!04457037!45237799!08784886!77399401!% 06884834!71710048!}% \@namedef{CALX_Lt11}{-109940!45566990!36526315!37952972!33201012!88367961!% 55231107!66831213!98626425!16076951!54934399!87837279!99008250!31828564!% 48505676!77978257!}% \@namedef{CALX_Lt12}{-119929!94245179!02833152!65393300!09994936!99662609!% 35541346!67246993!16084659!30586238!17625399!08670664!48334765!16993109!% 27476628!31799982!}% \@namedef{CALX_Lt13}{-129916!42683799!49884239!44443411!95471288!84750149!% 62632654!13955571!03723744!24673011!91038707!37169063!71947950!53040121!% 67956078!34801201!}% \@namedef{CALX_Lt14}{-139903!90862926!58938751!93524353!70049563!84724859!% 49107635!76711920!35795780!73300475!57703933!60206736!64116859!07354448!% 34347635!54230720!}% \@namedef{CALX_Lt15}{-149888!38762641!08145999!85113326!98120033!63016511!% 11532240!36085017!42950813!78893940!74839087!02268117!35860333!84593890!% 06887819!87858673!}% \@namedef{CALX_Lt16}{-159873!86363029!72307039!90218936!36364538!06014376!% 54570538!15479114!41359387!81013177!25507806!63475913!87503673!48505304!% 73988746!70914897!}% \@namedef{CALX_Lt17}{-169856!33644185!22636408!22549764!22164648!71798553!% 76475742!17089830!02223062!35802389!40008231!12843404!17016878!55342843!% 29393376!47412684!}% \@namedef{CALX_Lt18}{-179839!80586206!26523971!75248930!23335387!43841630!% 02516420!82650467!34722411!92804023!41673063!24512562!81773799!05996591!% 54509168!53965160!}% \@namedef{CALX_Lt19}{-189820!27169197!47296898!43072272!23162562!93919172!% 62058119!84542262!98164765!17209867!52040846!50742726!98308994!76164240!% 30423982!94334152!}% \@namedef{CALX_Lt20}{-199801!73373269!43981746!22892761!09842829!91171092!% 32262238!49246129!77472319!36422281!00206583!70652821!86077681!79639063!% 62673820!82768388!}% \@namedef{CALX_Lt21}{-209780!19178538!71066670!85418734!37284902!97423365!% 75157183!10554312!57479236!48032926!42556105!93134992!07273055!45917480!% 05098666!56016255!}% \@namedef{CALX_Lt22}{-219759!64565127!78263752!11018501!25184741!11778389!% 94901647!99057663!32137531!16643451!48281921!48993308!20984406!94937801!% 04328859!80472034!}% \@namedef{CALX_Lt23}{-229736!09513165!10271438!82548835!70693369!22622945!% 19049793!64519333!52195293!54503449!81560618!62179534!83457165!27473198!% 22642553!41858359!}% \@namedef{CALX_Lt24}{-239713!54002785!06537112!28089834!52209378!87403671!% 31740078!54034261!26937308!70135399!56281129!03423515!78865719!92665932!% 10217602!74161500!}% \@namedef{CALX_Lt25}{-249689!98014128!01019768!06493573!18204752!65925038!% 27465521!87394076!82375555!71009552!44225694!29566093!18140644!77293337!% 74303770!97685651!}% \@namedef{CALX_Lt26}{-259663!41527340!21952816!28658944!70887831!77974707!% 54889012!75507527!19212743!90871221!39672853!34241857!61324827!36228999!% 59115353!70360246!}% \@namedef{CALX_Lt27}{-269637!84522573!91607000!07450014!76275987!96437930!% 93207995!91845274!81956190!86942325!55608966!56007042!64869844!79847083!% 55565953!85721105!}% \@namedef{CALX_Lt28}{-279609!26979987!26053432!29180170!59247506!76487450!% 91450081!84426527!19606664!59005920!97898548!02251108!23143167!80991459!% 41526473!05080183!}% \@namedef{CALX_Lt29}{-289581!68879744!34926750!39589281!74721624!50620150!% 43855866!32752421!88942232!95154733!17513125!29368812!67341631!40273085!% 01085879!14832669!}% \@namedef{CALX_Lt30}{-299551!10202015!21188389!37246026!84631517!54663970!% 11961129!07092679!61225138!96569868!24365567!87428658!17849711!12105237!% 86726325!77972644!}% \@namedef{CALX_Lt31}{-309521!50926975!80889972!67312473!15160898!72260074!% 34656099!25035119!01377923!83147303!95062810!29786787!35005877!61263413!% 42990583!66249130!}% \@namedef{CALX_Lt32}{-319490!91034808!02936821!08612924!20163958!28744014!% 77544215!93692867!19355331!63458808!98577066!65740611!66720013!88239120!% 16250985!25049374!}% \@namedef{CALX_Lt33}{-329457!30505699!68851579!46953975!35133569!55606166!% 39651581!38752784!53299115!84840226!50521533!34981810!25260711!82717202!% 34380636!12754302!}% \@namedef{CALX_Lt34}{-339424!69319844!52537961!27647637!71876485!39998518!% 01828467!40264966!08249805!50253992!00201937!72543394!01850463!80505907!% 36966577!64279468!}% \@namedef{CALX_Lt35}{-349389!07457442!20044610!80194307!77548851!95210130!% 08845564!09026825!22986587!12854729!14342175!31437003!90542724!96472676!% 34316637!13724139!}% \@namedef{CALX_Lt36}{-359354!44898698!29329083!08087272!63252580!70248455!% 38870530!34855349!03361117!92741830!21268999!39716791!69638411!54524904!% 42513819!43883153!}% \@namedef{CALX_Lt37}{-369318!81623824!30021941!36705349!97344419!38143979!% 94947068!42503080!03784511!26707026!93788376!39105776!04421329!46348061!% 62906318!68548974!}% \@namedef{CALX_Lt38}{-379280!17613037!63190972!12265166!57316065!26176947!% 25633904!95642949!93152987!42815451!16688577!41700638!96012381!28375522!% 06458145!24615761!}% \@namedef{CALX_Lt39}{-389242!52846561!61105517!44809480!41916141!62442395!% 07511819!75782869!22551963!10567998!31707588!77585140!03825540!21223288!% 75681474!59559001!}% \@namedef{CALX_Lt40}{-399203!87304625!47000924!88212848!62453729!58581582!% 07048422!29302064!81489177!81446227!44068022!53961987!05532439!58809660!% 98603333!92113591!}% \@namedef{CALX_Lt41}{-409162!20967464!34843114!50190836!59298484!73973286!% 01872581!68651518!24002944!55920514!24365338!88936029!99246003!21604407!% 68473566!07924725!}% \@namedef{CALX_Lt42}{-419121!53815319!29093263!25303853!26823893!95589652!% 21851341!81002329!35262250!98017779!16171579!72444973!87207269!98306304!% 05564628!79252793!}% \@namedef{CALX_Lt43}{-429079!85828437!24472606!43951582!77777316!79189977!% 02118350!82327226!70564200!99394588!89554521!07382550!17631048!69463294!% 18368409!42474018!}% \@namedef{CALX_Lt44}{-439035!16987071!05727356!30358864!36652135!04524022!% 99161719!64561778!58544605!29803339!00239343!15774540!83255901!11209751!% 32315281!92450127!}% \@namedef{CALX_Lt45}{-448991!47271479!47393737!62558750!21432282!24671683!% 55017168!26205022!60973109!09195611!47762208!03717483!71754379!09553403!% 52657963!71596095!}% \@namedef{CALX_Lt46}{-458946!76661927!13563140!27383344!54425974!52490782!% 31232480!93982417!03252976!19268258!90505856!15489698!98579324!82352236!% 31179598!61420896!}% \@namedef{CALX_Lt47}{-468899!05138684!57647388!63477897!36151600!68321748!% 55795930!27751604!35002193!64102071!64225208!42851546!25787363!78859452!% 41035494!48753980!}% \@namedef{CALX_Lt48}{-478852!32682028!22144127!85358492!21732091!61517489!% 91002348!10455491!78203158!49112000!94872990!95852652!77210463!80838905!% 64167844!55863977!}% \@namedef{CALX_Lt49}{-488804!59272240!38402326!81538529!57341970!46821567!% 13507223!36151916!74614307!37763687!86270870!62475558!86104662!32994524!% 90295001!04872996!}% \@namedef{CALX_Lt50}{-498755!84889609!26387897!79754065!65280632!79650573!% 15641731!48573470!15776042!57770381!25653277!94540857!71090400!48287745!% 25303061!14936045!}% \@namedef{CALX_Lt51}{-508704!09514428!94449432!72322921!10562822!66063535!% 09160159!80806124!95011244!67561603!58330282!52236663!66886243!60758057!% 34584392!89869079!}% \@namedef{CALX_Lt52}{-518653!33126999!39084055!94677324!39869013!75089511!% 11857136!36988901!33870994!62760910!69151294!06741456!64758648!59601462!% 14679418!50776616!}% \@namedef{CALX_Lt53}{-528601!55707626!44703393!50114701!55630387!19685687!% 25578800!50557057!84966278!63124313!10680693!03734537!64349642!05982279!% 30648903!08123941!}% \@namedef{CALX_Lt54}{-538548!77236621!83399658!73816066!74280888!77235342!% 34574062!21163218!02468950!41180663!31099444!29434884!04927355!94369713!% 88291708!01700580!}% \@namedef{CALX_Lt55}{-548494!97694303!14711854!29186307!18637673!00905796!% 05120648!85591135!65689110!33838396!13883670!11187767!42048708!27778611!% 96916115!97918011!}% \@namedef{CALX_Lt56}{-558438!17060993!85392090!29575491!10315982!27121117!% 75627123!32229002!57345994!67337600!37438820!97353639!89732423!10768246!% 94203830!48452284!}% \@namedef{CALX_Lu-5100}{5100!13005442!18691369!25798304!28407466!59720605!% 10398581!56934406!17114698!24490037!55735647!44712033!71107581!74606828!% 42495774!03161169!}% \@namedef{CALX_Lu-5000}{5000!12500416!68229229!16927094!49453592!19999845!% 43399175!65250398!69664800!24170272!64816892!16689712!88251109!15433720!% 20118585!39054382!}% \@namedef{CALX_Lu-4900}{4900!12005392!17774590!08069011!14266647!04264023!% 91935611!52798808!92577480!46329302!64567924!69821812!55322584!78819228!% 31016520!54460521!}% \@namedef{CALX_Lu-4800}{4800!11520368!65327154!96283211!56144285!99206763!% 26830753!97377255!68364003!60275346!21940715!38801320!23555248!27910085!% 32245936!15615617!}% \@namedef{CALX_Lu-4700}{4700!11045346!08886632!78746467!49325413!63233429!% 65534594!93823434!55221984!30613136!78957246!00330863!11352129!50210663!% 76238381!81495733!}% \@namedef{CALX_Lu-4600}{4600!10580324!46452738!52750764!50781713!70570236!% 45347529!38165156!43056153!52260319!40132188!77839342!29081784!10940776!% 52291025!83258240!}% \@namedef{CALX_Lu-4500}{4500!10125303!76025193!15700901!43209524!21181431!% 70889180!37999502!19370650!32023574!07515510!78085486!84107389!08505702!% 73192509!58049490!}% \@namedef{CALX_Lu-4400}{4400!09680283!95603723!65112089!79222050!96255123!% 85388018!15268998!32620598!83327874!63012880!40830224!86750471!65976122!% 32725744!92362713!}% \@namedef{CALX_Lu-4300}{4300!09245265!03188062!98607553!26741912!39023342!% 04911116!15374049!42521427!11789287!39007805!34524165!79011600!41564381!% 17333285!15867599!}% \@namedef{CALX_Lu-4200}{4200!08820246!96777950!13916127!15594008!40686969!% 40163798!05880025!55877122!36450432!45324797!86788830!57268502!01695196!% 54326298!93127479!}% \@namedef{CALX_Lu-4100}{4100!08405229!74373130!08869857!85298706!11221229!% 11965688!69414066!19090823!91316685!40189646!14934408!45527875!43505135!% 61020102!77290190!}% \@namedef{CALX_Lu-4000}{4000!08000213!33973353!81401602!34065335!14842445!% 43952825!99134192!14339716!63045344!62697413!12872087!76876188!80017098!% 02844059!09060423!}% \@namedef{CALX_Lu-3900}{3900!07605197!73578378!29542627!68985985!49921842!% 89465056!21788771!48335804!62130552!76032495!29963406!65673176!29466153!% 80492490!81642636!}% \@namedef{CALX_Lu-3800}{3800!07220182!91187966!51420210!57429600!53137189!% 18953957!33228517!56725220!66002179!38588023!12925201!77999426!78250648!% 03013617!50873644!}% \@namedef{CALX_Lu-3700}{3700!06845168!84801887!45255236!79636358!07658128!% 59589051!64610456!02674764!15847952!54226203!05042739!72238271!06509561!% 23268773!76469883!}% \@namedef{CALX_Lu-3600}{3600!06480155!52419916!09359800!82512332!35166094!% 40049115!34731825!97268889!87190475!23249344!12337821!91750931!15860093!% 10956595!32393798!}% \@namedef{CALX_Lu-3500}{3500!06125142!92041833!42134805!34624429!51514730!% 50761005!15203518!67183390!99957571!02195407!01826201!26781641!33714984!% 49038022!22031007!}% \@namedef{CALX_Lu-3400}{3400!05780131!01667426!42067560!82395589!65841793!% 83090637!70732940!19815969!24732638!30904611!07455141!15106431!50232686!% 02420995!60873763!}% \@namedef{CALX_Lu-3300}{3300!05445119!79296488!07729385!07500248!02948550!% 60199611!66814345!48589117!21124756!49758220!52067555!22667238!01374295!% 45785201!63497418!}% \@namedef{CALX_Lu-3200}{3200!05120109!22928817!37773202!85460048!28767721!% 17456491!91763659!25230539!16188168!91838508!46007499!27138146!97770645!% 21360743!53179630!}% \@namedef{CALX_Lu-3100}{3100!04805099!30564219!30931145!45439800!58746069!% 31434016!49391201!27931443!93892739!80596078!35782321!32357363!67113310!% 96898417!73214943!}% \@namedef{CALX_Lu-3000}{3000!04500090!00202504!86012150!31243677!28972773!% 33632475!72749894!23485700!22709856!66881480!12899213!13488406!13335896!% 91799216!14250705!}% \@namedef{CALX_Lu-2900}{2900!04205081!29843491!01899560!63511639!09889757!% 78145286!18362474!49510363!90283205!57523571!43019398!71795160!44134752!% 73545288!06043005!}% \@namedef{CALX_Lu-2800}{2800!03920073!17487000!77548725!03116084!42425205!% 61525375!54116671!83845944!91424852!02369622!04013198!26845952!71220029!% 25976371!56437759!}% \@namedef{CALX_Lu-2700}{2700!03645065!61132863!11984597!15758714!76396512!% 18120444!82583692!98889224!79215866!60891219!52522232!48956286!67471771!% 79771311!88959262!}% \@namedef{CALX_Lu-2600}{2600!03380058!58780913!04299335!37767608!91033983!% 35121517!74787756!77961616!15379452!88195574!13609938!41849842!78872751!% 08269315!84187312!}% \@namedef{CALX_Lu-2500}{2500!03125052!08430991!53649902!43094498!77481621!% 48512459!57321705!00215678!52118758!85172012!57418254!94765583!60516679!% 75773780!18804078!}% \@namedef{CALX_Lu-2400}{2400!02880046!08082945!59255665!11512239!63136383!% 94018386!28018372!83630904!65627014!14849142!96608763!01514875!55046599!% 78136175!09018992!}% \@namedef{CALX_Lu-2300}{2300!02645040!55736628!20395993!98012467!57692339!% 96028125!01965666!78123124!46243341!57084582!78696571!99926184!99281518!% 30772861!42331849!}% \@namedef{CALX_Lu-2200}{2200!02420035!49391898!36407863!03403437!00761192!% 82310165!40275087!90572331!67828420!56186460!55227354!51782951!50055804!% 18433831!49814072!}% \@namedef{CALX_Lu-2100}{2100!02205030!87048621!06683449!46108030!90945675!% 13152894!18422377!10580286!08415852!15074848!90583691!59983652!76791134!% 55793632!34295911!}% \@namedef{CALX_Lu-2000}{2000!02000026!66706667!30667733!35161936!76247366!% 10338369!78882371!81886372!52534463!48747004!32211487!87821185!13646769!% 87618367!33073605!}% \@namedef{CALX_Lu-1900}{1900!01805022!86365914!07856097!44411980!85695520!% 64104504!13849077!43376804!26630485!96428492!67696578!99041631!96610589!% 52699877!87750779!}% \@namedef{CALX_Lu-1800}{1800!01620019!44026244!37791926!87914613!82088540!% 84963313!67701101!21119941!16952594!36785112!49550642!33422745!03169251!% 30066109!95253189!}% \@namedef{CALX_Lu-1700}{1700!01445016!37687547!20064208!96534540!15744761!% 51922915!65140404!66201373!37386546!78616220!52863463!76675113!16995365!% 76367149!19791869!}% \@namedef{CALX_Lu-1600}{1600!01280013!65349717!54305132!95743484!59164261!% 89308215!89160938!21346479!79953071!11910241!63453639!05225037!35039224!% 07482944!70844425!}% \@namedef{CALX_Lu-1500}{1500!01125011!25012656!40187689!84619088!02508456!% 80989796!82718969!63040110!44540981!05124403!61825214!88813416!44745393!% 82260468!94352242!}% \@namedef{CALX_Lu-1400}{1400!00980009!14676270!77423272!16043925!89809261!% 03412405!58668349!27248667!11143850!18443032!66271178!81479808!96572838!% 98580625!23435671!}% \@namedef{CALX_Lu-1300}{1300!00845007!32340473!65759273!78104641!75824661!% 27363698!03644819!69541978!60046932!49542078!12713098!06232700!12115854!% 75292272!98446152!}% \@namedef{CALX_Lu-1200}{1200!00720005!76005184!04976689!76691188!83462571!% 02940551!82550728!19406221!08230462!80890497!66168543!51401551!03668884!% 35252219!96257744!}% \@namedef{CALX_Lu-1100}{1100!00605004!43670326!94887716!19296172!41699884!% 02654356!20485797!90147331!24409157!23097982!20809623!04323624!43844477!% 16648444!23272745!}% \@namedef{CALX_Lu-1000}{1000!00500003!33335833!35333350!00014285!83928682!% 54068254!87735321!07551344!69426136!14863667!43769358!61920829!41735142!% 47258641!56167620!}% \@namedef{CALX_Lu-900}{900!00405002!43001640!26180988!85741832!86666597!% 45778396!70072328!51094132!62860712!63208696!37504185!02204651!13277243!% 70100975!90861354!}% \@namedef{CALX_Lu-800}{800!00320001!70667690!67322031!03576329!28573357!% 38937874!00426739!50757702!64859456!60770107!39250061!32305467!74089803!% 79928646!30476955!}% \@namedef{CALX_Lu-700}{700!00245001!14333933!58669475!29416176!49720604!% 60876235!88157692!41195527!88005344!09792970!04330774!69805874!96785490!% 31043273!65311981!}% \@namedef{CALX_Lu-600}{600!00180000!72000324!00155520!77760399!91067095!% 97689290!37934388!74802130!07696533!57742775!23200471!92750667!51656847!% 11965418!00327297!}% \@namedef{CALX_Lu-500}{500!00125000!41666822!91729166!92708444!94096447!% 38963391!30748754!48736199!37506307!64384094!61516092!79383865!19079005!% 38658963!55571249!}% \@namedef{CALX_Lu-400}{400!00080000!21333397!33353813!40160023!40579620!% 60055578!73976638!41444282!54174886!12344131!15533192!08108349!51944831!% 64112451!28337321!}% \@namedef{CALX_Lu-300}{300!00045000!09000020!25004860!01215003!12429391!% 55575843!44763446!75745585!57393927!37095315!21565352!73392677!48173349!% 90866655!62230970!}% \@namedef{CALX_Lu-200}{200!00020000!02666670!66667306!66773333!51619079!% 61910450!80389081!22690096!02371817!81044648!33000077!80369192!81924379!% 55038641!17400254!}% \@namedef{CALX_Lu-100}{100!00005000!00333333!58333353!33335000!00142857!% 26785725!39683539!68344877!42821075!51338265!62393229!05572905!20525781!% 96366122!06008490!}% \@namedef{CALX_Lu100}{-100!00004999!99666666!91666646!66668333!33190476!% 31547607!93651793!64988456!07178924!48663162!94749628!21212809!08046757!% 71887846!29388334!}% \@namedef{CALX_Lu200}{-200!00019999!97333337!33332693!33439999!81714317!% 71422882!54992252!10643919!97628182!42361065!95579542!76773667!23632445!% 84748756!10853752!}% \@namedef{CALX_Lu300}{-300!00044999!91000020!24995140!01214996!87572248!% 69424157!73334553!24342987!92606140!95717541!98101201!67683055!76179510!% 72097498!76625740!}% \@namedef{CALX_Lu400}{-400!00079999!78666730!66646186!73493309!92770096!% 73277775!56508694!94685253!45828948!66878731!35623434!21226628!79350236!% 12447153!31274181!}% \@namedef{CALX_Lu500}{-500!00124999!58333489!58270833!59374888!39334542!% 19370137!33834579!25287238!12580885!43651810!40541664!32644517!12663187!% 44187855!37099000!}% \@namedef{CALX_Lu600}{-600!00179999!28000323!99844480!77759600!09352808!% 02311918!94417614!87994925!93422954!48112179!72680828!49979009!78810739!% 89195702!34902476!}% \@namedef{CALX_Lu700}{-700!00244998!85667266!91330528!62747156!85053928!% 97462746!95673663!99019005!71683556!94318571!11990606!36178547!05727887!% 10184475!83515116!}% \@namedef{CALX_Lu800}{-800!00319998!29334357!32677977!70237004!08954279!% 94416934!16554708!35821753!97969779!26873164!89983629!41963696!76274240!% 55717926!48548661!}% \@namedef{CALX_Lu900}{-900!00404997!57001640!23819028!85728167!24095082!% 79291338!98730142!20495284!13950608!17623293!14690400!85608294!24363930!% 53687960!24069961!}% \@namedef{CALX_Lu1000}{-1000!00499996!66669166!64666683!33319047!74404650!% 79465078!45599678!92448669!59145292!54779189!70627466!77762710!26518834!% 87229093!00939162!}% \@namedef{CALX_Lu1100}{-1100!00604995!56336993!55112342!85907161!45223169!% 56197725!62054766!14582176!50588465!96112037!27040379!95793334!20494497!% 64999246!34306910!}% \@namedef{CALX_Lu1200}{-1200!00719994!24005183!95023409!76588812!24032852!% 98297795!45912131!97335338!33461890!20020540!27240585!20011701!97169779!% 28234970!32780817!}% \@namedef{CALX_Lu1300}{-1300!00844992!67673806!84240887!11258693!61441352!% 33726805!13425343!77978997!38187157!24070112!04822284!42431479!28154485!% 58258161!95336837!}% \@namedef{CALX_Lu1400}{-1400!00979990!85342937!22576978!82409411!12471336!% 35706020!84711473!91482136!31810827!86878640!07331196!99475059!61818465!% 08874389!12864819!}% \@namedef{CALX_Lu1500}{-1500!01124988!75012656!09812689!84130918!38214199!% 55543210!98747274!26612497!47259463!77707471!23639179!30579781!13152016!% 45166198!28245213!}% \@namedef{CALX_Lu1600}{-1600!01279986!34683050!45695426!28309859!47910895!% 66015350!00193520!08115590!14247701!29285570!03519128!62558691!47693580!% 50569664!47267542!}% \@namedef{CALX_Lu1700}{-1700!01444983!62354213!29936595!62028810!61527932!% 46730295!70061965!73360974!10136338!63486496!82345750!16902240!48983959!% 44618228!09355174!}% \@namedef{CALX_Lu1800}{-1800!01619980!56026243!62209206!86165413!72901603!% 86446030!87474951!09171299!59728667!64091659!10839664!70370352!13484619!% 04875984!35168384!}% \@namedef{CALX_Lu1900}{-1900!01804977!13699246!42145470!75191394!93528574!% 16850154!38775114!09915033!04598589!32654296!83226402!12181421!35158539!% 90196824!05012387!}% \@namedef{CALX_Lu2000}{-2000!01999973!33373332!69334399!98171460!57085969!% 27794963!61277628!18347684!61759442!79824715!52042490!86151640!64165806!% 18397338!62071812!}% \@namedef{CALX_Lu2100}{-2100!02204969!13048619!43319409!40962063!64769168!% 45444725!50239335!41780904!54923765!79618654!55448198!20428751!58990711!% 74808263!64931610!}% \@namedef{CALX_Lu2200}{-2200!02419964!50725229!63595916!29610033!51540529!% 82221623!97331249!82158035!93258190!32177011!29387843!84659190!03379759!% 26587616!69415317!}% \@namedef{CALX_Lu2300}{-2300!02644959!44403292!29608940!54951061!53387321!% 90835432!95190040!62203048!51326726!77094337!35918358!89589274!86426591!% 11865202!23363042!}% \@namedef{CALX_Lu2400}{-2400!02879953!92082942!40750704!98408035!55692172!% 74049233!63600872!92050294!21998280!00470150!16783845!75625729!92352206!% 25302480!93069732!}% \@namedef{CALX_Lu2500}{-2500!03124947!91764320!96358235!58989216!02824387!% 17169507!56602703!01004602!26523981!46193747!06699515!49685036!60853203!% 40794443!56468997!}% \@namedef{CALX_Lu2600}{-2600!03379941!41447574!95710961!81486246!49065522!% 21553730!24345837!74867790!52355615!70427181!25354289!84769471!23326555!% 29919859!70734334!}% \@namedef{CALX_Lu2700}{-2700!03644934!39132857!38028316!85871991!30987649!% 24702199!56872032!66241912!87945676!20460910!50247010!56742353!93489901!% 32600800!99066830!}% \@namedef{CALX_Lu2800}{-2800!03919926!82820327!22467337!97898193!41407770!% 95743295!57095103!57031236!79358506!41108059!12159264!00159200!97650196!% 19490506!02949955!}% \@namedef{CALX_Lu2900}{-2900!04204918!70510149!48120266!80892944!85046899!% 94332719!05064164!60576128!58213439!11212132!75446839!35423754!86989764!% 58475290!77178382!}% \@namedef{CALX_Lu3000}{-3000!04499910!00202495!14012149!68757962!96027344!% 76167533!12985106!44842428!39813840!60334701!36707083!28058303!83310134!% 54385120!54991741!}% \@namedef{CALX_Lu3100}{-3100!04804900!69897541!19098438!00165664!97346788!% 19465069!58315439!44961697!54068568!08537486!60993470!47769671!06547933!% 29093061!06386046!}% \@namedef{CALX_Lu3200}{-3200!05119890!77595470!62262588!53956033!82472781!% 33874997!48353516!77899902!80600708!17518124!08497183!21612910!38713776!% 25802475!87611100!}% \@namedef{CALX_Lu3300}{-3300!05444880!21296472!42313663!85733267!99206315!% 96380121!41899515!36384331!07654353!15219054!45857176!51302881!07057038!% 14649415!01349552!}% \@namedef{CALX_Lu3400}{-3400!05779868!99000741!57983932!65662208!15968176!% 37797816!59520203!23134537!20119536!12697617!60110549!28783560!68419162!% 14778284!28135322!}% \@namedef{CALX_Lu3500}{-3500!06124857!08708479!07926470!17464533!50666810!% 78519454!81414000!66953636!04420424!67084829!96643924!98751382!51122185!% 47507912!03822940!}% \@namedef{CALX_Lu3600}{-3600!06479844!48419891!90712758!58614720!42311500!% 83119764!88522413!33611386!33218724!43095557!56523058!40815957!73658194!% 95839217!81101975!}% \@namedef{CALX_Lu3700}{-3700!06844831!16135193!04830287!41735756!45539646!% 70431839!76007566!58101778!88299636!56867695!66743361!87136227!88405207!% 79249927!19437550!}% \@namedef{CALX_Lu3800}{-3800!07219817!09854601!48680153!97194602!28232023!% 78616486!86116015!29239577!68385790!31863649!12777708!30064790!19970247!% 08389847!16809843!}% \@namedef{CALX_Lu3900}{-3900!07604802!27578342!20574663!76897394!52394905!% 43656853!97342681!38070651!62087238!33491702!82495219!19223915!72542626!% 67955122!52670513!}% \@namedef{CALX_Lu4000}{-4000!07999786!67306646!18734930!99284382!18492985!% 04580786!96225846!20452517!30968425!27943275!41805568!20753069!09654435!% 30386890!45392240!}% \@namedef{CALX_Lu4100}{-4100!08404770!27039750!41288478!95524589!53422068!% 99554223!74538488!60401225!40179185!11015801!61032838!73090375!77930823!% 69404791!40010380!}% \@namedef{CALX_Lu4200}{-4200!08819753!04777897!86266840!56910198!22315550!% 63799137!65550528!10029455!98791415!13775989!89995073!35513666!92369499!% 02766319!91765737!}% \@namedef{CALX_Lu4300}{-4300!09244734!98521337!51603158!83450641!44383713!% 83069148!85842051!56292372!62150376!53939666!71391270!64641336!01882048!% 36127549!82539067!}% \@namedef{CALX_Lu4400}{-4400!09679716!06270324!35129787!33666402!92989952!% 95164961!11234441!92927988!09885350!17176393!90993126!72171505!68976160!% 71089589!03653678!}% \@namedef{CALX_Lu4500}{-4500!10124696!26025119!34575890!75582513!60173034!% 66690289!14123288!82882850!91425845!57613290!34930439!47922907!23687734!% 31313934!93716835!}% \@namedef{CALX_Lu4600}{-4600!10579675!55785989!47565045!38921738!65829565!% 02936955!52156570!83344510!03615240!72605519!62417973!42989480!09245986!% 65186531!94307151!}% \@namedef{CALX_Lu4700}{-4700!11044653!93553207!71612839!68497447!91775863!% 75445391!52080113!69586772!58995595!15309567!10384865!29564302!29392566!% 17285682!79245575!}% \@namedef{CALX_Lu4800}{-4800!11519631!37327053!04124474!78806162!20913485!% 74413910!04909733!48530811!36967630!30797771!18840195!65301077!66411119!% 24144835!06751482!}% \@namedef{CALX_Lu4900}{-4900!12004607!85107810!42392365!09819768!61727668!% 11726867!06589482!47520754!62444668!82130496!06093773!02782405!36002709!% 27427772!04172801!}% \@namedef{CALX_Lu5000}{-5000!12499583!34895770!83593738!83977397!38353019!% 14938226!69125473!23415747!63601812!14807063!30238573!94514879!55879584!% 18153093!93366937!}% \@namedef{CALX_Lu5100}{-5100!13004557!84691231!24788238!64376953!26445803!% 63083131!17976037!02539314!37766571!58799779!64229096!20416974!57931196!% 01965236!41122723!}% \@namedef{CALX_Lv-51}{51!00001300!50044217!01691300!94005079!52715915!% 51582617!24236246!74584275!16289244!82079549!59005935!53687449!52795747!% 43134993!57035449!}% \@namedef{CALX_Lv-50}{50!00001250!00041666!68229167!29166692!70834449!% 40525018!62289187!48449945!18287568!41668124!67070556!26326351!57654522!% 85062621!35452203!}% \@namedef{CALX_Lv-49}{49!00001200!50039216!34774534!14828406!20215502!% 39051948!18130549!36504573!95256679!16117477!45773743!77310202!70029491!% 09030805!22823594!}% \@namedef{CALX_Lv-48}{48!00001152!00036864!01327104!50960813!98432582!% 66941262!97270813!31975293!86806511!10085234!75874526!56337476!10633064!% 88536624!88754870!}% \@namedef{CALX_Lv-47}{47!00001104!50034607!67886587!37535686!03203278!% 58094592!16838103!71634382!78937949!35748025!75571656!99618109!51095304!% 65336283!41559047!}% \@namedef{CALX_Lv-46}{46!00001058!00032445!34452697!74525944!32383438!% 59690376!09696505!30336374!61919476!39996745!79058995!13816407!88155796!% 75797285!43505587!}% \@namedef{CALX_Lv-45}{45!00001012!50030375!01025156!61905638!83961471!% 31371465!34371727!59218053!56010982!37017590!91562318!30152274!40690050!% 25505980!66759942!}% \@namedef{CALX_Lv-44}{44!00000968!00028394!67603690!99649923!56052765!% 44466559!90544716!22063507!18244630!42893156!83349332!01728687!97942495!% 31578629!11645079!}% \@namedef{CALX_Lv-43}{43!00000924!50026502!34188033!87735032!46894229!% 81244768!39878850!86231457!44395216!57940801!77968146!73983086!66475989!% 28265000!52894989!}% \@namedef{CALX_Lv-42}{42!00000882!00024696!00777924!26138255!54838953!% 34202567!31951409!26396812!64321052!67034482!82467509!64147094!47613915!% 19565105!95521612!}% \@namedef{CALX_Lv-41}{41!00000840!50022973!67373107!14837914!78350985!% 05382440!35065017!01172786!96393912!95056611!48268841!16541085!77784625!% 04883859!52522283!}% \@namedef{CALX_Lv-40}{40!00000800!00021333!33973333!53813340!16000234!% 05722477!71719842!64454017!78125900!27194541!73160459!85173155!52589625!% 21216035!50991086!}% \@namedef{CALX_Lv-39}{39!00000760!50019773!00578360!43044845!66457489!% 54436215!58532337!75054874!25705089!41699688!13730779!70284467!08518610!% 87845602!93435417!}% \@namedef{CALX_Lv-38}{38!00000722!00018290!67187950!82513705!28489560!% 78421995!50391361!69910593!95333373!62004742!93226891!22226279!18480906!% 16330795!89746155!}% \@namedef{CALX_Lv-37}{37!00000684!50016884!33801873!72202129!00954537!% 11701123!88647570!67762007!24381957!68155970!85626621!26749490!26522224!% 96809909!57018641!}% \@namedef{CALX_Lv-36}{36!00000648!00015552!00419904!12093238!82797167!% 94884111!53136990!71857412!20805288!63144244!99403412!02278400!11048695!% 41568626!43636578!}% \@namedef{CALX_Lv-35}{35!00000612!50014291!67041823!02171044!73044362!% 74664273!17844734!41777645!45345774!13062665!24167339!12449500!16904852!% 22932790!59173849!}% \@namedef{CALX_Lv-34}{34!00000578!00013101!33667417!42420420!70800811!% 03337967!10019861!06022556!93182291!12603777!13488137!65240044!51051033!% 02586098!11390282!}% \@namedef{CALX_Lv-33}{33!00000544!50011979!00296480!32827080!75244722!% 38350754!72557419!88488939!30188114!07130270!94352704!52309944!06109418!% 02289572!03589190!}% \@namedef{CALX_Lv-32}{32!00000512!00010922!66928810!73377554!85623686!% 41868760!29468756!23421484!74231374!63675462!57602308!79563420!98414116!% 32689714!18425984!}% \@namedef{CALX_Lv-31}{31!00000480!50009930!33564213!64059165!01250652!% 80374510!54266200!34829544!34336384!56390897!77089386!58244198!62716575!% 18551577!83972458!}% \@namedef{CALX_Lv-30}{30!00000450!00009000!00202500!04860001!21500031!% 24286534!41093298!57733347!30389991!44166323!93896623!20059195!87044067!% 17579458!65270786!}% \@namedef{CALX_Lv-29}{29!00000420!50008129!66843486!95768897!45803911!% 47602002!78436786!79933899!13786474!92781470!74345877!59033394!93435816!% 30300575!65061901!}% \@namedef{CALX_Lv-28}{28!00000392!00007317!33486997!36775407!73648403!% 27561688!25261545!84291019!95320209!50760188!58049738!56479075!48065392!% 55741038!02675081!}% \@namedef{CALX_Lv-27}{27!00000364!50006561!00132860!27869782!04570096!% 44336524!89414818!72743905!61120300!43207318!08983942!90442674!03475418!% 55095156!02404114!}% \@namedef{CALX_Lv-26}{26!00000338!00005858!66780910!69042942!38152640!% 80735048!08151009!54518196!20838523!13810195!65162776!79562370!86311673!% 49391172!20857707!}% \@namedef{CALX_Lv-25}{25!00000312!50005208!33430989!60286458!74023446!% 21930994!30633423!82132817!85014044!30744119!30195539!60262428!61539695!% 31611220!43847766!}% \@namedef{CALX_Lv-24}{24!00000288!00004608!00082944!01592525!11850502!% 55210341!02274350!19948825!10908455!82669774!64456100!97078730!86436886!% 10415637!66421357!}% \@namedef{CALX_Lv-23}{23!00000264!50004055!66736626!92953935!51339319!% 69737066!50779923!31091112!88495492!27957107!78844709!75798052!94056499!% 67757656!72122497!}% \@namedef{CALX_Lv-22}{22!00000242!00003549!33391897!34364059!92229987!% 56336909!73771247!69622187!61064309!21692177!76482883!82906478!26202750!% 48697368!70441522!}% \@namedef{CALX_Lv-21}{21!00000220!50003087!00048620!25816820!34294356!% 07298410!27858302!65855188!88416254!25270059!35682906!78312092!76014740!% 30475516!73991849!}% \@namedef{CALX_Lv-20}{20!00000200!00002666!66706666!67306666!77333335!% 16190508!19048187!93661033!65265546!93168023!71817705!12055274!50843034!% 83970985!08491804!}% \@namedef{CALX_Lv-19}{19!00000180!50002286!33365913!58828553!21174314!% 77695983!94374310!09551916!03557077!17920313!68966161!30317246!82856156!% 54887174!59033698!}% \@namedef{CALX_Lv-18}{18!00000162!00001944!00026244!00377913!65668704!% 87460018!34638149!54210436!75352516!80841359!09058593!88060222!55722002!% 36578660!83852421!}% \@namedef{CALX_Lv-17}{17!00000144!50001637!66687546!91950638!10689595!% 41953152!48160288!07980356!93071994!82501941!23203349!94715318!03395502!% 84261594!96918200!}% \@namedef{CALX_Lv-16}{16!00000128!00001365!33349717!33543048!56129536!% 38347927!65442416!92641371!76575595!89557503!65232042!96221383!12870931!% 52978830!60513019!}% \@namedef{CALX_Lv-15}{15!00000112!50001125!00012656!25151875!01898437!% 74408485!34647085!12556380!22189783!05835597!61256357!02309307!59776883!% 41185887!42554243!}% \@namedef{CALX_Lv-14}{14!00000098!00000914!66676270!66774231!47921589!% 48392407!17806988!29005487!47691401!24557618!42803440!73323442!67486811!% 83800882!48412918!}% \@namedef{CALX_Lv-13}{13!00000084!50000732!33340473!58407591!94137801!% 58964074!87680637!62206417!39819068!10516997!08048021!68418298!52871573!% 24689173!28865103!}% \@namedef{CALX_Lv-12}{12!00000072!00000576!00005184!00049766!40497664!% 05118830!25176289!16166132!77451383!57651518!60401042!42289900!44852011!% 98480477!34876409!}% \@namedef{CALX_Lv-11}{11!00000060!50000443!66670326!91698876!86961926!% 86117215!17271053!22113261!44536370!26792295!72232552!52640074!88211718!% 35678406!53672972!}% \@namedef{CALX_Lv-10}{10!00000050!00000333!33335833!33353333!33500000!% 01428571!55357143!96825406!82539773!44878178!21075513!37622766!12943279!% 00577894!91612967!}% \@namedef{CALX_Lv-9}{9!00000040!50000243!00001640!25011809!80088573!50683281!% 33952269!12689581!62964182!91395264!74757700!99260877!36361566!17240504!% 92552408!}% \@namedef{CALX_Lv-8}{8!00000032!00000170!66667690!66673220!26710357!33632926!% 49716199!76817843!86739269!57411138!50144407!74337587!50309824!92825111!% 85029121!}% \@namedef{CALX_Lv-7}{7!00000024!50000114!33333933!58336694!73352941!50117649!% 00720600!16983734!39358637!80868099!28188149!36082093!06435330!46817626!% 14583377!}% \@namedef{CALX_Lv-6}{6!00000018!00000072!00000324!00001555!20007776!00039990!% 85924237!72548315!48903760!78695838!07372564!02071423!83854192!44168900!% 09529023!}% \@namedef{CALX_Lv-5}{5!00000012!50000041!66666822!91667291!66669270!83344494!% 04810732!88907490!08913070!48089714!30878963!55624631!46865633!03097822!% 29328805!}% \@namedef{CALX_Lv-4}{4!00000008!00000021!33333397!33333538!13334016!00002340!% 57151049!14314841!39787397!28635268!63158563!14541729!87894130!57885377!% 25360763!}% \@namedef{CALX_Lv-3}{3!00000004!50000009!00000020!25000048!60000121!50000312!% 42857962!98216472!71434476!32873247!13031299!73823938!93548433!85921628!% 79193916!}% \@namedef{CALX_Lv-2}{2!00000002!00000002!66666670!66666673!06666677!33333351!% 61904793!90476247!36508038!90793836!97547238!88023718!17694587!97915382!% 44657220!}% \@namedef{CALX_Lv-1}{1!00000000!50000000!33333333!58333333!53333333!50000000!% 14285714!41071428!68253968!35396825!48773448!85678210!75513375!58480408!% 54707514!}% \@namedef{CALX_Lv1}{-1!00000000!49999999!66666666!91666666!46666666!83333333!% 19047619!17261904!65079365!17936507!84559884!64321789!24486624!55805305!% 73863913!}% \@namedef{CALX_Lv2}{-2!00000001!99999997!33333337!33333326!93333343!99999981!% 71428603!42857085!96825499!22539496!35786777!11976281!82307752!59227474!% 69636685!}% \@namedef{CALX_Lv3}{-3!00000004!49999991!00000020!24999951!40000121!49999687!% 57143677!26783527!28577333!47126752!87057273!76176061!07134847!42649799!% 83329780!}% \@namedef{CALX_Lv4}{-4!00000007!99999978!66666730!66666461!86667349!33330992!% 76198668!19018491!93755651!24698064!72970972!85458270!50453791!70686056!% 68653006!}% \@namedef{CALX_Lv5}{-5!00000012!49999958!33333489!58332708!33335937!49988839!% 28620256!69425843!26373387!85243619!43144473!94375377!25065170!54045225!% 58443236!}% \@namedef{CALX_Lv6}{-6!00000017!99999928!00000323!99998444!80007775!99960009!% 14495666!27451684!63189474!41304165!55424491!97928688!11026392!70120340!% 57780837!}% \@namedef{CALX_Lv7}{-7!00000024!49999885!66667266!91663305!26686274!83215684!% 34053933!41349599!50469745!32465257!12026384!13918875!82575076!53223915!% 01737822!}% \@namedef{CALX_Lv8}{-8!00000031!99999829!33334357!33326779!73377023!99700406!% 87811437!56515491!61342428!55922309!36435048!25668695!42048904!21812446!% 15631138!}% \@namedef{CALX_Lv9}{-9!00000040!49999757!00001640!24988190!20088573!49316718!% 76809411!12310425!34392697!28605205!96831712!50771803!76846285!42218627!% 45339787!}% \@namedef{CALX_Lv10}{-10!00000049!99999666!66669166!66646666!66833333!% 31904762!02976189!36507946!50793559!88456821!78924486!62520091!01342435!% 40493533!65529900!}% \@namedef{CALX_Lv11}{-11!00000060!49999556!33336993!58301123!13628593!% 47216118!69652000!36220123!76281883!26546268!32496900!97902424!88014459!% 50330184!36416466!}% \@namedef{CALX_Lv12}{-12!00000071!99999424!00005183!99950233!60497663!% 94881170!82319134!83833991!06021461!22363341!56340333!59544268!78654970!% 89767703!41289152!}% \@namedef{CALX_Lv13}{-13!00000084!49999267!66673806!91592408!07471134!% 74369260!49585375!96127191!65212635!02855166!39472391!87206524!87942619!% 21367302!47605054!}% \@namedef{CALX_Lv14}{-14!00000097!99999085!33342937!33225768!54588255!% 84940929!84473609!04328424!36572927!28870204!75925775!42550852!79021503!% 38640789!77763216!}% \@namedef{CALX_Lv15}{-15!00000112!49998875!00012656!24848125!01898437!% 25591521!06075571!12444773!07888341!94380646!28392080!89394872!43850430!% 83610271!50144934!}% \@namedef{CALX_Lv16}{-16!00000127!99998634!66683050!66456951!49462868!% 94985416!41632740!40694160!59083292!64244954!64219734!06718036!92547575!% 62594118!67519117!}% \@namedef{CALX_Lv17}{-17!00000144!49998362!33354213!58049361!97356260!% 91380198!29112405!50357008!39041428!31802429!16334945!95824434!19376666!% 70799678!18739473!}% \@namedef{CALX_Lv18}{-18!00000161!99998056!00026243!99622086!45668703!% 12540009!20351994!45796704!18092808!01086693!21179107!47387445!41719661!% 91406638!48009090!}% \@namedef{CALX_Lv19}{-19!00000180!49997713!66699246!91171446!94507645!% 55637391!84849783!48793679!43027816!39101877!84211543!61120875!71845180!% 54022642!09054946!}% \@namedef{CALX_Lv20}{-20!00000199!99997333!33373333!32693333!43999998!% 17142889!14285145!39692779!68067786!46991976!28182318!28516154!06308014!% 30314729!22992335!}% \@namedef{CALX_Lv21}{-21!00000220!49996913!00048620!24183179!94294350!% 92701684!27856537!59178170!87779386!06989653!16214913!05859239!41361524!% 80387285!81183977!}% \@namedef{CALX_Lv22}{-22!00000241!99996450!66725230!65635940!45563313!% 76996560!78530469!63764265!56827309!13066159!95358741!05409626!63523540!% 67458769!57467250!}% \@namedef{CALX_Lv23}{-23!00000264!49995944!33403293!57046064!98005976!% 63596462!60299730!27325073!47080571!21900599!59825509!35396696!40127273!% 52404802!03040458!}% \@namedef{CALX_Lv24}{-24!00000287!99995392!00082943!98407475!51850489!% 44789934!16554193!80177981!65284619!98197471!08220295!53950016!52084253!% 36644473!06587450!}% \@namedef{CALX_Lv25}{-25!00000312!49994791!66764322!89713542!07356762!% 11402720!49672565!76391250!34647415!01930288!65703430!08170406!55771432!% 27416943!45344365!}% \@namedef{CALX_Lv26}{-26!00000337!99994141!33447577!30957058!64819284!% 52598807!31948467!79097471!31625486!98571398!78451840!77544348!13826432!% 36375974!30235592!}% \@namedef{CALX_Lv27}{-27!00000364!49993439!00132860!22130219!24570066!% 55664181!17969301!52667876!65298631!86950407!40517473!72398942!42144406!% 13036655!36008423!}% \@namedef{CALX_Lv28}{-28!00000391!99992682!66820330!63224593!86981698!% 05772589!58571371!49634706!91352212!49603586!56821598!27977824!45509378!% 81692318!09045812!}% \@namedef{CALX_Lv29}{-29!00000420!49991870!33510153!54231104!52470528!% 85732581!16499786!79240848!66206904!50243167!93236546!74156141!95329904!% 76085596!20522238!}% \@namedef{CALX_Lv30}{-30!00000449!99991000!00202499!95140001!21499968!% 75715105!83906701!43447632!69610017!41568676!06110209!61226518!46908201!% 52063441!53687027!}% \@namedef{CALX_Lv31}{-31!00000480!49990069!66897546!85940837!94583907!% 52960955!01826493!25143045!56393122!09713741!87679720!40234688!31564831!% 12203909!98411402!}% \@namedef{CALX_Lv32}{-32!00000511!99989077!33595477!26622448!72290254!% 91467321!81771521!12163648!40470502!71193711!76889052!79894746!89740802!% 70400138!40444469!}% \@namedef{CALX_Lv33}{-33!00000544!49988021!00296480!17172923!55244600!% 61652761!29597140!39574218!66864803!52685587!31170736!57235461!61561472!% 56681723!04059221!}% \@namedef{CALX_Lv34}{-34!00000577!99986898!67000750!57579584!44133994!% 29999830!71789696!31439531!90963037!18097362!35401448!38060454!78072320!% 50154655!65479837!}% \@namedef{CALX_Lv35}{-35!00000612!49985708!33708489!47828961!39710845!% 58674689!84336255!22072782!58690740!52304848!18665234!73439599!58591307!% 45696020!04228025!}% \@namedef{CALX_Lv36}{-36!00000647!99984448!00419903!87906768!42796944!% 05122941!24339873!35454904!67207385!54157985!54287131!72313693!47791313!% 60151235!00203824!}% \@namedef{CALX_Lv37}{-37!00000684!49983115!67135206!77797879!54287599!% 21640990!64549243!00188494!83435055!16764038!87841335!96530504!14596629!% 53106282!19815915!}% \@namedef{CALX_Lv38}{-38!00000721!99981709!33854617!17486304!75155900!% 54922207!30976595!75979163!07597755!60891771!22792697!99973532!85444366!% 11703191!65929637!}% \@namedef{CALX_Lv39}{-39!00000760!49980227!00578360!06955166!06457097!% 45577164!43782782!66225937!91333437!14229737!82609107!35707153!27047005!% 46073642!10904160!}% \@namedef{CALX_Lv40}{-40!00000799!99978666!67306666!46186673!49333099!% 27627239!61613490!89850835!55207712!68165458!27223019!37112564!12852715!% 35934457!13036138!}% \@namedef{CALX_Lv41}{-41!00000840!49977026!34039773!35162101!05017095!% 27970855!29575596!84005864!98970276!64093889!13304018!43737372!99032141!% 52730081!46363975!}% \@namedef{CALX_Lv42}{-42!00000881!99975304!00777923!73861762!74838294!% 65821639!31047695!07763583!60015014!28747994!91572008!98959249!24055027!% 85076707!87577820!}% \@namedef{CALX_Lv43}{-43!00000924!49973497!67521366!62264988!60226786!% 52117785!43523883!15324840!51595632!54777193!66850091!86508556!84594396!% 47688897!17727767!}% \@namedef{CALX_Lv44}{-44!00000967!99971605!34270357!00350100!62718519!% 88901893!98694921!65664548!02773215!67258137!81038385!69333967!27792399!% 05702897!29949007!}% \@namedef{CALX_Lv45}{-45!00001012!49969625!01025155!88094388!83960403!% 68670572!46975929!33883204!27193291!83855000!65705817!20131670!32560562!% 81181014!85062048!}% \@namedef{CALX_Lv46}{-46!00001057!99967554!67786030!25474087!25715526!% 73693076!26694812!87838453!67970668!17172710!16193527!00956846!46660178!% 05456045!20327156!}% \@namedef{CALX_Lv47}{-47!00001104!49965392!34553253!12464349!89868497!% 75298269!38160670!91897215!01563330!30057155!86191387!73507200!51741047!% 02642369!19799611!}% \@namedef{CALX_Lv48}{-48!00001151!99963136!01327103!49039226!78430905!% 33129185!22836451!97874830!34904986!82153262!10338249!98659757!64139573!% 00175501!10192738!}% \@namedef{CALX_Lv49}{-49!00001200!49960783!68107866!35171639!93546897!% 94364467!47845185!81413291!97602247!39268156!88533225!96325278!15455979!% 96164639!41403919!}% \@namedef{CALX_Lv50}{-50!00001249!99958333!34895832!70833359!37498883!% 92905970!96044147!80195888!15049833!92706875!41648751!77245267!72974662!% 42146948!18292846!}% \@namedef{CALX_Lv51}{-51!00001300!49955783!01691299!55994979!12713351!% 48531802!61906355!88500572!49238515!86827743!22734939!74485657!02724801!% 63736203!80193639!}% \def\CALX_Lzl{2994!0456!8401!7991!4546!8436!4207!6011!0148!8628!7729!7603!% 3327!9009!6757!2609!6773!5248!0235!9972!0508!9598!2983!4196!7784!0422!8624!% 8633!4095!2546!}% \@namedef{CALX_cdl0}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cdl1}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!5000!}% \@namedef{CALX_cdl2}{3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!}% \@namedef{CALX_cdl3}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!2500!}% \@namedef{CALX_cdl4}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!2000!}% \@namedef{CALX_cdl5}{6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!1666!}% \@namedef{CALX_cdl6}{5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!% 2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!% 2857!5714!1428!2857!5714!1428!2857!5714!1428!}% \@namedef{CALX_cdl7}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!1250!}% \@namedef{CALX_cdl8}{1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!% 1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!1111!% 1111!1111!1111!1111!1111!1111!1111!1111!1111!}% \@namedef{CALX_cdl9}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!1000!}% \@namedef{CALX_cdl10}{0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!% 0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!0909!% 0909!0909!0909!0909!0909!0909!0909!0909!0909!}% \@namedef{CALX_cdl11}{3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!0833!}% \@namedef{CALX_cdl12}{2307!0769!6923!2307!0769!6923!2307!0769!6923!2307!0769!% 6923!2307!0769!6923!2307!0769!6923!2307!0769!6923!2307!0769!6923!2307!0769!% 6923!2307!0769!6923!2307!0769!6923!2307!0769!}% \@namedef{CALX_cdl13}{2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!% 1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!% 1428!2857!5714!1428!2857!5714!1428!2857!0714!}% \@namedef{CALX_cdl14}{6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!0666!}% \@namedef{CALX_cdl15}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0625!}% \@namedef{CALX_cdl16}{9411!2352!0588!7647!9411!2352!0588!7647!9411!2352!0588!% 7647!9411!2352!0588!7647!9411!2352!0588!7647!9411!2352!0588!7647!9411!2352!% 0588!7647!9411!2352!0588!7647!9411!2352!0588!}% \@namedef{CALX_cdl17}{5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!% 5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!5555!% 5555!5555!5555!5555!5555!5555!5555!5555!0555!}% \@namedef{CALX_cdl18}{4736!5789!2631!2105!3684!8947!3157!0526!8421!4736!5789!% 2631!2105!3684!8947!3157!0526!8421!4736!5789!2631!2105!3684!8947!3157!0526!% 8421!4736!5789!2631!2105!3684!8947!3157!0526!}% \@namedef{CALX_cdl19}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0500!}% \@namedef{CALX_cdl20}{1904!0476!7619!1904!0476!7619!1904!0476!7619!1904!0476!% 7619!1904!0476!7619!1904!0476!7619!1904!0476!7619!1904!0476!7619!1904!0476!% 7619!1904!0476!7619!1904!0476!7619!1904!0476!}% \@namedef{CALX_cdl21}{5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!% 5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!5454!% 5454!5454!5454!5454!5454!5454!5454!5454!0454!}% \@namedef{CALX_cdl22}{7826!0434!3913!5217!6956!2608!3478!1304!1739!5652!0869!% 7826!0434!3913!5217!6956!2608!3478!1304!1739!5652!0869!7826!0434!3913!5217!% 6956!2608!3478!1304!1739!5652!0869!7826!0434!}% \@namedef{CALX_cdl23}{6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!0416!}% \@namedef{CALX_cdl24}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0400!}% \@namedef{CALX_cdl25}{6153!5384!8461!6153!5384!8461!6153!5384!8461!6153!5384!% 8461!6153!5384!8461!6153!5384!8461!6153!5384!8461!6153!5384!8461!6153!5384!% 8461!6153!5384!8461!6153!5384!8461!6153!0384!}% \@namedef{CALX_cdl26}{3703!0370!7037!3703!0370!7037!3703!0370!7037!3703!0370!% 7037!3703!0370!7037!3703!0370!7037!3703!0370!7037!3703!0370!7037!3703!0370!% 7037!3703!0370!7037!3703!0370!7037!3703!0370!}% \@namedef{CALX_cdl27}{1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!% 5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!5714!1428!2857!% 5714!1428!2857!5714!1428!2857!5714!1428!0357!}% \@namedef{CALX_cdl28}{7931!2413!5517!6896!8620!8275!0344!7931!2413!5517!6896!% 8620!8275!0344!7931!2413!5517!6896!8620!8275!0344!7931!2413!5517!6896!8620!% 8275!0344!7931!2413!5517!6896!8620!8275!0344!}% \@namedef{CALX_cdl29}{3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!0333!}% \@namedef{CALX_cdl30}{3225!1290!4516!5806!0322!6129!6451!2580!9032!1612!0645!% 2258!2903!5161!8064!3225!1290!4516!5806!0322!6129!6451!2580!9032!1612!0645!% 2258!2903!5161!8064!3225!1290!4516!5806!0322!}% % \end{macrocode} % \StoreCodelineNo {calxlogdata} % \cleardoublepage\let\calxlogdatanameUp\undefined %\gardesactifs %\let\relax %\let<*calxtrig>\gardesinactifs %------------------------------------------------------ %<*calxtrig>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxtrignameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Library \calxtrignameimp implementation} % \RaisedLabel{sec:calxtrigimp} % \addedcalx{2.0a1} % % \localtableofcontents % % calxtrig.tex: native sin, cos for calx.sty (wip). Input by calx.sty % (catcodes of calx.sty in force -- except for ! which will have catcode 12). % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code of this subsection is copied over from the xint packages, with % the package names changed. % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \catcode35=6 % # \catcode33=12 % ! \def\empty{}\def\space{ }\newlinechar10 \expandafter\let\expandafter\t\csname ver@calxtrig.tex\endcsname \expandafter\let\expandafter\c\csname ver@calx.sty\endcsname \expandafter \ifx\csname PackageWarningNoLine\endcsname\relax \def\y#1#2{\immediate\write128{^^JPackage #1 Warning:^^J% \space\space\space\space#2.^^J}}% \else \def\y#1#2{\PackageWarningNoLine{#1}{#2}}% \fi % attention that in this file \z by default does \endinput. \def\z{\endgroup\endinput}% \expandafter\ifx\csname numexpr\endcsname\relax \y{calx}{\numexpr not available, aborting input}% \else % \end{macrocode} % BEWARE: on 2026/10/09 I hit a problem I knew about from years ago but % forgot. It is known that TeX executes all macros on the line where % |\endinput| is found. But imagine |\endinput\input foo.tex\relax|, % then what will happen is that only the first line of foo.tex % (if its EOL is not hidden by a comment char) is executed, so basically % foo.tex is not read beyond that. I will put |\endinput| last in both % situations, as is logical anyhow. % \begin{macrocode} \ifx\c\relax % calx.sty not yet loaded. \ifx\PackageWarningNoLine\relax \y{calx}{% Loading of calxtrig.tex should happen via \string\input\space calx.sty\relax^^J\space\space\space\space Will try that now% }% \def\z{\endgroup \input calx.sty\relax\endinput}% \else \y{calx}{% Bad move! Inputting calxtrig.tex directly in a LaTeX\MessageBreak document is forbidden! Simply use \string\usepackage{calx}\MessageBreak in the preamble, as every obedient LaTeX user does!\MessageBreak Trying to recover now, hoping to be in the preamble% }% \def\z{\endgroup \RequirePackage{calx}\endinput}% \fi \else % either calx.sty is trying to load us, or a second loading is % attempted on us by \input. Abort if the latter. \ifx\t\relax \def\z{\endgroup}% \else \y{calx}{calxtrig.tex already loaded! Aborting this input}% \fi \fi \fi \z% % \end{macrocode} %\begin{lverb} % We arrive here only after a \XINTsetcatcodes which is done (near its tail) % in calx.sty. In particular ! has its normal catcode 12. But attention: % the \XINTsetcatcode does nothing with the letters F, I, N so we have to % be careful whenever we set them to be of catcode "other" (=12). % % There appears to be a problem with miniltx which provides \ProvidesFile % but does not let it define \ver@calxtrig.tex. So we define it always. %\end{lverb} % \subsection{Package identification} % \begin{macrocode} \ifdefined\ProvidesFile \ProvidesFile{calxtrig.tex}% [2026/11/01 v2.0a1 sin, cos, etc for xintexpr/calx (JFB)]% \fi \expandafter\def\csname ver@calxtrig.tex\endcsname {2026/11/01 v2.0a1 calx trig library}% % \end{macrocode} % \subsection{Loading data tables} % \begin{macrocode} \input calxtrigdata.tex\relax % \end{macrocode} % \subsection{Package implementation} %\begin{lverb} % Copied unchanged from xinttrig.sty: \XINT_SinAux_b, % \XINT_CosAux_b (Horner in \numexpr, 9-digit fixed point). %\end{lverb} % \begin{macrocode} \def\XINT_SinAux_b#1.% {% ((((((((% -#1/110+\xint_c_e_ix)/% -72)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -42)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -20)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -6)*#1/\xint_c_e_ix+\xint_c_e_ix }% \def\XINT_CosAux_b#1.% {% ((((((((((% -#1/132+\xint_c_e_ix)/% -90)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -56)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -30)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -12)*#1/\xint_c_e_ix+\xint_c_e_ix)/% -2)*#1/\xint_c_e_ix+\xint_c_e_ix }% % \end{macrocode} % \subsection{Function table entries, \csh{calxFpSin}, \csh{calxFpCos}} % calx: function table entries (pattern of |\XINT_flexpr_func_sqr|). % \begin{macrocode} \def\XINT_flexpr_func_sin #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSin#3}}% }% \def\XINT_flexpr_func_cos #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCos#3}}% }% \def\XINT_flexpr_func_asin #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAsin#3}}% }% \def\XINT_flexpr_func_acos #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAcos#3}}% }% \def\XINT_flexpr_func_asind #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAsind#3}}% }% \def\XINT_flexpr_func_acosd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAcosd#3}}% }% \def\XINT_flexpr_func_acsc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAcsc#3}}% }% \def\XINT_flexpr_func_asec #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAsec#3}}% }% \def\XINT_flexpr_func_atan #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAtan#3}}% }% \def\XINT_flexpr_func_atand #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpAtand#3}}% }% \def\XINT_flexpr_func_tan #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpTan#3}}% }% \def\XINT_flexpr_func_cot #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCot#3}}% }% \def\XINT_flexpr_func_sec #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSec#3}}% }% \def\XINT_flexpr_func_csc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCsc#3}}% }% \def\XINT_flexpr_func_sinc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSinc#3}}% }% \def\XINT_flexpr_func_sind #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSind#3}}% }% \def\XINT_flexpr_func_cosd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCosd#3}}% }% \def\XINT_flexpr_func_tand #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpTand#3}}% }% \def\XINT_flexpr_func_cotd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCotd#3}}% }% \def\XINT_flexpr_func_secd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpSecd#3}}% }% \def\XINT_flexpr_func_cscd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\calxFpCscd#3}}% }% \expandafter\def\csname XINT_flexpr_func_Arg\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpArg#3}}% }% \expandafter\def\csname XINT_flexpr_func_Argd\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpArgd#3}}% }% \expandafter\def\csname XINT_flexpr_func_pArg\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFppArg#3}}% }% \expandafter\def\csname XINT_flexpr_func_pArgd\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFppArgd#3}}% }% \expandafter\def\csname XINT_flexpr_func_atan2\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpAtantwo#3}}% }% \expandafter\def\csname XINT_flexpr_func_atan2d\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\calxFpAtantwod#3}}% }% \let\XINT_flexpr_func_tg\XINT_flexpr_func_tan \let\XINT_flexpr_func_cotg\XINT_flexpr_func_cot \let\XINT_flexpr_func_arcsin\XINT_flexpr_func_asin \let\XINT_flexpr_func_arccos\XINT_flexpr_func_acos \let\XINT_flexpr_func_arctg\XINT_flexpr_func_atan \let\XINT_flexpr_func_arcsec\XINT_flexpr_func_asec \let\XINT_flexpr_func_arccsc\XINT_flexpr_func_acsc % \end{macrocode} %\begin{lverb} % Syntax (f-expandable; X, Y f-expanded F, I or raw values, rounded to % P = \XINTdigits digits; results F or I values, rounded to P digits): %( % \calxFp{X} -> F(X) %: F = Sin, Cos, Tan, Cot, Sec, Csc, Sinc (radians), %: Sind, Cosd, Tand, Cotd, Secd, Cscd (degrees), %: Asin, Acos, Asec, Acsc, Atan (radians), %: Asind, Acosd, Atand (degrees) %: \calxFpArg{X}{Y} -> argument of (X, Y), in (-pi, pi] %: \calxFppArg{X}{Y} -> the same, in [0, 2pi) %: \calxFpArgd{X}{Y}, \calxFppArgd{X}{Y} -> the same in degrees %: \calxFpAtantwo{Y}{X}, \calxFpAtantwod{Y}{X} -> atan2(Y, X) = Arg(X, Y) %) % % \calxFpSin{X}, \calxFpCos{X}: P = \XINTdigits. X is first rounded to % P digits, then \CALX_sin_g, \CALX_cos_g: |X| < 0.8 goes to the series % kernels \CALX_sin_h, \CALX_cos_h, |X| >= 0.8 to the argument reduction % (\CALX_sin_r, \CALX_cos_r) then to the same kernels. P <= 8 ("ultra % fast, less precise", as xinttrig): \numexpr kernels % \CALX_sin_q, \CALX_cos_q (called by \CALX_sin_h, \CALX_cos_h). %\end{lverb} % \begin{macrocode} \def\calxFpSin{\romannumeral0\expandafter\CALX_sin_a \romannumeral0\CALX_fround{\XINTdigits}}% \def\calxFpCos{\romannumeral0\expandafter\CALX_cos_a \romannumeral0\CALX_fround{\XINTdigits}}% \def\calxFpAsin #1{\romannumeral0\expandafter\CALX_ad_a \romannumeral0\CALX_fround{\XINTdigits}{#1}a0}% \def\calxFpAcos #1{\romannumeral0\expandafter\CALX_ad_a \romannumeral0\CALX_fround{\XINTdigits}{#1}c0}% \def\calxFpAsind #1{\romannumeral0\expandafter\CALX_ad_a \romannumeral0\CALX_fround{\XINTdigits}{#1}a1}% \def\calxFpAcosd #1{\romannumeral0\expandafter\CALX_ad_a \romannumeral0\CALX_fround{\XINTdigits}{#1}c1}% \def\calxFpAcsc #1{\romannumeral0\expandafter\CALX_ae_a \romannumeral0\CALX_fround{\XINTdigits}{#1}a}% \def\calxFpAsec #1{\romannumeral0\expandafter\CALX_ae_a \romannumeral0\CALX_fround{\XINTdigits}{#1}c}% \def\calxFpAtan #1{\romannumeral0\expandafter\CALX_tq_a \romannumeral0\CALX_fround{\XINTdigits}{#1}{0}{1}{0}}% \def\calxFpAtand #1{\romannumeral0\expandafter\CALX_tq_a \romannumeral0\CALX_fround{\XINTdigits}{#1}{0}{1}{1}}% \def\calxFpTan #1{\romannumeral0\expandafter\CALX_sc_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fntan r}% \def\calxFpCot #1{\romannumeral0\expandafter\CALX_sc_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fncot r}% \def\calxFpSec #1{\romannumeral0\expandafter\CALX_sc_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fnsec r}% \def\calxFpCsc #1{\romannumeral0\expandafter\CALX_sc_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fncsc r}% \def\calxFpSinc #1{\romannumeral0\expandafter\CALX_sc_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fnsinc r}% \def\calxFpSind #1{\romannumeral0\expandafter\CALX_dg_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fnsin s}% \def\calxFpCosd #1{\romannumeral0\expandafter\CALX_dg_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fncos c}% \def\calxFpTand #1{\romannumeral0\expandafter\CALX_dg_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fntan t}% \def\calxFpCotd #1{\romannumeral0\expandafter\CALX_dg_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fncot u}% \def\calxFpSecd #1{\romannumeral0\expandafter\CALX_dg_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fnsec v}% \def\calxFpCscd #1{\romannumeral0\expandafter\CALX_dg_a \romannumeral0\CALX_fround{\XINTdigits}{#1}\CALX_fncsc w}% \def\calxFpArg {\romannumeral0\CALX_ar_a a0}% \def\calxFpArgd {\romannumeral0\CALX_ar_a a1}% \def\calxFppArg {\romannumeral0\CALX_ar_a p0}% \def\calxFppArgd {\romannumeral0\CALX_ar_a p1}% \def\calxFpAtantwo #1#2{\romannumeral0\CALX_ar_a a0{#2}{#1}}% \def\calxFpAtantwod #1#2{\romannumeral0\CALX_ar_a a1{#2}{#1}}% % \end{macrocode} %\begin{lverb} % Reduction constants (130 digits, mpmath; the 80 digits of xinttrig.sty % are a prefix): \CALX_trigR = 180/pi, \CALX_trigDg = pi/180; % \CALX_pdg

= pi/180 rounded to P+4 digits, P = 1, ..., 100. %\end{lverb} % \begin{macrocode} \edef\CALX_trigR{\romannumeral0\CALX_ffromraw {57295779513082320876798154814105170332405472466564321549160243861202847148% 32155263244096899585111094418622338163286489328144826460[-128]}}% \edef\CALX_trigDg{\romannumeral0\CALX_ffromraw {17453292519943295769236907684886127134428718885417254560971914401710091146% 03449443682241569634509482212304492507379059248385469228[-131]}}% \def\CALX_pdgmk #1.% {% \expandafter\edef\csname CALX_pdg#1\endcsname {\romannumeral0\CALX_fnround{#1+4}{\CALX_trigDg}}% \ifnum#1<100 \expandafter\CALX_pdgmk\the\numexpr#1+1\expandafter.\fi }% \CALX_pdgmk 1.\let\CALX_pdgmk\undefined % \end{macrocode} % \subsection{Dispatch and kernels for P at most 8} % Names with uppercase F, I, N are not usable below (catcode 12). % \begin{macrocode} \def\CALX_trigdigits{\XINTdigits}% \let\CALX_sinaux\XINT_SinAux_b \let\CALX_cosaux\XINT_CosAux_b % \end{macrocode} % ATTENTION setting from here on F, I, N to "other" catcode. % \begin{macrocode} \catcode`F 12 \catcode`I 12 \catcode`N 12 \def\CALX_sin_a #1% {% \if I#1\expandafter\CALX_sin_i\else\expandafter\CALX_sin_g\fi #1 }% \def\CALX_cos_a #1% {% \if I#1\expandafter\CALX_sin_i\else\expandafter\CALX_cos_g\fi #1 }% % \end{macrocode} % |#1| is I and we perhaps do not want to rely on its catcode being 12. % \begin{macrocode} \def\CALX_sin_i #1#2\xint:{\CALX_tr_sp#2}% % \end{macrocode} %\begin{lverb} % Dispatch. |X| < 0.8: \CALX_sin_h, \CALX_cos_h below; % otherwise reduction (\CALX_sin_r, \CALX_cos_r). %\end{lverb} % \begin{macrocode} \def\CALX_sin_g F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_sin_g_zero\fi \xint_orthat\CALX_sin_g_nonzero #1#2.% }% \def\CALX_sin_g_zero #1#2.#3.#4\xint:{ F+0.0.}% \def\CALX_sin_g_nonzero #1#2.#3.#4\xint:% {% \ifnum\numexpr#2+8*#3>\xint_c_ \xint_dothis\CALX_sin_r\fi \ifnum\ifnum\numexpr#2+8*#3=\xint_c_ \CALX_trig_top#4\xint:\else0\fi>\xint_c_vii \xint_dothis\CALX_sin_r\fi \xint_orthat\CALX_sin_g_small #1#2.#3.#4\xint:% }% \def\CALX_sin_g_small #1#2.#3.#4\xint:% {\expandafter\CALX_sin_h\the\numexpr(\CALX_trigdigits+7)/8% .#1#2.#3.#4\xint:}% \def\CALX_cos_g F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_cos_g_zero\fi \xint_orthat\CALX_cos_g_nonzero #1#2.% }% \def\CALX_cos_g_zero #1#2.#3.#4\xint:{ F+1.0.100000001!}% \def\CALX_cos_g_nonzero #1#2.#3.#4\xint:% {% \ifnum\numexpr#2+8*#3>\xint_c_ \xint_dothis\CALX_cos_g_reduce\fi \ifnum\ifnum\numexpr#2+8*#3=\xint_c_ \CALX_trig_top#4\xint:\else0\fi>\xint_c_vii \xint_dothis\CALX_cos_g_reduce\fi \xint_orthat\CALX_cos_g_small #1#2.#3.#4\xint:% }% \def\CALX_cos_g_reduce #1#2.#3.#4\xint:{\CALX_cos_r+#2.#3.#4\xint:}% \def\CALX_cos_g_small #1#2.#3.#4\xint:% {\expandafter\CALX_cos_h\the\numexpr(\CALX_trigdigits+7)/8% .#1#2.#3.#4\xint:}% \def\CALX_trig_top 1#1#2!#3\xint:% {% \if\relax\detokenize{#3}\relax\expandafter\xint_firstoftwo \else\expandafter\xint_secondoftwo\fi {#1}{\CALX_trig_top#3\xint:}% }% % \end{macrocode} %\begin{lverb} % P <= 8, |X| < 0.8 (\CALX_sin_q, \CALX_cos_q, called by \CALX_sin_h, % \CALX_cos_h): X has E = D + 8e <= 0 (|X| < 10^E); X may have up to % 8m digits (reduced argument). E < -4: sin X = round_P(X), cos X = 1 % (u/6 < 2 10^-11). Else A = the top 9 digits of M rounded (\CALX_rta), % X = A 10^(E-9) (1 + d), |d| < 6 10^-9; U9 = round(round(A^2/10^9) / % 10^(-2E)) (= round(10^9 u) within 1); S9 = 10^9 sin(X)/X, C9 = 10^9 % cos(X) by the Horner kernels of xinttrig; sin X = round_P(round(A % S9/10^9) 10^(E-9)), cos X = round_P(C9 10^-9), both rounded and % written as natives by \CALX_dgo (below). %\end{lverb} % \begin{macrocode} \def\CALX_sin_q #1#2.#3.% {% \ifnum\numexpr#2+8*#3<-\xint_c_iv \xint_dothis\CALX_sin_q_tiny\fi \xint_orthat\CALX_sin_q_compute #1#2.#3.% }% \def\CALX_sin_q_tiny #1#2.#3.#4\xint:% {\CALX_fnround{\CALX_trigdigits}{F#1#2.#3.#4}}% \def\CALX_sin_q_compute #1#2.#3.#4\xint:% {% \expandafter\CALX_sqa\the\numexpr#2+8*#3\expandafter.% \the\numexpr(2*#2+7)/16\expandafter.% \the\numexpr#2+8-8*((2*#2+7)/16).#1#4\xint:% }% \def\CALX_sqa #1.#2.#3.#4#5\xint:% {\expandafter\CALX_sqb\the\numexpr\CALX_rta#2.#3.#5\xint:.#4#1.}% \def\CALX_sqb #1.#2#3.% {% \expandafter\CALX_dgo\the\numexpr#2#1*(% \expandafter\CALX_sinaux\the\numexpr#1*#1/1000000000/% \CALX_pten{-2*#3}.)/1000000000.#3-9.% }% \def\CALX_cos_q #1#2.#3.% {% \ifnum\numexpr#2+8*#3<-\xint_c_iv \xint_dothis\CALX_cos_q_tiny\fi \xint_orthat\CALX_cos_q_compute #1#2.#3.% }% \def\CALX_cos_q_tiny #1#2.#3.#4\xint:{ F+1.0.100000001!}% \def\CALX_cos_q_compute #1#2.#3.#4\xint:% {% \expandafter\CALX_cqa\the\numexpr#2+8*#3\expandafter.% \the\numexpr(2*#2+7)/16\expandafter.% \the\numexpr#2+8-8*((2*#2+7)/16).#4\xint:% }% \def\CALX_cqa #1.#2.#3.#4\xint:% {\expandafter\CALX_cqb\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.}% \def\CALX_cqb #1.#2.% {% \expandafter\CALX_dgo\the\numexpr \expandafter\CALX_cosaux\the\numexpr#1*#1/1000000000/% \CALX_pten{-2*#2}..-9.% }% % \end{macrocode} %\begin{lverb} % sind, cosd, tand, cotd, secd, cscd for P <= 8, all in \numexpr, % 9-digit fixed point as \CALX_sin_q (kinds s, c, t, u, v, w). P > 8, NaN and % infinities go to \CALX_sc_a (jumper \CALX_dg_j), zero gives 0 or 1. % % Input (after \CALX_fround to P): |x| = A 10^(E-9) EXACTLY, E = D + 8e, % A integer, 10^8 <= A < 10^9 (\CALX_dg_one$empty: one block, A = b 10^(9-D); % \CALX_dg_two$empty: two blocks, A = b_1 10^(17-D) + b_0 / 10^(D-9), the % division being exact: x has at most P + 1 <= 9 significant digits). % % E < 2 (|x| < 10): no reduction, y = |x| (jumper \CALX_dg_l). Otherwise % the exact reduction of xinttrig's \XINT_sind_i (mod 360, quadrant by % rounding), in integers: %( %: I = floor(|x|), n = I mod 360, q = round((2n+1)/180) in 0..4, %: 10^7 y = (n - 90 q) 10^7 + 10^7 frac(|x|), -45 <= y <= 45, %) % then y = A' 10^(E'-9) (\CALX_dgw, \CALX_dgd), y = 0 giving A' = 0. % Quadrant (\CALX_dgq): sind = sign(x) times S(y), C(y), -S(y), % -C(y), S(y) for q = 0..4, cosd = C(y), -S(y), -C(y), S(y), C(y), with % S = sind, C = cosd on [-45, 45] (\CALX_dgks, \CALX_dgkc); tand, cotd % (odd, factor sign(x)): T, -1/T, T, -1/T, T and 1/T, -T, 1/T, -T, 1/T % (T = tand y); secd: 1/C, -1/S, -1/C, 1/S, 1/C; cscd (odd): 1/S, 1/C, % -1/S, -1/C, 1/S. Zero: tand 0, secd 1, cotd and cscd DivisionByZero. % For P > 8 the kinds t, u, v, w are those of \CALX_sc_a for tand, cotd % (\CALX_sc_d), secd (\CALX_sc_c), cscd (\CALX_sc_s). %\end{lverb} % \begin{macrocode} \def\CALX_dg_a #1% {% \ifnum\CALX_trigdigits>\xint_c_viii \CALX_dg_j\fi \if I#1\CALX_dg_j\fi \CALX_dg_b #1% }% \def\CALX_dg_j\fi #1\CALX_dg_b #2\xint:{\fi\CALX_sc_a #2\xint:}% \def\CALX_dg_b F#1#2.#3.#4\xint:#5% {% \ifnum#2=\xint_c_ \CALX_dg_z\fi \CALX_dg_c #2.#3.#1#4\xint:% }% \def\CALX_dg_z\fi\CALX_dg_c #1\xint:#2{\fi\csname CALX_dgz#2\endcsname}% \expandafter\def\csname CALX_dgzs\endcsname{ F+0.0.}% \expandafter\def\csname CALX_dgzc\endcsname{ F+1.0.100000001!}% \expandafter\def\csname CALX_dgzt\endcsname{ F+0.0.}% \expandafter\def\csname CALX_dgzu\endcsname {\CALX_nsig{DivisionByZero}{x / 0}{+}}% \expandafter\let\csname CALX_dgzv\expandafter\endcsname \csname CALX_dgzc\endcsname \expandafter\let\csname CALX_dgzw\expandafter\endcsname \csname CALX_dgzu\endcsname \def\CALX_dg_c #1.#2.#31#4!#5% {\xint_gob_til_xint: #5\CALX_dg_one\xint:\CALX_dg_two #1.#2.#3#4.}% \def\CALX_dg_one\xint:\CALX_dg_two #1.#2.#3#4.% {% \expandafter\CALX_dg_d\the\numexpr#1+8*#2\expandafter.% \the\numexpr#4*\CALX_pten{9-#1}.#3% }% \def\CALX_dg_two #1.#2.#3#4.#5!\xint:% {% \expandafter\CALX_dg_d\the\numexpr#1+8*#2\expandafter.% \the\numexpr#5*\CALX_pten{17-#1}+#4/\CALX_pten{#1-9}.#3% }% \def\CALX_dg_d #1.% {% \ifnum#1<\xint_c_ii \CALX_dg_l\fi \csname CALX_dge\ifnum#1>11 c\else#1\fi\endcsname#1.% }% \def\CALX_dg_l\fi #1\endcsname#2.#3.#4#5% {\fi\csname CALX_dgd#5\endcsname #4#3.#2.}% \expandafter\def\csname CALX_dgds\endcsname #1#2.#3.{\CALX_dgks #11.#2.#3.}% \expandafter\def\csname CALX_dgdc\endcsname #1#2.#3.{\CALX_dgkc 1.#2.#3.}% \expandafter\def\csname CALX_dgdt\endcsname #1#2.#3.{\CALX_dgkt #11.#2.#3.}% \expandafter\def\csname CALX_dgdu\endcsname #1#2.#3.% {\csname CALX_dgkb+\endcsname #11.#2.#3.}% \expandafter\def\csname CALX_dgdv\endcsname #1#2.#3.{\CALX_dgke 1.#2.#3.}% \expandafter\def\csname CALX_dgdw\endcsname #1#2.#3.{\CALX_dgkr #11.#2.#3.}% % \end{macrocode} %\begin{lverb} % \CALX_dge .. (one \csname from \CALX_dg_d, E = 2..11, c for % E > 11) gives \CALX_dg_s .<10^7 frac(|x|)>. For E <= 9, with k = 9 - % E: I = floor(A/10^k) = round((2A - 10^k)/(2 10^k)) and 10^7 frac(|x|) % = (A - I 10^k) 10^(E-2) (exact: frac(|x|) has at most k <= 7 decimal % digits); \CALX_dgdef builds these eight macros with literal powers of % ten. For E >= 10, x is an integer: n = ((A mod 360) (10^(E-9) mod % 360)) mod 360, 10^(E-9) = 10, 100 or 280 (mod 360). %\end{lverb} % \begin{macrocode} \def\CALX_dgdef #1#2#3#4% {% \expandafter\def\csname CALX_dge#1\endcsname##1.##2.% {% \expandafter\CALX_dg_s\the\numexpr\CALX_mod{((2*##2-#2)/#3)}% \expandafter.\the\numexpr(##2-#2*((2*##2-#2)/#3))#4.% }% }% \CALX_dgdef 2{10000000}{20000000}{}% \CALX_dgdef 3{1000000}{2000000}{*10}% \CALX_dgdef 4{100000}{200000}{*100}% \CALX_dgdef 5{10000}{20000}{*1000}% \CALX_dgdef 6{1000}{2000}{*10000}% \CALX_dgdef 7{100}{200}{*100000}% \CALX_dgdef 8{10}{20}{*1000000}% \CALX_dgdef 9{1}{2}{*10000000}% \expandafter\def\csname CALX_dge10\endcsname #1.#2.% {\expandafter\CALX_dg_s\the\numexpr\CALX_mod{\CALX_mod{#2}*10}.0.}% \expandafter\def\csname CALX_dge11\endcsname #1.#2.% {\expandafter\CALX_dg_s\the\numexpr\CALX_mod{\CALX_mod{#2}*100}.0.}% \expandafter\def\csname CALX_dgec\endcsname #1.#2.% {\expandafter\CALX_dg_s\the\numexpr\CALX_mod{\CALX_mod{#2}*280}.0.}% % \end{macrocode} %\begin{lverb} % \CALX_dg_s .., \CALX_dg_t$empty: q and 10^7 y; \CALX_dg_u % selects the quadrant macro with the sign token of x. %\end{lverb} % \begin{macrocode} \def\CALX_dg_s #1.{\expandafter\CALX_dg_t\the\numexpr(2*#1+1)/180.#1.}% \def\CALX_dg_t #1.#2.#3.% {\expandafter\CALX_dg_u\the\numexpr(#2-90*#1)*10000000+#3.#1.}% \def\CALX_dg_u #1.#2.#3#4{\csname CALX_dgq#4#2\endcsname#3#1.}% \expandafter\def\csname CALX_dgqs0\endcsname#1{\CALX_dgw\CALX_dgks#11.}% \expandafter\def\csname CALX_dgqs1\endcsname#1{\CALX_dgw\CALX_dgkc#11.}% \expandafter\def\csname CALX_dgqs2\endcsname#1{\CALX_dgw\CALX_dgks#1-1.}% \expandafter\def\csname CALX_dgqs3\endcsname#1{\CALX_dgw\CALX_dgkc#1-1.}% \expandafter\def\csname CALX_dgqs4\endcsname#1{\CALX_dgw\CALX_dgks#11.}% \expandafter\def\csname CALX_dgqc0\endcsname#1{\CALX_dgw\CALX_dgkc1.}% \expandafter\def\csname CALX_dgqc1\endcsname#1{\CALX_dgw\CALX_dgks-1.}% \expandafter\def\csname CALX_dgqc2\endcsname#1{\CALX_dgw\CALX_dgkc-1.}% \expandafter\def\csname CALX_dgqc3\endcsname#1{\CALX_dgw\CALX_dgks1.}% \expandafter\def\csname CALX_dgqc4\endcsname#1{\CALX_dgw\CALX_dgkc1.}% \expandafter\def\csname CALX_dgqt0\endcsname#1{\CALX_dgw\CALX_dgkt#11.}% \expandafter\def\csname CALX_dgqt1\endcsname#1% {\expandafter\CALX_dgw\csname CALX_dgkb#1\endcsname#1-1.}% \expandafter\def\csname CALX_dgqt2\endcsname#1{\CALX_dgw\CALX_dgkt#11.}% \expandafter\def\csname CALX_dgqt3\endcsname#1% {\expandafter\CALX_dgw\csname CALX_dgkb\if-#1+\else-\fi\endcsname#1-1.}% \expandafter\def\csname CALX_dgqt4\endcsname#1{\CALX_dgw\CALX_dgkt#11.}% \expandafter\def\csname CALX_dgqu0\endcsname#1% {\expandafter\CALX_dgw\csname CALX_dgkb+\endcsname#11.}% \expandafter\def\csname CALX_dgqu1\endcsname#1{\CALX_dgw\CALX_dgkt#1-1.}% \expandafter\def\csname CALX_dgqu2\endcsname#1% {\expandafter\CALX_dgw\csname CALX_dgkb-\endcsname#11.}% \expandafter\def\csname CALX_dgqu3\endcsname#1{\CALX_dgw\CALX_dgkt#1-1.}% \expandafter\def\csname CALX_dgqu4\endcsname#1% {\expandafter\CALX_dgw\csname CALX_dgkb+\endcsname#11.}% \expandafter\def\csname CALX_dgqv0\endcsname#1{\CALX_dgw\CALX_dgke1.}% \expandafter\def\csname CALX_dgqv1\endcsname#1{\CALX_dgw\CALX_dgkr-1.}% \expandafter\def\csname CALX_dgqv2\endcsname#1{\CALX_dgw\CALX_dgke-1.}% \expandafter\def\csname CALX_dgqv3\endcsname#1{\CALX_dgw\CALX_dgkr1.}% \expandafter\def\csname CALX_dgqv4\endcsname#1{\CALX_dgw\CALX_dgke1.}% \expandafter\def\csname CALX_dgqw0\endcsname#1{\CALX_dgw\CALX_dgkr#11.}% \expandafter\def\csname CALX_dgqw1\endcsname#1{\CALX_dgw\CALX_dgke#11.}% \expandafter\def\csname CALX_dgqw2\endcsname#1{\CALX_dgw\CALX_dgkr#1-1.}% \expandafter\def\csname CALX_dgqw3\endcsname#1{\CALX_dgw\CALX_dgke#1-1.}% \expandafter\def\csname CALX_dgqw4\endcsname#1{\CALX_dgw\CALX_dgkr#11.}% % \end{macrocode} %\begin{lverb} % \CALX_dgw .. (v = 10^7 y): \CALX_dgd gives, from % the digit count d of |v|, 10^(9-d) and E' = d - 7; then \CALX_dgx calls % the kernel with ... (A' carries % the sign of y). %\end{lverb} % \begin{macrocode} \def\CALX_dgw #1#2.#3.% {% \expandafter\CALX_dgx\expanded{\expandafter\CALX_dgd \the\numexpr\ifnum#3<\xint_c_-\fi#3.}#3.#1#2.% }% \def\CALX_dgd #1.% {% \CALX_nd_c #1{1.2}{1.2}{10.1}{100.0}{1000.-1}{10000.-2}{100000.-3}% {1000000.-4}{10000000.-5}{100000000.-6}\xint:.% }% \def\CALX_dgx #1.#2.#3.#4#5.% {\expandafter#4\the\numexpr#5\expandafter.\the\numexpr#3*#1.#2.}% % \end{macrocode} %\begin{lverb} % Kernels \CALX_dgks, \CALX_dgkc ... (f = +-1, |y| = |A| 10^(E-9) % degrees, t = pi y/180 radians). \CALX_dgu (inside \numexpr): U9 = % round(10^9 t^2) = round(round(A^2/10^9) r_E) with r_E = p_E/q_E, the % best approximation of 10^(2E) (pi/180)^2 by p_E, q_E < 2^31 (continued % fraction, relative error < 10^-11), \CALX_dgr for E = -2..2; E < -2: % U9 = 0 (t^2 < 3.1 10^-10). S9 = 10^9 sin(t)/t, C9 = 10^9 cos(t) by % \CALX_sinaux, \CALX_cosaux (xinttrig's Horner kernels); %( %: sind y = round(f A Z / 10^9) 10^(E-11), Z = round(S9 p/q), %: cosd y = f C9 10^-9, %) % p/q = 1489429756/853380389 (100 pi/180, relative error 10^-19). Error % before the final rounding: a few units of 10^-9 relative (Horner, % U9, Z), i.e. about 1 ulp at P = 8. %\end{lverb} % \begin{macrocode} \def\CALX_dgu #1.#2.% {\ifnum#2<-\xint_c_ii 0\else #1*#1/1000000000\csname CALX_dgr#2\endcsname\fi}% \expandafter\def\csname CALX_dgr2\endcsname{*920239054/302096661}% \expandafter\def\csname CALX_dgr1\endcsname{*53922105/1770158287}% \expandafter\def\csname CALX_dgr0\endcsname{*532125/1746863329}% \expandafter\def\csname CALX_dgr-1\endcsname{*4337/1423753114}% \expandafter\def\csname CALX_dgr-2\endcsname{*2/65656127}% \def\CALX_dgks #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*#2*(% (\expandafter\CALX_sinaux\the\numexpr\CALX_dgu#2.#3..)% *1489429756/853380389)/1000000000.#3-11.% }% \def\CALX_dgkc #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*(% \expandafter\CALX_cosaux\the\numexpr\CALX_dgu#2.#3..).-9.% }% % \end{macrocode} %\begin{lverb} % Kernels of tand, cotd, secd, cscd (same arguments ...; Z, C9 % as above): %( %: tan y = round(f A Z / C9) 10^(E-11) (\CALX_dgkt) %: cot y = round(f 10^17 / round(A Z / C9)) 10^(-E-6) (\CALX_dgkb) %: sec y = round(f 10^18 / C9) 10^-9 (\CALX_dgke) %: csc y = round(f round(10^17 / A) 10^9 / Z) 10^(-E-6) (\CALX_dgkr) %) % (products then divisions as one scaled \numexpr operation, all values % below 2^31). y = 0 (A = 0) in cot, csc: pole, DivisionByZero with the % sign s of the numerator of the general path (\CALX_dgkb+, \CALX_dgkb-; % csc: +), as \CALX_fdiv gives it. %\end{lverb} % \begin{macrocode} \def\CALX_dgkt #1.#2.#3.% {\expandafter\CALX_dgkta\the\numexpr\CALX_dgu#2.#3..#1.#2.#3.}% \def\CALX_dgkta #1.#2.#3.#4.% {% \expandafter\CALX_dgo\the\numexpr#2*#3*% ((\CALX_sinaux#1.)*1489429756/853380389)/(\CALX_cosaux#1.).#4-11.% }% \def\CALX_dgkbdef #1% {% \expandafter\def\csname CALX_dgkb#1\endcsname##1.##2##3.##4.% {\xint_gob_til_zero##2\CALX_dgpz#10\CALX_dgkba##1.##2##3.##4.}% }% \CALX_dgkbdef+\CALX_dgkbdef-\let\CALX_dgkbdef\undefined \def\CALX_dgpz #10#2#3.#4.#5.% {\CALX_nsig{DivisionByZero}{x / 0}{#1}}% \def\CALX_dgkba #1.#2.#3.% {\expandafter\CALX_dgkbb\the\numexpr\CALX_dgu#2.#3..#1.#2.#3.}% \def\CALX_dgkbb #1.#2.#3.#4.% {% \expandafter\CALX_dgo\the\numexpr#2*(1000000000*100000000/(#3*% ((\CALX_sinaux#1.)*1489429756/853380389)/(\CALX_cosaux#1.))).-#4-6.% }% \def\CALX_dgke #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*(1000000000*1000000000/(% \expandafter\CALX_cosaux\the\numexpr\CALX_dgu#2.#3..)).-9.% }% \def\CALX_dgkr #1.#2#3.#4.% {\xint_gob_til_zero#2\CALX_dgpz+0\CALX_dgkra#1.#2#3.#4.}% \def\CALX_dgkra #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*((1000000000*100000000/#2)*1000000000% /((\expandafter\CALX_sinaux\the\numexpr\CALX_dgu#2.#3..)% *1489429756/853380389)).-#3-6.% }% % \end{macrocode} %\begin{lverb} % Syntax: %( % \CALX_dgo .. -> F.. round_P(N 10^x) %: \CALX_dgoc ... -> F.. (M 10^g) %) % (P = \CALX_trigdigits; for \CALX_dgoc, 10^(P-1) <= M <= 10^P, b the % block exponent, g - 8b in 0..7.) % % \CALX_dgo .. (N a signed integer of at most 10 digits, x an % integer expression; also used by \CALX_sin_q, \CALX_cos_q): the native % round_P(N 10^x), without \CALX_ffromraw nor \CALX_fround. \CALX_dgy$empty: % sign apart, N = 0 gives F+0.0., else s = (number of digits of N) - P >= % 0 (N >= 10^7 for all callers: 8, 9 or 10 digits); \CALX_dgob$empty: M = % round(N/10^s) (\numexpr division, half away from zero as \CALX_fround), % g = x + s (|value| = M 10^g), block exponent b = round((2g - 7)/16), h = % g - 8b in 0..7; \CALX_dgoc$empty: D = h + P, plus 1 if M = 10^P (carry, as % \CALX_fround); \CALX_dgod$empty: F.. and the block(s) of M 10^h, % one if D <= 8, else two (\CALX_dgoe, \CALX_dgof$empty: high part % floor(M / 10^(8-h)), low part the rest times 10^h; D <= 16). %\end{lverb} % \begin{macrocode} \def\CALX_dgo #1% {\if-#1\expandafter\CALX_dgy\else\expandafter\CALX_dgy\expandafter+\fi#1}% \def\CALX_dgy #1#2.#3.% {% \ifnum#2=\xint_c_ \CALX_dgyz\fi \expandafter\CALX_dgob \the\numexpr\ifnum#2<1000000000 \ifnum#2<100000000 8\else9\fi \else10\fi-\CALX_trigdigits.#2.#3.#1% }% \def\CALX_dgyz\fi #1\CALX_dgob #2.#3.#4.#5{\fi\space F+0.0.}% \expandafter\def\csname CALX_pt9\endcsname{1000000000}% \def\CALX_dgob #1.#2.#3.% {% \expandafter\CALX_dgoc\the\numexpr#2/\CALX_pten{#1}\expandafter.% \the\numexpr(2*(#3+#1)-7)/16\expandafter.\the\numexpr#3+#1.% }% \def\CALX_dgoc #1.#2.#3.% {% \expandafter\CALX_dgod\the\numexpr#3-8*#2\expandafter.% \the\numexpr#3-8*#2+\CALX_trigdigits \ifnum#1<\CALX_pten{\CALX_trigdigits} \else+1\fi.#1.#2.% }% \def\CALX_dgod #1.#2.#3.#4.#5% {% \expanded{ F#5#2.#4.\ifnum#2>\xint_c_viii \CALX_dgoe#1.#3.\else \the\numexpr100000000+#3*\CALX_pten{#1}!\fi}% }% \def\CALX_dgoe #1.#2.% {% \expandafter\CALX_dgof\the\numexpr(2*#2-\CALX_pten{8-#1})% /(2*\CALX_pten{8-#1}).#1.#2.% }% \def\CALX_dgof #1.#2.#3.% {% \the\numexpr100000000+(#3-#1*\CALX_pten{8-#2})*\CALX_pten{#2}!% \the\numexpr100000000+#1!% }% % \end{macrocode} %\begin{lverb} % asind, acosd, atand and asin, acos, atan for P <= 8, all in \numexpr. % P > 8, NaN, % infinities, zero, |x| >= 1 (asind, acosd) go to the general code % (\CALX_as_a, \CALX_at_a; jumpers \CALX_ad_j, \CALX_ad_k, \CALX_tq_j, % \CALX_tq_k). |x| = A 10^(E-9) exactly (\CALX_rta, as \CALX_sin_q). % % Small kernel \CALX_ad_s ... (a = A 10^(E-9) <= % sqrt(2)/2): U9 = round(10^9 a^2) (0 if E < -4), Zd = round(R9 p'/q'), % R9 = 10^9 asin(a)/a by \CALX_asb (xinttrig's \XINT_Arcsin_Ib), p'/q' = % 853380389/1489429756 (180/(100 pi)); gives .. with N = % round(A Zd/den): asind a = N 10^(E-7) for den = 10^9 (half of it for % den = 2 10^9). A need not be normalized (E = 0, absolute accuracy). % % Large kernel \CALX_ad_l . (E = 0, A > 707106781): u = % sqrt(1 - a^2) = sqrt(d (2 10^9 - d)) 10^-9, d = 10^9 - A exact; with k % = 4, 3, 3, 2, 2, 1, 1, 0, 0 for d of 1, ..., 9 digits, s = % round(sqrt(d 10^(2k) (2 10^9 - d))) (u = s 10^(-9-k), s < 1.42 10^9) % by five Newton steps s + (P M/s - s)/2 (one scaled \numexpr division) % from a linear guess (\CALX_ad_lc, relative error < 25$%); then as the % small kernel with A = s: .<-k-7>., asind u = N 10^(-k-7). % % Finishers: \CALX_ad_ys .. gives round_P(s N 10^e) by \CALX_dgo; % \CALX_ad_yc ..{B} gives round_P(s (B o N 10^(e+7)) 10^-7) % (units of 10^-7 degree, B = 45, 90 or 180 degrees). asind: s V (small), % s (90 - V(u)) (large); acosd: 90 -+ V (small), V(u) or 180 - V(u) % (large). % % atand, t = |x|: (i) t <= tan(22.5): x' = 2t/(1+t^2) (A' = 2 A 10^9 / % (10^9 + U9), divided by 10 if it has ten digits), atand = s V(x')/2; % (ii) E = 0, tan(22.5) < t < 1: y' = (1-t^2)/(1+t^2), atand = s (45 - % V(y')/2); (iv) 1 <= t < tan(67.5): y' = (t^2-1)/(t^2+1) from (A - % 10^8)(A + 10^8)/10^8 and A^2/10^8 + 10^8, atand = s (45 + V(y')/2); (v) % t >= tan(67.5): r = 1/t (round(10^17/A), E' = 1 - E), x' = 2r/(1+r^2), % atand = s (90 - V(x')/2). No square root. % % Radians: the same kernels (tables \CALX_ad<1|0>, \CALX_tq % <1|0>, 1: degrees, 0: radians) with the finishers \CALX_ad_zs, % \CALX_ad_zc (result times pi/180 = 1489429756/853380389 / 100, in units % of 10^-9 radian, angles up to 90 degrees) and \CALX_ad_zm (times pi/18 = % 105115715/602268683, units of 10^-8 radian: acos of x < 0, results % >= pi/2 up to pi). % % acsc, asec for P <= 8 (\CALX_ae_a; |x| < 1, zero, x = +-1 and P > 8 go to % \CALX_ac_a): y = 1/|x|. 1 <= |x| < sqrt(2) (E = 1, A < 141421357): the % large kernel on u = sqrt(1 - y^2) with d = 10^9 (|x| - 1)/|x| from the % exact A (\CALX_ae_l: d 10^(2k) = (A - 10^8) 10^(2k+1) 10^8/A, no % cancellation); otherwise the small kernel on y, A' = round(10^17/A), % E' = 1 - E (\CALX_ae_t). Tables \CALX_ae (sign of x). %\end{lverb} % \begin{macrocode} \def\CALX_ad_a #1% {% \ifnum\CALX_trigdigits>\xint_c_viii \CALX_ad_j\fi \if I#1\CALX_ad_j\fi \CALX_ad_b #1% }% \def\CALX_ad_j\fi #1\CALX_ad_b #2\xint:{\fi\CALX_as_a #2\xint:}% \def\CALX_ad_b F#1#2.#3.#4\xint:% {% \ifnum\ifnum#2=\xint_c_ \xint_c_i\else\numexpr#2+8*#3\relax\fi >\xint_c_ \CALX_ad_k\fi \CALX_ad_ba #1#2.#3.#4\xint:% }% \def\CALX_ad_k\fi\CALX_ad_ba #1\xint:{\fi\CALX_as_a F#1\xint:}% \def\CALX_ad_ba #1#2.#3.#4\xint:% {% \expandafter\CALX_ad_bb\the\numexpr#2+8*#3\expandafter.% \the\numexpr(2*#2+7)/16\expandafter.% \the\numexpr#2+8-8*((2*#2+7)/16).#4\xint:#1% }% \def\CALX_ad_bb #1.#2.#3.#4\xint:#5% {\expandafter\CALX_ad_c\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.#5}% \def\CALX_ad_c #1.#2.#3#4#5% {% \csname CALX_ad#4#5\ifnum#2<\xint_c_ s\else \ifnum#1>707106781 l\else s\fi\fi\endcsname #1.#2.#3% }% \expandafter\def\csname CALX_ada1s\endcsname #1.#2.#3% {\CALX_ad_s#1.#2.1000000000.\CALX_ad_ys#3}% \expandafter\def\csname CALX_ada1l\endcsname #1.#2.#3% {\CALX_ad_l#1.\CALX_ad_yc{900000000}-#3}% \expandafter\def\csname CALX_adc1s\endcsname #1.#2.#3% {\CALX_ad_s#1.#2.1000000000.\CALX_ad_yc{900000000}{\if-#3+\else-\fi}+}% \expandafter\def\csname CALX_adc1l\endcsname #1.#2.#3% {\if-#3\expandafter\CALX_ad_cm\else\expandafter\CALX_ad_cp\fi #1.}% \def\CALX_ad_cp #1.{\CALX_ad_l#1.\CALX_ad_ys+}% \def\CALX_ad_cm #1.{\CALX_ad_l#1.\CALX_ad_yc{1800000000}-+}% \expandafter\def\csname CALX_ada0s\endcsname #1.#2.#3% {\CALX_ad_s#1.#2.1000000000.\CALX_ad_zs#3}% \expandafter\def\csname CALX_ada0l\endcsname #1.#2.#3% {\CALX_ad_l#1.\CALX_ad_zc{900000000}-#3}% \expandafter\def\csname CALX_adc0s\endcsname #1.#2.#3% {\if-#3\expandafter\CALX_ad_es\else\expandafter\CALX_ad_fs\fi #1.#2.}% \def\CALX_ad_es #1.#2.% {\CALX_ad_s#1.#2.1000000000.\CALX_ad_zm{900000000}++}% \def\CALX_ad_fs #1.#2.% {\CALX_ad_s#1.#2.1000000000.\CALX_ad_zc{900000000}-+}% \expandafter\def\csname CALX_adc0l\endcsname #1.#2.#3% {\if-#3\expandafter\CALX_ad_dm\else\expandafter\CALX_ad_dp\fi #1.}% \def\CALX_ad_dp #1.{\CALX_ad_l#1.\CALX_ad_zs+}% \def\CALX_ad_dm #1.{\CALX_ad_l#1.\CALX_ad_zm{1800000000}-+}% \def\CALX_ad_s #1.#2.% {% \expandafter\CALX_ad_sa\the\numexpr\ifnum#2<-\xint_c_iv 0\else #1*#1/1000000000/\CALX_pten{-2*#2}\fi.#1.#2.% }% \def\CALX_ad_sa #1.#2.#3.#4.#5% {% \expandafter#5\the\numexpr#2*((\CALX_asb#1.)*853380389/1489429756)/#4% \expandafter.\the\numexpr#3-7.% }% \def\CALX_ad_l #1.{\expandafter\CALX_ad_la\the\numexpr1000000000-#1.}% \def\CALX_ad_la #1.% {\expandafter\CALX_ad_lb\the\numexpr\CALX_nd_c #10001122334\xint:.#1.}% \def\CALX_ad_lb #1.#2.% {% \expandafter\CALX_ad_lc\the\numexpr#2*\CALX_pten{2*#1}\expandafter.% \the\numexpr2000000000-#2.#1.% }% \def\CALX_ad_lc #1.% {% \expandafter\CALX_ad_na\the\numexpr\ifnum#1<100000000 (#1+31622777)*38233/10000\else(#1+316227766)*120903/100000\fi.#1.% }% \def\CALX_ad_na #1.#2.#3.% {\expandafter\CALX_ad_nb\the\numexpr#1+(#2*#3/#1-#1)/2.#2.#3.}% \def\CALX_ad_nb #1.#2.#3.% {\expandafter\CALX_ad_nc\the\numexpr#1+(#2*#3/#1-#1)/2.#2.#3.}% \def\CALX_ad_nc #1.#2.#3.% {\expandafter\CALX_ad_nd\the\numexpr#1+(#2*#3/#1-#1)/2.#2.#3.}% \def\CALX_ad_nd #1.#2.#3.% {\expandafter\CALX_ad_ne\the\numexpr#1+(#2*#3/#1-#1)/2.#2.#3.}% \def\CALX_ad_ne #1.#2.#3.% {\expandafter\CALX_ad_lf\the\numexpr#1+(#2*#3/#1-#1)/2.}% \def\CALX_ad_lf #1.#2.% {% \expandafter\CALX_ad_sa\the\numexpr#1*#1/1000000000/\CALX_pten{2*#2}.% #1.-#2.1000000000.% }% \def\CALX_ad_ys #1.#2.#3{\expandafter\CALX_dgo\the\numexpr#3#1.#2.}% \def\CALX_ad_yc #1.#2.#3#4#5% {% \expandafter\CALX_dgo\the\numexpr#51*(#3#4(\ifnum#2<-16 0\else #1/\CALX_pten{-#2-7}\fi)).-7.% }% \def\CALX_ad_zs #1.#2.#3% {% \expandafter\CALX_dgo\the\numexpr#3#1*1489429756/853380389% \expandafter.\the\numexpr#2-2.% }% \def\CALX_ad_zc #1.#2.#3#4#5% {% \expandafter\CALX_dgo\the\numexpr#51*(#3#4(\ifnum#2<-16 0\else #1/\CALX_pten{-#2-7}\fi))*1489429756/853380389.-9.% }% \def\CALX_ad_zm #1.#2.#3#4#5% {% \expandafter\CALX_dgo\the\numexpr#51*(#3#4(\ifnum#2<-16 0\else #1/\CALX_pten{-#2-7}\fi))*105115715/602268683.-8.% }% \def\CALX_ae_a #1% {% \ifnum\CALX_trigdigits>\xint_c_viii \CALX_ae_j\fi \if I#1\CALX_ae_j\fi \CALX_ae_b #1% }% \def\CALX_ae_j\fi #1\CALX_ae_b #2\xint:{\fi\CALX_ac_a #2\xint:}% \def\CALX_ae_b F#1#2.#3.#4\xint:% {% \ifnum\ifnum#2=\xint_c_ \xint_c_\else\numexpr#2+8*#3\relax\fi <\xint_c_i \CALX_ae_k\fi \CALX_ae_ba #1#2.#3.#4\xint:% }% \def\CALX_ae_k\fi\CALX_ae_ba #1\xint:{\fi\CALX_ac_a F#1\xint:}% \def\CALX_ae_ba #1#2.#3.#4\xint:% {% \expandafter\CALX_ae_bb\the\numexpr#2+8*#3\expandafter.% \the\numexpr(2*#2+7)/16\expandafter.% \the\numexpr#2+8-8*((2*#2+7)/16).#4\xint:#1% }% \def\CALX_ae_bb #1.#2.#3.#4\xint:#5% {\expandafter\CALX_ae_c\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.#5}% \def\CALX_ae_c #1.#2.#3#4% {% \csname CALX_ae\ifnum#2=\xint_c_i\ifnum#1<141421357 \ifnum#1=100000000 o\else l\fi\else s\fi\else s\fi#4\if-#3m\else p\fi\endcsname #1.#2.% }% \expandafter\def\csname CALX_aesap\endcsname #1.#2.% {\CALX_ae_t#1.#2.\CALX_ad_zs+}% \expandafter\def\csname CALX_aesam\endcsname #1.#2.% {\CALX_ae_t#1.#2.\CALX_ad_zs-}% \expandafter\def\csname CALX_aescp\endcsname #1.#2.% {\CALX_ae_t#1.#2.\CALX_ad_zc{900000000}-+}% \expandafter\def\csname CALX_aescm\endcsname #1.#2.% {\CALX_ae_t#1.#2.\CALX_ad_zm{900000000}++}% \expandafter\def\csname CALX_aelap\endcsname #1.#2.% {\CALX_ae_l#1.\CALX_ad_zc{900000000}-+}% \expandafter\def\csname CALX_aelam\endcsname #1.#2.% {\CALX_ae_l#1.\CALX_ad_zc{900000000}--}% \expandafter\def\csname CALX_aelcp\endcsname #1.#2.% {\CALX_ae_l#1.\CALX_ad_zs+}% \expandafter\def\csname CALX_aelcm\endcsname #1.#2.% {\CALX_ae_l#1.\CALX_ad_zm{1800000000}-+}% \expandafter\def\csname CALX_aeoap\endcsname #1.#2.% {\CALX_ac_a F+1.0.100000001!\xint: a}% \expandafter\def\csname CALX_aeoam\endcsname #1.#2.% {\CALX_ac_a F-1.0.100000001!\xint: a}% \expandafter\def\csname CALX_aeocp\endcsname #1.#2.% {\CALX_ac_a F+1.0.100000001!\xint: c}% \expandafter\def\csname CALX_aeocm\endcsname #1.#2.% {\CALX_ac_a F-1.0.100000001!\xint: c}% \def\CALX_ae_t #1.#2.% {\expandafter\CALX_ae_u\the\numexpr100000000*1000000000/#1.#2.}% \def\CALX_ae_u #1.#2.% {% \expandafter\CALX_ad_s\the\numexpr\ifnum#1<1000000000 #1\else 100000000\fi\expandafter.\the\numexpr\ifnum#1<1000000000 1\else 2\fi-#2.1000000000.% }% \def\CALX_ae_l #1.% {\expandafter\CALX_ae_la\the\numexpr(#1-100000000)*1000000000/#1.#1.}% \def\CALX_ae_la #1.% {\expandafter\CALX_ae_lb\the\numexpr\CALX_nd_c #10001122334\xint:.#1.}% \def\CALX_ae_lb #1.#2.#3.% {% \expandafter\CALX_ad_lc\the\numexpr(#3-100000000)*\CALX_pten{2*#1+1}% *100000000/#3\expandafter.\the\numexpr2000000000-#2.#1.% }% \def\CALX_tq_a #1% {% \ifnum\CALX_trigdigits>\xint_c_viii \CALX_tq_j\fi \if I#1\CALX_tq_j\fi \CALX_tq_b #1% }% \def\CALX_tq_j\fi #1\CALX_tq_b #2\xint:{\fi\CALX_at_a #2\xint:}% \def\CALX_tq_b F#1#2.#3.#4\xint:% {% \ifnum#2=\xint_c_ \CALX_tq_k\fi \CALX_tq_ba #1#2.#3.#4\xint:% }% \def\CALX_tq_k\fi\CALX_tq_ba #1\xint:{\fi\CALX_at_a F#1\xint:}% \def\CALX_tq_ba #1#2.#3.#4\xint:% {% \expandafter\CALX_tq_bb\the\numexpr#2+8*#3\expandafter.% \the\numexpr(2*#2+7)/16\expandafter.% \the\numexpr#2+8-8*((2*#2+7)/16).#4\xint:#1% }% \def\CALX_tq_bb #1.#2.#3.#4\xint:#5% {\expandafter\CALX_tq_c\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.#5}% \def\CALX_tq_c #1.#2.#3#4#5#6% {% \csname CALX_tq\ifnum#2<\xint_c_ i\else\ifnum#2=\xint_c_ \ifnum#1>414213562 ii\else i\fi\else\ifnum#2=\xint_c_i \ifnum#1<241421357 iv\else v\fi\else v\fi\fi\fi#6\endcsname #1.#2.#3% }% \expandafter\def\csname CALX_tqi1\endcsname{\CALX_tq_i\CALX_ad_ys}% \expandafter\def\csname CALX_tqii1\endcsname{\CALX_tq_ii\CALX_ad_yc}% \expandafter\def\csname CALX_tqiv1\endcsname{\CALX_tq_iv\CALX_ad_yc}% \expandafter\def\csname CALX_tqv1\endcsname{\CALX_tq_v\CALX_ad_yc}% \expandafter\def\csname CALX_tqi0\endcsname{\CALX_tq_i\CALX_ad_zs}% \expandafter\def\csname CALX_tqii0\endcsname{\CALX_tq_ii\CALX_ad_zc}% \expandafter\def\csname CALX_tqiv0\endcsname{\CALX_tq_iv\CALX_ad_zc}% \expandafter\def\csname CALX_tqv0\endcsname{\CALX_tq_v\CALX_ad_zc}% \def\CALX_tq_i #1#2.#3.#4% {% \expandafter\CALX_tq_x\the\numexpr2*#2*1000000000/(1000000000+ \ifnum#3<-\xint_c_iv 0\else#2*#2/1000000000/\CALX_pten{-2*#3}\fi).% #3.#1#4% }% \def\CALX_tq_x #1.#2.% {% \ifnum#1<1000000000 \expandafter\CALX_tq_y\else \expandafter\CALX_tq_z\fi #1.#2.% }% \def\CALX_tq_y #1.#2.{\CALX_ad_s#1.#2.2000000000.}% \def\CALX_tq_z #1.#2.% {% \expandafter\CALX_ad_s\the\numexpr#1/10\expandafter.% \the\numexpr#2+1.2000000000.% }% \def\CALX_tq_ii #1#2.#3.#4% {\expandafter\CALX_tq_w\the\numexpr#2*#2/1000000000.#1#4}% \def\CALX_tq_w #1.#2#3% {% \expandafter\CALX_ad_s\the\numexpr(1000000000-#1)*1000000000/% (1000000000+#1).0.2000000000.#2{450000000}-#3% }% \def\CALX_tq_iv #1#2.#3.#4% {% \expandafter\CALX_ad_s\the\numexpr((#2-100000000)*(#2+100000000)% /100000000)*1000000000/(#2*#2/100000000+100000000).% 0.2000000000.#1{450000000}+#4% }% \def\CALX_tq_v #1#2.#3.% {\expandafter\CALX_tq_r\the\numexpr100000000*1000000000/#2.#3.#1}% \def\CALX_tq_r #1.#2.% {% \expandafter\CALX_tq_u\the\numexpr\ifnum#1<1000000000 #1\else 100000000\fi\expandafter.\the\numexpr\ifnum#1<1000000000 1\else 2\fi-#2.% }% \def\CALX_tq_u #1.#2.#3#4% {% \expandafter\CALX_tq_x\the\numexpr2*#1*1000000000/(1000000000+ \ifnum#2<-\xint_c_iv 0\else#1*#1/1000000000/\CALX_pten{-2*#2}\fi).% #2.#3{900000000}-#4% }% % \end{macrocode} % \subsection{Series kernel with column short products} %\begin{lverb} % Horner levels T_k = C_k - U T_(k+1) / 10^(4b) by column short products. % Level (b, m, n): U has b limbs (more limbs of U_0 enter as extra % precision), T_(k+1) m limbs, T_k n limbs. Columns c (weight 10^(4c) of % U T) from b+n-1 down to b-2; columns b-1, b-2 are guards (carry only). % Column text: terms `u*t+` with u = -(limb of U) balanced, t limb of T; % the text of column c-1 comes from the text of column c by \CALX_Zr % (`u*t+` -> `t+u*`: each u takes the t of the next term), with the next % u (f) opened in front and the next t (g) closing the last term. % Stream of a level, inside the \numexpr of the outermost column: %( \CALX_Zs \CALX_Zt \CALX_Zw %) % U list `u!..u!0!0!0!0!` (MS first, negated, balanced, top limb up to % 10^4 in modulus), T items `\CALX_Zn x_top.\CALX_Zl x. .. \CALX_Zl0.` % (\CALX_Zl evaluates a balanced limb where the item enters a text), % static item of column c: `C_c!`. % Column value x: the parent adds round(x/10^4) (\CALX_Zu, \CALX_Zg) and % the limb x - 10^4 round(x/10^4) in [-5000,5000] is left after the % parent's terminator; final levels: floor carry, limbs 0000..9999 % (\CALX_Zv$empty: \CALX_Zuf). Output after the outermost \numexpr$empty: %( x_top.\CALX_Zl x. ... (n limbs, MS first) %) % |u| <= 5000 (top <= 10^4), |t| <= 10^4, <= 28 terms: |x| < 1.5e9. %\end{lverb} % \begin{macrocode} \let\CALX_Zs\relax \let\CALX_Zt\relax \let\CALX_Zw\relax \let\CALX_Zq\relax \def\CALX_Za #1\CALX_Zs#2!#3\CALX_Zt#4.#5\CALX_Zw#6!#7#8% {% #6+#1\expandafter#8\the\numexpr\expandafter#7\expanded {#2*\CALX_Zr#1\CALX_Zx*#4.+}\CALX_Zs#3\CALX_Zt#5\CALX_Zw }% \def\CALX_Zb #1\CALX_Zs#2!#3\CALX_Zt#4.#5\CALX_Zw#6!#7#8% {% #6+\expandafter#8\the\numexpr\expandafter#7\expanded{#2*#4.+}% \CALX_Zs#3\CALX_Zt#5\CALX_Zw }% \def\CALX_Zc #1\CALX_Zs#2\CALX_Zt#3\CALX_Zw#4!#5#6% {#4+\expandafter#6\the\numexpr#5\CALX_Zs#2\CALX_Zt#3\CALX_Zw}% \def\CALX_Zz #1\CALX_Zs#2\CALX_Zw#3!{#3+#10.}% % \end{macrocode} %\begin{lverb} % \CALX_Zad$empty: as \CALX_Za when U is used up (f = 0): the first term's t % is % dropped instead of opening a zero term in front (\CALX_Zrf) %\end{lverb} % \begin{macrocode} \def\CALX_Zad #1\CALX_Zs#2!#3\CALX_Zt#4.#5\CALX_Zw#6!#7#8% {% #6+#1\expandafter#8\the\numexpr\expandafter#7\expanded {\CALX_Zrf#1\CALX_Zx*#4.+}\CALX_Zs#3\CALX_Zt#5\CALX_Zw }% \def\CALX_Zrf #1*#2+{#1*\CALX_Zr}% \def\CALX_Zr #1*#2+{#2+#1*\CALX_Zr}% \def\CALX_Zx*\CALX_Zr{}% \def\CALX_Zu #1.{#1/10000.\CALX_Zl#1.}% \def\CALX_Zg #1.{#1/10000.}% \def\CALX_Zl #1.{\the\numexpr#1-#1/10000*10000\relax}% \def\CALX_Zn #1.{#1}% % \end{macrocode} %\begin{lverb} % negating variants: a level whose output feeds a level computing % C + U T (instead of C - U T) uses the carry \CALX_Zun (limbs negated by % \CALX_Zln); the next level is \CALX_Zvn (top limb negated by \CALX_Znn) %\end{lverb} % \begin{macrocode} \def\CALX_Zun #1.{#1/10000.\CALX_Zln#1.}% \def\CALX_Zln #1.{\the\numexpr#1/10000*10000-#1\relax}% \def\CALX_Znn #1.{\the\numexpr-#1\relax}% % \end{macrocode} %\begin{lverb} % final variant: floor carry, limb as 4 digits followed by ! %\end{lverb} % \begin{macrocode} \def\CALX_Zuf #1.{\expandafter\CALX_Zuh\the\numexpr#1-#1/10000*10000.#1.}% \def\CALX_Zuh #1.% {\ifnum#1<\xint_c_ \expandafter\CALX_Zum\else\expandafter\CALX_Zup\fi#1.}% \def\CALX_Zum #1.#2.{(#2/10000-1).\CALX_Zlm#1.}% \def\CALX_Zup #1.#2.{#2/10000.\CALX_Zlp#1.}% \def\CALX_Zlm #1.{\the\numexpr10000+#1!}% \def\CALX_Zlp #1.{\expandafter\xint_gobble_i\the\numexpr10000+#1!}% % \end{macrocode} %\begin{lverb} % driver: \CALX_Zq{} %( \CALX_Zv{}{} or a client's final macro, which %: receives {}\CALX_Zq. %) %\end{lverb} % \begin{macrocode} \def\CALX_Zd #1\CALX_Zq#2#3{#3{#2}#1\CALX_Zq}% \def\CALX_Zv #1#2\CALX_Zq#3#4% {% \expandafter\CALX_Zd\the\numexpr#3\CALX_Zs#1\CALX_Zt\CALX_Zn#2% \CALX_Zl0.\CALX_Zw#4\CALX_Zq{#1}% }% \def\CALX_Zvn #1#2\CALX_Zq#3#4% {% \expandafter\CALX_Zd\the\numexpr#3\CALX_Zs#1\CALX_Zt\CALX_Znn#2% \CALX_Zl0.\CALX_Zw#4\CALX_Zq{#1}% }% % \end{macrocode} %\begin{lverb} % level whose T items are given whole (no \CALX_Zn prefix), U pad #5 (square % level of sin/cos); carry \CALX_Zuu$empty: limbs evaluated as `v!' (U % list) %\end{lverb} % \begin{macrocode} \def\CALX_Zvq #1#2\CALX_Zq#3#4#5% {% \expandafter\CALX_Zd\the\numexpr#3\CALX_Zs#1#5\CALX_Zt#2% \CALX_Zl0.\CALX_Zw#4\CALX_Zq{#1}% }% \def\CALX_Zuu #1.{#1/10000.\CALX_Zlu#1.}% \def\CALX_Zlu #1.{\the\numexpr#1-#1/10000*10000!}% % \end{macrocode} %\begin{lverb} % exact product level (all columns kept, C = 0): T negated as in \CALX_Zvn, % pads from the descriptor: \CALX_Zvp{}{}{}{} %\end{lverb} % \begin{macrocode} \def\CALX_Zvp #1#2\CALX_Zq#3#4#5#6% {% \expandafter\CALX_Zd\the\numexpr#3\CALX_Zs#1#5\CALX_Zt\CALX_Znn#2% \CALX_Zl0.#6\CALX_Zw#4\CALX_Zq{#1}% }% % \end{macrocode} %\begin{lverb} % load time: \CALX_Zlevp{b}{m}: product of U (b limbs) by T % (m limbs), columns b+m-1 down to 0, all limbs output (carry macro); % columns x < m (U used up for the text of x-1) use \CALX_Zad %\end{lverb} % \begin{macrocode} \def\CALX_Zlevp #1#2#3% {% \noexpand\CALX_Zvp{\noexpand\CALX_Zb}% {\expandafter\CALX_Zlpv\the\numexpr#1+#2-1\expandafter.\the\numexpr#2.#3}% {\expandafter\CALX_Zzr\the\numexpr#2-1.}% {\expandafter\CALX_Zlpz\the\numexpr#1-1.}% }% \def\CALX_Zlpv #1.#2.#3% column #1 (m = #2): C = 0, macro of #1-1, carry {% 0!\ifnum#1=\xint_c_i\noexpand\CALX_Zz\else \ifnum#1>#2 \noexpand\CALX_Za\else\noexpand\CALX_Zad\fi\fi\noexpand#3% \ifnum#1=\xint_c_i 0!\else\expandafter\CALX_Zlpv\the\numexpr#1-1.#2.#3\fi }% \def\CALX_Zlpz #1.{\ifnum#1>\xint_c_ \noexpand\CALX_Zl0.\expandafter\CALX_Zlpz \the\numexpr#1-1\expandafter.\fi}% % \end{macrocode} %\begin{lverb} % list helpers: \CALX_Zrev \CALX_Zq! reverses (inside \expanded); % \CALX_Zzr . k zero limbs 0!; \CALX_Zrep . k limbs 9999!; % \CALX_Ztn c1!c2!..\relax -> c1.\CALX_Zn c2 .. (T items, load time) %\end{lverb} % \begin{macrocode} \def\CALX_Zrev #1\CALX_Zq!{\CALX_Zrw#1\CALX_Zq!\relax}% \def\CALX_Zrw #1!#2\relax{\CALX_Zgob#1\CALX_Zre\CALX_Zq\CALX_Zrw#2\relax#1!}% \def\CALX_Zre\CALX_Zq\CALX_Zrw#1\relax\CALX_Zq!{}% \def\CALX_Zzr #1.{\ifnum#1>\xint_c_ 0!\expandafter\CALX_Zzr \the\numexpr#1-1\expandafter.\fi}% \def\CALX_Zrep #1.{\ifnum#1>\xint_c_ 9999!\expandafter\CALX_Zrep \the\numexpr#1-1\expandafter.\fi}% \def\CALX_Ztn #1!#2\relax{#1\CALX_Ztm#2\relax}% \def\CALX_Ztm #1\relax{\if\relax\detokenize{#1}\relax\else\CALX_Ztk#1\relax\fi}% \def\CALX_Ztk #1!#2\relax{.\noexpand\CALX_Zn#1\CALX_Ztm#2\relax}% % \end{macrocode} %\begin{lverb} % start: \CALX_Zst{}{}{} %\end{lverb} % \begin{macrocode} \def\CALX_Zst #1#2#3{\CALX_Zd#1.\CALX_Zq{#3}#2}% % \end{macrocode} %\begin{lverb} % U list from limbs u_1!..u_b!\CALX_Zq! (MS first, u_1 signed, others % 0..9999): -(u_i - 10^4 [u_i >= 5000] + [u_(i+1) >= 5000]), top limb % -(u_1 + [u_2 >= 5000]) kept whole; four zero limbs appended. %\end{lverb} % \begin{macrocode} \def\CALX_Zgob #1\CALX_Zq{}% \def\CALX_Zbt #1!#2!{\the\numexpr0-(#1)-#2/10000!\CALX_Zbn#2!}% \def\CALX_Zbn #1!#2!% {\CALX_Zgob#2\CALX_Zbe\CALX_Zq\the\numexpr-#2/10000-#1+10000*(#1/10000)!% \CALX_Zbn#2!}% \def\CALX_Zbe\CALX_Zq\the\numexpr-#1/10000#2!\CALX_Zbn\CALX_Zq!% {\the\numexpr#2!0!0!0!0!}% % \end{macrocode} %\begin{lverb} % load time: descriptor of a level (inside \edef) % \CALX_Zlev{b}{m}{n}{} % \CALX_Zlevx{b}{m}{n}{C} (\CALX_Zvn) %\end{lverb} % \begin{macrocode} \def\CALX_Zlev{\CALX_Zlevx\CALX_Zv}% \def\CALX_Zlevx #1#2#3#4#5#6% {% \noexpand#1{\expandafter\CALX_Zmac\the\numexpr#2+#4-1.#2.#3.}% {\expandafter\CALX_Zlv\the\numexpr#2+#4-1\expandafter.\expanded{#2.#3.#5}\relax#6}% }% \def\CALX_Zmac #1.#2.#3.% macro of column #1 (b = #2, m = #3) {% \ifnum#1>\numexpr#2+#3-1\relax\noexpand\CALX_Zc\else \ifnum#1=\numexpr#2+#3-1\relax\noexpand\CALX_Zb\else \ifnum#1<\numexpr#2-1\relax\noexpand\CALX_Zz\else\noexpand\CALX_Za \fi\fi\fi }% \def\CALX_Zlv #1.#2.#3.#4\relax#5% column #1 >= b-1: C! {% \ifnum#1<#2 0\else\CALX_Zhd#4\relax\fi!% \expandafter\CALX_Zmac\the\numexpr#1-1.#2.#3.% \ifnum#1>#2 \noexpand#5\else\noexpand\CALX_Zg\fi \ifnum#1<#2 0!\else \expandafter\CALX_Zlv\the\numexpr#1-1\expandafter.\the\numexpr#2% \expandafter.\the\numexpr#3\expandafter.\CALX_Ztl#4\relax\relax#5% \fi }% \def\CALX_Zhd #1!#2\relax{#1}% \def\CALX_Ztl #1!#2\relax{#2}% \let\CALX_qW\relax \def\CALX_gobW #1\CALX_qW{}% % \end{macrocode} % \subsection{Series kernels with three-limb passes (P above 40)} %\begin{lverb} % Generic path (P >= 9, |X| < 0.8): fixed point Horner on 4-digit limbs % with the precision schedule of xinttrig (decreasing widths). % u = X^2, S(u) = sum (-u)^k/(2k+1)!, C(u) = sum (-u)^k/(2k)!, c_k the % coefficients. Scale 10^(4A) (A limbs) at all levels. Level k = N-1..0: %( %: T_k = C_k - ceil(U_k T_{k+1} / 10^(4 b_k)), T_N = C_N, %) % C_k = floor(c_k 10^(4A)), U_k = floor(u 10^(4 b_k)) (b_k limbs, the % top b_k limbs of U_0). T_k is kept on its n_k significant limbs % (c_k 10^(4A) + 4 < 10^(4 n_k): the other limbs are zero), n_0 = A. % % Error on S (or C), units 10^(-4A), u <= 0.64: level k contributes % u^k (1 (C_k) + 1 (ceil) + 10^(4A-4 b_k) T_{k+1} 10^(-4A)), T_N 1, % tail u^(N+1)/(2N+3)! (resp. (2N+2)!). The table below (generated by % tools/trig_sched2.py with exact rationals, all P = 9..100) chooses N, % A, b_k, n_k so that the total is <= 0.005 10^-P S_min (S_min = % sin(0.8)/0.8, C_min = cos(0.8)): relative error <= 0.005 ulp before % the single final rounding (sin X = round_P(X S), cos X = round_P(C)). % % The c_k are computed at load time by the recurrence c_k = c_{k-1} / % ((2k)(2k+1)) (resp. ((2k-1)(2k))) on floor(10^140 c_k) (no factorial; % error < 2 10^-140, i.e. < 10^-30 unit), then truncated to 10^(4A). % % Product: the % level list has L = b_k + n_k items ,! (LS first), item i stands % for column i: items i < b_k are u_i,0!, items b_k + j are 0,c_j! (the % limbs of C_k), then the sentinel \CALX_qW,0!. One pass handles three % limbs t0, t1, t2 of T_{k+1} (missing ones are 0): with a window of the % three previous u's, column i becomes x = a + carry - t0 u_i - t1 u_(i-1) % - t2 u_(i-2); the pass emits u_(i-3),low(x)! (the u's move three items % up, the columns stay: the next pass multiplies by t3, t4, t5). After % ceil(m/3) passes the items hold the limbs of D = C_k 10^(4 b_k) - U_k % T_{k+1} modulo 10^(4L) (carries out of item L-1 and the u's leaving % the list only concern columns >= L), exact since 0 <= D < 10^(4L) % (D 10^(-4 b_k) = T_k, n_k limbs; for k = 0, C_0 = 10^(4A) is 0 modulo % 10^(4L)). T_k = items b_k..L-1. |x| < 3.0003 10^8: 1400000000 + x has % 10 digits, the first six minus 140000 are the carry, the last four % the low limb (carry by offset). %\end{lverb} % \begin{macrocode} % \end{macrocode} %\begin{lverb} % \CALX_tp ./!: the limbs, LS first, as pairs % ,0!, exactly of them (zero limbs added on top; a top % limb beyond is dropped: zero by construction). % \CALX_tq$empty: same, plain !. %\end{lverb} % \begin{macrocode} \def\CALX_tp #1.% {\ifnum#1>\xint_c_ \expandafter\CALX_tpa\else\expandafter\CALX_tpg\fi #1.}% \def\CALX_tpg #1.#2/!{}% \def\CALX_tpa #1.#2!{\CALX_gsl#2\CALX_tpe/\CALX_tpb#1.#2!}% \def\CALX_tpe/\CALX_tpb#1./!{\CALX_tpz#1.}% \def\CALX_tpb #1.1#2#3#4#5#6#7#8#9!% {% #6#7#8#9,0!\ifnum#1>\xint_c_i #2#3#4#5,0!\fi \expandafter\CALX_tp\the\numexpr#1-2.% }% \def\CALX_tpz #1.% {\ifnum#1>\xint_c_ 0000,0!\expandafter\CALX_tpz\the\numexpr#1-1.\fi}% \def\CALX_tq #1.% {\ifnum#1>\xint_c_ \expandafter\CALX_tqa\else\expandafter\CALX_tpg\fi #1.}% \def\CALX_tqa #1.#2!{\CALX_gsl#2\CALX_tqe/\CALX_tqb#1.#2!}% \def\CALX_tqe/\CALX_tqb#1./!{\CALX_tqz#1.}% \def\CALX_tqb #1.1#2#3#4#5#6#7#8#9!% {% #6#7#8#9!\ifnum#1>\xint_c_i #2#3#4#5!\fi \expandafter\CALX_tq\the\numexpr#1-2.% }% \def\CALX_tqz #1.% {\ifnum#1>\xint_c_ 0000!\expandafter\CALX_tqz\the\numexpr#1-1.\fi}% \def\CALX_tr #1.% {\ifnum#1>\xint_c_ \expandafter\CALX_tra\else\expandafter\CALX_tpg\fi #1.}% \def\CALX_tra #1.#2!{\CALX_gsl#2\CALX_tre/\CALX_trb#1.#2!}% \def\CALX_tre/\CALX_trb#1./!{\CALX_trz#1.}% \def\CALX_trb #1.1#2#3#4#5#6#7#8#9!% {% 0,#6#7#8#9!\ifnum#1>\xint_c_i 0,#2#3#4#5!\fi \expandafter\CALX_tr\the\numexpr#1-2.% }% \def\CALX_trz #1.% {\ifnum#1>\xint_c_ 0,0000!\expandafter\CALX_trz\the\numexpr#1-1.\fi}% \def\CALX_gsl #1/{}% % \end{macrocode} %\begin{lverb} % Kernels. \CALX_sin_h ...\xint: (K unused), same % for \CALX_cos_h. Schedule macro \CALX_ts

: ..{d}{skip} % {n}{C}{T_N} for level N-1, then \CALX_lv{d}{skip}{n}{C} for the next % levels, \CALX_lend{}{}{}{}. %\end{lverb} % \begin{macrocode} \def\CALX_sin_h #1.% {% \ifnum\CALX_trigdigits<\xint_c_ix \xint_dothis\CALX_sin_q\fi \ifcsname CALX_tfs\the\numexpr\CALX_trigdigits\endcsname \xint_dothis\CALX_sin_fixed\fi \xint_orthat\CALX_sin_scheduled }% \def\CALX_sin_fixed #1\xint:% {\csname CALX_tfs\the\numexpr\CALX_trigdigits\endcsname \xint:#1\xint: s}% \def\CALX_sin_scheduled #1\xint:% {\expandafter\CALX_sha\romannumeral`&&@\csname CALX_tss\the\numexpr\CALX_trigdigits\endcsname\xint:#1\xint: s}% \def\CALX_cos_h #1.% {% \ifnum\CALX_trigdigits<\xint_c_ix \xint_dothis\CALX_cos_q\fi \ifcsname CALX_tfc\the\numexpr\CALX_trigdigits\endcsname \xint_dothis\CALX_cos_fixed\fi \xint_orthat\CALX_cos_scheduled }% \def\CALX_cos_fixed #1\xint:% {\csname CALX_tfc\the\numexpr\CALX_trigdigits\endcsname \xint:#1\xint: c}% \def\CALX_cos_scheduled #1\xint:% {\expandafter\CALX_sha\romannumeral`&&@\csname CALX_tsc\the\numexpr\CALX_trigdigits\endcsname\xint:#1\xint: c}% % \end{macrocode} %\begin{lverb} % u 10^(4 b_0) < 1 iff D + 8e + 2 b_0 <= 0: then sin X = round_P(X), % cos X = 1 (b_0 >= A, 4A >= P + 3: u/6 < 0.005 10^-P). % % Generic path, all on the kernel CALX_Z: % X = N 10^(8e) (nb blocks), z = -e - nb >= 0 zero blocks, X' = N 10^(-8nb) % in [10^-8, 1): its limbs are those of N (\CALX_shr), X = X' % 10^(-8z). Square level (\CALX_Zvq): U = X', T = X' on b_0+1 limbs % (\CALX_tku, \CALX_tkn), output -X'^2 10^(4(b_0+1)) (|err| < 2.5 units); % \CALX_shu: U_0 list = 4z zero limbs, these limbs, 0!0!0!0!. Series % levels; sin and B: level 0 negated (\CALX_Zun), \CALX_shw swaps in the % X' list (carried in the stream after the descriptors), product level % (\CALX_Zvp, T = T_0 + 3 zero limbs): Y = X' T_0 10^12 on A+4 limbs, % |err| < 1 unit (relative < 10^(-4A-4)), \CALX_shx; cos and A: level 0 % floor carries, \CALX_shy. \CALX_shf: limbs dddd! (one zero limb in % front, one appended if needed: ..{pre}{post} static per P), % calxtrig's \CALX_rsa (m = m0 + z for sin), \CALX_sho: one % rounding to P (s, c) or P+4 with the continuation (A, B). % Schedule \CALX_ts

= ..{T_N}, three macros % with one parameter (the dynamic header) whose bodies are the level % descriptors: inserted by expansion, never grabbed. % Stream: \CALX_sha ..{T_N}\xint: % ..\xint:. %\end{lverb} % \begin{macrocode} \def\CALX_sha #1.#2.#3\xint:#4#5.#6.% {% \ifnum\numexpr#5+8*#6+2*#1<\xint_c_i \xint_dothis\CALX_sha_tiny\fi \xint_orthat\CALX_sha_regular #1.#2.#3\xint:#4#5.#6.% }% \def\CALX_sha_tiny #1.#2.#3\xint:#4#5.#6.#7\xint:#8% {\csname CALX_shz#8\endcsname#4#5.#6.#7\xint:}% \def\CALX_sha_regular #1.#2.#3\xint:#4#5.#6.#7\xint:#8% {% \expandafter\CALX_shb\expanded{{\CALX_shr#7\CALX_Zq!\relax}}% #3#1.\the\numexpr-#6-(#5+3)/8.#4#8% }% \def\CALX_shr #1#2!{\CALX_Zgob#1\CALX_shre\CALX_Zq\CALX_shrb#2!}% \def\CALX_shrb #1#2#3#4#5#6#7#8!#9\relax{\CALX_shr#9\relax#1#2#3#4!#5#6#7#8!}% \def\CALX_shre\CALX_Zq\CALX_shrb!#1\relax{}% \def\CALX_shzs #1\xint:{\CALX_fnround{\CALX_trigdigits}{F#1}}% \def\CALX_shzc #1\xint:{ F+1.0.100000001!}% % \end{macrocode} %\begin{lverb} % {X' limbs}{T_N}..: the square level ({header}) %\end{lverb} % \begin{macrocode} \def\CALX_shb #1#2#3#4#5#6.#7.% {% \expandafter#4\expandafter{\expanded{\expandafter\CALX_tku\expandafter \CALX_tkn\the\numexpr#6+1\expandafter.\expanded{#1\CALX_Zzr#6.0!}/% \noexpand\CALX_Zq{\CALX_Zbt#1\CALX_Zq!}}}{#2}#3#5#7.% }% \def\CALX_tkn #1{\noexpand\CALX_Zn#1.}% % \end{macrocode} %\begin{lverb} % after the square level: U_0 list, the series ({header}) %\end{lverb} % \begin{macrocode} \def\CALX_shu #1#2\CALX_Zq#3#4#5#6.% {% \expandafter#4\expandafter{\expanded{\unexpanded{#3}.\noexpand\CALX_Zq {\expandafter\CALX_Zzr\the\numexpr4*#6.\CALX_shux#20!0!0!0!}}}{#1}#5#6.% }% \def\CALX_shux #1.{#1!}% % \end{macrocode} %\begin{lverb} % end of the series: {output\CALX_Zq{X' list}} %\end{lverb} % \begin{macrocode} \def\CALX_shw #1#2\CALX_Zq#3#4{#4{#2\CALX_Zq{#3}}}% \def\CALX_shx #1#2.#3\CALX_Zq#4#5.#6#7{\CALX_shf#4#5.#6#7{#2}{#3}}% \def\CALX_shy #1.#2\CALX_Zq#3#4#5.#6#7{\CALX_shf#4 0.+#7{#1}{#2}}% \def\CALX_shf #1.#2.#3#4#5.#6#7#8#9% {% \expandafter\CALX_shg\expanded{#3\expandafter\xint_gobble_i \the\numexpr10000+#8!#9#4\relax#1.\the\numexpr#2+#5.}#6#7% }% \def\CALX_shg #1\relax#2.#3.#4#5% {\csname CALX_sho#5\expandafter\endcsname \expanded{{\CALX_rsa#2.#3.\CALX_bp#4#1}}}% \def\CALX_shos{\CALX_fnround{\CALX_trigdigits}}% \let\CALX_shoc\CALX_shos \def\CALX_shoA #1#2% {\expandafter#2\expandafter{\romannumeral0\CALX_fnround {\CALX_trigdigits+4}{#1}}}% \let\CALX_shoB\CALX_shoA % \end{macrocode} %\begin{lverb} % Load time: the coefficients floor(10^140 c_k), k = 0..40 % (iterated floor division by (2k)(2k+1), resp. (2k-1)(2k)), are stored % in calxdata.tex as 35 groups of 4 digits !, LS first in % \CALX_cd, MS first in \CALX_cm (generator % gencalxdata.py). The limbs of floor(c_k 10^(4A)) are groups 35 - A + 1 % to 35 (LS first): \CALX_tks skips m groups (7 per call), \CALX_tkt % (\CALX_tktx: 7 per call) takes n groups, each given as argument to a % converter (\CALX_tkr: item 0,!; \CALX_tkq: !; \CALX_tkm: % ), then drops the rest up to /. % % \CALX_tcoef{}{}{}{} ( \CALX_tr or % \CALX_tq): limbs of floor(c_k 10^(4A)), LS first, as items % (\CALX_tr) or limbs (\CALX_tq). %\end{lverb} % \begin{macrocode} \def\CALX_tcoef #1#2#3#4#5% {% \expandafter\CALX_tka\expandafter#5\the\numexpr35-(#3)\expandafter.% \the\numexpr#4\expandafter.% \romannumeral`&&@\csname CALX_cd#1\the\numexpr#2\endcsname/% }% \def\CALX_tka #1#2.% {\csname CALX_tks#2\expandafter\endcsname \csname CALX_tk\ifx#1\CALX_tr r\else q\fi\endcsname}% \def\CALX_tkr #1{0,#1!}\def\CALX_tkq #1{#1!}\def\CALX_tkm #1{#1}% \def\CALX_tku #1#2.% {\csname CALX_tkt\ifnum#2>\xint_c_vi x\else#2\fi\endcsname#1#2.}% \expandafter\def\csname CALX_tktx\endcsname #1#2.#3!#4!#5!#6!#7!#8!#9!% {#1{#3}#1{#4}#1{#5}#1{#6}#1{#7}#1{#8}#1{#9}% \expandafter\CALX_tku\expandafter#1\the\numexpr#2-7.}% \expandafter\def\csname CALX_tkt0\endcsname#1#2.#3/{}% \expandafter\def\csname CALX_tkt1\endcsname#1#2.#3!#4/{#1{#3}}% \expandafter\def\csname CALX_tkt2\endcsname#1#2.#3!#4!#5/{#1{#3}#1{#4}}% \expandafter\def\csname CALX_tkt3\endcsname#1#2.#3!#4!#5!#6/% {#1{#3}#1{#4}#1{#5}}% \expandafter\def\csname CALX_tkt4\endcsname#1#2.#3!#4!#5!#6!#7/% {#1{#3}#1{#4}#1{#5}#1{#6}}% \expandafter\def\csname CALX_tkt5\endcsname#1#2.#3!#4!#5!#6!#7!#8/% {#1{#3}#1{#4}#1{#5}#1{#6}#1{#7}}% \expandafter\def\csname CALX_tkt6\endcsname#1#2.#3!#4!#5!#6!#7!#8!#9/% {#1{#3}#1{#4}#1{#5}#1{#6}#1{#7}#1{#8}}% \expandafter\def\csname CALX_tks0\endcsname#1{\CALX_tku#1}% \expandafter\def\csname CALX_tks1\endcsname#1#2.#3!{\CALX_tku#1#2.}% \expandafter\def\csname CALX_tks2\endcsname#1#2.#3!#4!{\CALX_tku#1#2.}% \expandafter\def\csname CALX_tks3\endcsname#1#2.#3!#4!#5!{\CALX_tku#1#2.}% \expandafter\def\csname CALX_tks4\endcsname#1#2.#3!#4!#5!#6!% {\CALX_tku#1#2.}% \expandafter\def\csname CALX_tks5\endcsname#1#2.#3!#4!#5!#6!#7!% {\CALX_tku#1#2.}% \expandafter\def\csname CALX_tks6\endcsname#1#2.#3!#4!#5!#6!#7!#8!% {\CALX_tku#1#2.}% \expandafter\def\csname CALX_tks7\endcsname#1#2.#3!#4!#5!#6!#7!#8!#9!% {\CALX_tku#1#2.}% \def\CALX_tmpa #1% {% \expandafter\edef\csname CALX_tks#1\endcsname##1##2.##3!##4!% ##5!##6!##7!##8!##9!{\expandafter\noexpand \csname CALX_tks\the\numexpr#1-7\endcsname##1##2.}% \ifnum#1<35 \expandafter\CALX_tmpa\expandafter{\the\numexpr#1+1}\fi }% \CALX_tmpa{8}\let\CALX_tmpa\undefined % \end{macrocode} %\begin{lverb} % \CALX_tdef{}{

}{}{}{}{}{.. ...}: the % schedule \CALX_ts

, built in one \edef (the levels are unrolled % by \CALX_tdg inside it): ..{T_N} and the macros % \CALX_tsS, \CALX_tsQ, \CALX_tsF

. \CALX_tlet {

}{}: % same % schedule as for P'. The table (calxdata.tex, \CALX_tdata) has P >= 33 % only: for P <= 32 sin, cos, asin use the fixed path \CALX_tf. %\end{lverb} % \begin{macrocode} \def\CALX_tdef #1#2#3#4#5#6#7{\CALX_tdf{#1}{#2}{#3}{#4}{#5}{#6}#7/}% \def\CALX_tdf #1#2#3#4#5#6#7/% {% \expandafter\edef\csname CALX_ts#1#2\endcsname {#6.#3.{\expandafter\CALX_Ztn\expanded{\expandafter\CALX_Zrev \expanded{\CALX_tcoef{#1}{#4}{#3}{#5}\CALX_tq}\CALX_Zq!}\relax}% \expandafter\noexpand\csname CALX_tsS#1#2\endcsname \expandafter\noexpand\csname CALX_tsQ#1#2\endcsname \expandafter\noexpand\csname CALX_tsF#1#2\endcsname}% \expandafter\edef\csname CALX_tsS#1#2\endcsname##1% {\noexpand\CALX_Zd##1\expandafter\CALX_tdg\csname CALX_Zu\if#1sn\else f\fi \endcsname{#1}{#3}{#4-1}{#5}#7/\noexpand\CALX_shw}% \expandafter\edef\csname CALX_tsQ#1#2\endcsname##1% {\noexpand\CALX_Zd##1\CALX_Zlevx\CALX_Zvq{\the\numexpr#6+1\relax}% {\the\numexpr#6+1\relax}{\the\numexpr#6+1\relax}% {\expandafter\CALX_Zzr\the\numexpr#6+1.}\CALX_Zuu {\expandafter\CALX_Zzr\the\numexpr#6+2.}\noexpand\CALX_shu}% \expandafter\edef\csname CALX_tsF#1#2\endcsname##1% {\if#1s\noexpand\CALX_Zd##1\CALX_Zlevx\CALX_Zvp{\the\numexpr#3+4\relax}% {\the\numexpr#3+4\relax}{\the\numexpr#3+4\relax}% {\expandafter\CALX_Zzr\the\numexpr#3+4.}\CALX_Zuf {\expandafter\CALX_Zzr\the\numexpr#3+5.}% {\noexpand\CALX_Zl0.\noexpand\CALX_Zl0.\noexpand\CALX_Zl0.}% \noexpand\CALX_shx{\ifodd#3 \the\numexpr(#3+5)/2.\the\numexpr(#3+3)/2.% {0000!}{}\else\the\numexpr(#3+6)/2.% \the\numexpr(#3+4)/2.{0000!}{0000!}\fi}% \else \noexpand\CALX_shy##1{\ifodd#3 \the\numexpr(#3+3)/2.\the\numexpr(#3+1)/2.% {0000!}{0000!}\else\the\numexpr(#3+2)/2.\the\numexpr#3/2.{0000!}{}\fi}% \fi}% }% % \end{macrocode} %\begin{lverb} % levels k = N-1..0 from the pairs b_k.n_k. (m = n_(k+1)); level 0 with % C_0 = 10^(4A) on A+1 limbs, carry #1: \CALX_Zun (sin: negated items for % the product level), \CALX_Zuf (cos: floor carries, digits) %\end{lverb} % \begin{macrocode} \def\CALX_tdg #1#2#3#4#5#6.#7.#8/% {% \ifnum\numexpr#4\relax>\xint_c_ \CALX_Zlev{#6}{#5}{#7}{\expandafter\CALX_Zrev\expanded{\CALX_tcoef{#2}% {#4}{#3}{#7}\CALX_tq}\CALX_Zq!}\CALX_Zu \CALX_tdg#1{#2}{#3}{#4-1}{#7}#8/% \else \CALX_Zlev{#6}{#5}{#3+1}{1!\expandafter\CALX_Zzr\the\numexpr#3.}#1% \fi }% \def\CALX_tlet #1#2#3% {\expandafter\let\csname CALX_ts#1#2\expandafter\endcsname \csname CALX_ts#1#3\endcsname}% \CALX_tdata\let\CALX_tdata\undefined % \end{macrocode} % \subsection{Series kernels with fixed-arity short products (P up to 40)} %\begin{lverb} % Fixed path (P with A <= 11): square short products in the % manner of l3fp's \__fp_fixed_mul. Limbs % MS first in chunks of 4 braced groups {l1}{l2}{l3}{l4} (padded); a % level macro \CALX_m_ (generated by tools/trig_genfix.py) takes % the U chunks, the T chunks (s limbs each, a = ceil(s/4) chunks) and % the C chunks (n limbs) and computes, column e = n-1 .. -2 (weight % 10^(4e) at scale 10^(4A)), in one nested \the\numexpr chain (innermost % column first, its carry added to the outer one by \CALX_pk): %( %: 2100000000 + c_e - sum_{s-i-j=e} u_i t_j + carry, %) % products by \CALX_hd (diagonal d of a pair of chunks). Columns e < % -2 are omitted (their sum is < s 10^-4 < 0.002 unit: the budget is % 2.02 units per level in trig_sched2.py), T_k = columns 0..n-1 of % C 10^8 - sum, |T_k - (C - R)| < 1.002. Column value x: -1.09992 10^9 % < x < 10^5 for s <= 11 products, 2100000000 + x has 10 digits, the % first six minus 210000 are the carry (\CALX_pk), the last four the % limb; the top column has no carry out (0 <= T_k < 10^(4n)) except for % k = 0 where C_0 = 10^(4A) is 0 modulo 10^(4n): modular, exact. %\end{lverb} % \begin{macrocode} \def\CALX_pk #1#2#3#4#5#6{+#1#2#3#4#5#6-210000!}% \def\CALX_pg #1.% {\ifnum#1>\xint_c_iii \expandafter\CALX_pga\else\expandafter\CALX_pgb\fi #1.}% \def\CALX_pga #1.#2!#3!#4!#5!% {{{#2}{#3}{#4}{#5}}\expandafter\CALX_pg\the\numexpr#1-4.}% \def\CALX_pgb #1.{\csname CALX_pgr#1\endcsname}% \expandafter\def\csname CALX_pgr0\endcsname#1;{}% \expandafter\def\csname CALX_pgr1\endcsname#1!#2;{{{#1}{0000}{0000}{0000}}}% \expandafter\def\csname CALX_pgr2\endcsname#1!#2!#3;{{{#1}{#2}{0000}{0000}}}% \expandafter\def\csname CALX_pgr3\endcsname#1!#2!#3!#4;{{{#1}{#2}{#3}{0000}}}% \def\CALX_bl #1#2#3#4#5#6#7#8{{#1#2#3#4}{#5#6#7#8}}% % \end{macrocode} %\begin{lverb} % U_0 = floor(u 10^(16 a_0)), a_0 = ceil(b_0/4) chunks, from its native % blocks (padded on top with zero blocks). %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_ud1\endcsname 1#1!1#2!#3\CALX_qW% {{\CALX_bl#2\CALX_bl#1}}% \expandafter\def\csname CALX_ud2\endcsname 1#1!1#2!1#3!1#4!#5\CALX_qW% {{\CALX_bl#4\CALX_bl#3}{\CALX_bl#2\CALX_bl#1}}% \expandafter\def\csname CALX_ud3\endcsname 1#1!1#2!1#3!1#4!1#5!1#6!#7\CALX_qW% {{\CALX_bl#6\CALX_bl#5}{\CALX_bl#4\CALX_bl#3}{\CALX_bl#2\CALX_bl#1}}% % \end{macrocode} %\begin{lverb} % u: M (D <= 40 digits, n <= 5 blocks) as 4a limbs (a = ceil(n/2) % chunks, \CALX_xm), exact square M^2 (\CALX_sq, 2a chunks; % columns of at most 10 products: 10^9 + column + carry < 2 10^9 has 10 % digits, \CALX_pkq), then U_0 = floor(M^2 10^(16(e + a_0))): the shift % is a whole number of chunks (\CALX_fuq). D > 40: native square and % shifts (\CALX_fug). %\end{lverb} % \begin{macrocode} \def\CALX_fu #1.#2.% {% \ifnum#2>40 \expandafter\CALX_fug\else\expandafter\CALX_fuk\fi #1.#2.% }% \def\CALX_fuk #1.#2.#3.#4\xint:% {% \expandafter\CALX_fuq\expanded{{\csname CALX_xm\the\numexpr(2*#2+7)/16\endcsname#4}#1.#3.% \the\numexpr((2*#2+7)/16)/2.}% }% % \end{macrocode} %\begin{lverb} % Shift k = e + a_0 < a_0 (U_0 < 10^(16 a_0)): k >= 0 appends k zero % chunks, k < 0 keeps the first 2a + k chunks of M^2 (\CALX_kp); the % delta = 2a + k - a_0 top chunks (zero) are gobbled, or -delta zero % chunks are added on top. %\end{lverb} % \begin{macrocode} \def\CALX_fuq #1#2.#3.#4.% {% \expandafter\CALX_fur\the\numexpr#3+#2\expandafter.% \expanded{{\csname CALX_sq#4\endcsname#1}}#2.#4.% }% \def\CALX_fur #1.#2#3.#4.% {% \expandafter\CALX_fus\expanded{\ifnum#1<\xint_c_ {\csname CALX_kp\the\numexpr2*#4+#1\endcsname#2\CALX_qW}% \else{#2\csname CALX_zc#1\endcsname}\fi}% \the\numexpr2*#4+#1-#3.% }% \def\CALX_fus #1#2.% {\csname CALX_\ifnum#2<\xint_c_ zc\the\numexpr-#2\else gb#2\fi\endcsname#1}% \expandafter\def\csname CALX_zc0\endcsname{}% \expandafter\def\csname CALX_zc1\endcsname{{{0000}{0000}{0000}{0000}}}% \expandafter\def\csname CALX_zc2\endcsname {{{0000}{0000}{0000}{0000}}{{0000}{0000}{0000}{0000}}}% \expandafter\def\csname CALX_zc3\endcsname {{{0000}{0000}{0000}{0000}}{{0000}{0000}{0000}{0000}}% {{0000}{0000}{0000}{0000}}}% \expandafter\def\csname CALX_gb0\endcsname{}% \expandafter\let\csname CALX_gb1\endcsname\xint_gobble_i \expandafter\let\csname CALX_gb2\endcsname\xint_gobble_ii \expandafter\let\csname CALX_gb3\endcsname\xint_gobble_iii \expandafter\let\csname CALX_gb4\endcsname\xint_gobble_iv \expandafter\let\csname CALX_gb5\endcsname\xint_gobble_v \expandafter\let\csname CALX_gb6\endcsname\xint_gobble_vi \expandafter\let\csname CALX_gb7\endcsname\xint_gobble_vii \expandafter\def\csname CALX_kp1\endcsname#1#2\CALX_qW{{#1}}% \expandafter\def\csname CALX_kp2\endcsname#1#2#3\CALX_qW{{#1}{#2}}% \expandafter\def\csname CALX_kp3\endcsname#1#2#3#4\CALX_qW{{#1}{#2}{#3}}% \expandafter\def\csname CALX_kp4\endcsname#1#2#3#4#5\CALX_qW {{#1}{#2}{#3}{#4}}% \expandafter\def\csname CALX_kp5\endcsname#1#2#3#4#5#6\CALX_qW {{#1}{#2}{#3}{#4}{#5}}% \def\CALX_pkq #1#2#3#4#5#6{+#1#2#3#4#5#6-100000!}% \def\CALX_fug #1.#2.#3.#4\xint:% {% \expandafter\CALX_fua\romannumeral0\CALX_nshr{\numexpr-16*#3-16*#1}% {\romannumeral0\CALX_nshl{\numexpr16*#3+16*#1}{\romannumeral0\CALX_nmul {N+\the\numexpr(2*#2+7)/16.#4}{N+\the\numexpr(2*#2+7)/16.#4}}}% \xint:#1.% }% \def\CALX_fua N#1#2.#3\xint:#4.% {% \csname CALX_ud#4\endcsname#3100000000!100000000!100000000!% 100000000!100000000!100000000!\CALX_qW }% % \end{macrocode} %\begin{lverb} % \CALX_fv{}{}{}{}: one level. The % product macro \CALX_m_ takes T, C, then the first ceil(s/4) % chunks of U_0 untruncated (no extraction of the top s limbs: the % error is not larger, see tools/trig_genfix.py) and gobbles the others up to % \CALX_qW. %\end{lverb} % \begin{macrocode} \def\CALX_fv #1#2#3#4% {\expandafter\CALX_fw\expanded{{#1#3#2#4\CALX_qW}}{#4}}% \def\CALX_fw #1#2#3#4#5{#3{#4}{#5}{#1}{#2}}% \def\CALX_fend #1#2#3#4{ {#3}}% % \end{macrocode} %\begin{lverb} % Kernel entry, schedule \CALX_tf

: ...{m}{C}{T_N} % for level N-1, then \CALX_fv{m}{C} ..., \CALX_fend{}{}. %\end{lverb} % \begin{macrocode} \def\CALX_fha #1.#2.#3.#4\xint:#5#6.#7.#8\xint:#9% {% \ifnum\numexpr#6+8*#7+2*#2<\xint_c_i \CALX_fhj\fi \expandafter\CALX_fhb\expanded{{\CALX_fu #1.#6.#7.#8\xint:}}% #4\xint:{#9}{#5#6.#7.#8}{#3}% }% \def\CALX_fhj\fi\expandafter\CALX_fhb\expanded#1#2\xint:#3#4#5% {\fi\csname CALX_shz#3\endcsname#4\xint:}% \def\CALX_fhb #1#2#3#4#5\xint:% {% \expandafter\CALX_fhc\expanded{\romannumeral0\CALX_fv{#2}{#3}{#4}{#1}% #5} }% \def\CALX_fhc #1#2#3#4{\csname CALX_fk#2\endcsname{#1}#3.#4.}% % \end{macrocode} %\begin{lverb} % End: S (or C) = chunks, D = 16c digits (c = ceil(A/4) chunks, top limb % >= 6900), as a native float F+16c.-2c. (\CALX_sb). sin X = % round_P(X S) by the exact product of \CALX_fm_g (calxfp.sty), cos X = % round_P(C). % % For D <= 40, \CALX_fku replaces \CALX_fm_g (\CALX_fkt for D > 40): % exact product M S (M as a = ceil(n/2) chunks by % \CALX_xm, S = T_0 as c chunks) by \CALX_pm_ (generated, % tools/trig_genpm.py), limbs MS first, normalized by \CALX_rsa (of the % reduction B1: strip, reverse, exact D), e = e_X - 2c, then one % \CALX_fround to P (same result as \CALX_fm_g: exact product, one % rounding). %\end{lverb} % \begin{macrocode} \def\CALX_sbb #1#2#3#4{1#3#4!1#1#2!}% \expandafter\def\csname CALX_sb1\endcsname #1{\CALX_sbb#1}% \expandafter\def\csname CALX_sb2\endcsname #1#2{\CALX_sbb#2\CALX_sbb#1}% \expandafter\def\csname CALX_sb3\endcsname #1#2#3% {\CALX_sbb#3\CALX_sbb#2\CALX_sbb#1}% \def\CALX_fks #1#2#3.#4.#5.#6.% {% \ifnum#3>40 \xint_dothis\CALX_fkt\fi \xint_orthat\CALX_fku{#1}#2#3.#4.#5.#6.% }% \def\CALX_fku #1#2#3.#4.#5.#6.% {% \CALX_fnround{\CALX_trigdigits}{\csname CALX_pm\the\numexpr((2*#3+7)/16)/2\relax _\the\numexpr(#6+1)/4\expandafter\endcsname \expanded{\csname CALX_xm\the\numexpr(2*#3+7)/16\endcsname#5#1;#2% \the\numexpr2*(((2*#3+7)/16)/2+(#6+1)/4).% \the\numexpr2*((#6+1)/4)-#4.}}% }% \def\CALX_pmh #1#2#3#4#5#6{\CALX_pmi}% \def\CALX_pmi #1;#2#3.#4.{\expanded{\CALX_rsa#3.#4.\CALX_bp#2#1}}% \def\CALX_fkt #1#2#3.#4.#5.#6.% {% \expandafter\CALX_fm_g\expanded{{#2}{#3}{#4}{#5}{+}% {\the\numexpr16*((#6+1)/4)}{-\the\numexpr2*((#6+1)/4)}% {\csname CALX_sb\the\numexpr(#6+1)/4\endcsname#1}}{\CALX_trigdigits}% }% \def\CALX_fkc #1#2#3.#4.#5.#6.% {% \CALX_fnround{\CALX_trigdigits}{\expanded{F+\the\numexpr16*((#6+1)/4).% -\the\numexpr2*((#6+1)/4).% \csname CALX_sb\the\numexpr(#6+1)/4\endcsname#1}}% }% % \end{macrocode} %\begin{lverb} % Load time: chunks of floor(c_k 10^(4A)) mod 10^(4n), n limbs. %\end{lverb} % \begin{macrocode} \def\CALX_fsl #1#2#3#4#5#6#7#8% {\ifx\CALX_qW#1\else{#1#2#3#4#5#6#7#8}\expandafter\CALX_fsl\fi}% \def\CALX_fpl #1#2% {\ifx\CALX_qW#1\else{\CALX_bl#1\CALX_bl#2}\expandafter\CALX_fpl\fi}% \def\CALX_tkd #1#2#3#4% {% \expandafter\CALX_tke\the\numexpr(#3)-(#4)\expandafter.% \the\numexpr#4\expandafter.% \romannumeral`&&@\csname CALX_cm#1\the\numexpr#2\endcsname/% }% \def\CALX_tke #1.{\csname CALX_tks#1\endcsname\CALX_tkm}% \def\CALX_fco #1#2#3#4% {\expandafter\CALX_fcoa\expanded{1\CALX_tkd{#1}{#2}{#3}{#4}}\xint:#4.}% \def\CALX_fcoa 1#1\xint:#2.% {% \expandafter\CALX_fpl\expanded{\expandafter\CALX_fsl\expanded{#1% \xintReplicate{16*((#2+1)/4)-4*#2}{0}}% \CALX_qW\CALX_qW\CALX_qW\CALX_qW\CALX_qW\CALX_qW\CALX_qW\CALX_qW}% \CALX_qW\CALX_qW }% \def\CALX_fdef #1#2#3#4#5#6#7% {\ifnum#3>9 \expandafter\CALX_fdf\else\expandafter\CALX_gdf\fi {#1}{#2}{#3}{#4}{#5}{#6}#7/}% \def\CALX_fdf #1#2#3#4#5#6#7.#8.#9/% {% \edef\CALX_tacc{\noexpand\CALX_fha\the\numexpr(#6+1)/4.#6.#3.% {\expandafter\noexpand\csname CALX_m#7_#8\endcsname}% {\CALX_fco{#1}{#4-1}{#3}{#8}}{\CALX_fco{#1}{#4}{#3}{#5}}}% \CALX_fdg{#1}{#3}{#4-2}#9/% \expandafter\def\csname CALX_tf#1#2\expandafter\endcsname\expandafter {\CALX_tacc\CALX_fend{}{}}% }% \def\CALX_fdg #1#2#3#4/% {\if\relax\detokenize{#4}\relax\else\CALX_fdh{#1}{#2}{#3}#4/\fi}% \def\CALX_fdh #1#2#3#4.#5.#6/% {% \edef\CALX_tacc{\unexpanded\expandafter{\CALX_tacc}\noexpand\CALX_fv {\expandafter\noexpand\csname CALX_m#4_#5\endcsname}% {\CALX_fco{#1}{#3}{#2}{#5}}}% \CALX_fdg{#1}{#2}{#3-1}#6/% }% % \end{macrocode} %\begin{lverb} % Flat path (A <= 9, that is P <= 32): the levels are the % fixed-point multiply-subtract macros \CALX_xf of calxfp.sty, % limbs flat from one level to the next (no packing, no \expanded per % level). \CALX_tf

is ... (the % handler is \CALX_fha for A > 9); the chain \CALX_tg

takes the % U_0 chunks (#1 to #3, padded with empty groups, up to \xint:): %( %: \CALX_xf<..>#1{T_N limbs} \CALX_xf<..>{#1} ... %: \CALX_xf<..>{#1} \CALX_ge{} %) % is #2 (b = 5..8) or #2#3 (b = 9), the c arguments and text % of the contract of \CALX_xf (\CALX_gcf ... \CALX_gcoa{n-1}{b-6}); T_N % by \CALX_gcf ... \CALX_gtna. \CALX_gcf computes as \CALX_fco, its % final macro being given in the stream. \CALX_ge receives T_0 (A % limbs) then the finisher \CALX_gk placed by \CALX_gha (k the kind % letter, one \csname per call), then {X}{A}; it passes T_0 as chunks. % \CALX_gks, \CALX_gkc call \CALX_fks, \CALX_fkc as \CALX_fhc does. %\end{lverb} % \begin{macrocode} \def\CALX_gha #1.#2.#3.#4\xint:#5#6.#7.#8\xint:#9% {% \ifnum\numexpr#6+8*#7+2*#2<\xint_c_i \CALX_ghj#9\fi \expandafter#4\expanded{\CALX_fu #1.#6.#7.#8\xint:{}{}\xint:% \expandafter\noexpand\csname CALX_gk#9\endcsname}{#5#6.#7.#8}{#3}% }% \def\CALX_ghj #1\fi #2\expanded#3#4#5% {\fi\csname CALX_shz#1\endcsname#4\xint:}% \def\CALX_gl #1% {\ifcase#1\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\fi}% \def\CALX_gsh #1#2% {\expandafter\noexpand\csname CALX_xf\CALX_gl{#1}\CALX_gl{#2}\endcsname}% \def\CALX_gut #1{\ifnum#1>4 ####2\fi\ifnum#1>8 ####3\fi}% \def\CALX_gcf #1#2#3#4#5% {\expandafter#5\expanded{1\CALX_tkd{#1}{#2}{#3}{#4}}\xint:}% \def\CALX_gcoa 1#1\xint:{\CALX_gcb#1\xint:{}}% \def\CALX_gcb #1#2#3#4#5\xint:#6#7#8% {% \if\relax\detokenize{#5}\relax\CALX_gcp{#1#2#3#4}{#7}{#8}#6% \else\CALX_gcb#5\xint:{\CALX_gcp{#1#2#3#4}{#7}{#8}#6}{#7-1}{#8}\fi }% \def\CALX_gcp #1#2#3% {% \ifnum\numexpr#2<\numexpr#3\relax{#1}% \else+#1;\ifnum\numexpr#2=\xint_c_{}\fi\fi }% \def\CALX_gtna 1#1\xint:{\CALX_gtl#1\xint:}% \def\CALX_gtl #1#2#3#4#5\xint:% {{#1#2#3#4}\if\relax\detokenize{#5}\relax\else\CALX_gtl#5\xint:\fi}% \def\CALX_gdf #1#2#3#4#5#6#7.#8.#9/% {% \edef\CALX_gacc{\CALX_gsh{#7}{#8}####1% \CALX_gcf{#1}{#4}{#3}{#5}\CALX_gtna\CALX_gut{#7}% \CALX_gcf{#1}{#4-1}{#3}{#8}\CALX_gcoa{#8-1}{#7-6}}% \CALX_gdg{#1}{#3}{#4-2}#9/% \edef\CALX_gtmp{\noexpand\def \expandafter\noexpand\csname CALX_tg#1#2\endcsname ####1####2####3####4\noexpand\xint:{\unexpanded\expandafter {\CALX_gacc}\expandafter\noexpand\csname CALX_ge#3\endcsname{}}}% \CALX_gtmp \expandafter\edef\csname CALX_tf#1#2\endcsname {\noexpand\CALX_gha\the\numexpr(#6+1)/4.#6.#3.% \expandafter\noexpand\csname CALX_tg#1#2\endcsname}% }% \def\CALX_gdg #1#2#3#4/% {\if\relax\detokenize{#4}\relax\else\CALX_gdh{#1}{#2}{#3}#4/\fi}% \def\CALX_gdh #1#2#3#4.#5.#6/% {% \edef\CALX_gacc{\unexpanded\expandafter{\CALX_gacc}\CALX_gsh{#4}{#5}% {####1}\CALX_gut{#4}\CALX_gcf{#1}{#3}{#2}{#5}\CALX_gcoa{#5-1}{#4-6}}% \CALX_gdg{#1}{#2}{#3-1}#6/% }% \expandafter\def\csname CALX_ge4\endcsname #1#2#3#4#5% {#5{{{#1}{#2}{#3}{#4}}}}% \expandafter\def\csname CALX_ge5\endcsname #1#2#3#4#5#6% {#6{{{#1}{#2}{#3}{#4}}{{#5}{0000}{0000}{0000}}}}% \expandafter\def\csname CALX_ge6\endcsname #1#2#3#4#5#6#7% {#7{{{#1}{#2}{#3}{#4}}{{#5}{#6}{0000}{0000}}}}% \expandafter\def\csname CALX_ge7\endcsname #1#2#3#4#5#6#7#8% {#8{{{#1}{#2}{#3}{#4}}{{#5}{#6}{#7}{0000}}}}% \expandafter\def\csname CALX_ge8\endcsname #1#2#3#4#5#6#7#8#9% {#9{{{#1}{#2}{#3}{#4}}{{#5}{#6}{#7}{#8}}}}% \expandafter\def\csname CALX_ge9\endcsname #1#2#3#4#5#6#7#8% {\CALX_gv{{{#1}{#2}{#3}{#4}}{{#5}{#6}{#7}{#8}}}}% \def\CALX_gv #1#2#3{#3{#1{{#2}{0000}{0000}{0000}}}}% \def\CALX_gks #1#2#3{\CALX_fks{#1}#2.#3.}% \def\CALX_gkc #1#2#3{\CALX_fkc{#1}#2.#3.}% % \end{macrocode} %\begin{lverb} % Shortened chains: for u small the top levels % are not needed. Bound: the error of the full chain at u = 0.64, so the worst % case of the full schedule is kept. The data give \CALX_tg

(top level % Mtop = N), \CALX_tg

_ (top level M, same b_k, n_k), then \CALX_fsel % {

}{}{.. ...}: the full one becomes \CALX_tg

_ % and \CALX_tg

the selector: with t the top limb of U_0 (t = floor(10^4 % u)), the chain is the one of the smallest M with t < t_M (then u < t_M 10^-4 % <= u_max(M)), else Mtop. The \CALX_tf

_ made by \CALX_gdf are % removed. %\end{lverb} % \begin{macrocode} \def\CALX_fsel #1#2#3#4% {% \expandafter\let\csname CALX_tg#1#2_#3\expandafter\endcsname \csname CALX_tg#1#2\endcsname \CALX_fsu{#1}{#2}#4/% \expandafter\edef\csname CALX_gq#1#2\endcsname ##1##2\xint:% {\noexpand\csname CALX_tg#1#2_\CALX_fsn{#3}#4/\noexpand\endcsname}% \expandafter\edef\csname CALX_tg#1#2\endcsname ##1% {\expandafter\noexpand\csname CALX_gq#1#2\endcsname ##1\noexpand\xint:{##1}}% }% \def\CALX_fsn #1#2/% {\if\relax\detokenize{#2}\relax#1\else\CALX_fsm{#1}#2/\fi}% \def\CALX_fsm #1#2.#3.#4/% {\noexpand\ifnum##1<#3 \CALX_fsn{#2}#4/\noexpand\else#1\noexpand\fi}% \def\CALX_fsu #1#2#3/% {\if\relax\detokenize{#3}\relax\else\CALX_fsv{#1}{#2}#3/\fi}% \def\CALX_fsv #1#2#3.#4.#5/% {% \expandafter\let\csname CALX_tf#1#2_#3\endcsname\undefined \CALX_fsu{#1}{#2}#5/% }% % \end{macrocode} % \subsection{Inverse functions; tangent, secant, sinc, degrees} %\begin{lverb} % \calxFpAsin{X}: asin of round_P(X), P = \XINTdigits <= 100, after % xinttrig's @asin_l. With x = |X|, u = sqrt(1 - x^2) (x^2 exact, 1 - x^2 % rounded to 2P+8 digits, square root to P+4 digits); if x > sqrt(2)/2 % (round(10^9 x) > 707106781) the roles of x and u are exchanged and the % result is pi/2 minus the core value. Core (x <= sqrt(2)/2, y the other % one): tau = round(10^9 x) (\CALX_as_tau), T = 10^-9 round(tau S/10^9) % with S from the arcsine series in one \numexpr (\CALX_asb, from % xinttrig's \XINT_Arcsin_Ib), |asin x - T| about 10^-9; then %( %: D = x cos(T) - y sin(T) = sin(asin x - T), %) % cos(T) and sin(T) by the sin/cos kernels rounded to P+4 digits (P <= % 32: flat path, finishers \CALX_gkA, \CALX_gkB; P > 32: series path % \CALX_sha, finishers \CALX_shoA, \CALX_shoB), the two products exact % (\CALX_fmulx), their difference exact (2P+24 digits); % core = T + D, plus D^3 S(D^2) if P > 16 (S the arcsine series, % round((P+9)/18) terms, Horner at P digits, \CALX_ash), the sum % exact. T < 10^-8: core = x + x^3/6 (P <= 16), x + x^3 S(x^2) (P > 16, % \CALX_as_ser). x = 1: core 0, roles exchanged. % Operations whose operands have at most the target number of digits % use the entries without input rounding (\CALX_fsubu, \CALX_fmulu, % \CALX_faddu, \CALX_fsqru, \CALX_fdivu); the sums and differences of % exact values are exact (\CALX_faddx, \CALX_fsubx). % % \CALX_as_out{core}{n|s}{a}{b}{d}{g} (n: A = core, s: A = pi/2 - core; % a, b integers as \numexpr text, b = +-1) gives round_P(f (a pi/2 + b % A)) = round_P(f (k pi/2 + m core)): k = a, m = b (n) or k = a + b, m = % -b (s). k = 0: no sum; else k pi/2 + m core exact (2P+70 digits, pi/2 % to 130 digits rounded to 2P+70). f = 1/d (d = 1 or 2) times 180/pi if % g = 1, by \CALX_aso<2d+g-2>: 1/2 by the exact \CALX_fhalf, 180/pi by a % product at P+8 digits; then one rounding to P. Signs by \CALX_as_m % (product of two sign characters with the sign of a native). asin, % asind: a = 0, b = +-1; acos, acosd: a = 1, b = -1 (x >= 0) or 1 (x < % 0); acsc, asec: the same on y = 1/x (P+4 digits; x = 0: % DivisionByZero), with 1 - y^2 = (x^2 - 1)/x^2 at P+4 digits from the % exact x^2 - 1 and x^2 (\CALX_ac_b; no cancellation near |x| = 1). % % atan (xinttrig's @atan, no square root): t = |x|, T = t^2, z = 1/(1+T), % w = 1 - T (P+8 digits); the core on x' = 2tz, y' = |w|z (P+4 digits, % 2t exact; x'^2 + y'^2 = 1) gives A = 2 atan(t) % if w > 0, pi - 2 atan(t) if w < 0 (w = 0: A = pi/2); then d = 2. Entry % \CALX_at_a{c}{s}{g}: c pi/2 + s atan(x) (atan: c = 0, s = 1). Arg(x,y), % pArg, atan2(y,x) and degree versions: the cases of xinttrig's @Arg, % @pArg on the signs of y - x, y + x and y (\CALX_arx>-x>), q = y/x, x/y or x/(-y) at P+4 digits, then \CALX_at_b with the % (c, s) of the case; Arg(0,0) = 0. % % tan, cot, sec, csc, sinc and sind, cosd, tand, cotd, secd, cscd: % \CALX_sc_a gives the quadrant q and the reduced argument u. Radians: % |x| < 0.8: q = 0, u = x, else the reduction \CALX_red (|x| < 10^4) or % \CALX_rslow; both kernels % (\CALX_sc_k): S = sin u, C = cos u rounded to P+4 digits (finishers A % and B; tiny u: \CALX_shzA, \CALX_shzB). Degrees: \CALX_sc_f (below); % sind, cosd, secd, cscd compute only the one of S, C they need. Then % the finisher \CALX_fn{q}{sign}{S}{C}{x}: sin x and cos x from S, C % by the quadrant (\CALX_scS, \CALX_scC), one division at P+4 digits, % one rounding to P. % % Special values (IEEE 754 / C99 Annex F, calx zero being unsigned): NaN % (I?) gives I?; sin, cos, tan, cot, sec, csc, the degree versions, asin, % acos, asind, acosd of +-infinity signal InvalidOperation (I?, % \CALX_tr_sp); sinc(+-inf) = 0; acsc(+-inf) = 0, asec(+-inf) = pi/2; % atan(+-inf) = +-pi/2 (atand: +-90); Arg, pArg, atan2 (and degrees) % with an infinite argument: the atan2 table of C99 (\CALX_ari % , classes p, m infinities, f finite >= 0, g finite < 0): +-pi/2, % +-pi/4, +-3pi/4, 0, pi, -pi, pArg brought to [0, 2pi). Poles (tand(90), % cot(0), ...): division by zero, signal DivisionByZero, I+ or I-. %\end{lverb} % \begin{macrocode} \edef\CALX_asPi{\romannumeral0\CALX_ffromraw {15707963267948966192313216916397514420985846996875529104874722961539082031% 43104499314017412671058533991074043256641153323546922305[-129]}}% \def\CALX_as_a #1% {% \if I#1 \xint_dothis\CALX_as_a_special\fi \xint_orthat\CALX_as_a_finite #1% }% \def\CALX_as_a_special #1#2#3\xint:#4#5{\CALX_tr_sp#2}% \def\CALX_as_a_finite #1#2#3\xint:#4#5% {\CALX_as_b #2#3\xint:#4#5}% \def\CALX_as_b #1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_as_b_zero\fi \ifnum\CALX_trigdigits>100 \xint_dothis\CALX_as_b_invalid\fi \xint_orthat\CALX_as_b_regular #1#2.% }% \def\CALX_as_b_zero #1#2.#3.#4\xint:#5% {\CALX_as_out{F+0.0.}{n}{\if c#51\else0\fi}{\if c#5-\fi#11}{1}}% \def\CALX_as_b_invalid #1#2.#3.#4\xint:#5% {\CALX_as_err{asin, acos: not implemented for Digits > 100}% {\if c#51\else0\fi}{\if c#5-\fi#11}{1}}% \def\CALX_as_b_regular #1#2.#3.#4\xint:#5% {% \expandafter\CALX_as_c\the\numexpr\CALX_trigdigits.% F+#2.#3.#4\xint:% {\if c#51\else0\fi}{\if c#5-\fi#11}{1}% }% \def\CALX_as_err #1#2#3#4#5{\CALX_nsig{InvalidOperation}{#1}{}}% \def\CALX_as_c #1.#2\xint:% {% \expandafter\CALX_as_d\romannumeral0\CALX_fsubx {F+1.0.100000001!}{\CALX_fmulx{#2}{#2}}\xint:% #1.#2\xint:% }% \def\CALX_as_d F#1#2.% {% \if-#1 \xint_dothis\CALX_as_d_invalid\fi \ifnum#2=\xint_c_ \xint_dothis\CALX_as_d_zero\fi \xint_orthat\CALX_as_d_regular #1#2.% }% \def\CALX_as_d_invalid #1#2.#3\xint:#4.#5\xint:% {\CALX_as_err{asin, acos: |x|>1}}% \def\CALX_as_d_zero #1#2.#3\xint:#4.#5\xint:% {\CALX_as_out{F+0.0.}{s}}% \def\CALX_as_d_regular #1#2.#3\xint:#4.#5\xint:% {% \expandafter\CALX_as_e\romannumeral0\CALX_fsqrt {\the\numexpr#4+4\relax}{F#1#2.#3}\xint:#5\xint:% }% \def\CALX_as_e #1\xint:#2\xint:% {% \expandafter\CALX_as_f\the\numexpr\CALX_as_tau#2\xint:\expandafter.% \the\numexpr\CALX_trigdigits.{#2}{#1}% }% \def\CALX_as_f #1.#2.% {% \ifnum#1>707106781 \CALX_as_sw\fi \CALX_as_k #1.#2.n% }% \def\CALX_as_sw\fi\CALX_as_k #1.#2.n#3#4% {\fi\expandafter\CALX_as_k\the\numexpr\CALX_as_tau#4\xint:.#2.s{#4}{#3}}% \def\CALX_as_k #1.#2.% {% \expandafter\CALX_as_l\the\numexpr (\expandafter\CALX_asb\the\numexpr#1*#1/\xint_c_e_ix.)*#1/\xint_c_e_ix.% #2.% }% \def\CALX_as_l #1.#2.% {% \ifnum#1<\xint_c_x \CALX_as_tj\fi \expandafter\CALX_as_n\romannumeral0\CALX_ffromraw{#1[-9]}\xint:% #2.% }% \def\CALX_as_tj\fi\expandafter\CALX_as_n\romannumeral0\CALX_ffromraw #1\xint:#2.#3#4#5{\fi\CALX_as_tiny#2.#3{#4}}% \def\CALX_as_n F#1\xint:#2.% {\CALX_as_kc c{#1}A\CALX_as_o{#1}#2.}% \def\CALX_as_o #1#2#3.% {\CALX_as_kc s{#2}B\CALX_as_p{#1}{#2}#3.}% \def\CALX_as_p #1#2#3#4.#5#6#7% {% \expandafter\CALX_as_q\romannumeral0% \CALX_fsubx{\CALX_fmulx{#6}{#2}}{\CALX_fmulx{#7}{#1}}\xint:{#3}#4.#5% }% \def\CALX_as_q #1\xint:#2#3.% {% \ifnum#3>16 \CALX_as_qc\fi \CALX_as_r{#1}{#2}#3.% }% \def\CALX_as_qc\fi\CALX_as_r#1#2#3.% {% \fi\expandafter\CALX_as_r\expandafter{\romannumeral0\CALX_faddx {#1}{\CALX_as_ser{#3}{#1}}}{#2}#3.% }% \def\CALX_as_r #1#2#3.% {% \expandafter\CALX_as_out\expandafter{\romannumeral0\CALX_faddx{F#2}{#1}}% }% \def\CALX_as_tiny #1.#2#3% {% \expandafter\CALX_as_ty\romannumeral0\ifnum#1>16 \expandafter\CALX_as_ser\else\expandafter\CALX_as_tq\fi{#1}{#3}\xint:% #3\xint:#1.#2% }% \def\CALX_as_tq #1#2% {\CALX_fdivu{#1}{\CALX_fmul{#1}{#2}{\CALX_fsqr{#1}{#2}}}{F+1.0.100000006!}}% \def\CALX_as_ty #1\xint:F#2\xint:{\CALX_as_r{#1}{#2}}% \def\CALX_as_out #1#2#3#4#5#6% {% \CALX_fnround{\CALX_trigdigits}{\csname CALX_aso\the\numexpr2*#5+#6-2% \endcsname{\ifnum\numexpr\if s#2#3+(#4)\else#3\fi=\xint_c_ \expandafter\xint_secondoftwo\else\expandafter\xint_firstoftwo\fi {\CALX_faddx {\CALX_fmul{\the\numexpr2*\CALX_trigdigits+70\relax}{\CALX_asPi}% {\CALX_ffromraw{\the\numexpr\if s#2#3+(#4)\else#3\fi\relax[0]}}}}% {\xint_firstofone}% {\CALX_as_m{\ifnum\numexpr(#4)\if s#2*(-1)\fi<\xint_c_-\else+\fi}+#1}}}% }% \expandafter\def\csname CALX_aso0\endcsname #1{#1}% \expandafter\def\csname CALX_aso1\endcsname #1% {\CALX_fmul{\the\numexpr\CALX_trigdigits+8\relax}{#1}{\CALX_trigR}}% \expandafter\let\csname CALX_aso2\endcsname\CALX_fhalf \expandafter\def\csname CALX_aso3\endcsname #1% {\CALX_fmul{\the\numexpr\CALX_trigdigits+8\relax}{\CALX_fhalf{#1}}% {\CALX_trigR}}% \def\CALX_as_m #1#2F#3#4.% {\expanded{F\ifnum#4=\xint_c_+\else\if\if#1#2+\else-\fi#3+\else-\fi\fi#4.}}% \def\CALX_ac_a #1% {% \if I#1\xint_dothis\CALX_ac_i\fi \xint_orthat{\CALX_ac_f #1}% }% \def\CALX_ac_i #1#2\xint:#3% {% \if ?#1\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi{ I?}% {\CALX_as_out{F+0.0.}{n}{\if c#31\else0\fi}{0}{1}{0}}% }% \def\CALX_ac_f F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_ac_f_zero\fi \xint_orthat\CALX_ac_f_regular #1#2.% }% \def\CALX_ac_f_zero #1#2.#3.#4\xint:#5% {\CALX_nsig{DivisionByZero}{acsc, asec of 0}{}}% \def\CALX_ac_f_regular #1#2.#3.#4\xint:#5% {% \expandafter\CALX_ac_b\romannumeral0\CALX_fdivu {\the\numexpr\CALX_trigdigits+4\relax}{F+1.0.100000001!}% {F#1#2.#3.#4}\xint:#5{F#1#2.#3.#4}% }% \def\CALX_ac_z #1.#2\xint:{#1}% \def\CALX_ac_b F#1#2\xint:#3#4% {% \ifnum\CALX_trigdigits>100 \xint_dothis{\CALX_nsig{InvalidOperation}% {asin, acos: not implemented for Digits > 100}{}}\fi \xint_orthat{\expandafter\CALX_as_d\romannumeral0\CALX_fdiv {\the\numexpr\CALX_trigdigits+4\relax}% {\CALX_fsubx{\CALX_fmulx{#4}{#4}}{F+1.0.100000001!}}% {\CALX_fmulx{#4}{#4}}\xint:\CALX_trigdigits.F+#2\xint:}% {\if c#31\else0\fi}{\if c#3-\fi#11}{1}0% }% \def\CALX_at_a #1% {% \if I#1\xint_dothis\CALX_at_i\fi \xint_orthat{\CALX_at_b #1}% }% \def\CALX_at_i #1#2\xint:#3#4#5% {% \if ?#1\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi{ I?}% {\CALX_as_out{F+0.0.}{n}{(#3)+(#4)*(#11)}{0}{1}{#5}}% }% \def\CALX_at_b F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_at_b_zero\fi \ifnum\CALX_trigdigits>100 \xint_dothis\CALX_at_b_invalid\fi \xint_orthat\CALX_at_b_regular #1#2.% }% \def\CALX_at_b_zero #1#2.#3.#4\xint:#5#6#7% {\CALX_as_out{F+0.0.}{n}{2*(#5)}{0}{2}{#7}}% \def\CALX_at_b_invalid #1#2.#3.#4\xint:#5#6#7% {\CALX_nsig{InvalidOperation}{atan: not implemented for Digits > 100}{}}% \def\CALX_at_b_regular #1#2.#3.#4\xint:#5#6#7% {% \expandafter\CALX_at_c\romannumeral0\CALX_fsqru {\the\numexpr\CALX_trigdigits+8\relax}{F+#2.#3.#4}\xint:% F+#2.#3.#4\xint:#1{#5}{#6}{#7}% }% \def\CALX_at_c #1\xint:#2\xint:% {% \expandafter\CALX_at_cc\romannumeral0\CALX_fdivu {\the\numexpr\CALX_trigdigits+8\relax}{F+1.0.100000001!}% {\CALX_faddu{\the\numexpr\CALX_trigdigits+8\relax}{F+1.0.100000001!}% {#1}}\xint:#1\xint:#2\xint:% }% \def\CALX_at_cc #1\xint:#2\xint:% {% \expandafter\CALX_at_d\romannumeral0\CALX_fsubu {\the\numexpr\CALX_trigdigits+8\relax}{F+1.0.100000001!}{#2}\xint:% #1\xint:% }% \def\CALX_at_d F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_at_d_zero\fi \xint_orthat\CALX_at_d_regular #1#2.% }% \def\CALX_at_d_zero #1#2.#3\xint:#4\xint:#5\xint:#6#7#8#9% {\CALX_as_out{F+0.0.}{s}{2*(#7)}{(#8)*(#61)}{2}{#9}}% \def\CALX_at_d_regular #1#2.#3\xint:#4\xint:#5\xint:#6#7#8#9% {% \expandafter\CALX_at_e\romannumeral0\CALX_fmul {\the\numexpr\CALX_trigdigits+4\relax}{\CALX_faddx{#5}{#5}}{#4}\xint:% \romannumeral0\CALX_fmul{\the\numexpr\CALX_trigdigits+4\relax}% {F+#2.#3}{#4}\xint:% {\if-#1(2*(#7)+(#8)*2*(#61))\else2*(#7)\fi}% {(#8)*(#61)\if-#1*(-1)\fi}{2}{#9}% }% \def\CALX_at_e #1\xint:#2\xint:{\expandafter\CALX_as_e#2\xint:#1\xint:}% \def\CALX_ar_a #1#2#3#4% {% \expandafter\CALX_ar_b\romannumeral0% \CALX_fround{\CALX_trigdigits}{#3}% {#4}#1#2% }% \def\CALX_ar_b #1\xint:#2% {% \expandafter\CALX_ar_c\romannumeral0% \CALX_fround{\CALX_trigdigits}{#2}% #1\xint:% }% \def\CALX_ar_c #1#2\xint:#3#4\xint:#5#6% {% \if I#1\xint_dothis{\CALX_ar_inf{#1#2}{#3#4}#5#6}\fi \if I#3\xint_dothis{\CALX_ar_inf{#1#2}{#3#4}#5#6}\fi \xint_orthat{\expandafter\CALX_ar_d\romannumeral0\CALX_faddx {#1#2}{#3#4}\xint:#1#2\xint:#3#4\xint:#5#6}% }% \def\CALX_ar_d F#1#2.#3\xint:#4\xint:#5\xint:% {% \expandafter\CALX_ar_e\the\numexpr\CALX_ar_st#1#2.\expandafter.% \romannumeral0\CALX_fsubx{#4}{#5}\xint:#4\xint:#5\xint:% }% \def\CALX_tr_sp #1% {% \if ?#1\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi { I?}{\CALX_nsig{InvalidOperation}{trigonometric function of infinity}{}}% }% \def\CALX_sc_iz\fi\fi\CALX_tr_sp#1{\fi\fi\space F+0.0.}% \def\CALX_ar_inf #1#2#3#4% {% \ifcsname CALX_ari#3\CALX_arc#1\xint:\CALX_arc#2\xint:\endcsname \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\csname CALX_ari#3\CALX_arc#1\xint:\CALX_arc#2\xint:\endcsname{#4}}% { I?}% }% \def\CALX_arc #1#2\xint:% {\if I#1\if ?#2n\else\if+#2p\else m\fi\fi\else\CALX_arf#2\xint:\fi}% \def\CALX_arf #1#2.#3\xint:{\if-#1\ifnum#2>\xint_c_ g\else f\fi\else f\fi}% \expandafter\def\csname CALX_ariafm\endcsname% {\CALX_as_out{F+0.0.}{n}{2}{0}{1}}% \expandafter\def\csname CALX_ariafp\endcsname% {\CALX_as_out{F+0.0.}{n}{0}{0}{1}}% \expandafter\def\csname CALX_ariagm\endcsname% {\CALX_as_out{F+0.0.}{n}{-2}{0}{1}}% \expandafter\def\csname CALX_ariagp\endcsname% {\CALX_as_out{F+0.0.}{n}{0}{0}{1}}% \expandafter\def\csname CALX_ariamf\endcsname% {\CALX_as_out{F+0.0.}{n}{-1}{0}{1}}% \expandafter\def\csname CALX_ariamg\endcsname% {\CALX_as_out{F+0.0.}{n}{-1}{0}{1}}% \expandafter\def\csname CALX_ariamm\endcsname% {\CALX_as_out{F+0.0.}{n}{-3}{0}{2}}% \expandafter\def\csname CALX_ariamp\endcsname% {\CALX_as_out{F+0.0.}{n}{-1}{0}{2}}% \expandafter\def\csname CALX_ariapf\endcsname% {\CALX_as_out{F+0.0.}{n}{1}{0}{1}}% \expandafter\def\csname CALX_ariapg\endcsname% {\CALX_as_out{F+0.0.}{n}{1}{0}{1}}% \expandafter\def\csname CALX_ariapm\endcsname% {\CALX_as_out{F+0.0.}{n}{3}{0}{2}}% \expandafter\def\csname CALX_ariapp\endcsname% {\CALX_as_out{F+0.0.}{n}{1}{0}{2}}% \expandafter\def\csname CALX_aripfm\endcsname% {\CALX_as_out{F+0.0.}{n}{2}{0}{1}}% \expandafter\def\csname CALX_aripfp\endcsname% {\CALX_as_out{F+0.0.}{n}{0}{0}{1}}% \expandafter\def\csname CALX_aripgm\endcsname% {\CALX_as_out{F+0.0.}{n}{2}{0}{1}}% \expandafter\def\csname CALX_aripgp\endcsname% {\CALX_as_out{F+0.0.}{n}{0}{0}{1}}% \expandafter\def\csname CALX_aripmf\endcsname% {\CALX_as_out{F+0.0.}{n}{3}{0}{1}}% \expandafter\def\csname CALX_aripmg\endcsname% {\CALX_as_out{F+0.0.}{n}{3}{0}{1}}% \expandafter\def\csname CALX_aripmm\endcsname% {\CALX_as_out{F+0.0.}{n}{5}{0}{2}}% \expandafter\def\csname CALX_aripmp\endcsname% {\CALX_as_out{F+0.0.}{n}{7}{0}{2}}% \expandafter\def\csname CALX_arippf\endcsname% {\CALX_as_out{F+0.0.}{n}{1}{0}{1}}% \expandafter\def\csname CALX_arippg\endcsname% {\CALX_as_out{F+0.0.}{n}{1}{0}{1}}% \expandafter\def\csname CALX_arippm\endcsname% {\CALX_as_out{F+0.0.}{n}{3}{0}{2}}% \expandafter\def\csname CALX_arippp\endcsname% {\CALX_as_out{F+0.0.}{n}{1}{0}{2}}% \def\CALX_ar_st #1#2.{\ifnum#2=\xint_c_ 2\else\if-#1 0\else1\fi\fi}% \def\CALX_ar_e #1.F#2#3.#4\xint:#5\xint:#6\xint:#7% {% \ifnum\numexpr#1+\CALX_ar_st#2#3.=\xint_c_iv \CALX_ar_zero\fi \csname CALX_ar#7\ifnum\CALX_ar_st#2#3.=\xint_c_i 1\else0\fi \ifnum#1=\xint_c_i 1\else0\fi\CALX_ar_ys#5\xint:\endcsname{#6}{#5}% }% \def\CALX_ar_ys F#1#2.#3\xint:{\if-#1\ifnum#2>\xint_c_ m\else p\fi\else p\fi}% \def\CALX_ar_zero\fi\csname#1\endcsname#2#3% {\fi\CALX_as_out{F+0.0.}{n}{0}{0}{1}}% \def\CALX_ar_q #1#2% {% \expandafter\CALX_at_b\romannumeral0\CALX_fdivu {\the\numexpr\CALX_trigdigits+4\relax}{#1}{#2}\xint:% }% \expandafter\def\csname CALX_ara11m\endcsname #1#2% {\CALX_ar_q{#1}{#2}{1}{-1}}% \expandafter\def\csname CALX_ara11p\endcsname #1#2% {\CALX_ar_q{#1}{#2}{1}{-1}}% \expandafter\def\csname CALX_ara10m\endcsname #1#2% {\CALX_ar_q{#2}{#1}{-2}{1}}% \expandafter\def\csname CALX_ara10p\endcsname #1#2% {\CALX_ar_q{#2}{#1}{2}{1}}% \expandafter\def\csname CALX_ara01m\endcsname #1#2% {\CALX_ar_q{#2}{#1}{0}{1}}% \expandafter\def\csname CALX_ara01p\endcsname #1#2% {\CALX_ar_q{#2}{#1}{0}{1}}% \expandafter\def\csname CALX_ara00m\endcsname #1#2% {\CALX_ar_q{#1}{\CALX_as_m-+#2}{-1}{1}}% \expandafter\def\csname CALX_ara00p\endcsname #1#2% {\CALX_ar_q{#1}{\CALX_as_m-+#2}{-1}{1}}% \expandafter\def\csname CALX_arp11m\endcsname #1#2% {\CALX_ar_q{#1}{#2}{1}{-1}}% \expandafter\def\csname CALX_arp11p\endcsname #1#2% {\CALX_ar_q{#1}{#2}{1}{-1}}% \expandafter\def\csname CALX_arp10m\endcsname #1#2% {\CALX_ar_q{#2}{#1}{2}{1}}% \expandafter\def\csname CALX_arp10p\endcsname #1#2% {\CALX_ar_q{#2}{#1}{2}{1}}% \expandafter\def\csname CALX_arp01m\endcsname #1#2% {\CALX_ar_q{#2}{#1}{4}{1}}% \expandafter\def\csname CALX_arp01p\endcsname #1#2% {\CALX_ar_q{#2}{#1}{0}{1}}% \expandafter\def\csname CALX_arp00m\endcsname #1#2% {\CALX_ar_q{#1}{\CALX_as_m-+#2}{3}{1}}% \expandafter\def\csname CALX_arp00p\endcsname #1#2% {\CALX_ar_q{#1}{\CALX_as_m-+#2}{3}{1}}% \def\CALX_sc_a #1% {% \if I#1\xint_dothis\CALX_sc_i\fi \xint_orthat\CALX_sc_b }% \def\CALX_sc_i #1#2\xint:#3#4% {% \ifx#3\CALX_fnsinc\if ?#1\else\CALX_sc_iz\fi\fi \CALX_tr_sp#1% }% \def\CALX_sc_b #1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_sc_b_zero\fi \ifnum\CALX_trigdigits>100 \xint_dothis\CALX_sc_b_invalid\fi \xint_orthat\CALX_sc_b_regular #1#2.% }% \def\CALX_sc_b_zero #1#2.#3.#4\xint:#5#6% {#5{0}{#1}{F+0.0.}{F+1.0.100000001!}{F+0.0.}}% \def\CALX_sc_b_invalid #1#2.#3.#4\xint:#5#6% {\CALX_nsig{InvalidOperation}{trig: not implemented for Digits > 100}{}}% \def\CALX_sc_b_regular #1#2.#3.#4\xint:#5#6% {\csname CALX_sc_#6\endcsname #2.#3.#4\xint:{#1}#5{F#1#2.#3.#4}}% % \end{macrocode} %\begin{lverb} % P <= 8, tan, cot, sec, csc, sinc (\CALX_sc_rq, \CALX_sc_rqr: as % \CALX_sc_r, \CALX_sc_rr): \CALX_sc_kq takes q and r as % \CALX_sc_k, |r| = A 10^(E-9) (\CALX_rta), U9 = round(10^9 r^2) % (\CALX_qkz), S9 = 10^9 sin(r)/r, C9 = 10^9 cos(r) (\CALX_sinaux, % \CALX_cosaux), then one \numexpr per value (all quantities < 2^31): %( %: tan |r| = round(A S9 / C9) 10^(E-9) (\CALX_qkt) %: cot |r| = round(10^17 / round(A S9 / C9)) 10^(-E-8) (\CALX_qku) %: sec r = round(10^18 / C9) 10^-9 (\CALX_qke) %: csc |r| = round(round(10^17 / A) 10^9 / S9) 10^(-E-8) (\CALX_qkr) %) % times the sign f of the quadrant table \CALX_kq (signs of % x and r): tan = T, -1/T, cot = 1/T, -T for q even, odd; sec = 1/C, % -1/S, -1/C, 1/S; csc = 1/S, 1/C, -1/S, -1/C (q = 0..3). Output by % \CALX_dgo. r is never 0 (B1 gives 10^-W for R = 0). % % sinc: |x| < 0.8 (\CALX_sc_kp, \CALX_sc_kps): sinc x = S9 10^-9, no % division. Otherwise (\CALX_sc_kqs), |x| = A_x 10^(E_x-9), V = round(A % S9/10^9) (q even, sign of r, minus for q = 2) or V = C9 (q odd, minus % for q = 3), then one scaled division (\CALX_sc_kqf): %( %: sinc x = s round(V 10^9 / A_x) 10^(e-9) (V < A_x) %: sinc x = s round(V 10^8 / A_x) 10^(e-8) (V >= A_x) %) % with e = E - E_x (q even) or -E_x (q odd). %\end{lverb} % \begin{macrocode} \def\CALX_sc_r #1.#2.#3\xint:% {% \ifnum\CALX_trigdigits<\xint_c_ix \CALX_sc_rq\fi \ifnum\numexpr(#1+8*#2)*10\ifnum\numexpr#1+8*#2=\xint_c_ +\CALX_trig_top#3\xint:\fi>\xint_c_vii \CALX_sc_rr\fi \CALX_sc_k 0.F+#1.#2.#3\xint:% }% \def\CALX_sc_rq\fi #1\CALX_sc_k 0.F+#2.#3.#4\xint:% {% \fi \ifnum\numexpr(#2+8*#3)*10\ifnum\numexpr#2+8*#3=\xint_c_ +\CALX_trig_top#4\xint:\fi>\xint_c_vii \CALX_sc_rqr\fi \CALX_sc_kp 0.F+#2.#3.#4\xint:% }% \def\CALX_sc_rqr\fi\CALX_sc_kp 0.F+#1.#2.#3\xint:% {% \fi \ifnum\numexpr#1+8*#2>\xint_c_iv \CALX_rjs\fi \CALX_sc_kd\CALX_red #1.#2.#3\xint:\xint:% }% \def\CALX_sc_kd #1% {% \ifx#1\CALX_red\expandafter\CALX_sc_kdd\else \expandafter\CALX_sc_kds\fi }% \def\CALX_sc_kds{\expandafter\CALX_sc_kq\romannumeral0\CALX_rslow}% \def\CALX_sc_kdd #1.#2.#3\xint:\xint:% {% \expandafter\CALX_sc_kde\the\numexpr#1+8*#2\expandafter.% \the\numexpr(2*#1+7)/16\expandafter.% \the\numexpr#1+8-8*((2*#1+7)/16).#3\xint:% }% \def\CALX_sc_kde #1.#2.#3.#4\xint:% {% \expandafter\CALX_sc_kdf\romannumeral0\expandafter\CALX_rq \the\numexpr\CALX_rta#2.#3.#4\xint:.#1.% }% \def\CALX_sc_kdf #1.#2#3.#4.#5.#6.#7#8% {% \csname CALX_kdl\ifx#8\CALX_fnsinc z\else\ifx#8\CALX_fntan t\else \ifx#8\CALX_fncot u\else\ifx#8\CALX_fnsec v\else w\fi\fi\fi\fi \endcsname #1.#2#3.#4.#5.#6.#7% }% \expandafter\def\csname CALX_kdlz\endcsname #1.#2#3.#4.#5.#6.#7#8% {\CALX_sc_kqy#3.#4.#5.#6.#1#2}% \def\CALX_sc_kdl #1% {% \expandafter\def\csname CALX_kdl#1\endcsname ##1.##2##3.##4.##5.##6.##7##8% {\CALX_sc_kqb##3.##4.#1##1##2##7}% }% \CALX_sc_kdl t\CALX_sc_kdl u\CALX_sc_kdl v\CALX_sc_kdl w% \let\CALX_sc_kdl\undefined \def\CALX_sc_kp #1.F#2#3.#4.#5\xint:#6#7% {% \ifx#7\CALX_fnsinc \xint_dothis\CALX_sc_kps\fi \xint_orthat\CALX_sc_kq #1.F#2#3.#4.#5\xint:{#6}#7% }% \def\CALX_sc_kps #1.F#2#3.#4.#5\xint:#6#7#8% {% \expandafter\CALX_sc_kpa\the\numexpr#3+8*#4\expandafter.% \the\numexpr(2*#3+7)/16\expandafter.% \the\numexpr#3+8-8*((2*#3+7)/16).#5\xint:% }% \def\CALX_sc_kpa #1.#2.#3.#4\xint:% {\expandafter\CALX_sc_kpb\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.}% \def\CALX_sc_kpb #1.#2.% {% \expandafter\CALX_dgo\the\numexpr \expandafter\CALX_sinaux\the\numexpr\CALX_qkz#1.#2...-9.% }% \def\CALX_sc_kq #1.F#2#3.#4.#5\xint:#6#7% {% \ifx#7\CALX_fnsinc \xint_dothis\CALX_sc_kqs\fi \ifx#7\CALX_fntan \xint_dothis{\CALX_sc_kqx t}\fi \ifx#7\CALX_fncot \xint_dothis{\CALX_sc_kqx u}\fi \ifx#7\CALX_fnsec \xint_dothis{\CALX_sc_kqx v}\fi \ifx#7\CALX_fncsc \xint_dothis{\CALX_sc_kqx w}\fi \xint_orthat\CALX_sc_k #1.F#2#3.#4.#5\xint:{#6}#7% }% \def\CALX_sc_kqs #1.F#2#3.#4.#5\xint:#6#7#8% {\CALX_sc_kqt #8\xint:#1.#2#3.#4.#5\xint:}% \def\CALX_sc_kqt F#1#2.#3.#4\xint:% {% \expandafter\CALX_sc_kqu\the\numexpr#2+8*#3\expandafter.% \the\numexpr(2*#2+7)/16\expandafter.% \the\numexpr#2+8-8*((2*#2+7)/16).#4\xint:% }% \def\CALX_sc_kqu #1.#2.#3.#4\xint:% {\expandafter\CALX_sc_kqv\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.}% \def\CALX_sc_kqv #1.#2.#3.#4#5.#6.#7\xint:% {% \expandafter\CALX_sc_kqw\the\numexpr#5+8*#6\expandafter.% \the\numexpr(2*#5+7)/16\expandafter.% \the\numexpr#5+8-8*((2*#5+7)/16).#7\xint:#1.#2.#3#4% }% \def\CALX_sc_kqw #1.#2.#3.#4\xint:% {\expandafter\CALX_sc_kqy\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.}% \def\CALX_sc_kqy #1.#2.% {\expandafter\CALX_sc_kqz\the\numexpr\CALX_qkz#1.#2..#1.#2.}% \def\CALX_sc_kqz #1.#2.#3.#4.#5.#6% {% \ifodd#6 \expandafter\CALX_sc_kqo\else\expandafter\CALX_sc_kqe\fi #1.#2.#3.#4.#5.#6% }% \def\CALX_sc_kqo #1.#2.#3.#4.#5.#6#7% {% \expandafter\CALX_sc_kqf\the\numexpr\CALX_cosaux#1.\expandafter.% \the\numexpr\ifnum#6=\xint_c_iii -\fi1\expandafter.\the\numexpr-#5.#4.% }% \def\CALX_sc_kqe #1.#2.#3.#4.#5.#6#7% {% \expandafter\CALX_sc_kqf\the\numexpr#2*(\CALX_sinaux#1.)/1000000000% \expandafter.\the\numexpr\ifnum#6=\xint_c_ii -1*\fi#71\expandafter.% \the\numexpr#3-#5.#4.% }% \def\CALX_sc_kqf #1.#2.#3.#4.% {% \expandafter\CALX_dgo\the\numexpr#2*(\ifnum#1<#4 #1*1000000000/#4\else #1*100000000/#4\fi)\expandafter.\the\numexpr#3-\ifnum#1<#4 9\else 8\fi.% }% \def\CALX_sc_kqx #1#2.F#3#4.#5.#6\xint:#7#8#9% {% \expandafter\CALX_sc_kqa\the\numexpr#4+8*#5\expandafter.% \the\numexpr(2*#4+7)/16\expandafter.% \the\numexpr#4+8-8*((2*#4+7)/16).#6\xint:#1#2#3#7% }% \def\CALX_sc_kqa #1.#2.#3.#4\xint:% {\expandafter\CALX_sc_kqb\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.}% \def\CALX_sc_kqb #1.#2.#3#4#5#6{\csname CALX_kq#3#4\endcsname#6#5#1.#2.}% \expandafter\def\csname CALX_kqt0\endcsname#1#2{\CALX_qkt#11*#21.}% \expandafter\def\csname CALX_kqt1\endcsname#1#2{\CALX_qku-1*#11*#21.}% \expandafter\def\csname CALX_kqt2\endcsname#1#2{\CALX_qkt#11*#21.}% \expandafter\def\csname CALX_kqt3\endcsname#1#2{\CALX_qku-1*#11*#21.}% \expandafter\def\csname CALX_kqu0\endcsname#1#2{\CALX_qku#11*#21.}% \expandafter\def\csname CALX_kqu1\endcsname#1#2{\CALX_qkt-1*#11*#21.}% \expandafter\def\csname CALX_kqu2\endcsname#1#2{\CALX_qku#11*#21.}% \expandafter\def\csname CALX_kqu3\endcsname#1#2{\CALX_qkt-1*#11*#21.}% \expandafter\def\csname CALX_kqv0\endcsname#1#2{\CALX_qke1.}% \expandafter\def\csname CALX_kqv1\endcsname#1#2{\CALX_qkr-1*#21.}% \expandafter\def\csname CALX_kqv2\endcsname#1#2{\CALX_qke-1.}% \expandafter\def\csname CALX_kqv3\endcsname#1#2{\CALX_qkr#21.}% \expandafter\def\csname CALX_kqw0\endcsname#1#2{\CALX_qkr#11*#21.}% \expandafter\def\csname CALX_kqw1\endcsname#1#2{\CALX_qke#11.}% \expandafter\def\csname CALX_kqw2\endcsname#1#2{\CALX_qkr-1*#11*#21.}% \expandafter\def\csname CALX_kqw3\endcsname#1#2{\CALX_qke-1*#11.}% \def\CALX_qkz #1.#2.% {\ifnum#2<-\xint_c_iv 0\else#1*#1/1000000000/\CALX_pten{-2*#2}\fi}% \def\CALX_qkt #1.#2.#3.% {\expandafter\CALX_qkta\the\numexpr\CALX_qkz#2.#3..#1.#2.#3.}% \def\CALX_qkta #1.#2.#3.#4.% {% \expandafter\CALX_dgo\the\numexpr#2*#3*(\CALX_sinaux#1.)% /(\CALX_cosaux#1.).#4-9.% }% \def\CALX_qku #1.#2.#3.% {\expandafter\CALX_qkua\the\numexpr\CALX_qkz#2.#3..#1.#2.#3.}% \def\CALX_qkua #1.#2.#3.#4.% {% \expandafter\CALX_dgo\the\numexpr#2*(1000000000*100000000/(#3*% (\CALX_sinaux#1.)/(\CALX_cosaux#1.))).-#4-8.% }% \def\CALX_qke #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*(1000000000*1000000000/(% \expandafter\CALX_cosaux\the\numexpr\CALX_qkz#2.#3..)).-9.% }% \def\CALX_qkr #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*((1000000000*100000000/#2)% *1000000000/(\expandafter\CALX_sinaux\the\numexpr\CALX_qkz#2.#3..)).% -#3-8.% }% \def\CALX_sc_rr\fi\CALX_sc_k 0.F+#1.#2.#3\xint:% {% \fi \ifnum\numexpr#1+8*#2>\xint_c_iv \CALX_rjs\fi \expandafter\CALX_sc_k\romannumeral0\CALX_red #1.#2.#3\xint:\xint:% }% % \end{macrocode} %\begin{lverb} % Degree reduction, \CALX_sc_f|x|: \CALX_sc_ks (sind, % cscd), \CALX_sc_kc (cosd, secd), \CALX_sc_k (tand, cotd). With t = D + % 8e (|x| < 10^t): %- t < 2: q = 0, u = |x| pi/180 at P+4 digits (\CALX_sc_fz, constant % \CALX_pdg

); %- 2 <= t <= 6: q = round(|x|/90) in \numexpr from the nine leading % digits (\CALX_rta); q = 0: as above; else (\CALX_sc_fk) r = |x| - 90q % at P+8 digits (exact: r has at most P digits), 90q a one-block native % (\CALX_sc_fv), u = r pi/180 at P+4 digits, quadrant q mod 4; %- t > 6: \CALX_sc_fo, exact reduction modulo 360 (\CALX_red_a). % %\end{lverb} % \begin{macrocode} \def\CALX_sc_d{\CALX_sc_f\CALX_sc_k}% \def\CALX_sc_s{\CALX_sc_f\CALX_sc_ks}% \def\CALX_sc_c{\CALX_sc_f\CALX_sc_kc}% \let\CALX_sc_t\CALX_sc_d \let\CALX_sc_u\CALX_sc_d \let\CALX_sc_v\CALX_sc_c \let\CALX_sc_w\CALX_sc_s \def\CALX_sc_f #1#2.#3.% {% \ifnum\numexpr#2+8*#3>\xint_c_vi \xint_dothis\CALX_sc_fo\fi \ifnum\numexpr#2+8*#3<\xint_c_ii \xint_dothis{\CALX_sc_fz 0.}\fi \xint_orthat\CALX_sc_fg #1#2.#3.% }% \def\CALX_sc_fg #1#2.#3.#4\xint:% {% \expandafter\CALX_sc_fh\the\numexpr(\CALX_rta \the\numexpr(2*#2+7)/16\relax.\the\numexpr#2+8-8*((2*#2+7)/16).% #4\xint:)/(90*\CALX_pten{9-#2-8*#3}).#1#2.#3.#4\xint:% }% \def\CALX_sc_fh #1.% {\ifnum#1=\xint_c_ \expandafter\CALX_sc_fz\else \expandafter\CALX_sc_fk\fi #1.}% \def\CALX_sc_fz 0.#1#2\xint:% {% \expandafter#1\expandafter0\expandafter.\romannumeral0% \CALX_fmul{\the\numexpr\CALX_trigdigits+4\relax}{F+#2}% {\csname CALX_pdg\the\numexpr\CALX_trigdigits\endcsname}\xint:% }% \def\CALX_sc_fk #1.#2#3\xint:% {% \expandafter#2\the\numexpr#1-4*((2*#1-3)/8)\expandafter.% \romannumeral0\CALX_fmul{\the\numexpr\CALX_trigdigits+4\relax}% {\romannumeral0\CALX_fsub{\the\numexpr\CALX_trigdigits+8\relax}% {F+#3}{\expandafter\CALX_sc_fv\the\numexpr100000000+90*#1.}}% {\csname CALX_pdg\the\numexpr\CALX_trigdigits\endcsname}\xint:% }% \def\CALX_sc_fv #1.{\expandafter\CALX_sc_fw\the\numexpr\CALX_nd#1..#1.}% \def\CALX_sc_fw #1.#2.{F+#1.0.#2!}% \def\CALX_sc_fo #1#2\xint:% {\expandafter#1\romannumeral0\CALX_red_a F+#2\xint:\xint:}% % \end{macrocode} %\begin{lverb} % One kernel: \CALX_sc_ks q.u (sine and cosecant) runs the sine kernel % for q even, the cosine kernel for q odd; \CALX_sc_kc q.u (cosine and % secant) the reverse. \CALX_sc_ku: sine kernel, finisher B, result in % the S slot (\CALX_sc_pu); \CALX_sc_kv: cosine kernel, finisher A, % result in the C slot (\CALX_sc_pv); the other slot is empty. u = 0: % \CALX_sc_k. \CALX_sc_k: both kernels (u = 0: \CALX_sc_kz, S = 0, C = % 1). %\end{lverb} % \begin{macrocode} \def\CALX_sc_ks #1.F#2#3.% {% \ifnum#3=\xint_c_ \CALX_sc_kj\fi \ifodd#1 \expandafter\CALX_sc_kv\else\expandafter\CALX_sc_ku\fi #1.F#2#3.% }% \def\CALX_sc_kc #1.F#2#3.% {% \ifnum#3=\xint_c_ \CALX_sc_kj\fi \ifodd#1 \expandafter\CALX_sc_ku\else\expandafter\CALX_sc_kv\fi #1.F#2#3.% }% \def\CALX_sc_kj\fi #1\fi{\fi\CALX_sc_k}% \def\CALX_sc_ku #1.F#2\xint:% {\CALX_as_kc s{#2}B\CALX_sc_pu #1.}% \def\CALX_sc_kv #1.F#2\xint:% {\CALX_as_kc c{#2}A\CALX_sc_pv #1.}% \def\CALX_sc_pu #1#2.#3#4{#4{#2}{#3}{#1}{}}% \def\CALX_sc_pv #1#2.#3#4{#4{#2}{#3}{}{#1}}% \def\CALX_sc_k #1.F#2#3.#4\xint:% {% \ifnum#3=\xint_c_ \CALX_sc_kz\fi \CALX_as_kc c{#2#3.#4}A\CALX_sc_m{#2#3.#4}#1.% }% \def\CALX_sc_kz\fi\CALX_as_kc#1#2A\CALX_sc_m#3#4.#5#6% {\fi#6{#4}{#5}{F+0.0.}{F+1.0.100000001!}}% \def\CALX_sc_m #1#2#3.% {\CALX_as_kc s{#2}B\CALX_sc_n{#1}#3.}% \def\CALX_sc_n #1#2#3.#4#5{#5{#3}{#4}{#1}{#2}}% \def\CALX_shzA #1\xint:#2{#2{F+1.0.100000001!}}% \def\CALX_shzB #1\xint:#2% {\expandafter#2\expandafter{\romannumeral0\CALX_fnround {\CALX_trigdigits+4}{F#1}}}% \def\CALX_scS #1{\csname CALX_scs\the\numexpr#1\endcsname}% \def\CALX_scC #1{\csname CALX_scc\the\numexpr#1\endcsname}% \expandafter\def\csname CALX_scs0\endcsname #1#2#3{\CALX_as_m#1+#2}% \expandafter\def\csname CALX_scs1\endcsname #1#2#3{\CALX_as_m#1+#3}% \expandafter\def\csname CALX_scs2\endcsname #1#2#3{\CALX_as_m#1-#2}% \expandafter\def\csname CALX_scs3\endcsname #1#2#3{\CALX_as_m#1-#3}% \expandafter\def\csname CALX_scc0\endcsname #1#2{\CALX_as_m++#2}% \expandafter\def\csname CALX_scc1\endcsname #1#2{\CALX_as_m+-#1}% \expandafter\def\csname CALX_scc2\endcsname #1#2{\CALX_as_m+-#2}% \expandafter\def\csname CALX_scc3\endcsname #1#2{\CALX_as_m++#1}% \def\CALX_sc_q #1#2% {\CALX_fnround{\CALX_trigdigits}{\CALX_fdiv {\the\numexpr\CALX_trigdigits+4\relax}{#1}{#2}}}% \def\CALX_fnsin #1#2#3#4#5% {\CALX_fnround{\CALX_trigdigits}{\CALX_scS{#1}#2{#3}{#4}}}% \def\CALX_fncos #1#2#3#4#5% {\CALX_fnround{\CALX_trigdigits}{\CALX_scC{#1}{#3}{#4}}}% \def\CALX_fntan #1#2#3#4#5{\CALX_sc_q{\CALX_scS{#1}#2{#3}{#4}}% {\CALX_scC{#1}{#3}{#4}}}% \def\CALX_fncot #1#2#3#4#5{\CALX_sc_q{\CALX_scC{#1}{#3}{#4}}% {\CALX_scS{#1}#2{#3}{#4}}}% \def\CALX_fnsec #1#2#3#4#5{\CALX_sc_q{F+1.0.100000001!}% {\CALX_scC{#1}{#3}{#4}}}% \def\CALX_fncsc #1#2#3#4#5{\CALX_sc_q{F+1.0.100000001!}% {\CALX_scS{#1}#2{#3}{#4}}}% \def\CALX_fnsinc #1#2#3#4#5{\CALX_fnsc #5\xint:{#1}{#2}{#3}{#4}{#5}}% \def\CALX_fnsc F#1#2.% {% \ifnum#2=\xint_c_ \xint_dothis\CALX_fnsc_zero\fi \xint_orthat\CALX_fnsc_regular #1#2.% }% \def\CALX_fnsc_zero #1#2.#3\xint:#4#5#6#7#8% { F+1.0.100000001!}% \def\CALX_fnsc_regular #1#2.#3\xint:#4#5#6#7#8% {\CALX_sc_q{\CALX_scS{#4}#5{#6}{#7}}{#8}}% \def\CALX_as_tau F+#1.#2.#3\xint:% {% \ifnum\numexpr#1+8*#2<-\xint_c_viii 0\else \ifnum\numexpr#1+8*#2>\xint_c_ 1000000000\else (\CALX_rta\the\numexpr(2*#1+7)/16\relax.% \the\numexpr#1+8-8*((2*#1+7)/16)\relax.#3\xint:)% /\CALX_pten{-#1-8*#2}\fi\fi }% \def\CALX_as_pp {\ifnum\CALX_trigdigits<\xint_c_ix 9\else\the\numexpr\CALX_trigdigits\fi}% \def\CALX_as_kc {% \ifnum\CALX_trigdigits>32 \expandafter\CALX_as_kb\else \expandafter\CALX_as_ka\fi }% \def\CALX_as_ka #1#2{\csname CALX_tf#1\CALX_as_pp\endcsname\xint:#2\xint:}% \def\CALX_as_kb #1#2% {% \expandafter\CALX_sha\romannumeral`&&@\csname CALX_ts#1\the\numexpr\CALX_trigdigits\endcsname\xint:#2\xint:% }% \def\CALX_gkA #1#2#3#4% {% \expandafter#4\expandafter{\romannumeral0\CALX_fnround {\CALX_trigdigits+4}{\CALX_asch{#1}#3.}}% }% \def\CALX_gkB #1#2#3#4% {% \expandafter#4\expandafter{\romannumeral0\CALX_fmul {\the\numexpr\CALX_trigdigits+4\relax}{F#2}{\CALX_asch{#1}#3.}}% }% \def\CALX_asch #1#2.% {\expanded{F+\the\numexpr16*((#2+1)/4).-\the\numexpr2*((#2+1)/4).% \csname CALX_sb\the\numexpr(#2+1)/4\endcsname#1}}% \def\CALX_as_ser #1#2% {\expandafter\CALX_as_sea\romannumeral0\CALX_fsqr{#1}{#2}\xint:{#1}{#2}}% \def\CALX_as_sea #1\xint:#2#3% {% \CALX_fmul{#2}{\CALX_fmul{#2}{#3}{#1}}% {\csname CALX_ash\CALX_gl{\numexpr(#2+9)/18\relax}\endcsname{#2}{#1}}% }% \edef\CALX_asca{\romannumeral0\CALX_ffromraw {1666666666666666666666666666666666666666666666666666666666666666666666% 66666666666666666666666666666666666666666666666666[-120]}}% \edef\CALX_ascb{\romannumeral0\CALX_ffromraw {7500000000000000000000000000000000000000000000000000000000000000000000% 00000000000000000000000000000000000000000000000000[-121]}}% \edef\CALX_ascc{\romannumeral0\CALX_ffromraw {4464285714285714285714285714285714285714285714285714285714285714285714% 28571428571428571428571428571428571428571428571428[-121]}}% \edef\CALX_ascd{\romannumeral0\CALX_ffromraw {3038194444444444444444444444444444444444444444444444444444444444444444% 44444444444444444444444444444444444444444444444444[-121]}}% \edef\CALX_asce{\romannumeral0\CALX_ffromraw {2237215909090909090909090909090909090909090909090909090909090909090909% 09090909090909090909090909090909090909090909090909[-121]}}% \edef\CALX_ascf{\romannumeral0\CALX_ffromraw {1735276442307692307692307692307692307692307692307692307692307692307692% 30769230769230769230769230769230769230769230769230[-121]}}% \def\CALX_asha #1#2% {\CALX_asca}% \def\CALX_ashb #1#2% {\CALX_fadd{#1}{\CALX_asca}{\CALX_fmul{#1}{#2}{\CALX_ascb}}}% \def\CALX_ashc #1#2% {\CALX_fadd{#1}{\CALX_asca}{\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascb}% {\CALX_fmul{#1}{#2}{\CALX_ascc}}}}}% \def\CALX_ashd #1#2% {\CALX_fadd{#1}{\CALX_asca}{\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascb}% {\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascc}{\CALX_fmul{#1}{#2}% {\CALX_ascd}}}}}}}% \def\CALX_ashe #1#2% {\CALX_fadd{#1}{\CALX_asca}{\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascb}% {\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascc}{\CALX_fmul{#1}{#2}% {\CALX_fadd{#1}{\CALX_ascd}{\CALX_fmul{#1}{#2}{\CALX_asce}}}}}}}}}% \def\CALX_ashf #1#2% {\CALX_fadd{#1}{\CALX_asca}{\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascb}% {\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_ascc}{\CALX_fmul{#1}{#2}% {\CALX_fadd{#1}{\CALX_ascd}{\CALX_fmul{#1}{#2}{\CALX_fadd{#1}{\CALX_asce}% {\CALX_fmul{#1}{#2}{\CALX_ascf}}}}}}}}}}}% \def\CALX_asb #1.% {%(((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((% #1*1849/1980+\xint_c_e_ix)*% 1681/1806)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 1521/1640)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 1369/1482)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 1225/1332)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 1089/1190)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 961/1056)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 841/930)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 729/812)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 625/702)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 529/600)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 441/506)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 361/420)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 289/342)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 225/272)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 169/210)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 121/156)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 81/110)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 49/72)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 25/42)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 9/20)*#1/\xint_c_e_ix+\xint_c_e_ix)*% 1/6)*#1/\xint_c_e_ix+\xint_c_e_ix }% % \end{macrocode} %\begin{lverb} % Generated by tools/trig_genpm.py: \CALX_pm_, a, c = 1..3. %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_pm1_1\endcsname#1#2% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#2\relax!% }% \expandafter\def\csname CALX_pm1_2\endcsname#1#2#3% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#2\CALX_hpa#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#2\CALX_hpb#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#2\CALX_hpc#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#3\relax!% }% \expandafter\def\csname CALX_pm1_3\endcsname#1#2#3#4% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#2\CALX_hpa#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#2\CALX_hpb#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#2\CALX_hpc#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#3\CALX_hpa#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#3\CALX_hpb#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#3\CALX_hpc#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#4\relax!% }% \expandafter\def\csname CALX_pm2_1\endcsname#1#2#3% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#3\CALX_hpa#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#3\CALX_hpb#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#3\CALX_hpc#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#3\relax!% }% \expandafter\def\csname CALX_pm2_2\endcsname#1#2#3#4% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#3\CALX_hpa#1#4% \CALX_hpa#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#3\CALX_hpb#1#4% \CALX_hpb#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#3\CALX_hpc#1#4% \CALX_hpc#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#4\CALX_hpd#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#4\CALX_hpe#2#3% \CALX_hpa#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#4\CALX_hpf#2#3% \CALX_hpb#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#4\CALX_hpg#2#3% \CALX_hpc#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#4\relax!% }% \expandafter\def\csname CALX_pm2_3\endcsname#1#2#3#4#5% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#3\CALX_hpa#1#4% \CALX_hpa#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#3\CALX_hpb#1#4% \CALX_hpb#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#3\CALX_hpc#1#4% \CALX_hpc#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#4\CALX_hpd#2#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#4\CALX_hpa#1#5% \CALX_hpe#2#3\CALX_hpa#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#4\CALX_hpb#1#5% \CALX_hpf#2#3\CALX_hpb#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#4\CALX_hpc#1#5% \CALX_hpg#2#3\CALX_hpc#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#5\CALX_hpd#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#5\CALX_hpe#2#4% \CALX_hpa#2#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#5\CALX_hpf#2#4% \CALX_hpb#2#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#5\CALX_hpg#2#4% \CALX_hpc#2#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#5\relax!% }% \expandafter\def\csname CALX_pm3_1\endcsname#1#2#3#4% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#4\CALX_hpa#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#4\CALX_hpb#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#4\CALX_hpc#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#4\CALX_hpa#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#4\CALX_hpb#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#4\CALX_hpc#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#3#4\relax!% }% \expandafter\def\csname CALX_pm3_2\endcsname#1#2#3#4#5% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#4\CALX_hpa#1#5% \CALX_hpa#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#4\CALX_hpb#1#5% \CALX_hpb#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#4\CALX_hpc#1#5% \CALX_hpc#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#5\CALX_hpd#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#5\CALX_hpe#2#4% \CALX_hpa#2#5\CALX_hpa#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#5\CALX_hpf#2#4% \CALX_hpb#2#5\CALX_hpb#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#5\CALX_hpg#2#4% \CALX_hpc#2#5\CALX_hpc#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#5\CALX_hpd#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#5\CALX_hpe#3#4% \CALX_hpa#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#5\CALX_hpf#3#4% \CALX_hpb#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#5\CALX_hpg#3#4% \CALX_hpc#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#3#5\relax!% }% \expandafter\def\csname CALX_pm3_3\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_pmh\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#4\CALX_hpa#1#5% \CALX_hpa#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#4\CALX_hpb#1#5% \CALX_hpb#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#4\CALX_hpc#1#5% \CALX_hpc#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#5\CALX_hpd#2#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#5\CALX_hpa#1#6% \CALX_hpe#2#4\CALX_hpa#2#5\CALX_hpa#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#5\CALX_hpb#1#6% \CALX_hpf#2#4\CALX_hpb#2#5\CALX_hpb#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#5\CALX_hpc#1#6% \CALX_hpg#2#4\CALX_hpc#2#5\CALX_hpc#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#6\CALX_hpd#2#5% \CALX_hpd#3#4% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#6\CALX_hpe#2#5% \CALX_hpa#2#6\CALX_hpe#3#4\CALX_hpa#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#6\CALX_hpf#2#5% \CALX_hpb#2#6\CALX_hpf#3#4\CALX_hpb#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#6\CALX_hpg#2#5% \CALX_hpc#2#6\CALX_hpg#3#4\CALX_hpc#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#6\CALX_hpd#3#5% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#6\CALX_hpe#3#5% \CALX_hpa#3#6% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#6\CALX_hpf#3#5% \CALX_hpb#3#6% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#6\CALX_hpg#3#5% \CALX_hpc#3#6% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#3#6% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#3#6% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#3#6% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#3#6\relax!% }% % \end{macrocode} % \subsection{Generated helpers and products} % Generated by |tools/trig_genfix.py|: helpers. % \begin{macrocode} \def\CALX_hda #1#2#3#4#5#6#7#8{-#1*#5}% \def\CALX_hdb #1#2#3#4#5#6#7#8{-#1*#6-#2*#5}% \def\CALX_hdc #1#2#3#4#5#6#7#8{-#1*#7-#2*#6-#3*#5}% \def\CALX_hdd #1#2#3#4#5#6#7#8{-#1*#8-#2*#7-#3*#6-#4*#5}% \def\CALX_hde #1#2#3#4#5#6#7#8{-#2*#8-#3*#7-#4*#6}% \def\CALX_hdf #1#2#3#4#5#6#7#8{-#3*#8-#4*#7}% \def\CALX_hdg #1#2#3#4#5#6#7#8{-#4*#8}% \def\CALX_csa #1#2#3#4{#1}% \def\CALX_csb #1#2#3#4{#2}% \def\CALX_csc #1#2#3#4{#3}% \def\CALX_csd #1#2#3#4{#4}% \def\CALX_poaa #1#2#3#4#5#6{\CALX_pg 1.}% \def\CALX_poab #1#2#3#4#5#6{\CALX_pg 2.}% \def\CALX_poac #1#2#3#4#5#6{\CALX_pg 3.}% \def\CALX_poad #1#2#3#4#5#6{\CALX_pg 4.}% \def\CALX_poae #1#2#3#4#5#6{\CALX_pg 5.}% \def\CALX_poaf #1#2#3#4#5#6{\CALX_pg 6.}% \def\CALX_poag #1#2#3#4#5#6{\CALX_pg 7.}% \def\CALX_poah #1#2#3#4#5#6{\CALX_pg 8.}% \def\CALX_poai #1#2#3#4#5#6{\CALX_pg 9.}% \def\CALX_poaj #1#2#3#4#5#6{\CALX_pg 10.}% \def\CALX_poak #1#2#3#4#5#6{\CALX_pg 11.}% % \end{macrocode} % Generated: square of M for u. % \begin{macrocode} \def\CALX_hpa #1#2#3#4#5#6#7#8{+#1*#5}% \def\CALX_hpb #1#2#3#4#5#6#7#8{+#1*#6+#2*#5}% \def\CALX_hpc #1#2#3#4#5#6#7#8{+#1*#7+#2*#6+#3*#5}% \def\CALX_hpd #1#2#3#4#5#6#7#8{+#1*#8+#2*#7+#3*#6+#4*#5}% \def\CALX_hpe #1#2#3#4#5#6#7#8{+#2*#8+#3*#7+#4*#6}% \def\CALX_hpf #1#2#3#4#5#6#7#8{+#3*#8+#4*#7}% \def\CALX_hpg #1#2#3#4#5#6#7#8{+#4*#8}% \def\CALX_pqa #1#2#3#4#5#6{\CALX_pg 8.}% \def\CALX_pqb #1#2#3#4#5#6{\CALX_pg 16.}% \def\CALX_pqc #1#2#3#4#5#6{\CALX_pg 24.}% \expandafter\def\csname CALX_xm1\endcsname1#1!% {{{0000}{0000}\CALX_bl#1}}% \expandafter\def\csname CALX_xm2\endcsname1#1!1#2!% {{\CALX_bl#2\CALX_bl#1}}% \expandafter\def\csname CALX_xm3\endcsname1#1!1#2!1#3!% {{{0000}{0000}\CALX_bl#3}{\CALX_bl#2\CALX_bl#1}}% \expandafter\def\csname CALX_xm4\endcsname1#1!1#2!1#3!1#4!% {{\CALX_bl#4\CALX_bl#3}{\CALX_bl#2\CALX_bl#1}}% \expandafter\def\csname CALX_xm5\endcsname1#1!1#2!1#3!1#4!1#5!% {{{0000}{0000}\CALX_bl#5}{\CALX_bl#4\CALX_bl#3}{\CALX_bl#2\CALX_bl#1}}% \expandafter\def\csname CALX_sq1\endcsname#1% {% \expandafter\CALX_pqa\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#1\relax!;% }% \expandafter\def\csname CALX_sq2\endcsname#1#2% {% \expandafter\CALX_pqb\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#1\CALX_hpa#1#2% \CALX_hpa#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#1\CALX_hpb#1#2% \CALX_hpb#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#1\CALX_hpc#1#2% \CALX_hpc#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#2\CALX_hpd#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#2\CALX_hpe#2#1% \CALX_hpa#2#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#2\CALX_hpf#2#1% \CALX_hpb#2#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#2\CALX_hpg#2#1% \CALX_hpc#2#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#2\relax!;% }% \expandafter\def\csname CALX_sq3\endcsname#1#2#3% {% \expandafter\CALX_pqc\the\numexpr 1000000000% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpa#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpb#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpc#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#1\CALX_hpa#1#2% \CALX_hpa#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#1\CALX_hpb#1#2% \CALX_hpb#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#1\CALX_hpc#1#2% \CALX_hpc#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#2\CALX_hpd#2#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#2\CALX_hpa#1#3% \CALX_hpe#2#1\CALX_hpa#2#2\CALX_hpa#3#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#2\CALX_hpb#1#3% \CALX_hpf#2#1\CALX_hpb#2#2\CALX_hpb#3#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#2\CALX_hpc#1#3% \CALX_hpg#2#1\CALX_hpc#2#2\CALX_hpc#3#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#1#3\CALX_hpd#2#2% \CALX_hpd#3#1% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#1#3\CALX_hpe#2#2% \CALX_hpa#2#3\CALX_hpe#3#1\CALX_hpa#3#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#1#3\CALX_hpf#2#2% \CALX_hpb#2#3\CALX_hpf#3#1\CALX_hpb#3#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#1#3\CALX_hpg#2#2% \CALX_hpc#2#3\CALX_hpg#3#1\CALX_hpc#3#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#2#3\CALX_hpd#3#2% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#2#3\CALX_hpe#3#2% \CALX_hpa#3#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#2#3\CALX_hpf#3#2% \CALX_hpb#3#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#2#3\CALX_hpg#3#2% \CALX_hpc#3#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpd#3#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpe#3#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpf#3#3% \expandafter\CALX_pkq\the\numexpr 1000000000\CALX_hpg#3#3\relax!;% }% % \end{macrocode} % Generated: products, shapes (s, n) of the tables. % \begin{macrocode} \expandafter\def\csname CALX_m1_2\endcsname#1#2#3% {% \expandafter\CALX_poab\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hda#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdb#3#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m2_2\endcsname#1#2#3% {% \expandafter\CALX_poab\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2\CALX_hda#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdb#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdc#3#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m2_3\endcsname#1#2#3% {% \expandafter\CALX_poac\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#2\CALX_hda#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdb#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdc#3#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m3_3\endcsname#1#2#3% {% \expandafter\CALX_poac\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2\CALX_hda#3#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#2\CALX_hdb#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdc#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#3#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m3_4\endcsname#1#2#3% {% \expandafter\CALX_poad\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#2\CALX_hda#3#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#2\CALX_hdb#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdc#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#3#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m4_4\endcsname#1#2#3% {% \expandafter\CALX_poad\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2\CALX_hda#3#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#2\CALX_hdb#3#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#2\CALX_hdc#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#3#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#3#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m4_5\endcsname#1#2#3#4% {% \expandafter\CALX_poae\the\numexpr 2100000000+\CALX_csa#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#2% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#2\CALX_hda#4#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#2\CALX_hdb#4#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#3\CALX_hdc#4#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#4#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#4#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m5_5\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poae\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#5#1\CALX_hda#5#2% \CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#5#1\CALX_hdb#5#2% \CALX_hdb#6#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m5_6\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poaf\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#5#1\CALX_hda#5#2% \CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#5#1\CALX_hdb#5#2% \CALX_hdb#6#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m6_6\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poaf\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hde#5#1% \CALX_hda#5#2\CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#5#1\CALX_hdb#5#2% \CALX_hdb#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#5#1\CALX_hdc#5#2% \CALX_hdc#6#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m6_7\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poag\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hde#5#1% \CALX_hda#5#2\CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#5#1\CALX_hdb#5#2% \CALX_hdb#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#5#1\CALX_hdc#5#2% \CALX_hdc#6#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m7_7\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poag\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hde#5#1% \CALX_hda#5#2\CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hdf#5#1% \CALX_hdb#5#2\CALX_hdb#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#5#1\CALX_hdc#5#2% \CALX_hdc#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#5#2\CALX_hdd#6#1% \relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m7_8\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poah\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hde#5#1% \CALX_hda#5#2\CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdf#5#1% \CALX_hdb#5#2\CALX_hdb#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#5#1\CALX_hdc#5#2% \CALX_hdc#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#5#2\CALX_hdd#6#1% \relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m8_8\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_poah\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3\CALX_hda#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hdb#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdc#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdd#5#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hde#5#1% \CALX_hda#5#2\CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hdf#5#1% \CALX_hdb#5#2\CALX_hdb#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdg#5#1% \CALX_hdc#5#2\CALX_hdc#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#5#2\CALX_hdd#6#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#5#2\CALX_hde#6#1% \CALX_hda#6#2\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m8_9\endcsname#1#2#3#4#5#6#7% {% \expandafter\CALX_poai\the\numexpr 2100000000+\CALX_csa#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#3% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#3\CALX_hda#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#3\CALX_hdb#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#4\CALX_hdc#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hdd#6#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hde#6#1% \CALX_hda#6#2\CALX_hda#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdf#6#1% \CALX_hdb#6#2\CALX_hdb#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#5\CALX_hdg#6#1% \CALX_hdc#6#2\CALX_hdc#7#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#6#2\CALX_hdd#7#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#6#2\CALX_hde#7#1% \CALX_hda#7#2\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m9_9\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_poai\the\numexpr 2100000000+\CALX_csa#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hda#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hdb#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdc#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#5\CALX_hdd#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#5\CALX_hde#7#1% \CALX_hda#7#2\CALX_hda#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#5\CALX_hdf#7#1% \CALX_hdb#7#2\CALX_hdb#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#5\CALX_hdg#7#1% \CALX_hdc#7#2\CALX_hdc#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#6\CALX_hdd#7#2% \CALX_hdd#8#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#7#2\CALX_hda#7#3% \CALX_hde#8#1\CALX_hda#8#2\CALX_hda#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#7#2\CALX_hdb#7#3% \CALX_hdf#8#1\CALX_hdb#8#2\CALX_hdb#9#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m9_10\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_poaj\the\numexpr 2100000000+\CALX_csa#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hda#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdb#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#5\CALX_hdc#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#5\CALX_hdd#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#5\CALX_hde#7#1% \CALX_hda#7#2\CALX_hda#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#5\CALX_hdf#7#1% \CALX_hdb#7#2\CALX_hdb#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#6\CALX_hdg#7#1% \CALX_hdc#7#2\CALX_hdc#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#6\CALX_hdd#7#2% \CALX_hdd#8#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hde#7#2\CALX_hda#7#3% \CALX_hde#8#1\CALX_hda#8#2\CALX_hda#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#7#2\CALX_hdb#7#3% \CALX_hdf#8#1\CALX_hdb#8#2\CALX_hdb#9#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m10_10\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_poaj\the\numexpr 2100000000+\CALX_csa#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hda#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hdb#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdc#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#5\CALX_hdd#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#5\CALX_hde#7#1% \CALX_hda#7#2\CALX_hda#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#5\CALX_hdf#7#1% \CALX_hdb#7#2\CALX_hdb#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#5\CALX_hdg#7#1% \CALX_hdc#7#2\CALX_hdc#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#6\CALX_hdd#7#2% \CALX_hdd#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#6\CALX_hde#7#2% \CALX_hda#7#3\CALX_hde#8#1\CALX_hda#8#2\CALX_hda#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#7#2\CALX_hdb#7#3% \CALX_hdf#8#1\CALX_hdb#8#2\CALX_hdb#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#7#2\CALX_hdc#7#3% \CALX_hdg#8#1\CALX_hdc#8#2\CALX_hdc#9#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m10_11\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_poak\the\numexpr 2100000000+\CALX_csa#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hda#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdb#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#5\CALX_hdc#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#5\CALX_hdd#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#5\CALX_hde#7#1% \CALX_hda#7#2\CALX_hda#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#5\CALX_hdf#7#1% \CALX_hdb#7#2\CALX_hdb#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#6\CALX_hdg#7#1% \CALX_hdc#7#2\CALX_hdc#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#6\CALX_hdd#7#2% \CALX_hdd#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#6\CALX_hde#7#2% \CALX_hda#7#3\CALX_hde#8#1\CALX_hda#8#2\CALX_hda#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdf#7#2\CALX_hdb#7#3% \CALX_hdf#8#1\CALX_hdb#8#2\CALX_hdb#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#7#2\CALX_hdc#7#3% \CALX_hdg#8#1\CALX_hdc#8#2\CALX_hdc#9#1\relax!;\CALX_gobW% }% \expandafter\def\csname CALX_m11_11\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_poak\the\numexpr 2100000000+\CALX_csa#4% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#4\CALX_hda#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#4\CALX_hdb#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#4\CALX_hdc#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#5\CALX_hdd#7#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#5\CALX_hde#7#1% \CALX_hda#7#2\CALX_hda#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#5\CALX_hdf#7#1% \CALX_hdb#7#2\CALX_hdb#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csd#5\CALX_hdg#7#1% \CALX_hdc#7#2\CALX_hdc#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csa#6\CALX_hdd#7#2% \CALX_hdd#8#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csb#6\CALX_hde#7#2% \CALX_hda#7#3\CALX_hde#8#1\CALX_hda#8#2\CALX_hda#9#1% \expandafter\CALX_pk\the\numexpr 2100000000+\CALX_csc#6\CALX_hdf#7#2% \CALX_hdb#7#3\CALX_hdf#8#1\CALX_hdb#8#2\CALX_hdb#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdg#7#2\CALX_hdc#7#3% \CALX_hdg#8#1\CALX_hdc#8#2\CALX_hdc#9#1% \expandafter\CALX_pk\the\numexpr 2100000000\CALX_hdd#7#3\CALX_hdd#8#2% \CALX_hdd#9#1\relax!;\CALX_gobW% }% % \end{macrocode} % \subsection{Schedules of the fixed path} % Generated: schedules (P with |A <= 11|). % \begin{macrocode} \CALX_fdata\let\CALX_fdata\undefined % \end{macrocode} % \subsection{Argument reduction} %\begin{lverb} % Reduction B1, for 0.8 <= |X| < 10^4 (E = D + 8e <= 4; E > 4: % \CALX_rslow, below), m = ceil((P+6)/8) (m = 2 if P <= 8, \CALX_trigm), % W = 8m >= P + 6 and H = round(pi/2 10^W): %( %: k = round(2|X|/pi), R = |X| 10^W - k H, r = R 10^-W. %) % k: Xh = the top 9 digits of M (rounded), Xh = |X| 10^(9-E) (1 + d), % |d| < 10^-8; k = round(round(Xh c / 10^9) / 10^(9-E)), c = 636619772 % (2/pi 10^9 rounded, relative error < 8 10^-10): the error on 2|X|/pi is % < 0.0017, so |r| < pi/4 + 0.0017 pi/2 < 0.79 < 0.8 (domain of the % series kernels). E = 0: k = 1. k <= 6367 (one limb; the integer part of % |X| is in the low limb of the units group). % % R: 4-digit limbs, columns j = 2m..0 of x_j - k h_j + carry in one % nested \numexpr chain (\CALX_rd, generated by tools/trig_genred.py, % h_j literal; m >= 8: in two macros, \CALX_rdb taking the inner part % of the chain built by \CALX_rd), carry by offset 1200000000. % |X| 10^W is an integer (-8e <= % D <= P + 7 < W + 8, hence z = e + m >= 0): its blocks are z zero blocks % then the blocks of M % (and a zero units block if E = 0), m + 1 groups of 8 digits. |r| < 1: % the units limb is 0000 (R >= 0) or 9999 (R < 0), the higher limbs are % not computed (exact modulo 10^(4(2m+1))). % % Output (\CALX_rh): q = k mod 4 and r as a native float, sign of R, % e = -m, leading zero blocks stripped, D exact (\CALX_nd); for R < 0 the % blocks are 99999999 - b (= |R| - 1). R = 0 gives r = 10^-W. Error on r % (radians): < (k/2 + 1) 10^-W <= 3185 10^-(P+6) < 0.0032 10^-P. %\end{lverb} % \begin{macrocode} \def\CALX_red #1.#2.% {% \ifnum\numexpr#1+8*#2=\xint_c_ \xint_dothis{\CALX_rkc 1.}\fi \xint_orthat{\expandafter\CALX_rka\the\numexpr(2*#1+7)/16\expandafter.% \the\numexpr#1+8-8*((2*#1+7)/16).}% #1.#2.% }% \def\CALX_rka #1.#2.#3.#4.#5\xint:% {% \expandafter\CALX_rkc\the\numexpr(\CALX_rta#1.#2.#5\xint:)% *636619772/1000000000/\CALX_pten{9-#3-8*#4}.#3.#4.#5\xint:% }% % \end{macrocode} %\begin{lverb} % \CALX_rta ..\xint: (inside \numexpr): Xh from the top % block T (d digits) and the next one B: T 10^(9-d) + round(B/10^(d-1)). %\end{lverb} % \begin{macrocode} \def\CALX_rta #1.% {\ifnum#1>\xint_c_ii\expandafter\CALX_rtb\else\expandafter\CALX_rtc\fi#1.}% \def\CALX_rtb #1.#2.1#3!{\expandafter\CALX_rta\the\numexpr#1-1.#2.}% \def\CALX_rtc #1.{\csname CALX_rt#1\endcsname}% \expandafter\def\csname CALX_rt1\endcsname #1.1#2!#3\xint:% {#2*\CALX_pten{9-#1}}% \expandafter\def\csname CALX_rt2\endcsname #1.1#2!1#3!#4\xint:% {#3*\CALX_pten{9-#1}+#2/\CALX_pten{#1-1}}% % \end{macrocode} %\begin{lverb} % \CALX_rkc ...\xint: calls \CALX_rd with {k}, % the m + 1 groups (\CALX_zg, \CALX_bg), then ;.. %\end{lverb} % \begin{macrocode} \def\CALX_trigm{\ifnum\CALX_trigdigits<\xint_c_ix 2\else (\CALX_trigdigits+9)/8\fi}% \def\CALX_rkc #1.#2.#3.#4\xint:% {% \csname CALX_rd\the\numexpr\CALX_trigm\expandafter\endcsname \expanded{{#1}% \csname CALX_zg\the\numexpr#3+\CALX_trigm\endcsname \CALX_bg#4\xint:\ifnum\numexpr#2+8*#3=\xint_c_{00000000}\fi ;\the\numexpr\CALX_trigm.\the\numexpr#1-4*((2*#1-3)/8).}% }% \def\CALX_bg #1{\xint_gob_til_xint: #1\CALX_bge\xint:\CALX_bh#1}% \def\CALX_bge\xint:\CALX_bh\xint:{}% \def\CALX_bh 1#1!{{#1}\CALX_bg}% \expandafter\def\csname CALX_zg0\endcsname{}% \expandafter\def\csname CALX_zg1\endcsname{{00000000}}% \expandafter\def\csname CALX_zg2\endcsname{{00000000}{00000000}}% \expandafter\def\csname CALX_zg3\endcsname {{00000000}{00000000}{00000000}}% \expandafter\def\csname CALX_zg4\endcsname {{00000000}{00000000}{00000000}{00000000}}% \expandafter\def\csname CALX_zg5\endcsname {{00000000}{00000000}{00000000}{00000000}{00000000}}% \expandafter\def\csname CALX_zg6\endcsname {{00000000}{00000000}{00000000}{00000000}{00000000}{00000000}}% \expandafter\edef\csname CALX_zg7\endcsname{\csname CALX_zg6\endcsname {00000000}}% \expandafter\edef\csname CALX_zg8\endcsname{\csname CALX_zg7\endcsname {00000000}}% \expandafter\edef\csname CALX_zg9\endcsname{\csname CALX_zg8\endcsname {00000000}}% \expandafter\edef\csname CALX_zg10\endcsname{\csname CALX_zg9\endcsname {00000000}}% \expandafter\edef\csname CALX_zg11\endcsname{\csname CALX_zg10\endcsname {00000000}}% \expandafter\edef\csname CALX_zg12\endcsname{\csname CALX_zg11\endcsname {00000000}}% \expandafter\edef\csname CALX_zg13\endcsname{\csname CALX_zg12\endcsname {00000000}}% \expandafter\edef\csname CALX_zg14\endcsname{\csname CALX_zg13\endcsname {00000000}}% \def\CALX_lo #1#2#3#4{}% \def\CALX_hi #1#2#3#4#5#6#7#8{#1#2#3#4}% \def\CALX_rp #1#2#3#4#5#6{+#1#2#3#4#5#6-120000!}% % \end{macrocode} %\begin{lverb} % \CALX_rh: the chain output !!...!!;.. % (limbs MS first); the low limb of the top column gives the sign. % \CALX_rsa .. strips the leading zero blocks (pairs % of limbs), \CALX_rv reverses the others (LS first) inside \expanded. % : \CALX_bp (1) or \CALX_bn (complement). %\end{lverb} % \begin{macrocode} \def\CALX_rh #1#2#3#4#5#6#7!#8;#9.% {% \expandafter\CALX_rz\expanded{\csname CALX_rs\ifnum#7=\xint_c_ p\else n\fi\endcsname#9.#9.#8}\xint:% }% \def\CALX_rz #1\xint:#2.{ #2.#1}% \def\CALX_rsp #1.#2.{\CALX_rsa#1.#2.\CALX_bp+}% \def\CALX_rsn #1.#2.{\CALX_rsa#1.#2.\CALX_bn-}% \def\CALX_bp #1#2{1#1#2}% \def\CALX_bn #1#2{\the\numexpr199999999-#1#2\relax}% \def\CALX_rsa #1.#2.#3#4% {% \ifnum#1=\xint_c_ \xint_dothis{F+1.-#2.100000001!}\fi \xint_orthat{\CALX_rsb#1.#2.#3#4}% }% \def\CALX_rsb #1.#2.#3#4#5!#6!% {% \ifnum#3{#5}{#6}=100000000 \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expandafter\CALX_rsa\the\numexpr#1-1.#2.#3#4}% {F#4\the\numexpr8*#1-8+\expandafter\CALX_nd\the\numexpr#3{#5}{#6}.% .-#2.\expandafter\CALX_rv\the\numexpr#1-1.{#3{#5}{#6}!}#3}% }% \def\CALX_rv #1.{\ifnum#1=\xint_c_ \CALX_rve\fi\CALX_rvb#1.}% \def\CALX_rve\fi\CALX_rvb#1.#2#3{\fi#2}% \def\CALX_rvb #1.#2#3#4!#5!% {\expandafter\CALX_rv\the\numexpr#1-1.{#3{#4}{#5}!#2}#3}% \def\CALX_nd #1.% {% \ifnum#1<100010000 \ifnum#1<100000100 \ifnum#1<100000010 1\else2\fi \else\ifnum#1<100001000 3\else4\fi\fi \else \ifnum#1<101000000 \ifnum#1<100100000 5\else6\fi \else\ifnum#1<110000000 7\else8\fi\fi \fi }% % \end{macrocode} %\begin{lverb} % Generated by tools/trig_genred.py: \CALX_rd, m = 2..14 (and % \CALX_rdb, m >= 8). %\end{lverb} % \begin{macrocode} \expandafter\def\csname CALX_rd2\endcsname#1#2#3#4% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#4-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*8966\relax!% }% \expandafter\def\csname CALX_rd3\endcsname#1#2#3#4#5% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#5-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*1322\relax!% }% \expandafter\def\csname CALX_rd4\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#6-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*3975\relax!% }% \expandafter\def\csname CALX_rd5\endcsname#1#2#3#4#5#6#7% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#7-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*986\relax!% }% \expandafter\def\csname CALX_rd6\endcsname#1#2#3#4#5#6#7#8% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#8-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*9688\relax!% }% \expandafter\def\csname CALX_rd7\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#9-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*1049\relax!% }% \expandafter\def\csname CALX_rd8\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb8\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*2962\relax!% }% }% \expandafter\def\csname CALX_rdb8\endcsname#1#2#3% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#3-#1*1% #2}% \expandafter\def\csname CALX_rd9\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb9\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*2961% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*5390% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*8203\relax!% }% }% \expandafter\def\csname CALX_rdb9\endcsname#1#2#3#4% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#4-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*9632% #2}% \expandafter\def\csname CALX_rd10\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb10\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*2961% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*5390% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*8203% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*1431% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*450\relax!% }% }% \expandafter\def\csname CALX_rdb10\endcsname#1#2#3#4#5% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#5-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*8966% #2}% \expandafter\def\csname CALX_rd11\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb11\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*2961% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*5390% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*8203% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*1431% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*449% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*9314% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*174\relax!% }% }% \expandafter\def\csname CALX_rdb11\endcsname#1#2#3#4#5#6% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#6-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*1321% #2}% \expandafter\def\csname CALX_rd12\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb12\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*2961% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*5390% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*8203% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*1431% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*449% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*9314% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*174% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*1267% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*1059\relax!% }% }% \expandafter\def\csname CALX_rdb12\endcsname#1#2#3#4#5#6#7% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#7-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*3975% #2}% \expandafter\def\csname CALX_rd13\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb13\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*9687% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*2961% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*5390% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*8203% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*1431% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*449% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*9314% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*174% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*1267% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*1058% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*5339% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*9107\relax!% }% }% \expandafter\def\csname CALX_rdb13\endcsname#1#2#3#4#5#6#7#8% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#8-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*985% #2}% \expandafter\def\csname CALX_rd14\endcsname#1#2#3#4#5#6#7#8#9% {% \csname CALX_rdb14\endcsname{#1}{% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#9-#1*5529% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#9-#1*1048% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*7472% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*2961% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*5390% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*8203% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*1431% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*449% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*9314% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*174% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*1267% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*1058% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*5339% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*9107% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#2-#1*4043% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#2-#1*2566\relax!% }% }% \expandafter\def\csname CALX_rdb14\endcsname#1#2#3#4#5#6#7#8#9% {% \expandafter\CALX_rh\the\numexpr 1200000000+\CALX_lo#9-#1*1% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#8-#1*5707% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#8-#1*9632% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#7-#1*6794% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#7-#1*8966% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#6-#1*1923% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#6-#1*1321% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#5-#1*6916% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#5-#1*3975% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#4-#1*1442% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#4-#1*985% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_hi#3-#1*8469% \expandafter\CALX_rp\the\numexpr 1200000000+\CALX_lo#3-#1*9687% #2}% % \end{macrocode} %\begin{lverb} % Reduction for 10^4 <= |X| < 10^E, E = D + 8e <= min(P, 126 - P), from % the callers (\CALX_sin_r, \CALX_cos_r, \CALX_sc_rr) when E > 4: jumpers % \CALX_rj (sin, cos) and \CALX_rjs (tan, cot, sec, csc, sinc), which % replace \CALX_red by \CALX_rslow, or, if E > min(P, 126 - P), drop the % continuation (\CALX_rjx, \CALX_rjxs: also the finisher and its three % arguments) and signal ControversialOperation (result I?). % % Integers (M: the integer of the blocks of |X|, |X| = M 10^(8e)): %( %: W = 8 ceil((P+E+2)/8) <= 128, G = E + 3, %: T = round(2/pi 10^G), k = round(M T 10^(8e-G)), %: H = round(pi/2 10^W), R = M 10^(W+8e) - k H, r = R 10^-W, %) % T and H by rounded shifts (\CALX_nshrr) of \CALX_rT = round(2/pi % 10^130) and \CALX_rH = round(pi/2 10^129). The error on 2|X|/pi is % < 0.006 (|r| < 0.8); the error on r is < (k/2 + 1) 10^-W <= 0.005 % 10^-P. q = k mod 4 from the low block of k; r rounded to P+4 digits. %\end{lverb} % \begin{macrocode} \edef\CALX_rT{\romannumeral0\CALX_nfromraw {63661977236758134307553505349005744813783858296182579499066937623558719% 05369061403604552110650123438242913709070318321475716473845}}% \edef\CALX_rH{\romannumeral0\CALX_nfromraw {15707963267948966192313216916397514420985846996875529104874722961539082% 03143104499314017412671058533991074043256641153323546922305}}% \def\CALX_rj\fi#1\CALX_red #2.#3.% {% \fi \ifnum\numexpr#2+8*#3>\numexpr\ifnum\CALX_trigdigits>63 126-\fi \CALX_trigdigits\relax \CALX_rjx\fi #1\CALX_rslow #2.#3.% }% \def\CALX_rjs\fi#1\CALX_red #2.#3.% {% \fi \ifnum\numexpr#2+8*#3>\numexpr\ifnum\CALX_trigdigits>63 126-\fi \CALX_trigdigits\relax \CALX_rjxs\fi #1\CALX_rslow #2.#3.% }% \def\CALX_rjx\fi#1\xint:\xint:% {\fi\CALX_nsig{ControversialOperation}{trig: argument too large}{}}% \def\CALX_rjxs\fi#1\xint:\xint:#2#3#4% {\fi\CALX_nsig{ControversialOperation}{trig: argument too large}{}}% % \end{macrocode} %\begin{lverb} % \CALX_rslow, P <= 8 (\CALX_rse; then 5 <= E <= P, |x| < 10^8): A exact % (9 digits), F = 10^(9-E), a = floor(A/F) = 10^4 a1 + a0, b = A - a F; %( %: k = 6366 a1 + round((a1 1977236758/10^5 + a0 636619772/10^4 %: + b 636619772/10^(13-E)) / 10^5) %) % (2/pi to 10 digits, error on 2|x|/pi < 0.001); B1 with m = 3 (W = 24) % and k = 10^4 k1 + k0 (\CALX_rwk, columns x_j - k0 h_j - k1 h_(j-1), % H = round(pi/2 10^24); x_5, x_6 from G = (A 10^(E-5)) mod 10^8, the % lower limbs of |x| 10^24 being 0); output by \CALX_rh as \CALX_red. % Error on r < (k/2 + 1) 10^-24. P > 8: \CALX_rsl. %\end{lverb} % \begin{macrocode} \def\CALX_rslow {% \ifnum\CALX_trigdigits<\xint_c_ix \xint_dothis\CALX_rse\fi \xint_orthat\CALX_rsl }% \def\CALX_rse #1.#2.#3\xint:% {% \expandafter\CALX_rsf\the\numexpr#1+8*#2\expandafter.% \the\numexpr(2*#1+7)/16\expandafter.% \the\numexpr#1+8-8*((2*#1+7)/16).#3\xint:% }% \def\CALX_rsf #1.#2.#3.#4\xint:% {\expandafter\CALX_rsg\the\numexpr\CALX_rta#2.#3.#4\xint:.#1.}% \def\CALX_rsg #1.#2.% {% \expandafter\CALX_rsh\the\numexpr(2*#1-\CALX_pten{9-#2})% /(2*\CALX_pten{9-#2}).#1.#2.% }% \def\CALX_rsh #1.% {\expandafter\CALX_rsi\the\numexpr(2*#1-10000)/20000.#1.}% \def\CALX_rsi #1.#2.#3.#4.% {% \expandafter\CALX_rsj\the\numexpr#1*6366+(#1*1977236758/100000% +(#2-#1*10000)*636619772/10000% +(#3-#2*\CALX_pten{9-#4})*636619772/\CALX_pten{13-#4})/100000.% #3.#4.% }% \def\CALX_rsj #1.#2.#3.% {% \expandafter\CALX_rsm\the\numexpr(#2-((2*#2-\CALX_pten{13-#3})% /(2*\CALX_pten{13-#3}))*\CALX_pten{13-#3})*\CALX_pten{#3-5}% \expandafter.\the\numexpr(2*#1-10000)/20000\expandafter.% \the\numexpr#1-4*((2*#1-3)/8).#1.% }% \def\CALX_rsm #1.% {\expandafter\CALX_rwk\the\numexpr(2*#1-10000)/20000.#1.}% \def\CALX_rwk #1.#2.#3.#4.#5.% {% \expandafter\CALX_rh\the\numexpr1200000000+#1-(#5-#3*10000)-#3*5707% \expandafter\CALX_rp\the\numexpr1200000000+#2-#1*10000% -(#5-#3*10000)*5707-#3*9632% \expandafter\CALX_rp\the\numexpr1200000000-(#5-#3*10000)*9632-#3*6794% \expandafter\CALX_rp\the\numexpr1200000000-(#5-#3*10000)*6794-#3*8966% \expandafter\CALX_rp\the\numexpr1200000000-(#5-#3*10000)*8966-#3*1923% \expandafter\CALX_rp\the\numexpr1200000000-(#5-#3*10000)*1923-#3*1322% \expandafter\CALX_rp\the\numexpr1200000000-(#5-#3*10000)*1322\relax!% ;3.#4.% }% \def\CALX_rsl #1.#2.% {% \expandafter\CALX_rxa\the\numexpr8*((\CALX_trigdigits+#1+8*#2+5)/8)% \expandafter.\the\numexpr#1+8*#2\expandafter.% \the\numexpr(2*#1+7)/16.#2.% }% \def\CALX_rxa #1.#2.#3.#4.#5\xint:% {% \expandafter\CALX_rxb\romannumeral0\CALX_nshrr{#2+3-8*#4}% {\romannumeral0\CALX_nmul{N+#3.#5}% {\romannumeral0\CALX_nshrr{127-#2}{\CALX_rT}}}% \xint:#1.#3.#4.#5\xint:% }% \def\CALX_rxb N+#1.#2!#3\xint:#4.#5.#6.#7\xint:% {% \expandafter\CALX_red_z\the\numexpr#2-4*((2*#2-3)/8)\expandafter.% \romannumeral0\CALX_fnround{\CALX_trigdigits+4}% {\CALX_ffromraw{\expanded{\romannumeral0\CALX_ntoraw {\romannumeral0\CALX_nsub {\romannumeral0\CALX_nshl{#4+8*#6}{N+#5.#7}}% {\romannumeral0\CALX_nmul{N+#1.#2!#3}% {\romannumeral0\CALX_nshrr{129-#4}{\CALX_rH}}}}% [-#4]}}}% }% % \end{macrocode} %\begin{lverb} % Degree reduction \CALX_red_a (\CALX_sc_fo, route of xinttrig), Y = |x| % in degrees: T = floor(Y 10^L), L = 8 ceil((P+5)/8) (xinttrig: P+5 % decimals); I = % floor(T/10^L), m = I mod 360 (10^8 = 280 mod 360 and 280^2 = 280 mod % 360: m = (b_0 + 280 sum_{j>0} b_j) mod 360 on the blocks b_j of I); % q = floor((m+45)/90) = round((2m+1)/180) in 0..4; r_fix = T - (I - m + % 90q) 10^L, |r_fix| <= 45 10^L; r = round_{P+4}(r_fix 10^-L Dg), Dg = % pi/180 rounded to P+4 digits; |r| <= 0.786 (u <= 0.62). % % Absolute error of r (radians): < 10^-(P+5) + 10^-(P+4) (Dg, rounding % of r). % % Radians (\CALX_sin_s, \CALX_cos_s, q from \CALX_red or \CALX_rslow): % quadrant q mod 4: sin = S, C, -S, -C (times sign of X), cos = C, -S, % -C, S, with S, C the series kernels at r (K = max(2, ceil((P+4)/8)), % final rounding to P). %\end{lverb} % \begin{macrocode} \def\CALX_trigL{(8*((\CALX_trigdigits+8)/8))}% \def\CALX_sin_r #1#2.#3.#4\xint:% {% \ifnum\CALX_trigdigits<\xint_c_ix \CALX_rpq s#1\fi \ifnum\numexpr#2+8*#3>\xint_c_iv \CALX_rj\fi \expandafter\CALX_sin_s\expandafter#1% \romannumeral0\CALX_red #2.#3.#4\xint:\xint:% }% \def\CALX_cos_r #1#2.#3.#4\xint:% {% \ifnum\CALX_trigdigits<\xint_c_ix \CALX_rpq c+\fi \ifnum\numexpr#2+8*#3>\xint_c_iv \CALX_rj\fi \expandafter\CALX_cos_s\romannumeral0\CALX_red #2.#3.#4\xint:\xint:% }% % \end{macrocode} %\begin{lverb} % P <= 8, 0.8 <= |x| < 10^4: reduction in \numexpr without natives % (\CALX_rq .., |x| = A 10^(E-9) exact, E <= 4), output % ..... (r = s A' 10^(E'-9), A' 9 digits): %( %: k = round(2|x|/pi) (c = 636619772), pi/2 = (H1 + H2 10^-9 + %: H3 10^-18) 10^-9, H1 = 1570796326, H2 = 794896619, H3 = 231321691, %: 10^9 r = R1 - R2 10^-9, R1 = A 10^E - k H1 - floor(k H2/10^9), %: R2 = (k H2 mod 10^9) + round(k H3/10^9) %) % (A 10^E - k H1 by halves of 10^5, k H2 by halves of 10^4 and 10^5: all % intermediate values < 2^31). |R1| >= 2: A' from R1 and R2 with the % digit count of |R1| (minus 1 if R1 > 0); |R1| <= 1: from R1 10^9 - R2 % (relative accuracy kept when r is small). Callers: \CALX_rpq (sin, % cos: \CALX_rps, \CALX_rpc, kernels \CALX_rks, \CALX_rkk) and % \CALX_sc_kd (tan, cot, sec, csc, sinc). %\end{lverb} % \begin{macrocode} \def\CALX_rpq #1#2\fi #3\romannumeral0\CALX_red #4.#5.#6\xint:\xint:% {% \fi \ifnum\numexpr#4+8*#5>\xint_c_iv \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {#3\romannumeral0\CALX_red #4.#5.#6\xint:\xint:}% {\expandafter\CALX_rpa\the\numexpr#4+8*#5\expandafter.% \the\numexpr(2*#4+7)/16\expandafter.% \the\numexpr#4+8-8*((2*#4+7)/16).#6\xint:#1#2}% }% \def\CALX_rpa #1.#2.#3.#4\xint:% {% \expandafter\CALX_rpb\romannumeral0\expandafter\CALX_rq \the\numexpr\CALX_rta#2.#3.#4\xint:.#1.% }% \def\CALX_rpb #1.#2#3.#4.#5.#6.#7#8% {\csname CALX_rp#7#1\endcsname#8#2#3.#4.}% \expandafter\def\csname CALX_rps0\endcsname#1#2{\CALX_rks#11*#21.}% \expandafter\def\csname CALX_rps1\endcsname#1#2{\CALX_rkk#11.}% \expandafter\def\csname CALX_rps2\endcsname#1#2{\CALX_rks-1*#11*#21.}% \expandafter\def\csname CALX_rps3\endcsname#1#2{\CALX_rkk-1*#11.}% \expandafter\def\csname CALX_rpc0\endcsname#1#2{\CALX_rkk1.}% \expandafter\def\csname CALX_rpc1\endcsname#1#2{\CALX_rks-1*#21.}% \expandafter\def\csname CALX_rpc2\endcsname#1#2{\CALX_rkk-1.}% \expandafter\def\csname CALX_rpc3\endcsname#1#2{\CALX_rks#21.}% \def\CALX_rks #1.#2.#3.% {% \ifnum#3<-\xint_c_iv \xint_dothis\CALX_rks_tiny\fi \xint_orthat\CALX_rks_regular #1.#2.#3.% }% \def\CALX_rks_tiny #1.#2.#3.% {\expandafter\CALX_dgo\the\numexpr#1*#2\expandafter.\the\numexpr#3-9.}% \def\CALX_rks_regular #1.#2.#3.% {\expandafter\CALX_rksa\the\numexpr\CALX_qkz#2.#3..#1.#2.#3.}% \def\CALX_rksa #1.#2.#3.#4.% {% \expandafter\CALX_dgo \the\numexpr#2*#3*(\CALX_sinaux#1.)/1000000000.#4-9.% }% \def\CALX_rkk #1.#2.#3.% {% \expandafter\CALX_dgo\the\numexpr#1*(% \expandafter\CALX_cosaux\the\numexpr\CALX_qkz#2.#3..).-9.% }% \def\CALX_rq #1.#2.% {% \expandafter\CALX_rqa \the\numexpr(#1*636619772/1000000000)/\CALX_pten{9-#2}.#1.#2.% }% \def\CALX_rqa #1.#2.#3.% {% \expandafter\CALX_rqb\the\numexpr(2*#2-\CALX_pten{5-#3})% /(2*\CALX_pten{5-#3}).#1.#2.#3.% }% \def\CALX_rqb #1.#2.#3.#4.% {% \expandafter\CALX_rqc\the\numexpr(#1-#2*15707)*100000% +(#3-#1*\CALX_pten{5-#4})*\CALX_pten{#4}-#2*96326.#2.#3.#4.% }% \def\CALX_rqc #1.#2.% {\expandafter\CALX_rqd\the\numexpr(2*#2*7948-10000)/20000.#1.#2.}% \def\CALX_rqd #1.#2.#3.% {% \expandafter\CALX_rqe\the\numexpr(#3*7948-#1*10000)*100000+#3*96619.% #1.#2.#3.% }% \def\CALX_rqe #1.#2.#3.#4.% {% \expandafter\CALX_rqf\the\numexpr#3-#2-\ifnum#1<1000000000 0\else1\fi \expandafter.\the\numexpr#1-\ifnum#1<1000000000 0\else1000000000\fi +#4*231321691/1000000000.#4.% }% \def\CALX_rqf #1.#2.#3.% {% \expandafter\CALX_rqg\the\numexpr#3-4*((2*#3-3)/8)\expandafter.% \romannumeral0\ifnum\ifnum#1<\xint_c_ -\fi#1<\xint_c_ii \expandafter\CALX_rqs\else\expandafter\CALX_rql\fi #1.#2.% }% \def\CALX_rqg #1.#2.#3.{ #1.#2.#3.}% \def\CALX_rql #1.#2.% {% \expandafter\CALX_rqm\the\numexpr\ifnum#1>\xint_c_ #1-1\else-#1\fi .#1.#2.% }% \def\CALX_rqm #1.% {\expandafter\CALX_rqn\the\numexpr\CALX_nd_c #19987654321\xint:.}% \def\CALX_rqn #1.#2.#3.% {% \ifnum#2>\xint_c_ \expandafter\CALX_rqp\else\expandafter\CALX_rqo\fi #1.#2.#3.% }% \def\CALX_rqp #1.#2.#3.% {% \expandafter\CALX_rqw\the\numexpr#2*\CALX_pten{9-#1}-#3/\CALX_pten{#1}% \expandafter.\the\numexpr#1-9.+% }% \def\CALX_rqo #1.#2.#3.% {% \expandafter\CALX_rqw\the\numexpr-#2*\CALX_pten{9-#1}+#3/\CALX_pten{#1}% \expandafter.\the\numexpr#1-9.-% }% \def\CALX_rqw #1.#2.#3{ #3#1.#2.}% \def\CALX_rqs #1.#2.% {\expandafter\CALX_rqt\the\numexpr#1*1000000000-#2.}% \def\CALX_rqt #1#2.% {% \if-#1\expandafter\CALX_rqu\expandafter-\else \expandafter\CALX_rqu\expandafter+\expandafter#1\fi #2.% }% \def\CALX_rqu #1#2.% {% \expandafter\CALX_rqv\the\numexpr \CALX_nd_c #2{10}987654321\xint:.#1#2.% }% \def\CALX_rqv #1.#2#3.% {% \expandafter\CALX_rqw\the\numexpr\ifnum#1=10 #3/10\else #3*\CALX_pten{9-#1}\fi\expandafter.\the\numexpr#1-18.#2% }% \def\CALX_sin_s #1#2.#3\xint:% {% \ifcase#2 \expandafter\CALX_fin_p\expandafter s% \or \expandafter\CALX_fin_p\expandafter c% \or \expandafter\CALX_fin_n\expandafter s% \else \expandafter\CALX_fin_n\expandafter c% \fi #1{#3}% }% \def\CALX_cos_s #1.#2\xint:% {% \ifcase#1 \expandafter\CALX_fin_p\expandafter c% \or \expandafter\CALX_fin_n\expandafter s% \or \expandafter\CALX_fin_n\expandafter c% \else \expandafter\CALX_fin_p\expandafter s% \fi +{#2}% }% \def\CALX_fin_p #1#2% {\if-#2\expandafter\CALX_fin_neg\else\expandafter\CALX_ser\fi{#1}}% \def\CALX_fin_n #1#2% {\if-#2\expandafter\CALX_ser\else\expandafter\CALX_fin_neg\fi{#1}}% \def\CALX_fin_neg #1#2% {\expandafter\CALX_fopp_a\romannumeral0\CALX_ser{#1}{#2}\xint:}% \def\CALX_ser #1#2{\CALX_ser_a #1#2\xint:}% \def\CALX_ser_a #1F#2\xint:% {% \if s#1\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expandafter\CALX_sin_h}{\expandafter\CALX_cos_h}% \the\numexpr\ifnum\CALX_trigdigits<\xint_c_ix 2\else (\CALX_trigdigits+7)/8\fi.#2\xint:% }% \def\CALX_red_a F+#1.#2.#3\xint:% {% \expandafter\CALX_red_b\romannumeral0\CALX_nshr {\numexpr-8*#2-\CALX_trigL}{\romannumeral0\CALX_nshl {\numexpr8*#2+\CALX_trigL}{\expanded{N+\the\numexpr(2*#1+7)/16.#3}}}% \xint:% }% \def\CALX_red_b #1\xint:% {% \expandafter\CALX_red_c \romannumeral0\CALX_nshr{\CALX_trigL}{#1}\xint:#1\xint:% }% \def\CALX_red_c #1\xint:#2\xint:% {% \expandafter\CALX_red_d\the\numexpr\CALX_mmod #1\xint:.#1\xint:#2\xint:% }% \def\CALX_red_d #1.% {\expandafter\CALX_red_e\the\numexpr(2*#1+1)/180.#1.}% \def\CALX_red_e #1.#2.#3\xint:#4\xint:% {% \expandafter\CALX_red_f\romannumeral0\CALX_nsub{#4}% {\romannumeral0\CALX_nshl{\CALX_trigL}% {\romannumeral0\CALX_nsub{#3}% {\expanded{\CALX_nsmall{\numexpr#2-90*#1}}}}}% \xint:#1.% }% \def\CALX_red_f #1\xint:#2.% {% \expandafter\CALX_red_g\romannumeral`&&@% \csname CALX_pdg\the\numexpr\CALX_trigdigits\endcsname\xint:#1\xint:#2.% }% \def\CALX_red_g F+#1.#2.#3\xint:#4\xint:#5.% {% \expandafter\CALX_red_z\the\numexpr\ifnum#5=4 0\else#5\fi \expandafter.\romannumeral0\CALX_fnround{\CALX_trigdigits+4}% {\CALX_ffromraw{\expanded{\romannumeral0\CALX_ntoraw {\romannumeral0\CALX_nmul{#4}% {\expanded{N+\the\numexpr(2*#1+7)/16.#3}}}% [\the\numexpr8*#2-\CALX_trigL]}}}% }% \def\CALX_red_z #1.{ #1.}% % \end{macrocode} %\begin{lverb} % \CALX_mmod N.\xint: (inside \numexpr): I mod 360. %\end{lverb} % \begin{macrocode} \def\CALX_mmod N#1.1#2!#3\xint:% {% \expandafter\CALX_mmod_b\the\numexpr\CALX_msum 0.#31;!.#2.% }% \def\CALX_msum #1.1#2#3!% {% \if;#2\xint_dothis{#1}\fi \xint_orthat{\expandafter\CALX_msum\the\numexpr#1+#2#3.}% }% \def\CALX_mod #1{(#1-360*((2*(#1)-359)/720))}% \def\CALX_mmod_b #1.#2.{\CALX_mod{\CALX_mod{#2}+280*\CALX_mod{#1}}}% % \end{macrocode} %\begin{lverb} % \CALX_nsmall{c}: native integer c, |c| < 10^8 (use inside \expanded). %\end{lverb} % \begin{macrocode} \def\CALX_nsmall #1{\expandafter\CALX_nsmall_a\the\numexpr#1.}% \def\CALX_nsmall_a #1.% {% \ifnum#1=\xint_c_ N+0.\else N\ifnum#1<\xint_c_-\else+\fi1.% \the\numexpr100000000\ifnum#1<\xint_c_-(#1)\else+#1\fi!\fi }% % \end{macrocode} % Back to caller calx.sty. We restore letter catcodes. % Memo: the docstrip extraction will add |\endinput| anyhow. % \begin{macrocode} \catcode`F 11 \catcode`I 11 \catcode`N 11 % \end{macrocode} % \subsection{Trigonometric functions of \cshnolabel{xinteval}, constants} %\begin{lverb} % Trigonometric functions of \xinteval: % \calxRaw applies % \calxFp (at \XINTdigits, raw argument rounded on entry) and % converts the F result back to raw A[N]. One macro token per function, % as required by the \xintdeffunc hooks (\XINT:NE:f:one:from:one, two). % % Variables twoPi, threePiover2, Pi, Piover2, oneDegree, oneRadian (raw, % P digits, from 110-digit literals), redefined by \xintDigits (with or % without *) and \xintSetDigits. A future constant (e.g. for exp(1)) % goes into \CALX_trigvars too. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1#2% {% \expandafter\edef\csname calxRaw#2\endcsname##1% {\noexpand\romannumeral0\noexpand\CALX_ftoraw {\expandafter\noexpand\csname calxFp#2\endcsname{##1}}}% \expandafter\edef\csname XINT_expr_func_#1\endcsname##1##2##3% {% \noexpand\expandafter ##1\noexpand\expandafter ##2% \noexpand\expandafter{% \noexpand\romannumeral`&&@\noexpand\XINT:NEhook:f:one:from:one {\noexpand\romannumeral`&&@\expandafter\noexpand \csname calxRaw#2\endcsname##3}}% }% }% \XINT_tmpa{sin}{Sin}% \XINT_tmpa{cos}{Cos}% \XINT_tmpa{tan}{Tan}% \XINT_tmpa{cot}{Cot}% \XINT_tmpa{sec}{Sec}% \XINT_tmpa{csc}{Csc}% \XINT_tmpa{sinc}{Sinc}% \XINT_tmpa{sind}{Sind}% \XINT_tmpa{cosd}{Cosd}% \XINT_tmpa{tand}{Tand}% \XINT_tmpa{cotd}{Cotd}% \XINT_tmpa{secd}{Secd}% \XINT_tmpa{cscd}{Cscd}% \XINT_tmpa{asin}{Asin}% \XINT_tmpa{acos}{Acos}% \XINT_tmpa{asind}{Asind}% \XINT_tmpa{acosd}{Acosd}% \XINT_tmpa{atan}{Atan}% \XINT_tmpa{atand}{Atand}% \XINT_tmpa{asec}{Asec}% \XINT_tmpa{acsc}{Acsc}% \def\XINT_tmpa #1#2% {% \expandafter\edef\csname calxRaw#2\endcsname##1##2% {\noexpand\romannumeral0\noexpand\CALX_ftoraw {\expandafter\noexpand\csname calxFp#2\endcsname{##1}{##2}}}% \expandafter\edef\csname XINT_expr_func_#1\endcsname##1##2##3% {% \noexpand\expandafter ##1\noexpand\expandafter ##2% \noexpand\expandafter{% \noexpand\romannumeral`&&@\noexpand\XINT:NEhook:f:one:from:two {\noexpand\romannumeral`&&@\expandafter\noexpand \csname calxRaw#2\endcsname##3}}% }% }% \XINT_tmpa{Arg}{Arg}% \XINT_tmpa{Argd}{Argd}% \XINT_tmpa{pArg}{pArg}% \XINT_tmpa{pArgd}{pArgd}% \XINT_tmpa{atan2}{Atantwo}% \XINT_tmpa{atan2d}{Atantwod}% \let\XINT_tmpa\undefined \let\XINT_expr_func_tg\XINT_expr_func_tan \let\XINT_expr_func_cotg\XINT_expr_func_cot \let\XINT_expr_func_arcsin\XINT_expr_func_asin \let\XINT_expr_func_arccos\XINT_expr_func_acos \let\XINT_expr_func_arctg\XINT_expr_func_atan \let\XINT_expr_func_arcsec\XINT_expr_func_asec \let\XINT_expr_func_arccsc\XINT_expr_func_acsc \def\CALX_trigvars {% \xintdeffloatvar twoPi := 0+ 6.28318530717958647692528676655900576839433879875021164% 1949889184615632812572417997256069650684234135964296173;% \xintdeffloatvar threePiover2 := 0+ 4.71238898038468985769396507491925432629575409906265873% 14624168884617246094293134979420522380131756019732221298;% \xintdeffloatvar Pi := 0+ 3.14159265358979323846264338327950288419716939937510582% 09749445923078164062862089986280348253421170679821480865;% \xintdeffloatvar Piover2 := 0+ 1.57079632679489661923132169163975144209858469968755291% 04874722961539082031431044993140174126710585339910740433;% \xintdeffloatvar oneDegree := 0+ 0.01745329251994329576923690768488612713442871888541725% 4560971914401710091146034494436822415696345094822123044925;% \xintdeffloatvar oneRadian := 0+ 57.2957795130823208767981548141051703324054724665643215% 49160243861202847148321552632440968995851110944186223382;% }% \CALX_trigvars % \end{macrocode} % The |\endinput| added during docstrip extraction. % \StoreCodelineNo {calxtrig} % \cleardoublepage\let\calxtrignameUp\undefined %\gardesactifs %\let\relax %\let<*calxtrigdata>\gardesinactifs %------------------------------------------------------ %<*calxtrigdata>^^A------------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname calxtrigdatanameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Library \calxtrignameimp data tables} % \RaisedLabel{sec:calxtrigdataimp} % \addedcalx{2.0a1} % % calxtrigdata.tex: generated by gencalxdata.py (private repository). % Do not edit. Data of calxtrig.tex, input by it under the standard % catcode regime set by |\XINTsetcatcodes|. No explicit |\endinput| is % added at the file end, as it will get added by docstrip extraction. % %\begin{lverb} % This file is loaded from calxtrig.tex in a context having done % \XINTsetcatcodes, in particular the exclamation mark has catcode 12. % % The definition of \ver@calxtrigdata.tex control sequence done also under % existence of LaTeX \ProvidesFile is due to a miniltx feature (under % investigation). %\end{lverb} % \begin{macrocode} \ifdefined\ProvidesFile \ProvidesFile{calxtrigdata.tex}[2026/11/01 v2.0a1 calx trig data (JFB)]% \fi \expandafter\def\csname ver@calxtrigdata.tex\endcsname {2026/11/01 v2.0a1 calx trig data (JFB)}% \@namedef{CALX_cds0}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms0}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cds1}{6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!1666!}% \@namedef{CALX_cms1}{1666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!}% \@namedef{CALX_cds2}{3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!0083!}% \@namedef{CALX_cms2}{0083!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!% 3333!3333!3333!3333!3333!3333!3333!3333!3333!3333!}% \@namedef{CALX_cds3}{9841!4126!2698!9841!4126!2698!9841!4126!2698!9841!% 4126!2698!9841!4126!2698!9841!4126!2698!9841!4126!2698!9841!4126!2698!9841!% 4126!2698!9841!4126!2698!9841!4126!2698!9841!0001!}% \@namedef{CALX_cms3}{0001!9841!2698!4126!9841!2698!4126!9841!2698!4126!% 9841!2698!4126!9841!2698!4126!9841!2698!4126!9841!2698!4126!9841!2698!4126!% 9841!2698!4126!9841!2698!4126!9841!2698!4126!9841!}% \@namedef{CALX_cds4}{3192!2557!9065!9858!9223!5731!6525!5890!2398!3192!% 2557!9065!9858!9223!5731!6525!5890!2398!3192!2557!9065!9858!9223!5731!6525!% 5890!2398!3192!2557!9065!9858!9223!5731!0275!0000!}% \@namedef{CALX_cms4}{0000!0275!5731!9223!9858!9065!2557!3192!2398!5890!% 6525!5731!9223!9858!9065!2557!3192!2398!5890!6525!5731!9223!9858!9065!2557!% 3192!2398!5890!6525!5731!9223!9858!9065!2557!3192!}% \@namedef{CALX_cds5}{5210!7750!1718!8544!1083!5052!1877!4417!8385!5210!% 7750!1718!8544!1083!5052!1877!4417!8385!5210!7750!1718!8544!1083!5052!1877!% 4417!8385!5210!7750!1718!8544!1083!5052!0002!0000!}% \@namedef{CALX_cms5}{0000!0002!5052!1083!8544!1718!7750!5210!8385!4417!% 1877!5052!1083!8544!1718!7750!5210!8385!4417!1877!5052!1083!8544!1718!7750!% 5210!8385!4417!1877!5052!1083!8544!1718!7750!5210!}% \@namedef{CALX_cds6}{9392!1459!8216!3836!5904!2660!8281!0348!7105!2725!% 4793!1549!7170!9237!5993!1614!3682!0438!6059!8126!4882!0503!2571!9327!4947!% 7015!3771!9392!1459!8216!3836!5904!0160!0000!0000!}% \@namedef{CALX_cms6}{0000!0000!0160!5904!3836!8216!1459!9392!3771!7015!% 4947!9327!2571!0503!4882!8126!6059!0438!3682!1614!5993!9237!7170!1549!4793!% 2725!7105!0348!8281!2660!5904!3836!8216!1459!9392!}% \@namedef{CALX_cds7}{2854!9340!5562!9732!7170!8631!6610!5001!1700!3489!% 2832!4769!0367!0663!7838!7245!8493!0906!4124!6324!3975!1002!4155!7044!7880!% 1985!0113!4759!9816!3181!1637!7647!0000!0000!0000!}% \@namedef{CALX_cms7}{0000!0000!0000!7647!1637!3181!9816!4759!0113!1985!% 7880!7044!4155!1002!3975!6324!4124!0906!8493!7245!7838!0663!0367!4769!2832!% 3489!1700!5001!6610!8631!7170!9732!5562!9340!2854!}% \@namedef{CALX_cds8}{2216!0990!6638!5991!4989!0693!5061!7812!9454!5306!% 5929!7039!0258!5223!9918!4033!9222!3973!3103!2045!2735!3349!0162!0320!8301!% 9455!3198!2076!3455!7254!1145!0028!0000!0000!0000!}% \@namedef{CALX_cms8}{0000!0000!0000!0028!1145!7254!3455!2076!3198!9455!% 8301!0320!0162!3349!2735!2045!3103!3973!9222!4033!9918!5223!0258!7039!5929!% 5306!9454!7812!5061!0693!4989!5991!6638!0990!2216!}% \@namedef{CALX_cds9}{6497!0704!7417!7239!3201!8452!4166!8385!0904!3378!% 5017!0254!1375!1828!7368!7321!4266!4134!2611!9918!0738!4922!2807!6872!8123!% 9559!9716!2432!2466!0635!0822!0000!0000!0000!0000!}% \@namedef{CALX_cms9}{0000!0000!0000!0000!0822!0635!2466!2432!9716!9559!% 8123!6872!2807!4922!0738!9918!2611!4134!4266!7321!7368!1828!1375!0254!5017!% 3378!0904!8385!4166!8452!3201!7239!7417!0704!6497!}% \@namedef{CALX_cds10}{6777!8501!9993!2421!5055!3972!8700!6781!2811!6603!% 1297!1310!1146!5909!8136!3969!5105!2176!9006!4737!5287!3035!5054!4373!4757!% 2308!1261!6339!9410!9572!0001!0000!0000!0000!0000!}% \@namedef{CALX_cms10}{0000!0000!0000!0000!0001!9572!9410!6339!1261!2308!% 4757!4373!5054!3035!5287!4737!9006!2176!5105!3969!8136!5909!1146!1310!1297!% 6603!2811!6781!8700!3972!5055!2421!9993!8501!6777!}% \@namedef{CALX_cds11}{8214!0431!3162!8127!1274!5818!7151!8570!9313!2522!% 6445!3164!5081!7442!2960!6470!4713!2573!2646!7934!3231!2812!3152!9119!7716!% 8403!6306!0170!6817!0038!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms11}{0000!0000!0000!0000!0000!0038!6817!0170!6306!8403!% 7716!9119!3152!2812!3231!7934!2646!2573!4713!6470!2960!7442!5081!3164!6445!% 2522!9313!8570!7151!5818!1274!8127!3162!0431!8214!}% \@namedef{CALX_cds12}{0530!6034!8788!1246!0302!9193!9511!5230!8715!7420!% 9410!8021!4041!6012!1171!1894!2891!4104!8904!0529!6872!9204!5321!1948!3396!% 8447!2843!6950!0644!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms12}{0000!0000!0000!0000!0000!0000!0644!6950!2843!8447!% 3396!1948!5321!9204!6872!0529!8904!4104!2891!1894!1171!6012!4041!8021!9410!% 7420!8715!5230!9511!9193!0302!1246!8788!6034!0530!}% \@namedef{CALX_cds13}{0912!5735!4143!8178!2464!6010!1295!3070!1750!3999!% 9315!9284!0945!4923!3363!3179!9434!6871!7861!1339!4739!6836!2571!1484!5546!% 6379!6898!9183!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms13}{0000!0000!0000!0000!0000!0000!0000!9183!6898!6379!% 5546!1484!2571!6836!4739!1339!7861!6871!9434!3179!3363!4923!0945!9284!9315!% 3999!1750!3070!1295!6010!2464!8178!4143!5735!0912!}% \@namedef{CALX_cds14}{6885!6398!8502!9024!4411!1571!4164!1161!3438!8810!% 4050!0713!0974!0437!9844!0865!0147!4405!6992!3831!5769!8764!3155!7169!6447!% 6288!3099!0011!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms14}{0000!0000!0000!0000!0000!0000!0000!0011!3099!6288!% 6447!7169!3155!8764!5769!3831!6992!4405!0147!0865!9844!0437!0974!0713!4050!% 8810!3438!1161!4164!1571!4411!9024!8502!6398!6885!}% \@namedef{CALX_cds15}{7727!3576!8869!1740!8725!2732!8187!4280!8928!9686!% 7455!3914!4377!1871!9419!1043!4785!4972!2921!5692!7468!6299!7949!5351!0415!% 6125!0121!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms15}{0000!0000!0000!0000!0000!0000!0000!0000!0121!6125!% 0415!5351!7949!6299!7468!5692!2921!4972!4785!1043!9419!1871!4377!3914!7455!% 9686!8928!4280!8187!2732!8725!1740!8869!3576!7727!}% \@namedef{CALX_cds16}{7658!0353!5122!0200!6334!3894!3871!3337!0671!3636!% 1162!1907!5146!0863!7613!8040!1481!2211!3298!8149!5868!0280!7195!6207!6335!% 1151!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms16}{0000!0000!0000!0000!0000!0000!0000!0000!0000!1151!% 6335!6207!7195!0280!5868!8149!3298!2211!1481!8040!7613!0863!5146!1907!1162!% 3636!0671!3337!3871!3894!6334!0200!5122!0353!7658!}% \@namedef{CALX_cds17}{0703!9933!6726!7260!7013!7574!4263!5557!1479!5734!% 1992!2993!9441!2546!7149!6401!7488!9228!6380!8981!9920!1890!5863!5929!9677!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms17}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 9677!5929!5863!1890!9920!8981!6380!9228!7488!6401!7149!2546!9441!2993!1992!% 5734!1479!5557!4263!7574!7013!7260!6726!9933!0703!}% \@namedef{CALX_cds18}{2170!4767!6431!4697!9209!1739!5476!2879!2178!2917!% 8297!5084!5427!3132!8451!9043!2287!0307!2745!1538!0713!9153!6017!2654!0007!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms18}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0007!2654!6017!9153!0713!1538!2745!0307!2287!9043!8451!3132!5427!5084!8297!% 2917!2178!2879!5476!1739!9209!4697!6431!4767!2170!}% \@namedef{CALX_cds19}{1141!2439!8135!0306!4102!9326!1467!7991!6917!1506!% 9857!9132!7857!0224!6949!9027!3975!1599!7694!4339!5135!9756!0246!0049!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms19}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0049!0246!9756!5135!4339!7694!1599!3975!9027!6949!0224!7857!9132!9857!% 1506!6917!7991!1467!9326!4102!0306!8135!2439!1141!}% \@namedef{CALX_cds20}{3897!3995!0407!0866!0039!8463!2872!0718!1870!1080!% 2762!4987!6736!0908!2120!4487!2191!7891!4510!4240!8271!9310!0298!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms20}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0298!9310!8271!4240!4510!7891!2191!4487!2120!0908!6736!4987!2762!% 1080!1870!0718!2872!8463!0039!0866!0407!3995!3897!}% \@namedef{CALX_cds21}{8678!7338!5747!0238!1866!1721!2327!8483!9823!1251!% 1956!5739!5950!4939!7138!5633!9829!1886!2195!6774!2108!1655!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms21}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!1655!2108!6774!2195!1886!9829!5633!7138!4939!5950!5739!1956!% 1251!9823!8483!2327!1721!1866!0238!5747!7338!8678!}% \@namedef{CALX_cds22}{6761!6200!8174!3969!4046!1854!8602!4261!9151!4828!% 5450!1467!1917!7972!5422!2472!9833!2803!4718!6508!8359!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms22}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!8359!6508!4718!2803!9833!2472!5422!7972!1917!1467!5450!% 4828!9151!4261!8602!1854!4046!3969!8174!6200!6761!}% \@namedef{CALX_cds23}{9568!1186!2839!2638!1898!7762!2302!5122!7062!2971!% 8684!4195!7105!6978!9197!8682!5938!3960!2851!8666!0003!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms23}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0003!8666!2851!3960!5938!8682!9197!6978!7105!4195!8684!% 2971!7062!5122!2302!7762!1898!2638!2839!1186!9568!}% \@namedef{CALX_cds24}{4638!3023!1489!8819!1437!8362!0893!8531!0253!4406!% 7499!4291!4773!8153!3515!7903!3165!4708!4397!0016!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms24}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0016!4397!4708!3165!7903!3515!8153!4773!4291!7499!% 4406!0253!8531!0893!8362!1437!8819!1489!3023!4638!}% \@namedef{CALX_cds25}{2052!0350!2428!9364!0831!3113!1102!0015!8455!5095!% 2124!3425!1778!0454!7268!4571!9640!4695!0064!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms25}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0064!4695!9640!4571!7268!0454!1778!3425!2124!% 5095!8455!0015!1102!3113!0831!9364!2428!0350!2052!}% \@namedef{CALX_cds26}{6582!9506!7968!0028!9554!0080!3930!3697!2031!3006!% 6216!6452!5000!7721!6065!1525!9245!0233!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms26}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0233!9245!1525!6065!7721!5000!6452!6216!% 3006!2031!3697!3930!0080!9554!0028!7968!9506!6582!}% \@namedef{CALX_cds27}{0628!5956!6460!8363!9531!5925!0361!4247!8741!9953!% 8358!3301!9466!1803!3049!6246!0787!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms27}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0787!6246!3049!1803!9466!3301!8358!% 9953!8741!4247!0361!5925!9531!8363!6460!5956!0628!}% \@namedef{CALX_cds28}{9586!9838!9835!4397!6334!3062!2127!4904!9053!8417!% 9441!3064!0789!0956!4957!2467!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms28}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!2467!4957!0956!0789!3064!9441!% 8417!9053!4904!2127!3062!6334!4397!9835!9838!9586!}% \@namedef{CALX_cds29}{3047!2618!2770!9475!0486!9168!7545!9951!3184!1624!% 0213!5936!6189!6829!7210!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms29}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!7210!6829!6189!5936!0213!% 1624!3184!9951!7545!9168!0486!9475!2770!2618!3047!}% \@namedef{CALX_cds30}{7044!6694!6052!3461!9967!1272!8338!1215!5039!1183!% 1683!6802!3195!9701!0001!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms30}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0001!9701!3195!6802!1683!% 1183!5039!1215!8338!1272!9967!3461!6052!6694!7044!}% \@namedef{CALX_cds31}{7492!2428!9584!3003!7949!4828!5442!9265!3070!0064!% 6493!6061!0438!0005!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms31}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0005!0438!6061!6493!% 0064!3070!9265!5442!4828!7949!3003!9584!2428!7492!}% \@namedef{CALX_cds32}{9684!3615!7413!5262!2761!0198!4196!1997!8039!3492!% 6494!1246!0012!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms32}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0012!1246!6494!% 3492!8039!1997!4196!0198!2761!5262!7413!3615!9684!}% \@namedef{CALX_cds33}{3233!8863!6577!3707!9851!7611!4765!5995!0354!6188!% 4189!0027!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms33}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0027!4189!% 6188!0354!5995!4765!7611!9851!3707!6577!8863!3233!}% \@namedef{CALX_cds34}{1737!7344!5071!4184!2864!1879!1627!6996!8516!4376!% 0058!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms34}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0058!% 4376!8516!6996!1627!1879!2864!4184!5071!7344!1737!}% \@namedef{CALX_cds35}{3891!1653!6025!3127!4123!0839!6793!5546!5808!0117!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms35}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0117!5808!5546!6793!0839!4123!3127!6025!1653!3891!}% \@namedef{CALX_cds36}{4850!8434!9557!6809!8674!7505!6808!7078!0223!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms36}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0223!7078!6808!7505!8674!6809!9557!8434!4850!}% \@namedef{CALX_cds37}{2134!1095!1189!8693!7307!3979!0772!0403!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms37}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0403!0772!3979!7307!8693!1189!1095!2134!}% \@namedef{CALX_cds38}{1762!3932!6994!8550!4052!7854!0688!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms38}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0688!7854!4052!8550!6994!3932!1762!}% \@namedef{CALX_cds39}{6923!9393!6563!6213!7952!1117!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms39}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!1117!7952!6213!6563!9393!6923!}% \@namedef{CALX_cds40}{7582!2351!8848!9926!1724!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cms40}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!1724!9926!8848!2351!7582!}% \@namedef{CALX_cdc0}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc0}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cdc1}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!5000!}% \@namedef{CALX_cmc1}{5000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cdc2}{6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!0416!}% \@namedef{CALX_cmc2}{0416!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!% 6666!6666!6666!6666!6666!6666!6666!6666!6666!6666!}% \@namedef{CALX_cdc3}{8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!% 8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!% 8888!8888!8888!8888!8888!8888!8888!8888!8888!0013!}% \@namedef{CALX_cmc3}{0013!8888!8888!8888!8888!8888!8888!8888!8888!8888!% 8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!% 8888!8888!8888!8888!8888!8888!8888!8888!8888!8888!}% \@namedef{CALX_cdc4}{8730!3015!1587!8730!3015!1587!8730!3015!1587!8730!% 3015!1587!8730!3015!1587!8730!3015!1587!8730!3015!1587!8730!3015!1587!8730!% 3015!1587!8730!3015!1587!8730!3015!1587!2480!0000!}% \@namedef{CALX_cmc4}{0000!2480!1587!3015!8730!1587!3015!8730!1587!3015!% 8730!1587!3015!8730!1587!3015!8730!1587!3015!8730!1587!3015!8730!1587!3015!% 8730!1587!3015!8730!1587!3015!8730!1587!3015!8730!}% \@namedef{CALX_cdc5}{7319!5255!8906!3985!1922!5573!0652!8589!2239!7319!% 5255!8906!3985!1922!5573!0652!8589!2239!7319!5255!8906!3985!1922!5573!0652!% 8589!2239!7319!5255!8906!3985!1922!5573!0027!0000!}% \@namedef{CALX_cmc5}{0000!0027!5573!1922!3985!8906!5255!7319!2239!8589!% 0652!5573!1922!3985!8906!5255!7319!2239!8589!0652!5573!1922!3985!8906!5255!% 7319!2239!8589!0652!5573!1922!3985!8906!5255!7319!}% \@namedef{CALX_cdc6}{2100!8979!6809!9878!6756!4587!7656!4534!2365!5434!% 2312!0143!3212!0090!7921!0989!7868!5698!8767!5645!3476!6545!3423!1254!4323!% 1201!9032!2100!8979!6809!9878!6756!2087!0000!0000!}% \@namedef{CALX_cmc6}{0000!0000!2087!6756!9878!6809!8979!2100!9032!1201!% 4323!1254!3423!6545!3476!5645!8767!5698!7868!0989!7921!0090!3212!0143!2312!% 5434!2365!4534!7656!4587!6756!9878!6809!8979!2100!}% \@namedef{CALX_cdc7}{2813!0104!3444!5988!7564!9475!9162!5024!5507!2337!% 2485!1539!5512!9945!7570!8686!7405!3602!1861!4866!9634!5035!2326!5666!8210!% 9786!1697!1385!7247!7729!4559!4707!0011!0000!0000!}% \@namedef{CALX_cmc7}{0000!0000!0011!4707!4559!7729!7247!1385!1697!9786!% 8210!5666!2326!5035!9634!4866!1861!3602!7405!8686!7570!9945!5512!1539!2485!% 2337!5507!5024!9162!9475!7564!5988!3444!0104!2813!}% \@namedef{CALX_cdc8}{7678!6833!2847!1858!4823!1789!6038!2812!0731!0218!% 0802!9673!4397!8791!8614!8577!6780!7556!2757!4770!6498!6937!2759!5440!1117!% 0749!4382!5297!8738!3323!9477!0477!0000!0000!0000!}% \@namedef{CALX_cmc8}{0000!0000!0000!0477!9477!3323!8738!5297!4382!0749!% 1117!5440!2759!6937!6498!4770!2757!7556!6780!8577!8614!8791!4397!9673!0802!% 0218!0731!2812!6038!1789!4823!1858!2847!6833!7678!}% \@namedef{CALX_cdc9}{3456!3388!0924!7555!0832!0594!9170!9322!7191!4183!% 5329!4835!6125!4734!9995!9112!1067!8554!9616!8446!4040!3519!3342!0573!4350!% 1636!4622!6226!6858!2069!5619!0001!0000!0000!0000!}% \@namedef{CALX_cmc9}{0000!0000!0000!0001!5619!2069!6858!6226!4622!1636!% 4350!0573!3342!3519!4040!8446!9616!8554!1067!9112!9995!4734!6125!4835!5329!% 4183!7191!9322!9170!0594!0832!7555!0924!3388!3456!}% \@namedef{CALX_cdc10}{2324!8535!9870!0861!6160!3422!2708!2419!9045!8668!% 7250!7512!4068!4091!0868!3366!7213!5706!9130!9495!1036!3746!6140!1843!9906!% 8477!6485!3121!7623!1031!0041!0000!0000!0000!0000!}% \@namedef{CALX_cmc10}{0000!0000!0000!0000!0041!1031!7623!3121!6485!8477!% 9906!1843!6140!3746!1036!9495!9130!5706!7213!3366!0868!4091!4068!7512!7250!% 8668!9045!2419!2708!3422!6160!0861!9870!8535!2324!}% \@namedef{CALX_cdc11}{8944!9931!2726!6928!9320!3816!4486!7126!4218!8027!% 8240!2786!6870!1177!8097!8816!8413!9189!0863!2488!4331!4683!2502!9744!7488!% 3286!5057!3924!6791!0889!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc11}{0000!0000!0000!0000!0000!0889!6791!3924!5057!3286!% 7488!9744!2502!4683!4331!2488!0863!9189!8413!8816!8097!1177!6870!2786!8240!% 8027!4218!7126!4486!3816!9320!6928!2726!9931!8944!}% \@namedef{CALX_cdc12}{3258!0851!9715!1171!7553!9825!7797!0773!7888!5521!% 5268!0548!1045!0310!9290!7352!2279!2607!2610!3247!1801!0117!3048!8713!4904!% 1183!1096!3757!6117!0001!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc12}{0000!0000!0000!0000!0000!0001!6117!3757!1096!1183!% 4904!8713!3048!0117!1801!3247!2610!2607!2279!7352!9290!0310!1045!0548!5268!% 5521!7888!0773!7797!9825!7553!1171!9715!0851!3258!}% \@namedef{CALX_cdc13}{4635!4847!1876!0817!6550!2276!4981!2893!7258!7977!% 1515!0693!5540!2923!0814!5842!4726!5542!2265!6174!7956!4584!9435!0074!9746!% 2247!6263!7959!0024!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc13}{0000!0000!0000!0000!0000!0000!0024!7959!6263!2247!% 9746!0074!9435!4584!7956!6174!2265!5542!4726!5842!0814!2923!5540!0693!1515!% 7977!7258!2893!4981!2276!6550!0817!1876!4847!4635!}% \@namedef{CALX_cdc14}{9675!5561!6576!1720!7945!5571!0760!3681!9705!5499!% 7475!0688!8248!2675!5477!5113!4265!7745!2780!1119!7312!4172!1520!7910!6983!% 2370!9889!0327!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc14}{0000!0000!0000!0000!0000!0000!0000!0327!9889!2370!% 6983!7910!1520!4172!7312!1119!2780!7745!4265!5113!5477!2675!8248!0688!7475!% 5499!9705!3681!0760!5571!7945!1720!6576!5561!9675!}% \@namedef{CALX_cdc15}{9562!0879!4950!3967!0480!4719!3805!2705!6781!0293!% 1135!1357!5699!8014!1994!2362!8338!4146!0566!6461!1525!5292!6438!5905!2881!% 9876!3769!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc15}{0000!0000!0000!0000!0000!0000!0000!0000!3769!9876!% 2881!5905!6438!5292!1525!6461!0566!4146!8338!2362!1994!8014!5699!1357!1135!% 0293!6781!2705!3805!4719!0480!3967!4950!0879!9562!}% \@namedef{CALX_cdc16}{2741!1674!9027!6616!9022!8522!7755!0133!2154!9990!% 8357!2934!9824!8495!1231!5345!8899!2967!8841!8927!3670!9259!7435!4854!9075!% 8003!0003!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc16}{0000!0000!0000!0000!0000!0000!0000!0000!0003!8003!% 9075!4854!7435!9259!3670!8927!8841!2967!8899!5345!1231!8495!9824!2934!8357!% 9990!2154!0133!7755!8522!9022!6616!9027!1674!2741!}% \@namedef{CALX_cdc17}{4637!7657!5444!4123!5480!5114!9231!4509!1784!0695!% 9740!4761!0445!9143!0223!4060!2102!3006!3332!4357!7231!6184!5211!7535!8715!% 0033!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc17}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0033!% 8715!7535!5211!6184!7231!4357!3332!3006!2102!4060!0223!9143!0445!4761!9740!% 0695!1784!4509!9231!5114!5480!4123!5444!7657!4637!}% \@namedef{CALX_cdc18}{0297!6387!7964!3812!0750!4377!2618!6543!0596!7937!% 6999!8138!0817!5904!2698!4622!4652!1367!1566!6916!6386!8663!2662!8220!0268!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc18}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0268!8220!2662!8663!6386!6916!1566!1367!4652!4622!2698!5904!0817!8138!6999!% 7937!0596!6543!2618!4377!0750!3812!7964!6387!0297!}% \@namedef{CALX_cdc19}{4530!5125!7274!1965!9979!3729!7249!1654!9794!8760!% 4428!6186!6458!8766!1011!2080!5060!2376!0072!9251!0281!0504!9632!1911!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc19}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!1911!9632!0504!0281!9251!0072!2376!5060!2080!1011!8766!6458!6186!4428!% 8760!9794!1654!7249!3729!9979!1965!7274!5125!4530!}% \@namedef{CALX_cdc20}{9778!3810!6703!5507!1602!6983!7786!9449!6672!4287!% 3246!4478!6196!7255!6923!3975!9849!3539!4942!3858!9128!1743!2256!0001!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc20}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0001!2256!1743!9128!3858!4942!3539!9849!3975!6923!7255!6196!4478!3246!% 4287!6672!9449!7786!6983!1602!5507!6703!3810!9778!}% \@namedef{CALX_cdc21}{3188!5571!7152!0258!0239!4011!0068!4779!2425!3835!% 4113!6785!5874!2402!6955!2249!2671!1140!4393!1291!0673!1174!0007!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc21}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0007!1174!0673!1291!4393!1140!2671!2249!6955!2402!5874!6785!4113!% 3835!2425!4779!0068!4011!0239!0258!7152!5571!3188!}% \@namedef{CALX_cdc22}{4288!9030!7857!8641!2087!3448!7098!1783!1814!7301!% 5271!6039!6271!8748!4025!1264!2496!6179!2322!2881!6184!0037!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc22}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0037!6184!2881!2322!6179!2496!1264!4025!8748!6271!6039!5271!% 7301!1814!1783!7098!3448!2087!8641!7857!9030!4288!}% \@namedef{CALX_cdc23}{9712!5786!3438!3999!9218!4822!8230!0744!1938!9670!% 8161!7205!3954!7999!2291!8097!9126!6147!4015!7315!0181!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc23}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0181!7315!4015!6147!9126!8097!2291!7999!3954!7205!8161!% 9670!1938!0744!8230!4822!9218!3999!3438!5786!9712!}% \@namedef{CALX_cdc24}{7282!8149!2975!2138!0456!9745!3797!8023!2438!5895!% 7472!0295!3898!9520!2274!7264!5123!0707!5476!0805!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc24}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0805!5476!0707!5123!7264!2274!9520!3898!0295!7472!% 5895!2438!8023!3797!9745!0456!2138!2975!8149!7282!}% \@namedef{CALX_cdc25}{4692!7860!3829!7576!2428!8767!6217!0770!1205!9888!% 8349!4685!0695!3163!0670!3158!1663!9494!3287!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc25}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!3287!9494!1663!3158!0670!3163!0695!4685!8349!% 9888!1205!0770!6217!8767!2428!7576!3829!7860!4692!}% \@namedef{CALX_cdc26}{8885!3852!2354!1526!6362!4290!8290!5961!7662!9328!% 9463!1988!5034!9239!1485!0857!9993!2397!0001!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc26}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0001!2397!9993!0857!1485!9239!5034!1988!9463!% 9328!7662!5961!8290!4290!6362!1526!2354!3852!8885!}% \@namedef{CALX_cdc27}{4566!7583!5332!0000!4251!5927!9887!3586!0778!7463!% 9744!1600!0648!9217!7704!3546!3319!0004!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc27}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0004!3319!3546!7704!9217!0648!1600!9744!% 7463!0778!3586!9887!5927!4251!0000!5332!7583!4566!}% \@namedef{CALX_cdc28}{6439!0820!0651!0685!1063!4570!1256!9540!6048!9820!% 8184!4701!4990!4496!2554!0647!0014!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc28}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0014!0647!2554!4496!4990!4701!8184!% 9820!6048!9540!1256!4570!1063!0685!0651!0820!6439!}% \@namedef{CALX_cdc29}{9820!4479!3445!9041!8729!0914!5209!7153!7914!5834!% 2576!0225!5186!2947!5430!0042!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc29}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0042!5430!2947!5186!0225!2576!% 5834!7914!7153!5209!0914!8729!9041!3445!4479!9820!}% \@namedef{CALX_cdc30}{9717!8376!9212!1157!8008!7652!8625!4165!7386!2193!% 2670!4932!4936!1780!0120!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc30}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0120!1780!4936!4932!2670!% 2193!7386!4165!8625!7652!8008!1157!9212!8376!9717!}% \@namedef{CALX_cdc31}{2049!3011!3807!9249!0805!4214!2876!3729!3468!4051!% 9059!1883!7632!0317!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc31}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0317!7632!1883!9059!% 4051!3468!3729!2876!4214!0805!9249!3807!3011!2049!}% \@namedef{CALX_cdc32}{9492!5037!1868!2078!9499!2887!2741!9832!2547!7032!% 2132!1032!0788!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc32}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0788!1032!2132!% 7032!2547!9832!2741!2887!9499!2078!1868!5037!9492!}% \@namedef{CALX_cdc33}{6661!3842!0718!8413!0041!0003!9306!1696!3758!4598!% 0704!1837!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc33}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!1837!0704!% 4598!3758!1696!9306!0003!0041!8413!0718!3842!6661!}% \@namedef{CALX_cdc34}{9900!6747!9949!8730!7644!9670!2275!2735!7652!2002!% 4032!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc34}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!4032!% 2002!7652!2735!2275!9670!7644!8730!9949!6747!9900!}% \@namedef{CALX_cdc35}{6310!7390!7786!2059!2755!9598!2308!3814!2407!8348!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc35}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 8348!2407!3814!2308!9598!2755!2059!7786!7390!6310!}% \@namedef{CALX_cdc36}{4081!5717!7722!7126!3251!7928!7038!6743!6330!0001!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc36}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0001!6330!6743!7038!7928!3251!7126!7722!5717!4081!}% \@namedef{CALX_cdc37}{0065!2141!9183!1983!8090!8479!7929!0230!0003!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc37}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0003!0230!7929!8479!8090!1983!9183!2141!0065!}% \@namedef{CALX_cdc38}{5685!2777!8568!8403!2069!4789!3036!0005!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc38}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0005!3036!4789!2069!8403!8568!2777!5685!}% \@namedef{CALX_cdc39}{6945!2101!8551!0878!8257!8305!0008!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc39}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0008!8305!8257!0878!8551!2101!6945!}% \@namedef{CALX_cdc40}{4211!0492!6707!4077!9724!0013!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!}% \@namedef{CALX_cmc40}{0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!0000!% 0000!0000!0000!0000!0013!9724!4077!6707!0492!4211!}% \def\CALX_tdata{% \CALX_tdef s{33}{10}{14}{3}{10}{3.3.3.4.4.5.5.6.6.6.6.7.7.7.7.8.8.9.9.9.9.10.% 10.10.10.10.10.10.}% \CALX_tdef s{34}{10}{15}{2}{10}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.7.7.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_tlet s{35}{34}% \CALX_tlet s{36}{34}% \CALX_tdef s{37}{11}{16}{2}{11}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.8.8.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_tlet s{38}{37}% \CALX_tlet s{39}{37}% \CALX_tlet s{40}{37}% \CALX_tdef s{41}{12}{17}{2}{12}{2.3.3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.9.9.10.% 10.11.11.11.11.12.12.12.12.12.12.12.}% \CALX_tlet s{42}{41}% \CALX_tlet s{43}{41}% \CALX_tdef s{44}{12}{18}{2}{12}{2.2.2.3.3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.9.% 9.10.10.11.11.11.11.12.12.12.12.12.12.12.}% \CALX_tdef s{45}{13}{18}{3}{13}{3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.10.% 10.10.11.11.12.12.12.12.13.13.13.13.13.13.13.}% \CALX_tlet s{46}{45}% \CALX_tdef s{47}{13}{19}{2}{13}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.% 10.10.10.11.11.12.12.12.12.13.13.13.13.13.13.13.}% \CALX_tlet s{48}{47}% \CALX_tdef s{49}{14}{19}{3}{14}{3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.10.% 10.11.11.11.11.12.12.13.13.13.13.14.14.14.14.14.14.14.}% \CALX_tlet s{50}{49}% \CALX_tdef s{51}{14}{20}{2}{14}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.% 10.10.11.11.11.11.12.12.13.13.13.13.14.14.14.14.14.14.14.}% \CALX_tlet s{52}{51}% \CALX_tdef s{53}{15}{20}{3}{15}{3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.% 11.11.11.12.12.12.12.13.13.14.14.14.14.15.15.15.15.15.15.15.}% \CALX_tdef s{54}{15}{21}{2}{15}{2.3.3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.10.10.% 11.11.11.11.12.12.12.12.13.13.14.14.14.14.15.15.15.15.15.15.15.}% \CALX_tlet s{55}{54}% \CALX_tlet s{56}{54}% \CALX_tdef s{57}{16}{21}{3}{16}{3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.10.11.% 11.12.12.12.12.13.13.13.13.14.14.15.15.15.15.16.16.16.16.16.16.16.}% \CALX_tdef s{58}{16}{22}{2}{16}{2.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.10.% 11.11.12.12.12.12.13.13.13.13.14.14.15.15.15.15.16.16.16.16.16.16.16.}% \CALX_tlet s{59}{58}% \CALX_tlet s{60}{58}% \CALX_tdef s{61}{17}{23}{3}{17}{3.3.3.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.10.% 10.11.11.12.12.13.13.13.13.14.14.14.14.15.15.16.16.16.16.17.17.17.17.17.17.% 17.}% \CALX_tlet s{62}{61}% \CALX_tlet s{63}{61}% \CALX_tlet s{64}{61}% \CALX_tdef s{65}{18}{24}{3}{18}{3.4.4.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.% 11.11.11.12.12.13.13.14.14.14.14.15.15.15.15.16.16.17.17.17.17.18.18.18.18.% 18.18.18.}% \CALX_tlet s{66}{65}% \CALX_tlet s{67}{65}% \CALX_tdef s{68}{18}{25}{2}{18}{2.3.3.4.4.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.% 11.11.11.11.12.12.13.13.14.14.14.14.15.15.15.15.16.16.17.17.17.17.18.18.18.% 18.18.18.18.}% \CALX_tdef s{69}{19}{25}{3}{19}{3.4.4.5.5.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.% 11.12.12.12.12.13.13.14.14.15.15.15.15.16.16.16.16.17.17.18.18.18.18.19.19.% 19.19.19.19.19.}% \CALX_tlet s{70}{69}% \CALX_tlet s{71}{69}% \CALX_tdef s{72}{19}{26}{2}{19}{2.3.3.4.4.5.5.5.5.6.6.7.7.8.8.9.9.9.9.10.10.% 11.11.12.12.12.12.13.13.14.14.15.15.15.15.16.16.16.16.17.17.18.18.18.18.19.% 19.19.19.19.19.19.}% \CALX_tdef s{73}{20}{26}{3}{20}{3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.10.10.10.10.11.% 11.12.12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.17.17.18.18.19.19.19.19.% 20.20.20.20.20.20.20.}% \CALX_tlet s{74}{73}% \CALX_tlet s{75}{73}% \CALX_tdef s{76}{20}{27}{2}{20}{2.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.10.10.10.% 10.11.11.12.12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.17.17.18.18.19.19.% 19.19.20.20.20.20.20.20.20.}% \CALX_tdef s{77}{21}{27}{3}{21}{3.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.11.11.11.% 11.12.12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.18.18.19.19.20.20.% 20.20.21.21.21.21.21.21.21.}% \CALX_tlet s{78}{77}% \CALX_tdef s{79}{21}{28}{2}{21}{2.3.3.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.11.% 11.11.11.12.12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.18.18.19.19.% 20.20.20.20.21.21.21.21.21.21.21.}% \CALX_tlet s{80}{79}% \CALX_tdef s{81}{22}{28}{3}{22}{3.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.11.12.% 12.12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.19.19.20.20.% 21.21.21.21.22.22.22.22.22.22.22.}% \CALX_tlet s{82}{81}% \CALX_tdef s{83}{22}{29}{2}{22}{2.3.3.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.% 11.12.12.12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.19.19.% 20.20.21.21.21.21.22.22.22.22.22.22.22.}% \CALX_tlet s{84}{83}% \CALX_tdef s{85}{23}{29}{3}{23}{3.4.4.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.11.12.% 12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.18.18.19.19.19.19.20.20.20.20.% 21.21.22.22.22.22.23.23.23.23.23.23.23.}% \CALX_tlet s{86}{85}% \CALX_tdef s{87}{23}{30}{3}{23}{3.3.3.4.4.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.% 11.12.12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.18.18.19.19.19.19.20.20.% 20.20.21.21.22.22.22.22.23.23.23.23.23.23.23.}% \CALX_tlet s{88}{87}% \CALX_tdef s{89}{24}{30}{4}{24}{4.4.4.5.5.6.6.7.7.8.8.9.9.10.10.10.10.11.11.% 12.12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.19.19.20.20.20.20.21.% 21.21.21.22.22.23.23.23.23.24.24.24.24.24.24.24.}% \CALX_tlet s{90}{89}% \CALX_tdef s{91}{24}{31}{3}{24}{3.4.4.4.4.5.5.6.6.7.7.8.8.9.9.10.10.10.10.11.% 11.12.12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.19.19.20.20.20.20.% 21.21.21.21.22.22.23.23.23.23.24.24.24.24.24.24.24.}% \CALX_tlet s{92}{91}% \CALX_tdef s{93}{25}{31}{4}{25}{4.5.5.5.5.6.6.7.7.8.8.9.9.10.10.11.11.11.11.% 12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.20.20.21.21.21.% 21.22.22.22.22.23.23.24.24.24.24.25.25.25.25.25.25.25.}% \CALX_tdef s{94}{25}{32}{3}{25}{3.4.4.5.5.5.5.6.6.7.7.8.8.9.9.10.10.11.11.11.% 11.12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.20.20.21.21.% 21.21.22.22.22.22.23.23.24.24.24.24.25.25.25.25.25.25.25.}% \CALX_tlet s{95}{94}% \CALX_tlet s{96}{94}% \CALX_tdef s{97}{26}{32}{4}{26}{4.5.5.6.6.6.6.7.7.8.8.9.9.10.10.11.11.12.12.% 12.12.13.13.14.14.15.15.16.16.16.16.17.17.18.18.19.19.19.19.20.20.21.21.22.% 22.22.22.23.23.23.23.24.24.25.25.25.25.26.26.26.26.26.26.26.}% \CALX_tdef s{98}{26}{33}{3}{26}{3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.10.10.11.11.12.% 12.12.12.13.13.14.14.15.15.16.16.16.16.17.17.18.18.19.19.19.19.20.20.21.21.% 22.22.22.22.23.23.23.23.24.24.25.25.25.25.26.26.26.26.26.26.26.}% \CALX_tlet s{99}{98}% \CALX_tlet s{100}{98}% \CALX_tdef c{33}{10}{15}{2}{10}{2.3.3.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_tlet c{34}{33}% \CALX_tlet c{35}{33}% \CALX_tdef c{36}{10}{16}{2}{10}{2.2.2.3.3.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.9.% 9.9.9.10.10.10.10.10.10.10.}% \CALX_tdef c{37}{11}{16}{3}{11}{3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_tlet c{38}{37}% \CALX_tdef c{39}{11}{17}{2}{11}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.11.11.11.11.11.11.11.}% \CALX_tlet c{40}{39}% \CALX_tdef c{41}{12}{17}{3}{12}{3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.9.9.9.9.10.10.% 10.10.11.11.11.11.12.12.12.12.12.12.12.}% \CALX_tdef c{42}{12}{18}{2}{12}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.9.9.9.9.10.% 10.10.10.11.11.11.11.12.12.12.12.12.12.12.}% \CALX_tlet c{43}{42}% \CALX_tlet c{44}{42}% \CALX_tdef c{45}{13}{18}{3}{13}{3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.10.10.10.% 10.11.11.11.11.12.12.12.12.13.13.13.13.13.13.13.}% \CALX_tdef c{46}{13}{19}{2}{13}{2.3.3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.10.10.% 10.10.11.11.11.11.12.12.12.12.13.13.13.13.13.13.13.}% \CALX_tlet c{47}{46}% \CALX_tlet c{48}{46}% \CALX_tdef c{49}{14}{20}{3}{14}{3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.10.% 11.11.11.11.12.12.12.12.13.13.13.13.14.14.14.14.14.14.14.}% \CALX_tlet c{50}{49}% \CALX_tlet c{51}{49}% \CALX_tdef c{52}{14}{21}{2}{14}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.% 10.11.11.11.11.12.12.12.12.13.13.13.13.14.14.14.14.14.14.14.}% \CALX_tdef c{53}{15}{21}{3}{15}{3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.10.% 10.11.11.12.12.12.12.13.13.13.13.14.14.14.14.15.15.15.15.15.15.15.}% \CALX_tlet c{54}{53}% \CALX_tlet c{55}{53}% \CALX_tdef c{56}{15}{22}{2}{15}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.% 10.10.11.11.12.12.12.12.13.13.13.13.14.14.14.14.15.15.15.15.15.15.15.}% \CALX_tdef c{57}{16}{22}{3}{16}{3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.% 11.11.11.12.12.13.13.13.13.14.14.14.14.15.15.15.15.16.16.16.16.16.16.16.}% \CALX_tlet c{58}{57}% \CALX_tdef c{59}{16}{23}{2}{16}{2.3.3.4.4.5.5.5.5.6.6.7.7.8.8.8.8.9.9.10.10.% 11.11.11.11.12.12.13.13.13.13.14.14.14.14.15.15.15.15.16.16.16.16.16.16.16.}% \CALX_tlet c{60}{59}% \CALX_tdef c{61}{17}{23}{3}{17}{3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.10.11.% 11.12.12.12.12.13.13.14.14.14.14.15.15.15.15.16.16.16.16.17.17.17.17.17.17.% 17.}% \CALX_tlet c{62}{61}% \CALX_tdef c{63}{17}{24}{2}{17}{2.3.3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.9.9.10.10.% 11.11.12.12.12.12.13.13.14.14.14.14.15.15.15.15.16.16.16.16.17.17.17.17.17.% 17.17.}% \CALX_tlet c{64}{63}% \CALX_tdef c{65}{18}{24}{3}{18}{3.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.10.10.11.% 11.12.12.13.13.13.13.14.14.15.15.15.15.16.16.16.16.17.17.17.17.18.18.18.18.% 18.18.18.}% \CALX_tdef c{66}{18}{25}{2}{18}{2.3.3.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.10.% 10.11.11.12.12.13.13.13.13.14.14.15.15.15.15.16.16.16.16.17.17.17.17.18.18.% 18.18.18.18.18.}% \CALX_tlet c{67}{66}% \CALX_tlet c{68}{66}% \CALX_tdef c{69}{19}{25}{3}{19}{3.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.11.11.% 11.12.12.13.13.14.14.14.14.15.15.16.16.16.16.17.17.17.17.18.18.18.18.19.19.% 19.19.19.19.19.}% \CALX_tdef c{70}{19}{26}{3}{19}{3.3.3.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.% 11.11.11.12.12.13.13.14.14.14.14.15.15.16.16.16.16.17.17.17.17.18.18.18.18.% 19.19.19.19.19.19.19.}% \CALX_tlet c{71}{70}% \CALX_tlet c{72}{70}% \CALX_tdef c{73}{20}{26}{4}{20}{4.4.4.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.11.12.% 12.12.12.13.13.14.14.15.15.15.15.16.16.17.17.17.17.18.18.18.18.19.19.19.19.% 20.20.20.20.20.20.20.}% \CALX_tdef c{74}{20}{27}{3}{20}{3.4.4.4.4.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.% 11.12.12.12.12.13.13.14.14.15.15.15.15.16.16.17.17.17.17.18.18.18.18.19.19.% 19.19.20.20.20.20.20.20.20.}% \CALX_tlet c{75}{74}% \CALX_tlet c{76}{74}% \CALX_tdef c{77}{21}{28}{3}{21}{3.4.4.5.5.5.5.6.6.7.7.8.8.9.9.10.10.10.10.11.% 11.12.12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.18.18.18.18.19.19.19.19.% 20.20.20.20.21.21.21.21.21.21.21.}% \CALX_tlet c{78}{77}% \CALX_tlet c{79}{77}% \CALX_tlet c{80}{77}% \CALX_tdef c{81}{22}{29}{3}{22}{3.4.4.5.5.6.6.6.6.7.7.8.8.9.9.10.10.11.11.11.% 11.12.12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.19.19.19.19.20.20.% 20.20.21.21.21.21.22.22.22.22.22.22.22.}% \CALX_tlet c{82}{81}% \CALX_tlet c{83}{81}% \CALX_tlet c{84}{81}% \CALX_tdef c{85}{23}{30}{3}{23}{3.4.4.5.5.6.6.7.7.7.7.8.8.9.9.10.10.11.11.12.% 12.12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.20.20.20.20.% 21.21.21.21.22.22.22.22.23.23.23.23.23.23.23.}% \CALX_tlet c{86}{85}% \CALX_tlet c{87}{85}% \CALX_tlet c{88}{85}% \CALX_tdef c{89}{24}{31}{3}{24}{3.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.11.12.% 12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.18.18.19.19.19.19.20.20.21.21.% 21.21.22.22.22.22.23.23.23.23.24.24.24.24.24.24.24.}% \CALX_tlet c{90}{89}% \CALX_tlet c{91}{89}% \CALX_tdef c{92}{24}{32}{2}{24}{2.3.3.4.4.5.5.6.6.7.7.8.8.8.8.9.9.10.10.11.% 11.12.12.13.13.13.13.14.14.15.15.16.16.16.16.17.17.18.18.19.19.19.19.20.20.% 21.21.21.21.22.22.22.22.23.23.23.23.24.24.24.24.24.24.24.}% \CALX_tdef c{93}{25}{32}{3}{25}{3.4.4.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.11.12.% 12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.19.19.20.20.20.20.21.21.% 22.22.22.22.23.23.23.23.24.24.24.24.25.25.25.25.25.25.25.}% \CALX_tlet c{94}{93}% \CALX_tlet c{95}{93}% \CALX_tdef c{96}{25}{33}{2}{25}{2.3.3.4.4.5.5.6.6.7.7.8.8.9.9.9.9.10.10.11.% 11.12.12.13.13.14.14.14.14.15.15.16.16.17.17.17.17.18.18.19.19.20.20.20.20.% 21.21.22.22.22.22.23.23.23.23.24.24.24.24.25.25.25.25.25.25.25.}% \CALX_tdef c{97}{26}{33}{3}{26}{3.4.4.5.5.6.6.7.7.8.8.9.9.10.10.10.10.11.11.% 12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.20.20.21.21.21.% 21.22.22.23.23.23.23.24.24.24.24.25.25.25.25.26.26.26.26.26.26.26.}% \CALX_tlet c{98}{97}% \CALX_tlet c{99}{97}% \CALX_tdef c{100}{26}{34}{2}{26}{2.3.3.4.4.5.5.6.6.7.7.8.8.9.9.10.10.10.10.% 11.11.12.12.13.13.14.14.15.15.15.15.16.16.17.17.18.18.18.18.19.19.20.20.21.% 21.21.21.22.22.23.23.23.23.24.24.24.24.25.25.25.25.26.26.26.26.26.26.26.}% }% \def\CALX_fdata{% \CALX_fdef s{9}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{9_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{9_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef s{9_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef s{9_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel s{9}{6}{5.2440.4.670.3.105.2.5.}% \CALX_fdef s{10}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{10_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{10_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef s{10_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef s{10_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel s{10}{6}{5.2440.4.670.3.105.2.5.}% \CALX_fdef s{11}{4}{7}{1}{4}{1.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{11_6}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{11_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{11_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef s{11_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef s{11_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel s{11}{7}{6.3298.5.1163.4.278.3.35.2.1.}% \CALX_fdef s{12}{4}{7}{1}{4}{1.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{12_6}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{12_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef s{12_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef s{12_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef s{12_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel s{12}{7}{6.3298.5.1163.4.278.3.35.2.1.}% \CALX_fdef s{13}{5}{8}{2}{5}{2.2.2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{13_7}{5}{7}{2}{5}{2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{13_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{13_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{13_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef s{13_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel s{13}{8}{7.2979.6.1130.5.323.4.59.3.5.}% \CALX_fdef s{14}{5}{8}{2}{5}{2.2.2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{14_7}{5}{7}{2}{5}{2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{14_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{14_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{14_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef s{14_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel s{14}{8}{7.2979.6.1130.5.323.4.59.3.5.}% \CALX_fdef s{15}{5}{8}{2}{5}{2.2.2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{15_7}{5}{7}{2}{5}{2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{15_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{15_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{15_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef s{15_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel s{15}{8}{7.2979.6.1130.5.323.4.59.3.5.}% \CALX_fdef s{16}{5}{9}{1}{5}{1.2.2.2.2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{16_8}{5}{8}{2}{5}{2.2.2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{16_7}{5}{7}{2}{5}{2.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{16_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{16_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef s{16_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef s{16_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel s{16}{9}{8.4990.7.2387.6.890.5.245.4.42.3.3.}% \CALX_fdef s{17}{6}{9}{2}{6}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{17_8}{6}{8}{3}{6}{3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{17_7}{6}{7}{3}{6}{3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{17_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{17_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{17_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel s{17}{9}{8.3117.7.1299.6.436.5.106.4.15.}% \CALX_fdef s{18}{6}{9}{2}{6}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{18_8}{6}{8}{3}{6}{3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{18_7}{6}{7}{3}{6}{3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{18_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{18_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{18_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel s{18}{9}{8.3117.7.1299.6.436.5.106.4.15.}% \CALX_fdef s{19}{6}{10}{2}{6}{2.2.2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{19_9}{6}{9}{2}{6}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{19_8}{6}{8}{3}{6}{3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{19_7}{6}{7}{3}{6}{3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{19_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{19_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{19_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel s{19}{10}{9.4078.8.1953.7.776.6.243.5.53.4.6.}% \CALX_fdef s{20}{6}{10}{2}{6}{2.2.2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{20_9}{6}{9}{2}{6}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{20_8}{6}{8}{3}{6}{3.3.3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{20_7}{6}{7}{3}{6}{3.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{20_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{20_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef s{20_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel s{20}{10}{9.4078.8.1953.7.776.6.243.5.53.4.6.}% \CALX_fdef s{21}{7}{10}{3}{7}{3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{21_9}{7}{9}{3}{7}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{21_8}{7}{8}{4}{7}{4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{21_7}{7}{7}{4}{7}{4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{21_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{21_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{21_4}{7}{4}{6}{7}{6.7.7.7.7.7.7.7.}% \CALX_fsel s{21}{10}{9.3284.8.1483.7.563.6.167.5.34.4.4.}% \CALX_fdef s{22}{7}{11}{2}{7}{2.3.3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_10}{7}{10}{3}{7}{3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_9}{7}{9}{3}{7}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_8}{7}{8}{4}{7}{4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_7}{7}{7}{4}{7}{4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{22_4}{7}{4}{6}{7}{6.7.7.7.7.7.7.7.}% \CALX_fsel s{22}{11}{10.3626.9.1779.8.754.7.263.6.70.5.12.4.1.}% \CALX_fdef s{23}{7}{11}{2}{7}{2.3.3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_10}{7}{10}{3}{7}{3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_9}{7}{9}{3}{7}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_8}{7}{8}{4}{7}{4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_7}{7}{7}{4}{7}{4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{23_4}{7}{4}{6}{7}{6.7.7.7.7.7.7.7.}% \CALX_fsel s{23}{11}{10.3626.9.1779.8.754.7.263.6.70.5.12.4.1.}% \CALX_fdef s{24}{7}{11}{2}{7}{2.3.3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_10}{7}{10}{3}{7}{3.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_9}{7}{9}{3}{7}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_8}{7}{8}{4}{7}{4.4.4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_7}{7}{7}{4}{7}{4.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef s{24_4}{7}{4}{6}{7}{6.7.7.7.7.7.7.7.}% \CALX_fsel s{24}{11}{10.3626.9.1779.8.754.7.263.6.70.5.12.4.1.}% \CALX_fdef s{25}{8}{12}{2}{8}{2.3.3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.% 8.}% \CALX_fdef s{25_11}{8}{11}{3}{8}{3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef s{25_10}{8}{10}{4}{8}{4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{25_9}{8}{9}{4}{8}{4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{25_8}{8}{8}{5}{8}{5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{25_7}{8}{7}{5}{8}{5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{25_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{25_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel s{25}{12}{11.3597.10.1836.9.832.8.322.7.101.6.23.5.3.}% \CALX_fdef s{26}{8}{12}{2}{8}{2.3.3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.% 8.}% \CALX_fdef s{26_11}{8}{11}{3}{8}{3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef s{26_10}{8}{10}{4}{8}{4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{26_9}{8}{9}{4}{8}{4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{26_8}{8}{8}{5}{8}{5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{26_7}{8}{7}{5}{8}{5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{26_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{26_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel s{26}{12}{11.3597.10.1836.9.832.8.322.7.101.6.23.5.3.}% \CALX_fdef s{27}{8}{12}{2}{8}{2.3.3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.% 8.}% \CALX_fdef s{27_11}{8}{11}{3}{8}{3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef s{27_10}{8}{10}{4}{8}{4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{27_9}{8}{9}{4}{8}{4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{27_8}{8}{8}{5}{8}{5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{27_7}{8}{7}{5}{8}{5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{27_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{27_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel s{27}{12}{11.3597.10.1836.9.832.8.322.7.101.6.23.5.3.}% \CALX_fdef s{28}{8}{13}{1}{8}{1.2.2.3.3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.% 8.8.8.}% \CALX_fdef s{28_12}{8}{12}{2}{8}{2.3.3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.% 8.8.}% \CALX_fdef s{28_11}{8}{11}{3}{8}{3.4.4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef s{28_10}{8}{10}{4}{8}{4.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{28_9}{8}{9}{4}{8}{4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{28_8}{8}{8}{5}{8}{5.5.5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{28_7}{8}{7}{5}{8}{5.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{28_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef s{28_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel s{28}{13}{12.5121.11.2952.10.1498.9.669.8.254.7.77.6.17.5.2.}% \CALX_fdef s{29}{9}{13}{2}{9}{2.3.3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.% 9.9.9.}% \CALX_fdef s{29_12}{9}{12}{3}{9}{3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef s{29_11}{9}{11}{4}{9}{4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef s{29_10}{9}{10}{5}{9}{5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{29_9}{9}{9}{5}{9}{5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{29_8}{9}{8}{6}{9}{6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{29_7}{9}{7}{6}{9}{6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{29_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{29_5}{9}{5}{8}{9}{8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel s{29}{13}{12.3696.11.1971.10.950.9.403.8.144.7.40.6.8.5.1.}% \CALX_fdef s{30}{9}{13}{2}{9}{2.3.3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.% 9.9.9.}% \CALX_fdef s{30_12}{9}{12}{3}{9}{3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef s{30_11}{9}{11}{4}{9}{4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef s{30_10}{9}{10}{5}{9}{5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{30_9}{9}{9}{5}{9}{5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{30_8}{9}{8}{6}{9}{6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{30_7}{9}{7}{6}{9}{6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{30_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{30_5}{9}{5}{8}{9}{8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel s{30}{13}{12.3696.11.1971.10.950.9.403.8.144.7.40.6.8.5.1.}% \CALX_fdef s{31}{9}{14}{2}{9}{2.2.2.3.3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.% 9.9.9.9.9.}% \CALX_fdef s{31_13}{9}{13}{2}{9}{2.3.3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.% 9.9.9.9.}% \CALX_fdef s{31_12}{9}{12}{3}{9}{3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef s{31_11}{9}{11}{4}{9}{4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef s{31_10}{9}{10}{5}{9}{5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{31_9}{9}{9}{5}{9}{5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{31_8}{9}{8}{6}{9}{6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{31_7}{9}{7}{6}{9}{6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{31_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel s{31}{14}{13.4589.12.2660.11.1394.10.654.9.268.8.91.7.24.6.4.}% \CALX_fdef s{32}{9}{14}{2}{9}{2.2.2.3.3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.% 9.9.9.9.9.}% \CALX_fdef s{32_13}{9}{13}{2}{9}{2.3.3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.% 9.9.9.9.}% \CALX_fdef s{32_12}{9}{12}{3}{9}{3.4.4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef s{32_11}{9}{11}{4}{9}{4.5.5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef s{32_10}{9}{10}{5}{9}{5.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{32_9}{9}{9}{5}{9}{5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{32_8}{9}{8}{6}{9}{6.6.6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{32_7}{9}{7}{6}{9}{6.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef s{32_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel s{32}{14}{13.4589.12.2660.11.1394.10.654.9.268.8.91.7.24.6.4.}% \CALX_fdef s{33}{10}{14}{3}{10}{3.3.3.4.4.5.5.6.6.6.6.7.7.7.7.8.8.9.9.9.9.10.% 10.10.10.10.10.10.}% \CALX_fdef s{34}{10}{15}{2}{10}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.7.7.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_fdef s{35}{10}{15}{2}{10}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.7.7.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_fdef s{36}{10}{15}{2}{10}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.7.7.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_fdef s{37}{11}{16}{2}{11}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.8.8.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef s{38}{11}{16}{2}{11}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.8.8.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef s{39}{11}{16}{2}{11}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.8.8.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef s{40}{11}{16}{2}{11}{2.3.3.4.4.4.4.5.5.6.6.7.7.7.7.8.8.8.8.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef c{9}{4}{7}{2}{4}{2.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{9_6}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{9_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{9_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef c{9_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef c{9_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel c{9}{7}{6.2817.5.963.4.227.3.28.2.1.}% \CALX_fdef c{10}{4}{7}{2}{4}{2.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{10_6}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{10_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{10_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef c{10_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef c{10_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel c{10}{7}{6.2817.5.963.4.227.3.28.2.1.}% \CALX_fdef c{11}{4}{7}{2}{4}{2.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{11_6}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{11_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{11_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef c{11_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fdef c{11_2}{4}{2}{4}{4}{4.4.4.4.}% \CALX_fsel c{11}{7}{6.2817.5.963.4.227.3.28.2.1.}% \CALX_fdef c{12}{4}{8}{1}{4}{1.2.2.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{12_7}{4}{7}{2}{4}{2.2.2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{12_6}{4}{6}{2}{4}{2.3.3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{12_5}{4}{5}{3}{4}{3.3.3.4.4.4.4.4.4.4.}% \CALX_fdef c{12_4}{4}{4}{3}{4}{3.4.4.4.4.4.4.4.}% \CALX_fdef c{12_3}{4}{3}{4}{4}{4.4.4.4.4.4.}% \CALX_fsel c{12}{8}{7.4912.6.2217.5.740.4.166.3.19.}% \CALX_fdef c{13}{5}{8}{2}{5}{2.3.3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{13_7}{5}{7}{3}{5}{3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{13_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{13_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{13_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef c{13_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel c{13}{8}{7.2963.6.1138.5.333.4.63.3.5.}% \CALX_fdef c{14}{5}{8}{2}{5}{2.3.3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{14_7}{5}{7}{3}{5}{3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{14_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{14_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{14_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef c{14_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel c{14}{8}{7.2963.6.1138.5.333.4.63.3.5.}% \CALX_fdef c{15}{5}{9}{2}{5}{2.2.2.3.3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{15_8}{5}{8}{2}{5}{2.3.3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{15_7}{5}{7}{3}{5}{3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{15_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{15_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{15_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef c{15_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel c{15}{9}{8.3836.7.1720.6.618.5.164.4.27.3.2.}% \CALX_fdef c{16}{5}{9}{2}{5}{2.2.2.3.3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{16_8}{5}{8}{2}{5}{2.3.3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{16_7}{5}{7}{3}{5}{3.3.3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{16_6}{5}{6}{3}{5}{3.4.4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{16_5}{5}{5}{4}{5}{4.4.4.5.5.5.5.5.5.5.}% \CALX_fdef c{16_4}{5}{4}{4}{5}{4.5.5.5.5.5.5.5.}% \CALX_fdef c{16_3}{5}{3}{5}{5}{5.5.5.5.5.5.}% \CALX_fsel c{16}{9}{8.3836.7.1720.6.618.5.164.4.27.3.2.}% \CALX_fdef c{17}{6}{10}{2}{6}{2.3.3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{17_9}{6}{9}{3}{6}{3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{17_8}{6}{8}{3}{6}{3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{17_7}{6}{7}{4}{6}{4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{17_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{17_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{17_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel c{17}{10}{9.3425.8.1584.7.617.6.189.5.41.4.5.}% \CALX_fdef c{18}{6}{10}{2}{6}{2.3.3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{18_9}{6}{9}{3}{6}{3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{18_8}{6}{8}{3}{6}{3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{18_7}{6}{7}{4}{6}{4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{18_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{18_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{18_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel c{18}{10}{9.3425.8.1584.7.617.6.189.5.41.4.5.}% \CALX_fdef c{19}{6}{10}{2}{6}{2.3.3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{19_9}{6}{9}{3}{6}{3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{19_8}{6}{8}{3}{6}{3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{19_7}{6}{7}{4}{6}{4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{19_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{19_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{19_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel c{19}{10}{9.3425.8.1584.7.617.6.189.5.41.4.5.}% \CALX_fdef c{20}{6}{11}{1}{6}{1.2.2.3.3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_10}{6}{10}{2}{6}{2.3.3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_9}{6}{9}{3}{6}{3.3.3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_8}{6}{8}{3}{6}{3.4.4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_7}{6}{7}{4}{6}{4.4.4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_6}{6}{6}{4}{6}{4.5.5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_5}{6}{5}{5}{6}{5.5.5.6.6.6.6.6.6.6.}% \CALX_fdef c{20_4}{6}{4}{5}{6}{5.6.6.6.6.6.6.6.}% \CALX_fsel c{20}{11}{10.5473.9.3041.8.1405.7.542.6.163.5.34.4.4.}% \CALX_fdef c{21}{7}{11}{2}{7}{2.3.3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_10}{7}{10}{3}{7}{3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_9}{7}{9}{4}{7}{4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_8}{7}{8}{4}{7}{4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_7}{7}{7}{5}{7}{5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{21_4}{7}{4}{6}{7}{6.7.7.7.7.7.7.7.}% \CALX_fsel c{21}{11}{10.3472.9.1692.8.718.7.252.6.68.5.12.4.1.}% \CALX_fdef c{22}{7}{11}{2}{7}{2.3.3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_10}{7}{10}{3}{7}{3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_9}{7}{9}{4}{7}{4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_8}{7}{8}{4}{7}{4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_7}{7}{7}{5}{7}{5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{22_4}{7}{4}{6}{7}{6.7.7.7.7.7.7.7.}% \CALX_fsel c{22}{11}{10.3472.9.1692.8.718.7.252.6.68.5.12.4.1.}% \CALX_fdef c{23}{7}{12}{2}{7}{2.2.2.3.3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.% 7.}% \CALX_fdef c{23_11}{7}{11}{2}{7}{2.3.3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.% }% \CALX_fdef c{23_10}{7}{10}{3}{7}{3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{23_9}{7}{9}{4}{7}{4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{23_8}{7}{8}{4}{7}{4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{23_7}{7}{7}{5}{7}{5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{23_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{23_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fsel c{23}{12}{11.4708.10.2583.9.1237.8.510.7.172.6.44.5.7.}% \CALX_fdef c{24}{7}{12}{2}{7}{2.2.2.3.3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.% 7.}% \CALX_fdef c{24_11}{7}{11}{2}{7}{2.3.3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.% }% \CALX_fdef c{24_10}{7}{10}{3}{7}{3.4.4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{24_9}{7}{9}{4}{7}{4.4.4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{24_8}{7}{8}{4}{7}{4.5.5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{24_7}{7}{7}{5}{7}{5.5.5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{24_6}{7}{6}{5}{7}{5.6.6.6.6.7.7.7.7.7.7.7.}% \CALX_fdef c{24_5}{7}{5}{6}{7}{6.6.6.7.7.7.7.7.7.7.}% \CALX_fsel c{24}{12}{11.4708.10.2583.9.1237.8.510.7.172.6.44.5.7.}% \CALX_fdef c{25}{8}{12}{3}{8}{3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.% 8.}% \CALX_fdef c{25_11}{8}{11}{3}{8}{3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef c{25_10}{8}{10}{4}{8}{4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{25_9}{8}{9}{5}{8}{5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{25_8}{8}{8}{5}{8}{5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{25_7}{8}{7}{6}{8}{6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{25_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{25_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel c{25}{12}{11.3595.10.1845.9.843.8.331.7.105.6.25.5.3.}% \CALX_fdef c{26}{8}{13}{2}{8}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.% 8.8.8.}% \CALX_fdef c{26_12}{8}{12}{3}{8}{3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.% 8.8.}% \CALX_fdef c{26_11}{8}{11}{3}{8}{3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef c{26_10}{8}{10}{4}{8}{4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{26_9}{8}{9}{5}{8}{5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{26_8}{8}{8}{5}{8}{5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{26_7}{8}{7}{6}{8}{6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{26_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{26_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel c{26}{13}{12.4168.11.2309.10.1148.9.502.8.186.7.55.6.12.5.1.}% \CALX_fdef c{27}{8}{13}{2}{8}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.% 8.8.8.}% \CALX_fdef c{27_12}{8}{12}{3}{8}{3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.% 8.8.}% \CALX_fdef c{27_11}{8}{11}{3}{8}{3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef c{27_10}{8}{10}{4}{8}{4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{27_9}{8}{9}{5}{8}{5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{27_8}{8}{8}{5}{8}{5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{27_7}{8}{7}{6}{8}{6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{27_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{27_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel c{27}{13}{12.4168.11.2309.10.1148.9.502.8.186.7.55.6.12.5.1.}% \CALX_fdef c{28}{8}{13}{2}{8}{2.3.3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.% 8.8.8.}% \CALX_fdef c{28_12}{8}{12}{3}{8}{3.3.3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.% 8.8.}% \CALX_fdef c{28_11}{8}{11}{3}{8}{3.4.4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.% }% \CALX_fdef c{28_10}{8}{10}{4}{8}{4.5.5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{28_9}{8}{9}{5}{8}{5.5.5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{28_8}{8}{8}{5}{8}{5.6.6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{28_7}{8}{7}{6}{8}{6.6.6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{28_6}{8}{6}{6}{8}{6.7.7.7.7.8.8.8.8.8.8.8.}% \CALX_fdef c{28_5}{8}{5}{7}{8}{7.7.7.8.8.8.8.8.8.8.}% \CALX_fsel c{28}{13}{12.4168.11.2309.10.1148.9.502.8.186.7.55.6.12.5.1.}% \CALX_fdef c{29}{9}{14}{2}{9}{2.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.% 9.9.9.9.9.}% \CALX_fdef c{29_13}{9}{13}{3}{9}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.9.9.9.}% \CALX_fdef c{29_12}{9}{12}{4}{9}{4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef c{29_11}{9}{11}{4}{9}{4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef c{29_10}{9}{10}{5}{9}{5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{29_9}{9}{9}{6}{9}{6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{29_8}{9}{8}{6}{9}{6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{29_7}{9}{7}{7}{9}{7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{29_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel c{29}{14}{13.3935.12.2217.11.1144.10.530.9.214.8.72.7.19.6.3.}% \CALX_fdef c{30}{9}{14}{2}{9}{2.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.% 9.9.9.9.9.}% \CALX_fdef c{30_13}{9}{13}{3}{9}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.9.9.9.}% \CALX_fdef c{30_12}{9}{12}{4}{9}{4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef c{30_11}{9}{11}{4}{9}{4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef c{30_10}{9}{10}{5}{9}{5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{30_9}{9}{9}{6}{9}{6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{30_8}{9}{8}{6}{9}{6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{30_7}{9}{7}{7}{9}{7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{30_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel c{30}{14}{13.3935.12.2217.11.1144.10.530.9.214.8.72.7.19.6.3.}% \CALX_fdef c{31}{9}{14}{2}{9}{2.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.% 9.9.9.9.9.}% \CALX_fdef c{31_13}{9}{13}{3}{9}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.9.9.9.}% \CALX_fdef c{31_12}{9}{12}{4}{9}{4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef c{31_11}{9}{11}{4}{9}{4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef c{31_10}{9}{10}{5}{9}{5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{31_9}{9}{9}{6}{9}{6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{31_8}{9}{8}{6}{9}{6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{31_7}{9}{7}{7}{9}{7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{31_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel c{31}{14}{13.3935.12.2217.11.1144.10.530.9.214.8.72.7.19.6.3.}% \CALX_fdef c{32}{9}{15}{1}{9}{1.2.2.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.% 9.9.9.9.9.9.9.}% \CALX_fdef c{32_14}{9}{14}{2}{9}{2.3.3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.% 9.9.9.9.9.9.}% \CALX_fdef c{32_13}{9}{13}{3}{9}{3.4.4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.9.9.9.}% \CALX_fdef c{32_12}{9}{12}{4}{9}{4.4.4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.% 9.9.}% \CALX_fdef c{32_11}{9}{11}{4}{9}{4.5.5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.% }% \CALX_fdef c{32_10}{9}{10}{5}{9}{5.6.6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{32_9}{9}{9}{6}{9}{6.6.6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{32_8}{9}{8}{6}{9}{6.7.7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{32_7}{9}{7}{7}{9}{7.7.7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fdef c{32_6}{9}{6}{7}{9}{7.8.8.8.8.9.9.9.9.9.9.9.}% \CALX_fsel c{32}{15}{14.5737.13.3657.12.2069.11.1065.10.491.9.197.8.65.7.17.% 6.3.}% \CALX_fdef c{33}{10}{15}{2}{10}{2.3.3.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_fdef c{34}{10}{15}{2}{10}{2.3.3.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_fdef c{35}{10}{15}{2}{10}{2.3.3.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.10.10.10.}% \CALX_fdef c{36}{10}{16}{2}{10}{2.2.2.3.3.4.4.5.5.5.5.6.6.7.7.7.7.8.8.8.8.9.% 9.9.9.10.10.10.10.10.10.10.}% \CALX_fdef c{37}{11}{16}{3}{11}{3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef c{38}{11}{16}{3}{11}{3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.9.10.% 10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef c{39}{11}{17}{2}{11}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.11.11.11.11.11.11.11.}% \CALX_fdef c{40}{11}{17}{2}{11}{2.3.3.3.3.4.4.5.5.6.6.6.6.7.7.8.8.8.8.9.9.9.% 9.10.10.10.10.11.11.11.11.11.11.11.}% }% % \end{macrocode} % \StoreCodelineNo {calxtrigdata} % \cleardoublepage\let\calxtrigdatanameUp\undefined % \MakePercentComment %------------------------------------------------------ %<*dtx>----------------------------------------------------------- \cleardoublepage \section{Cumulative line and macro count} % le 6 juin 2022 j'ajoute le décompte des macros \def\mymacro #1{\mymacroaux #1} \def\mymacroaux #1#2#3{\strut \csname #1nameimp\endcsname&\dtt{#2}&(\dtt{#3})\tabularnewline } \indent \begin{tabular}[t]{rrr} module&lines¯os\tabularnewline \xintApplyInline\mymacro\storedlinecounts \end{tabular} \hfil \begin{minipage}[t]{10cm} \def\mymacroaux #1#2#3{#2}% Total number of code lines: \dtt{\the\numexpr \xintListWithSep+{\xintApply\mymacro\storedlinecounts}\relax }. \ifdefined\totala (but \dtt{\the\numexpr \totala+\totalb\relax} lines among them start either with \{\% or with \}\%). \fi Each package or library file starts with circa \dtt{50} lines dealing with catcodes, package identification and reloading management, also for Plain \TeX\strut. \bigskip \def\mymacroaux #1#2#3{#3}% Total number of def'ed (or let'ed) macros: \dtt{\the\numexpr \xintListWithSep+{\xintApply\mymacro\storedlinecounts}\relax }. This is an approximation as some macros are def'ed in a way escaping the automated detection, in particular this applies to \xintexprnameimp macros associated to infix operators and syntax elements, whose construction uses |\csname|-based definitions with a template and auxiliary macros. Their number has been evaluated manually (last updated in June 2022, probably outdated) at being at least about \dtt{452}. This number is probably now wrong but is incorporated into the \calxnameimp count shown left, and the total above. \bigskip Version {\calxbndlversion} of {\calxbndldate}.\par \end{minipage} \CheckSum {72542}% 2.0a1 % 40833 pour 1.4q, 40773 pour 1.4p, % 40137 pour 1.4o, 40137 pour 1.4n, 38900 pour 1.4m, 39032 pour 1.4l, % 38925 pour 1.4k, 38590 pour 1.4j, 38591 pour 1.4i, 38427 pour 1.4h % 38423 pour 1.4g, 38212 pour 1.4f, 38813 pour 1.4e, 35184 pour 1.4d % 35109 pour 1.4c, 35103 pour 1.4b, 34648 pour 1.4a, 34575 pour 1.4 % 33497 pour 1.3f, 33274 pour 1.3e, 31601 pour 1.3d, 31122 pour 1.3c % 31069 pour 1.3b, 30482 pour 1.3a, 30621 pour 1.3, 30988 pour 1.2q, % 30982 pour 1.2p, 30524 pour 1.2o, 30303 pour 1.2h, 30403 pour 1.2i, % 30750 pour 1.2j, 30677 pour 1.2k, 30931 pour 1.2l, 30439 pour 1.2m, % 30253 pour 1.2n \makeatletter\check@checksum \Finale %% End of file xint.dtx