4

I was trying to print the first few terms of hyperfactorials, which are defined by H(0)=1 and H(n)=H(n-1)*n^n.

  1. When fpeval is used for calculation and inteval is used for printing:
\documentclass{article}
\usepackage{tikz}
\usepackage{xfp}
\begin{document}

These are the first few terms of hyperfactorials. \\
\edef\x{1}
\foreach[remember=\x] \i in {1,2,...,13} {
    \edef\x{\fpeval{\x*\i^\i}}
    $\inteval{\x}$ \\
}
\end{document}

Error:

! Number too big.

Output (when ignoring error):

These are the first few terms of hyperfactorials.
1
4
108
27648
86400000
2147483647
2147483647
2147483647
2147483647
2147483647
2147483647
2147483647
2147483647
  1. When fpeval is used for calculation and printing:
\documentclass{article}
\usepackage{tikz}
\usepackage{xfp}
\begin{document}

These are the first few terms of hyperfactorials. \\
\edef\x{1}
\foreach[remember=\x] \i in {1,2,...,13} {
    \edef\x{\fpeval{\x*\i^\i}}
    $\fpeval{\x}$ \\
}
\end{document}

Output:

These are the first few terms of hyperfactorials.
1
4
108
27648
86400000
4031078400000
3319766398771200000
55696437941726560000000000
21577941222941860000000000000000000
215779412229418600000000000000000000000000000
61564384586635060000000000000000000000000000000000000000
548914237009501600000000000000000000000000000000000000000000000000000
166252458044258000000000000000000000000000000000000000000000000000000000000000000000
  1. When inteval is used for calculation and printing:
\documentclass{article}
\usepackage{tikz}
\usepackage{xfp}
\begin{document}

These are the first few terms of hyperfactorials. \\
\edef\x{1}
\foreach[remember=\x] \i in {1,2,...,13} {
    \edef\y{\x}
    \foreach[parse=true][remember=\y] \j in {1,...,\i} {
        \edef\y{\inteval{\y*\i}}
    }
    $\inteval{\y}$ \\
    \edef\x{\y}
}
\end{document}

Error:

! Arithmetic overflow.

Output (when ignoring error):

These are the first few terms of hyperfactorials.
1
1
1
1
1
1
1
1
1
1
1
1
1

Correct output:

These are the first few terms of hyperfactorials.
1
4
108
27648
86400000
4031078400000
3319766398771200000
55696437941726556979200000
21577941222941856209168026828800000
215779412229418562091680268288000000000000000
61564384586635053951550731889313964883968000000000000000
548914237009501581804104224704637116078267727827959808000000000000000
166252458044258018207674078620690924617735088270974773221032328167424000000000000000

Comparing the three cases it is clear that using \fpeval for both calculation and printing results in the best accuracy. Why is \fpeval more precise? Shouldn't integers have more precision and range since there are no exponent bits? Also are there any packages/commands that cover huge integers with 100% accuracy? Finally what are the exact range and precision of \fpeval and \inteval?

0

3 Answers 3

4

The \inteval command is a thin wrapper around e-TeX's \numexpr primitive. This allows simple arithmetic without needing assignment, but remains tied to TeX's idea of an integer: the maximum is 231. In contrast, \fpeval is a macro-based implementation to provide a IEEE 754 compliant floating point approach. This has 16b digits of precision in the mantissa and an exponent of up to 10000.

It would be possible to implement a extended ('big') integer expression system in the same way as \fpeval. However, the reason that we have \fpeval is primarily for areas that calculations come up in typesetting: more classically, approximations like trig have been used for e.g. scaling graphics. There is not a need to do that for big integers as they do not come up in typesetting. Notably, the performance of a macro-base approach will always be slower than exposing a primitive: as such, \inteval will never be changed as we need it for a range of low-level operations.

2
  • By the way is the floating point unit of LaTeX really IEEE 754 compliant? I thought IEEE 754 requires the representation to be binary (maybe it would be IEEE 854 compliant then, but I'm not too sure)
    – user202729
    Oct 30, 2022 at 6:54
  • @user202729 Yes, I do mean 754: this allows the base to be either 2 or 10
    – Joseph Wright
    Oct 30, 2022 at 22:03
3

Why is \fpeval more precise? Shouldn't integers have more precision and range since there are no exponent bits?

Compare: why is double data type in C more precise than int?

In the case of C, double takes 8 bytes while int takes 4. They're not equal comparison.

Also are there any packages/commands that cover huge integers with 100% accuracy?

Finally what are the exact range and precision of \fpeval and \inteval?

You need to somehow know the information that

  • \fpeval is implemented internally with expl3's \fp_eval:n. Quoting interface3.pdf:

    interface3.pdf screenshot of floating point

    Thus, 16 significant digits, and exponents are up to approximately 10000.

  • \inteval is implemented internally with expl3's \int_eval:n...

    interface3.pdf screenshot of integer

    ... which is in turn implemented with e-TeX primitive \numexpr... (quoting etex_man.pdf)

    eTeX manual quote

    So that's the exact rule. Up to approximately 231 (except for the scaling operation).

3
  • (personally I think it would be better if the LaTeX3 developers add a "TeXhacker's note" to describe what things are based on e.g. how \exp:w is based on \romannumeral or in this case \int_eval:w is based on \numexpr, instead of trying to re-describe it in their own words, which is in my opinion not always that precise and would take longer for people who already know the primitive to figure out what is going on)
    – user202729
    Oct 21, 2022 at 6:18
  • 1
    We do add notes where this seems relevant, but there is a risk that people then rely on underlying primitive behaviour rather than the semantics defined in interface3. For example, \exp_not:n is \unexpanded, but as it's n-type, using \exp_not:n \exp_after:wN { } is not supported (and for kernel work we define a separate \__kernel_exp_not:w name for that reason).
    – Joseph Wright
    Oct 21, 2022 at 6:55
  • @JosephWright I guess there's some curse of knowledge in play here too. For now reading the documentation of these again they does describe exactly what the functions do, but I just somehow didn't get it earlier before learning the low-level command. (after all, interface3.pdf is a reference manual not a "book" so maybe it's not the best in terms of teaching, but that's quite a lot of effort needed to improve the situation)
    – user202729
    Oct 21, 2022 at 19:19
2

With respect to your question: "Also are there any packages/commands that cover huge integers with 100% accuracy? " I would say that if you're doing any sort of computationally intensive math, you should look into the sagetex package which gives you a CAS, Sage. It's similar to Mathematica, except it's free. Your problem provides a possible reason why: you just wanted to get hyperfactorial calculations into your document and move on with life. Instead, you find yourself presented with problems like your number is too big, bad output, and arithmetic flow errors. Along the journey you found "\fpeval for both calculation and printing results in the best accuracy." which raised even more questions as to, "Why is \fpeval more precise? Shouldn't integers have more precision and range since there are no exponent bits?". Now you have several answers already telling you about the limitations of various approaches. Great! It can get you through this problem but it's easy to imagine the next problem (and there will be a next problem given that you're investigating hyperfactorials); there will always be doubt about the accuracy of your answers because LaTeX isn't a CAS.

Here's some code that can solve the original problem that brought you here, calculating H(n) accurately:

\documentclass{article}
\usepackage{sagetex,amsmath,seqsplit}
\begin{document}
These are the first few terms of hyperfactorials. \\

\begin{sagesilent}
def H(n):
    if n==1:
        return 1
    else:
        return H(n-1)*n^n

output = r"\noindent "
for i in range(1,12):
    output += r"H(%d)= %d\\"%(i,H(i))
\end{sagesilent}
\sagestr{output}
Sage can even calculate $H(100)$ but since it has    so many digits, we need
to use the sepsplit package so it won't overflow the line:\\

\begin{sagesilent}
BigN = r"$H(100)=\seqsplit{%s}$"%(str(H(100)))
\end{sagesilent}
\noindent \sagestr{BigN}
\end{document}

The output, running in Cocalc is below: enter image description here

The sagetex package also gives you access to Python programming. With a CAS, Python, and LaTeX you can handle almost any problem quickly and spend less time digging into accuracy of \fpeval.

In \sagetex, the \sagesilent mode is work you are giving to Sage. The function H(n) is defined using Python. Since I want to create a string for LaTeX to typeset (using the calculation that Sage has found) I need a raw string which can handle problematic input such as \. The lines for i in range(1,12): output += r"H(%d)= %d\\"%(i,H(i)) runs a loop that puts i (the counter) and H(i) into the spots where %d is. Note that %d is for integers, %f for floating point data, and %s for string data. That output is put into your LaTex document with \sagestr{output}. Bigger values of H(n) will overflow the line so the package seqsplit is used for making the output show over multiple lines. Note from the picture that this is a 4 page document; a lot of pages were needed to typeset H(100).

The Sage documentation says, "Thanks to the GNU Multiprecision Library (GMP), Sage can handle very large numbers, even numbers with millions or billions of digits." If you search for GMP, you can find them here where they say, "GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating-point numbers. There is no practical limit to the precision except the ones implied by the available memory in the machine GMP runs on. GMP has a rich set of functions, and the functions have a regular interface.

The main target applications for GMP are cryptography applications and research, Internet security applications, algebra systems, computational algebra research, etc." That's great news but I need to mention that running Sage in your LaTeX document limits its power. For example, I can calculate H(1000) easily in Sage but if I try to do that in LaTeX code above I will get an error that too much recursion was involved.

Finally, it's worth knowing that Sage can be used as an engine in plotting. See, for example, here. Search this site for more examples.

The drawback of sagetex is that Sage is not part of the LaTeX distribution. Installing it on your computer and getting it to work is problematic for some. The easiest way to get started is with a free Cocalc account.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .