How to calculate factorial with xfp package

I'm trying to calculate the factorial with the xfp package. In the documentation (http://ctan.cs.uu.nl/macros/latex/contrib/l3packages/xfp.pdf), I have found the function name to be fact. My code looks as follows:

\documentclass{article}
\usepackage{xfp}
\begin{document}
\fpeval{fact(4)}
\end{document}


But, I get following error:

! Undefined control sequence.
<argument> \LaTeX3 error:
Unknown fp word fact.
l.4 \fpeval{fact(4)}


While other functions do work (e.g. no error for \fpeval{16*4^3} or \fpeval{cosd(60)*45} )

What am I doing wrong? I am using TeXstudio.

UPDATE

In the preamble I set \usepackage{xfp}[2019/08/25] with the date I found in the documentation between square brackets.

I get the same error as before and following warning:

You have requested, on input line 3, version 2019/08/25' of package xfp,
but only version 2018-09-24 L3 Floating point unit' is available.


When I set \usepackage{xfp}[2018/09/24], I get same error (and no warning).

In any case (with or without date in square brackets), I see following lines in log-file:

Package: expl3 2018-09-24 L3 programming layer (code)
Package: xparse 2018-09-24 L3 Experimental document command parser
Package: xfp 2018-09-24 L3 Floating point unit


I'm using Texworks remotely via the company server, so I have no access to package manager or whatever. Also can not use texdoc. Is there a way to force package update from within Texworks? (probably not ...)

• I think you just need to update your packages, the fact function was added as recently as march this year it seems, so the version you have on your system probably doesn't correspond to the manual you read. Jul 12, 2019 at 16:31
• I can add that you probably have the documentation installed as part of your TeX distribution, and you can look it up via a command prompt/terminal, and the command texdoc <packagename>. So with texdoc xfp you'll get the manual for the specific version of xfp you currently have. Jul 12, 2019 at 16:35
• – Werner
Jul 16, 2019 at 21:58
• Above link led me to the xintexpr which does everything I need.
– Carl
Jul 17, 2019 at 18:46

You should really update your L3 packages. But, if this is for some reason not desired, then you can copy the relevant code from the updated package in your document in order to use the new code.

MWE:

\documentclass{article}
\usepackage{xfp}
\makeatletter
\ExplSyntaxOn
\long \def \__kernel_primitive:NN #1#2
{
\tex_global:D \tex_let:D #2 #1
}
\__kernel_primitive:NN \numexpr               \tex_numexpr:D
\cs_new_eq:NN \int_value:w      \tex_number:D
\cs_new_eq:NN \__fp_int_eval:w \tex_numexpr:D
\cs_new:Npn \__fp_parse_word_fact:N
{ \__fp_parse_unary_function:NNN \__fp_fact_o:w ? }
\int_const:Nn \c__fp_fact_max_arg_int { 3248 }
\cs_new:Npn \__fp_fact_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
\if_case:w #2 \exp_stop_f:
\__fp_case_return_o:Nw \c_one_fp
\or:
\or:
\if_meaning:w 0 #3
\exp_after:wN \__fp_case_return_same_o:w
\fi:
\or:
\__fp_case_return_same_o:w
\fi:
\if_meaning:w 2 #3
\__fp_case_use:nw { \__fp_invalid_operation_o:fw { fact } }
\fi:
\__fp_fact_pos_o:w
\s__fp \__fp_chk:w #2 #3 #4 ;
}
\cs_new:Npn \__fp_fact_pos_o:w #1;
{
\__fp_small_int:wTF #1;
{ \__fp_fact_int_o:n }
{ \__fp_invalid_operation_o:fw { fact } #1; }
}
\cs_new:Npn \__fp_fact_int_o:n #1
{
\if_int_compare:w #1 > \c__fp_fact_max_arg_int
\__fp_case_return:nw
{
\exp_after:wN \exp_after:wN \exp_after:wN \__fp_overflow:w
\exp_after:wN \c_inf_fp
}
\fi:
\exp_after:wN \__fp_sanitize:Nw
\exp_after:wN 0
\int_value:w \tex_numexpr:D
\__fp_fact_loop_o:w #1 . 4 , { 1 } { } { } { } { } { } ;
}
\cs_new:Npn \__fp_fact_loop_o:w #1 . #2 ;
{
\if_int_compare:w #1 < 12 \exp_stop_f:
\__fp_fact_small_o:w #1
\fi:
\exp_after:wN \__fp_ep_mul:wwwwn
\exp_after:wN 4 \exp_after:wN ,
\exp_after:wN { \int_value:w \__fp_int_eval:w #1 * (#1 - 1) }
{ } { } { } { } { } ;
#2 ;
{
\exp_after:wN \__fp_fact_loop_o:w
\int_value:w \__fp_int_eval:w #1 - 2 .
}
}
\cs_new:Npn \__fp_fact_small_o:w #1 \fi: #2 ; #3 ; #4
{
\fi:
\exp_after:wN \__fp_ep_mul:wwwwn
\exp_after:wN 4 \exp_after:wN ,
\exp_after:wN
{
\int_value:w
\if_case:w #1 \exp_stop_f:
1 \or: 1 \or: 2 \or: 6 \or: 24 \or: 120 \or: 720 \or: 5040
\or: 40320 \or: 362880 \or: 3628800 \or: 39916800
\fi:
} { } { } { } { } { } ;
#3 ;
\__fp_ep_to_float_o:wwN 0
}
\ExplSyntaxOff
\makeatother
\begin{document}
\fpeval{fact(4)}
\end{document}


Note that this may break at some point, I tested a few cases but there might be code that I didn't copy that is called for other cases that I didn't test. So update if you can.