# pgfmath: rounded number without pgfmathprintnumber

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}

• 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
• Just for comparison: In xfp the following works out of the box: \fpeval{round(0.09, 2)}. May 25, 2021 at 19:21

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}

• 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. May 25, 2021 at 19:39

Why not with xfp package?

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


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}%
\iffounddot\errtrue\fi\founddottrue\setcounter{decs}{0}}% IF .
{\tctestifnum{##1>/}%
{\tctestifnum{##1<:}%
{%
\iffounddot\stepcounter{decs}\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
\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}


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}


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

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