1

\IfDecimal returns an error number to big with large decimal. My goal is to print a percent rounded to to places if it is a number, otherwise just print the value of the parameter. Is there away around this size limit or is there another way around this given that I don't yet know whether I have a parsible number? The \SomePerc is a simplified macro that I am trying to use. Input to SomePerc is either a floating point or a "-" (as dash not negative)

\documentclass[]{article}
\usepackage{siunitx}
\usepackage{xstring}

\newcommand\SomePerc[1]{ \IfDecimal{#1} {\qty[ exponent-mode = fixed, fixed-exponent = 0, drop-exponent=true, drop-zero-decimal=true, round-mode=places, round-precision =2]{#1e2}{\percent} } {#1} }

\begin{document}

\IfDecimal{0.05479140921}{true}{false} \IfDecimal{0.0547914092}{true}{false}

\num{0.054791409210}

\SomePerc{0.05479140921} \SomePerc{0.0547914092}

\end{document}

The latex compiler says:

Number too big. \IfDecimal{0.05479140921}
Number too big. \SomePerc{0.05479140921}
Mombird
  • 13
  • Probably some xstring bug. I don't think this package is very actively developed though, so either roll your own or use something else e.g.. egreg's answer based on l3regex https://tex.stackexchange.com/questions/463814/check-whether-string-represents-valid-number-for-pgf# – user202729 May 20 '23 at 00:32
  • what exactly is the kind of input your \SomePerc is supposedly accepting? – user691586 May 20 '23 at 09:02

1 Answers1

2

The following defines \ifdecimal, an expandable, fastish test that works for arbitrarily big numbers and places. It works for both , and . as the decimal separator, and arbitrary many signs. Everything that has at least one digit, at most one decimal separator, and no spaces is considered a decimal number. The input is fully expanded then stringified, the result of which has to match the aforementioned rules.

\documentclass{article}

\makeatletter % needed to get a space inside of a definition \newcommand\exparg@o[2]{\expanded{\unexpanded{#1}\expandafter}\expandafter{#2}}

% the front facing macro \newcommand\ifdecimal[1] {% \expandafter\ifdecimal@space\detokenize\expanded{{#1}}\STOP \ifdecimal@true }

% true and false branching \let\ifdecimal@true@firstoftwo \long\def\ifdecimal@false#1\ifdecimal@true#2#3{#3}

% check has no spaces \exparg@o{\def\ifdecimal@space#1\STOP}% {% @firstofone{\ifdecimal@space@#1\STOP\ifdecimal@false} \STOP % <- space \ifdecimal@sign#1\MARK,\MARK } \def\ifdecimal@space@#1 #2\STOP{}

% strip leading signs \def\ifdecimal@sign#1% {% \ifdecimal@sign@#1-\ifdecimal@sign@true+#1\ifdecimal@sign@true +-\ifdecimal@dot#1% } \def\ifdecimal@sign@#1+-{} \def\ifdecimal@sign@true#1+-\ifdecimal@dot#2{\ifdecimal@sign}

% turn one , into a . and then remove one decimal marker \def\ifdecimal@dot#1,{\ifdecimal@dot@#1.} \def\ifdecimal@dot@#1.{\ifdecimal@healmark\ifdecimal@empty#1} \def\ifdecimal@healmark#1\MARK#2\MARK{#1\STOP}

% check is non-empty \def\ifdecimal@empty#1\STOP {% \ifdecimal@empty@\MARK#1\STOP\ifdecimal@false\MARK\STOP % the {0 \ifdecimal@done} works as the right delimiter to the input argument \ifdecimal@digits#1{0 \ifdecimal@done}% } \def\ifdecimal@empty@#1\MARK\STOP{}

% check only digits left \def\ifdecimal@digits#1% {% \ifnum9<1#1 \else \expandafter\ifdecimal@false \fi \ifdecimal@digits } \def\ifdecimal@done#1\ifdecimal@digits{\fi} \let\MARK\relax \let\STOP\relax \makeatother

% simple tests whether the macro works \newcommand\ASSERT[2] {% \begingroup \edef\tmpa{#2}% \def\tmpb{#1}% \expandafter \endgroup \ifx\tmpa\tmpb \else \GenericError{}{Assertion failed for \detokenize{#2}}{}{}% \fi }

\ASSERT{true}{\ifdecimal{0.}{true}{false}} \ASSERT{true}{\ifdecimal{.0}{true}{false}} \ASSERT{true}{\ifdecimal{0.0}{true}{false}} \ASSERT{true}{\ifdecimal{00}{true}{false}} \ASSERT{true}{\ifdecimal{+-+-+-+-00}{true}{false}} \ASSERT{false}{\ifdecimal{.}{true}{false}} \ASSERT{false}{\ifdecimal{+}{true}{false}} \ASSERT{false}{\ifdecimal{-}{true}{false}} \ASSERT{false}{\ifdecimal{+-}{true}{false}} \ASSERT{false}{\ifdecimal{+-.}{true}{false}} \ASSERT{false}{\ifdecimal{0+}{true}{false}} \ASSERT{false}{\ifdecimal{0.0.0}{true}{false}} \ASSERT{false}{\ifdecimal{a}{true}{false}}

\newcommand\five{5} \ASSERT{true}{\ifdecimal{\five}{true}{false}} \ASSERT{true}{\ifdecimal{\five .\five}{true}{false}} \ASSERT{true}{\ifdecimal{\empty .\five}{true}{false}} \ASSERT{false}{\ifdecimal{\five .\relax}{true}{false}}

\stop

Skillmon
  • 60,462