4

enter image description here

If I have a decimal number, say 0.09155, but I want to display a rounded version with two digits after the point: 0.09.
The standard way is to use \pgfmathprintnumber[fixed, precision=2]{0.09155}.

So my question is: can I get the wanted value, here 0.09, by pgfmath-calculation, that means without using pgfmathprintnumber?

\documentclass[margin=5pt, varwidth]{standalone}
\usepackage{tikz}
\begin{document}
\pgfmathsetmacro\x{0.09155}

$x = \x$, but 
$x \approx \pgfmathprintnumber[fixed, precision=2]{\x}$
\end{document}
4
  • 2
    Like \pgfmathsetmacro\xx{int(\x*100)/100} you mean? Don't know if it will always work though, or if you'll get ...999999 or ....0000001 in some cases. (Why not use \pgfmathprintnumber?) May 25, 2021 at 16:56
  • It could work like int(100*(\x-frac(100*\x)/100))/100. PS: Why or why not is not the question here. It's good to have a working solution for this. It is not always possible to predict when these will be needed.
    – cis
    May 25, 2021 at 18:06
  • Realized you need round, not int, but anyways: your version doesn't always give the correct results, and mine gives e.g. 0.06999 instead of 0.07. Try this for example: \documentclass[margin=5pt, varwidth]{standalone} \usepackage{tikz} \begin{document} \pgfmathsetseed{42} \foreach\i in {1,...,100}{\pgfmathsetmacro\x{rnd}\pgfmathsetmacro\xx{round(\x*100)/100}\pgfmathsetmacro\xxx{round(100*(\x-frac(100*\x)/100))/100}$x = \x$, but $x \approx \pgfmathprintnumber[fixed, precision=2]{\x}$ and $x\approx \xx$ and $x\approx \xxx$ \\}\end{document} May 25, 2021 at 19:18
  • 1
    Just for comparison: In xfp the following works out of the box: \fpeval{round(0.09, 2)}.
    – Skillmon
    May 25, 2021 at 19:21

4 Answers 4

3

The following defines a roundn function for pgfmath that takes two arguments, one being the number to be rounded, the second being the number of places you want the number to round to.

\documentclass[]{article}

\usepackage{pgfmath}
\pgfmathsetmacro\x{0.09155}
\pgfmathdeclarefunction{roundn}{2}
  {\pgfmathparse{round(#1 * 10^(#2)) / (10^(#2))}}

\begin{document}
$x = \x$, but
$x \approx \pgfmathparse{roundn(\x,2)}\pgfmathresult$
\end{document}
2
  • Precision is a problem, so you get e.g. 0.239999 instead of 0.24, but I guess there's nothing to do about that with pgf alone. May 25, 2021 at 19:31
  • @TorbjørnT. well, that's the problem with floating point numbers, they can't have arbitrary values.
    – Skillmon
    May 25, 2021 at 19:39
4

Why not with xfp package?

screenshot

\documentclass[margin=5pt, varwidth]{standalone}
\usepackage{tikz}
\usepackage{xfp}
\begin{document}
\pgfmathsetmacro\x{0.09155}

$x = \x$, but 
$x \approx \pgfmathprintnumber[fixed, precision=2]{\x}$

\bigskip
With xfp package:

$x = \x$, but 
$x \approx \fpeval{round(\x,2)}$

\end{document}
3

Here's a home-grown version with tokcycle (i.e., no pgf). It rounds to a level specified in \savedigits.

\documentclass{article}
\usepackage{tokcycle}
\newcounter{decs}
\def\savedigits{2}
\newif\iferr
\newif\iffounddot
\newcommand\roundit[1]{%
  \errfalse
  \setcounter{decs}{0}%
  \founddotfalse% MADE T WHEN DECIMAL HAS BEEN 1ST LOCATED
  \tokcycle% CYCLE THROOUGH EACH TOKEN
  {\tctestifx{.##1}%
   {\addcytoks{##1}%
    \iffounddot\errtrue\fi\founddottrue\setcounter{decs}{0}}% IF .
   {\tctestifnum{`##1>`/}%
    {\tctestifnum{`##1<`:}%
     {%
       \iffounddot\stepcounter{decs}\fi%
       \ifnum\thedecs<\savedigits\relax\addcytoks{##1}\else
       \ifnum\thedecs=\savedigits\relax\addcytoks{\roundlast ##1}\else
       \ifnum\thedecs=\numexpr\savedigits+1 \addcytoks{##1}\fi\fi\fi
     }%
     {\errtrue}% IF ASCII > `9
    }%
    {\errtrue}% IF ASCII < `0
   }%
  }% APPLY ABOVE LOGIC FOR CHAR TOKENS
  {\errtrue}% IF BRACES
  {\errtrue}% IF CONTROL SEQUENCE
  {}% IGNORE SPACES
  {#1}% THE ARGUMENT
  \addcytoks{\space}
  \iferr ERROR\else\the\cytoks\fi
}
\newcommand\roundlast[2]{\ifnum0#2>4 \the\numexpr#1+1 \else#1\fi}
\begin{document}
\noindent
0) \roundit{0.09155}\\
1) \roundit{12.3}\\
2) \roundit{0.127}\\
3) \roundit{1.2.3}\\
4) \roundit{1.3\today}\\
5) \roundit{321.345 678}\\
6) \roundit{000321.305}\\
7) \roundit{.006 300 345}\\
8) \roundit{0003x1.345}\\
9) \roundit{1230}\\
9a) \roundit{1230.}\\
A) \roundit{123.078}\\
B) \roundit{0003;345}\\
\end{document}

enter image description here

If you don't mind dispensing with the error checking, here is a different token cycle that employs a new (2021-05-27) feature to look-ahead at the input stream pushing and popping tokens as needed, as well as to truncate the cycle based on what occurs inside the cycle.

\documentclass{article}
\usepackage{tokcycle}[2021-05-27]
\newcommand\roundit[1]{\tokcycle
 {\ifx.##1.%
    \tcpop\tenths
    \tcpop\hundredths
    \tcpop\thousandths
    \ifnum 0\thousandths>4 
      \tenths\the\numexpr\hundredths+1 \else\tenths\hundredths\fi
    \tcpush{\noexpand\truncatecycle}%
  \else
    ##1%
  \fi
 }% DO THE ABOVE FOR EACH CHARACTER
 {\processtoks{\truncatecycle}}% IF GROUP
 {\truncatecycle}% IF MACRO
 {##1}% IF SPACE
 {#1}}
\begin{document}
\noindent
0) \roundit{0.09155}\\
1) \roundit{12.3}\\
2) \roundit{0.127}\\
5) \roundit{321.345 678}\\
6) \roundit{000321.305}\\
7) \roundit{.006 300 345}\\
9) \roundit{1230}\\
9a) \roundit{1230.}\\
A) \roundit{123.078}\\
\end{document}

enter image description here

1

Since pgfmath calculates imprecisely, it is better to use pgfmathprintnumber:

enter image description here

\documentclass[margin=5mm, varwidth]{standalone}
\usepackage{tikz}

\pgfmathdeclarefunction{roundn}{2}{%
\pgfmathparse{#1}%
\pgfmathparse{"\pgfmathprintnumber[fixed, precision=#2]{\pgfmathresult}"}%
}
\begin{document}
Test: \pgfmathparse{roundn(1.23456,2)}\pgfmathresult

Test: \pgfmathparse{roundn(sqrt(2),3)}\pgfmathresult
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .