Verificando um número de ponto flutuante válido

Verificando um número de ponto flutuante válido

Quero fazer o seguinte: estou gerando um relatório que pode ser configurado para unidades imperiais ou métricas. Todos os valores estão originalmente em unidades métricas, portanto no caso de unidades imperiais todos os valores devem ser convertidos. Alguns valores podem ser N/A ou qualquer outro valor de string, caso o valor não seja aplicável. O documento é gerado automaticamente. Para conversão estou usando o pacote fp, mas o desafio é verificar a entrada. O pacote fp (e pgfmath) certamente irá errar se você tentar fazer contas com valores não numéricos. Isto é o que tenho atualmente (funciona apenas para entrada de números inteiros)

% 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
}

Usando pgfmath alguém poderia fazer algo assim

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

Mas não consigo definir o manipulador de erros do pgfmath para gerar NaN no caso de entrada incorreta para pgfmathfloatparsenumber

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

Obrigado por qualquer ajuda!

Responder1

Você também pode usar \IfDecimaldeo xstringpacote:

insira a descrição da imagem aqui

Código:

\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}

Responder2

ATUALIZADO para lidar com negativos.

Uma chamada para \testrealconfigura um loop recursivo que verifica cada byte da string.

Primeiro, ele remove um negativo inicial, se existir, pois isso não afetará se o restante da string é ou não um número real válido.

Com o que resta, aqui está como procede. Ele observa que nenhum dígito nem ponto decimal foi encontrado na string, mas assume que é um número real válido.

Percorrendo cada byte sucessivo, o teste alternará para o estado "falha" se localizar um não-decimal e um não-dígito. O teste também falhará se encontrar duas casas decimais na string. Mas mesmo que ambos os testes sejam aprovados, ele deve ter encontrado pelo menos um dígito para passar no teste.

\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} 

insira a descrição da imagem aqui

Responder3

datatoolfornece condicionais para testar se um argumento é numérico ou não:

insira a descrição da imagem aqui

\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}

Existe \DTLisnumericale \DTLifnumerical. Veja a seção2.2 condicionais ifthen(pág. 16) dodatatoolguia de usuario.

Responder4

Não entendi bem qual é sua intenção, mas aqui está um exemplo rápido de como encontrar soluções PGF.

\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}

Isso vai dar

NaN

NaN

39.37007

nan

informação relacionada