13

I want to do the following: I am generating a report which can be set to be in imperial or metric units. All values are originally in metric units, so in the case of imperial units all values should be converted. Some values can be say N/A or any other string value, in case the value is not applicable. The document is automatically generated. For conversion I am using the fp package, but the challenge is the checking the input. The fp package (and pgfmath) will ofcourse) err if you try to do math with non-numerical values. This is what I currently have (only works for integer input)

% Convert meters to inches
\newcommand{\convertmtoin}[2]
{
    \if!\ifnum9<1#1!\else_\fi   
    \FPeval{val}{#1*39.3700787} \FPround{\val}{\val}{#2}
    \else
    \def\val{#1}
    \fi
}

Using pgfmath one could do something like this

\newcommand{\convertmtoin}[2]
{
    \pgfmathfloatparsenumber{#1}
    \pgfmathfloatifflags{\pgfmathresult}{3}{\FPeval{val}{#1*39.3700787} \FPround{\val}{\val}{#2}}{\def\val{#1}} 
}

But I am not able to set the error handler of pgfmath to output NaN in the case of erronous input to pgfmathfloatparsenumber

\pgfkeys{/pgf/fpu/handlers/invalid number={??}{??}}

Thanks for any help!

6

You can also use \IfDecimal from the xstring package:

enter image description here

Code:

\documentclass{article}
\usepackage{xstring}

\newcommand*{\CheckIfNumerical}[1]{%
    \IfDecimal{#1}{%
        ``#1" is a number.%
    }{%
        ``#1" is NOT a number.%
    }%
}%


\begin{document}
\par\CheckIfNumerical{7}
\par\CheckIfNumerical{3.14}
\par\CheckIfNumerical{NaN}
\par\CheckIfNumerical{7. 0}
\par\CheckIfNumerical{7.0X09}
\end{document}
3

datatool provides conditionals for testing whether an argument is numerical or not:

enter image description here

\documentclass{article}
\usepackage{datatool}% http://ctan.org/pkg/datatool
\newcommand{\testreal}[1]{\ifthenelse{\DTLisnumerical{#1}}{T}{F}}
\begin{document}

\testreal{just}

\testreal{123John}

\testreal{324.56}

\testreal{.}

\testreal{23.4.56}

\testreal{346}
\end{document}

There is \DTLisnumerical and \DTLifnumerical. See section 2.2 ifthen conditionals (p 16) of the datatool user guide.

3

UPDATED to handle negatives.

A call to \testreal sets up a recursive loop that checks every byte in the string.

First, it strips off a leading negative, if it exists, since that will not affect if the remainder of the string is or is not a valid real number.

With what remains, here is how it proceeds. It notes that no digit nor decimal point has yet been found in the string, but assumes that it is a valid real number.

Going through each successive byte, the test will toggle to the "fail" state if it locates a non-decimal, non-digit. The test will also fail if it finds two decimal points in the string. But even if both those tests are passed, it must have found at least one digit, to pass the test.

\documentclass[]{article}

\def\testreal#1{\def\founddigit{F}\def\itsanumber{T}\def\fndpt{F}%
  \edef\tmp{\testleadneg#1\relax}%
  \expandafter\testrealhelper\tmp\relax%
  \if T\founddigit\itsanumber\else F\fi}

\def\testrealhelper#1#2\relax{%
\if.#1\if T\fndpt\def\itsanumber{F}\else\def\fndpt{T}\fi\else
\if1#1\FD\else
\if2#1\FD\else
\if3#1\FD\else
\if4#1\FD\else
\if5#1\FD\else
\if6#1\FD\else
\if7#1\FD\else
\if8#1\FD\else
\if9#1\FD\else
\if0#1\FD\else\def\itsanumber{F}%
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
\if\relax#2\else\testrealhelper#2\relax\fi}

\def\testleadneg#1#2\relax{\if-#1#2\else#1#2\fi}

\def\FD{\def\founddigit{T}}
\begin{document}
\testreal{just}    \testreal{-just}

\testreal{123John} \testreal{-123John}

\testreal{324.56}  \testreal{-324.56}

\testreal{.}       \testreal{-.}

\testreal{23.4.56} \testreal{-23.4.56}

\testreal{346}     \testreal{-346}
\end{document} 

enter image description here

1

I didn't quite get what your intention is but here is a quick example for coming up with PGF solutions.

\documentclass[]{article}
\usepackage{pgf}
\usepgflibrary{fpu}

\pgfmathdeclarefunction{m2in}{1}{%
\begingroup
\pgfkeys{/pgf/fpu}
\pgfmathfloatparsenumber{#1}
\pgfmathfloatifflags{\pgfmathresult}{3}{%True Not a number
    \def\pgfmathresult{3Y0.0e0]}%
    \pgfmathfloattofixed{\pgfmathresult}%
    }{% False it is a number including inf
    \pgfmathfloatparsenumber{#1}%
    \pgfmathfloatmultiplyfixed{\pgfmathresult}{39.3700787}%
    \pgfmathfloattofixed{\pgfmathresult}%
    }
    \pgfmathsmuggle\pgfmathresult%
\endgroup
}%

\pgfkeys{/pgf/fpu/handlers/invalid number/.code={%
  \pgfmathfloatparsenumber{3Y0.0e0]}%
  }
}

\begin{document}
\pgfmathfloatparsenumber{435...}% NaN
    \pgfmathprintnumber[fixed]{\pgfmathresult}

\pgfmathfloatparsenumber{la la laa}% NaN
    \pgfmathprintnumber[fixed]{\pgfmathresult}

\pgfmathparse{m2in(1.000)}\pgfmathprintnumber[fixed,precision=5]\pgfmathresult

\pgfmathparse{m2in(4..4)}\pgfmathresult
\end{document}

This will give

NaN

NaN

39.37007

nan

  • Is it possible to put out the content, instead of NaN? – cis Oct 21 '18 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.