[pstricks] Suggestions for \psPrintValue

Michael Sharpe msharpe at ucsd.edu
Mon Apr 27 04:15:25 CEST 2009


On Apr 26, 2009, at 1:42 PM, Buddy Ledger wrote:

>> Buddy, it's a good idea! But there is one thing left. When usind
>> descimals=2 you should always get two decimals 12.799344 -> 12.80,
>> but your solution gives 12.8. However, I changed the code to take the
>> comma and algebraic option into account.
>
> Herbert,
>
> That is great! Thanks.
>
> I've been trying to incorporate another option, where horizontal space
> can be preserved to create compound objects without the need for  
> manual
> makebox{} commands.  My attempts have been unsuccessful, but I think  
> it
> is possible.  knowing \psk at decimals and \psk at fontscale we should be  
> able
> to calculate the space required for the \psPrintValue object.  For
> scientific notation the character space required is roughly
> 3+\psk at decimals+floor(log(expon))+1 and for regular numbers
> floor(log(#))+\psk at decimals (FP package crashed on me when trying
> this).  This could also be done with count registers if you could read
> an input value one character at a time and test for decimal point or  
> "E"
> along the way (I don't know how to do this).
>
> The motivation here is to allow \psPrintValue to mesh properly with  
> text
> or other \psPrintValue objects.  I've included an example of my failed
> attempt at a generic solution.  As well I have included another  
> routine
> which demontrates what I want to be able to achieve, this routine is
> very specific and would have to be re-written to achieve different
> output, whereas if a space preservation option was possible within
> \psPrintValue generic objects could be created using the basic
> \psPrintValue routine.


You might get some ideas from the appended file, which gives a way to  
round a number given in either conventional form or in formats like  
1.23E-04 or -12.34e005, to a fixed number of decimal places. It works  
entirely at the TeX level, so there is no need to call \psPrintValue  
unless you have a number that is the result of a Postscript  
computation. This is not a completed package---the handling of the  
case where \decplaces<0 in not yet finished. Also, the size of numbers  
handled is limited. The string of output digits, not counting the  
period and sign, must be no more than 2^{31}, as it is stored in a  
single count register, unlike the fp package. The other thing is that  
\decplaces should have been handled as a keyword. See the end of the  
file for usage and test examples.

Michael

\documentclass{article}
\usepackage{pstricks-add}
\makeatletter
\newcount\my at cnta
\newcount\my at cntb
\newcount\my at cntc
\newcount\my at cntn
\newcount\my at cntx
\newcount\my at cnty
\newcount\my at cntz
%
\def\decplaces{1}
\newif\if at period
\let\@tmpA\@empty
\let\@tmpB\@empty
\newif\if at anE
\newif\if at neg
%
\def\hasnegsign#1-#2\@nil{%check if expression contains .--call with  
\hasnegsign#1-\@nil
% Check for value of \my at cntz to determine if exponent present
\xdef\@tmpA{#1}%
\xdef\@tmpB{#2}%
\ifx\@tmpB\@empty\@negfalse \else %
%remove neg from end of \@tmpB
\expandafter\removeneg\@tmpB %
\@negtrue\fi}%
%
\def\removeneg#1-{\xdef\@tmpA{#1}}%
%
\def\hasperiod#1.#2\@nil{%check if expression contains .--call with  
\hasperiod#1.\@nil
% Check for value of \my at cntz to determine if exponent present
\xdef\@tmpA{#1}%
\xdef\@tmpB{#2}%
\ifx\@tmpB\@empty\@periodfalse \else %
%remove period from end of \@tmpB
\expandafter\removeper\@tmpB %
\@periodtrue\fi}%
%
\def\removeper#1.{\xdef\@tmpB{#1}}%
%
\def\hasanE#1E#2\@nil{%check if expression contains an E--call with  
\hasanE#1E\@nil
\xdef\@tmpA{#1}%
\xdef\@tmpB{#2}%
\ifx\@tmpB\@empty %try lower case
   \expandafter\hasane\@tmpA e\@nil %
   \ifx\@tmpB\@empty \@anEfalse %
   \else %
     \@anEtrue %
     \expandafter\removee\@tmpB %
   \fi %
\else %
   %remove E from end of \@tmpB
   \expandafter\removeE\@tmpB %
\@anEtrue\fi}%
%
\def\hasane#1e#2\@nil{%check if expression contains an e--call with  
\hasane#1E\@nil
\xdef\@tmpA{#1}%
\xdef\@tmpB{#2}%
}%
%
\def\removeE#1E{\xdef\@tmpB{#1}}%
\def\removee#1e{\xdef\@tmpB{#1}}%

\def\get at length#1#2\@nil{%
\def\@@tmp{#2}\ifx#1\@empty\else\advance\my at cntx by\@ne \ifx\@@tmp 
\@empty\else\get at length#2\@nil \fi\fi %
}%
%
\def\fmtnum#1{%#1=number
\my at cntn=0 %
\hasanE#1E\@nil %checks if e/E format
\if at anE %\mantissa in \@tmpA, exponent in \@tmpB
   \my at cntn=\@tmpB \fi%
\expandafter\hasnegsign\@tmpA-\@nil %set \@negtrue if neg, abs val in  
\@tmpA
\expandafter\hasperiod\@tmpA.\@nil %
\my at cntx=0 %
\ifx\@tmpA\@empty\my at cntx=\z@ \else\expandafter\get at length\@tmpA\@nil  
\fi%
\my at cntz=\my at cntx %length of pre-.
\my at cntx=0 %
\ifx\@tmpB\@empty\my at cntx=\z@ \else\expandafter\get at length\@tmpB\@nil  
\fi%
\my at cnty=\my at cntx %length of post-.
\ifnum\my at cntn=0 % do nothing
\else %
   \advance\my at cntx\my at cntz %total length
   \advance\my at cnty by-\my at cntn %
   \advance\my at cntz\my at cntn %new length of pre-.
   \ifnum\my at cntz<\z@ %
     \advance\my at cntx by -\my at cntz %
     \edef\@tmpB{\@tmpA\@tmpB}%
     \let\@tmpA\@empty %
     \loop\edef\@tmpB{0\@tmpB}\advance\my at cntz\@ne %
      \ifnum\my at cntz<\z@ \repeat % cntz=0 at end of loop
      \my at cnty=\my at cntx %
   \else %
     \ifnum\my at cntz>\my at cntx %
       \let\@tmpB\@empty %
       \my at cnty=\z@ %
       \my at cnta=\my at cntz %
       \edef\@tmpA{\@tmpA\@tmpB}%
       \loop\edef\@tmpA{\@tmpA0}\advance\my at cnta\m at ne %
        \ifnum\my at cnta>\my at cntx \repeat %
     \else %period is somewhere inside string
       \edef\@nxtB{\@tmpA\@tmpB}%
       \@splitstring{\@nxtB}{\my at cntz}
       \let\@tmpA\@nxtA %
       \let\@tmpB\@nxtB %
     \fi %
   \fi %
\fi %
\my at cnta=\decplaces \relax%
\ifnum\my at cnta<0 %leave as is
\else
   \ifnum\my at cnty<\decplaces \relax%
     \loop\edef\@tmpB{\@tmpB0}\advance\my at cnty\@ne %
     \ifnum\my at cnty<\my at cnta\repeat %
\else % rounding code
    \ifnum\my at cnty>\decplaces \relax%round off \@tmpB
   \let\my at tempa\@empty %
   \edef\@nxtB{\@tmpA\@tmpB} %
    \my at cntb=\my at cntz \advance\my at cntb\decplaces \relax%
   \@splitstring{\@nxtB}{\my at cntb}%
   \ifx\@nxtA\@empty\my at cnta=0 \else\my at cnta=\@nxtA \fi%
   \expandafter\nextchar\@nxtB\@nil %
   \my at cntc=\@nxtA \relax%first digit in what's cut off
   \ifnum\my at cntc >4\relax \advance\my at cnta\@ne \fi %
   \edef\@nxtB{\the\my at cnta}%
    \my at cntx=\z@ %
    \expandafter\get at length\@nxtB\@nil %
    \ifnum\my at cntx<\decplaces\relax %
      \loop\edef\@nxtB{0\@nxtB}\advance\my at cntx\@ne \ifnum\my at cntx< 
\decplaces\relax\repeat \fi%
     \my at cntz=\my at cntx \advance\my at cntz -\decplaces\relax%
     \@splitstring{\@nxtB}{\my at cntz}%
     \let\@tmpA\@nxtA\let\@tmpB\@nxtB%
\fi \fi \fi %
\my at cnta=\decplaces \relax%
\ifx\@tmpA\@empty \edef\@tmpA{0}\fi %
\edef\@tmpA{\if at neg-\fi \@tmpA}%
\ifnum\my at cnta<0\relax%
   #1%
\else %
   \ifnum\my at cnta=\z@ %
     \@tmpA %
   \else %
     \@tmpA.\@tmpB %
\fi\fi %
}%
\def\@splitstring#1#2{%#1=string, #2=position to split at
%results returned in \@nxtA, \@nxtB, no padding
\my at cntb=#2 %
\let\@nxtA\@empty %
\xdef\@nxtB{#1}%
\let\my at tempa\@empty %
\ifnum\my at cntb>\z@ %
\loop\expandafter\nextchar\@nxtB\@nil \edef\my at tempa{\my at tempa\@nxtA} 
\advance\my at cntb\m at ne\ifnum\my at cntb>0\repeat %
\let\@nxtA\my at tempa \fi}%
%
\def\nextchar#1#2\@nil{%
\def\@nxtA{#1}\def\@nxtB{#2}%
}%
\makeatother
\begin{document}
\def\decplaces{2}
Test \verb|\fmtnum| macro
\vspace{1cm}

\begin{tabular}{lr}\hline
Unformatted & Formatted\\\hline
12E-02 & \fmtnum{12E-02}\\
-12e04 & \fmtnum{-12e04}\\
-127.415 & \fmtnum{-127.415}\\
99.995 & \fmtnum{99.995}\\
.01267 & \fmtnum{.01267}\\
1.267E-02 & \fmtnum{1.267E-02}\\
-12.6 &\def\decplaces{0} \fmtnum{-12.6}\\
123456789.60 &\def\decplaces{0}  \fmtnum{123456789.60}\\\hline
\end{tabular}

\end{document}



More information about the PSTricks mailing list