Array variable with fp package: How to use \FPeval in array?
Your code does not work because the way that the fp
package parses its input. In TeX when you define a delimited macro the delimiter text must always be present, so \somevalues
must always be followed by a (
, then some text, then a closing )
. When fp
tries to parse your expression it separates the tokens and adds other tokens in between, then the error you get is:
! Use of \somevalues doesn't match its definition.
<argument> \somevalues
\FP@gen@code {2}
because what follows \somevalues
is \FP@gen@code
, not a (
.
Since you're using expl3
anyway you can use its l3fp
module, which offers an expandable FP engine. Being expandable means that you can do
The~value~of~$\pi^2$~is:~\fp_eval:n { pi^2 }
or even
\setlength{\textwidth}{\fp_eval:n{ 10*30 } pt}
Here I emulated fp
's macros \FPadd
, \FPset
and \FPeval
using l3fp
instead. Note that these emulated macros aren't expandable anymore.
Now you can do, for instance:
\FPset\ans{5}
\FPeval\ans{ans+10}
ans is: \ans % prints 15
Every macro, say, \ans
, used as the first argument to \FP<something>
is defined with the result of the operation, plus a FP word called ans
is defined and will contain that same value, so inside an expression you can use either \ans
or ans
.
CAUTION! This does not perform any verification whatsoever if the involved macros are already defined, so you can accidentally overwrite something important. \FPeval\pi{6.283185}
might not be a good idea.
Here's the code (I only changed the definitions of the FP functions; your array handling and test code is the same):
\documentclass{article}
% \usepackage{fp}
\usepackage{siunitx,amsmath}
%\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newarray}{m}
{
\seq_new:c { l_hafid_array_ \cs_to_str:N #1 _seq }
\cs_new:Npn #1 (##1)
{
\seq_item:cn { l_hafid_array_ \cs_to_str:N #1 _seq } { ##1 }
}
}
\NewDocumentCommand{\readarray}{mm}
{
\seq_set_split:cnn { l_hafid_array_#1_seq } { & } { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
% Stolen from l3fp:
\fp_new:N \l__sandu_temp_fp
\cs_set_protected:Npn \sandu_fp_name:nn #1 #2
{
\cs_undefine:c { c__sandu_#1_fp }
\fp_const:cn { c__sandu_#1_fp } { #2 }
\__sandu_define_fp_name:cn { c__sandu_#1_fp } { #1 }
}
\cs_new_protected:Npn \__sandu_define_fp_name:Nn #1 #2
{
\cs_set:cpn { __fp_parse_word_#2:N }
{ \exp_after:wN #1 \exp:w \exp_end_continue_f:w \__fp_parse_infix:NN }
}
\cs_generate_variant:Nn \__sandu_define_fp_name:Nn { c }
\cs_generate_variant:Nn \sandu_fp_name:nn { f }
% Emulating fp.sty
\NewDocumentCommand \FPadd {m mm}
{
\tl_set:Nx #1 { \fp_eval:n { #2 + #3 } }
\sandu_fp_name:fn { \cs_to_str:N #1 } { #1 }
}
\NewDocumentCommand \FPeval {m m}
{
\tl_set:Nx #1 { \fp_eval:n { #2 } }
\sandu_fp_name:fn { \cs_to_str:N #1 } { #1 }
}
\NewDocumentCommand \FPset {m m}
{
\tl_set:Nx #1 { \fp_eval:n { #2 } }
\sandu_fp_name:fn { \cs_to_str:N #1 } { #1 }
}
\ExplSyntaxOff
\begin{document}
\newarray\somevalues
\readarray{somevalues}{1&2&3.5&4&5}
\begin{align*}
v_1 &= \somevalues(1)\\
v_2 &= \somevalues(2)\\
v_3 &= \somevalues(3)\\
v_4 &= \somevalues(4)\\
v_5 &= \somevalues(5)
\end{align*}
First number = \somevalues(1)\\
Second number = \somevalues(2)
\FPadd\xx{\somevalues(1)}{\somevalues(2)}
\FPeval{\xx}{round(xx,4)}%
sum of first two numbers = \xx
\FPeval\xx{\somevalues(1)+\somevalues(2)}
\FPeval{\xx}{round(xx,4)}%
sum of first two numbers = \xx
%
\newcount\counter
\counter=5
\FPset\ans{0}
\loop
%\somevalues(\counter)\\
\FPadd\ans{\ans}{\somevalues(\counter)}
%\FPeval\ans{\ans+\somevalues(\counter)}
\advance \counter by -1
\unless\ifnum \counter<1
\repeat
%
\FPeval{\ans}{round(ans,4)}%
sum of all numbers = \ans
\end{document}
which prints:
P.S.: Don't do \newcount\count
because you'll redefine the TeX primitive \count
. Use another name.
Don't use \newcount
if you don't know about its quirks: for instance, it doesn't check whether the control sequence is already defined. If you want another spectacular wreckage, try \newcount\box
.
You're mixing syntaxes. Something like
\newarray\somevalues
\setarray\somevalues{1&2&3}
\somevalues(1)
is in arrayjobx
style and is not something I'd use, because it can confuse the parser for \fpeval
. Better standard argument delimiters, that is, braces.
There is no need to use fp
when you're already using expl3
.
\documentclass{article}
\usepackage{siunitx,amsmath}
\usepackage{xparse,xfp}
\ExplSyntaxOn
\NewDocumentCommand{\newarray}{m}
{
\seq_new:c { l_hafid_array_#1_seq }
\cs_new:cpn { #1 } ##1
{
\seq_item:cn { l_hafid_array_#1_seq } { ##1 }
}
}
\NewDocumentCommand{\readarray}{mm}
{
\seq_set_split:cnn { l_hafid_array_#1_seq } { & } { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
\NewExpandableDocumentCommand{\sumarray}{O{15}m}
{
\fp_eval:n { round( \seq_use:cn { l_hafid_array_#2_seq } { + }, #1 ) }
}
\ExplSyntaxOff
\begin{document}
\newarray{somevalues}
\readarray{somevalues}{1&2&3.5&4&5}
\begin{align*}
v_1 &= \somevalues{1}\\
v_2 &= \somevalues{2}\\
v_3 &= \somevalues{3}\\
v_4 &= \somevalues{4}\\
v_5 &= \somevalues{5}
\end{align*}
First number = \somevalues{1}
Second number = \somevalues{2}
sum of first two numbers =
\fpeval{ round(\somevalues{1}+\somevalues{2},4) }
Sum of the array \sumarray[4]{somevalues}
Sum of the array \sumarray[0]{somevalues}
\end{document}
The optional argument to \sumarray
is the number of digits for the rounding.