TeX - LaTeX Asked on June 9, 2021
I wish to build a (simple) implementation of abs.
I tried FPabs
but I get a lot of zeros after the decimal point. I could get rid of them with the FP round function, but I don’t know the number of decimals I will have.
I think a string manipulation approach is better. I could use the xstring
package to get rid of the minus as in -12.3 to get 12.3 but a full package just for that …
Is there a simple way to get rid or consume the "-" of "-12.3" for instance to get "12.3" ?
You can define gobbleminus
by this way:
defgobbleminus#1{ifx-#1else#1fi}
%test:
gobbleminus -12
gobbleminus 1234
gobbleminus .24
Correct answer by wipet on June 9, 2021
I'm sure you get a LaTeX3 solution by one of the experts in no time and I really don't think that a string-based solution is the best you can do here, but while you wait here is a simple, argument-based solution.
The solution is not expandable, which might be a bit of deal-breaker depending on what you want to do (but: see below).
The main idea is to use delimited arguments (How does TeX look for delimited arguments?) to strip characters from a string. In order not to run into trouble here, we first check whether the characters are actually present.
ifstrstartswith
works by defining a helper macro fstr@ifstrstartswith@i
that grabs arguments as follows
#1<characters to find>#2&
if we now pass a string to fstr@ifstrstartswith@i
that starts with <characters to find>
, TeX's argument parse rules make #1
come up empty. In order to avoid errors, we always call fstr@ifstrstartswith@i
with fstr@ifstrstartswith@i <string><characters to find>&
. This means that even if <string>
does not contain <characters to find>
at all, we still have called the macro with the right argument signature.
The characters stripping now works similarly. We check that <string>
actually starts with <characters to remove>
and then apply a helper macro fstr@stripfromstart@i
with signature
<characters to remove>#1&
which then strips off the <characters to remove>
from the beginning of <string>
when called as fstr@stripfromstart@i <string>&
.
documentclass[british]{article}
usepackage[T1]{fontenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
% {<characters to find>}{<string>}
newrobustcmd*{ifstrstartswith}[2]{%
deffstr@ifstrstartswith@i##1#1##2&{%
ifblank{##1}}%
fstr@ifstrstartswith@i#2#1&}
% {<characters to remove>}{<string>}
newrobustcmd*{stripfromstart}[2]{%
deffstr@stripfromstart@i#1##1&{##1}%
ifstrstartswith{#1}{#2}
{fstr@stripfromstart@i#2&}
{#2}}
makeatother
newcommand*{mysimpleabs}{stripfromstart{-}}
begin{document}
mysimpleabs{4.5}
mysimpleabs{-4.5}
end{document}
Of course you don't want to try mysimpleabs{-4.5-5}
or mysimpleabs{-4.5+5}
.
edit Come to think of it, we can make this expandable if we hard-code the -
. Still, string manipulation does not strike me as the best way to deal with this.
documentclass[british]{article}
usepackage[T1]{fontenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
newcommand*{fstr@ifstrstartswithminus@i}{} % just to reserve the name
deffstr@ifstrstartswithminus@i#1-#2&{ifblank{#1}}
newcommand*{ifstrstartswithminus}[1]{%
fstr@ifstrstartswithminus@i#1-&}
newcommand*{fstr@stripminusfromstart@i}{} % just to reserve the name
deffstr@stripminusfromstart@i-#1&{#1}
newcommand*{stripminusfromstart}[1]{%
ifstrstartswithminus{#1}
{fstr@stripminusfromstart@i#1&}
{#1}}
makeatother
newcommand*{mysimpleabs}{stripminusfromstart}
begin{document}
mysimpleabs{4.5}
mysimpleabs{-4.5}
edeffoo{mysimpleabs{12.3}}
meaningfoo
edeffoo{mysimpleabs{-12.3}}
meaningfoo
end{document}
Answered by moewe on June 9, 2021
You could use xfp (the package is very short, it contains only two definitions to create wrappers around fp_eval:n
and int_eval:n
):
documentclass{article}
usepackage{xfp}
begin{document}
fpeval{abs(-12.3)}
end{document}
It is expandable, that means you can fed it to num
for formatting. Here I change the period to a command:
documentclass{article}
usepackage{xfp,siunitx}
sisetup{locale=DE}
begin{document}
num{fpeval{abs(-12.3)}}
end{document}
Answered by Ulrike Fischer on June 9, 2021
If you know that the thing you're removing the minus from starts with a minus or a digit, then the old school way of doing this would be
makeatletter
defgobbleminus#1{ifnum#17<z@ @firstoftwofi #1}
makeatother
e.g.
gobbleminus 12.3 % Expands to 12.3
gobbleminus -12.3 % Expands to 12.3
gobbleminus -0.1000 % Expands to 0.1000
If your data is being generated by expanding something, you will of course need to make sure it gets sufficiently expanded before letting gobbleminus act on it.
Another catch is that
gobbleminus .123 % Raises error
since . is not a minus or digit. Though it occurs to me that one could make it tolerate this as well, by changing the definition to
makeatletter
defgobbleminus#1{ifdim#17pt<z@ @firstoftwofi #1}
makeatother
Answered by Lars H on June 9, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP