4

Some functions are defined in xfp. Example: You can write something like \fpeval{max(1, 2, 3, 4)} and get 4 as the result.

I would like to define functions like crbt(x) = x^(1/3) or the greatest common divisor of a variable number of integers. \fpeval{gcd(6, 12, 120)} should expand to 6. Is this possible?

Sorry, I am not able to create an MWE. There is so much code in expl3. I don't know where to begin.

Thanks. :)

3

1 Answer 1

6

Beware of the dog answer!

There is some experimental code for l3fp (xfp) in l3trial/l3fp-extras, which provides the feature you are looking for. However, this code is not distributed yet (you won't find it in your TeX installation) because it's in one way or another incomplete. You are free to use that code, but beware that it may be changed/removed without prior notice.


Installation: Should you want to try it, clone the repository with git clone 'https://github.com/latex3/latex3.git' (or just download the files in the folder linked above), then in the folder latex3/l3trial/l3fp-extras run pdftex l3fp-extras.ins, then copy the unpacked l3fp-extras.sty to your working directory.

Using it: Since there is barely no documentation, here is what I guessed found out from looking at the code:

  • For simple functions, like your cube root example, you can use:

    \fp_set_function:nnn { <name> } { <arg list> } { <function> }
    

    for example:

    \fp_set_function:nnn { cbrt } { x } { x^(1/3) }
    
  • For more complex functions, like your GCD example, you can use:

    \fp_new_function:Npn <function> <parameters> { <definition> }
    

    for example, to compute the GCD using Euclid's recursive algorithm:

    \fp_new_function:Npn \GCD #1 #2
      {
        \fp_compare:nNnTF {#1} > {#2}
          { \__gcd_aux:nn {#1} {#2} }
          { \__gcd_aux:nn {#2} {#1} }
      }
    \cs_new:Npn \__gcd_aux:nn #1 #2
      {
        \fp_compare:nNnTF {#2} = { 0 }
          {#1} { \GCD (#1-#2,#2) }
      }
    

The simple cases, that are like typing shortcuts (e.g., cbrt(8) instead of 8^(1/3)) can be solved with the more powerful \fp_set_function:nnn, but it doesn't let you go too far from simple expressions yet. For more complicate cases, where you need, for example, comparisons, you have to use (read: I managed to make it work with) \fp_new_function:Npn. It defines a macro that takes a bunch of arguments and processes them inside the fp expression.

Note that in the simpler case you can then call \fpeval{cbrt(8)}, whereas in the second case you have to precede the function name with a backslash: \fpeval{\GCD(3,4)}. I didn't manage to make \GCD work with the symbolic name.

Also it seems it is not yet possible to have a variable number of arguments, so you have to write \GCD(\GCD(6, 12), 120) instead of \GCD(6, 12, 120).

Anyway, here it goes:

\documentclass{article}
\usepackage{l3fp-extras}
\usepackage{xfp}
\ExplSyntaxOn
\fp_set_function:nnn { cbrt } { x } { x^(1/3) }
%
\fp_new_function:Npn \GCD #1 #2
  {
    \fp_compare:nNnTF {#1} > {#2}
      { \__gcd_aux:nn {#1} {#2} }
      { \__gcd_aux:nn {#2} {#1} }
  }
\cs_new:Npn \__gcd_aux:nn #1 #2
  {
    \fp_compare:nNnTF {#2} = { 0 }
      {#1} { \GCD (#1-#2,#2) }
  }
\ExplSyntaxOff
\begin{document}
\fpeval{cbrt(8)} % prints 2

\fpeval{\GCD(1071, 462)} % prints 21

\fpeval{\GCD(\GCD(6, 12), 120)} % prints 6
\end{document}
1
  • Really fascinating. Please include this in xfp. Jun 10, 2021 at 21:47

You must log in to answer this question.

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