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}

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.