# round-mode conditional on number size

I would like to give numbers with three decimals places of precision, unless they are so small that this would round them down to zero. In that case, I would like three significant figures instead.

Here is a minimal non-working example:

\documentclass{article}
\usepackage[round-mode=places,round-precision=3]{siunitx}
\begin{document}

\num{0.0437}  % gives 0.044

\num{0.00437} % gives 0.004

\num{0.000437}% I want this to give 0.000437

\end{document}


Right now I do it by overriding the settings from the preamble for any number that is small enough. So I'd replace \num with \num[round-mode=figures]. But I'd like to do it automatically if I can.

I read the source of siunitx.sty but I still don't grok LaTeX3-style programming. I'd appreciate any advice.

• I'm not sure how this can be mathematically defined… Commented Oct 1, 2021 at 12:40
• @egreg ‘If (number<0.001)....‘ Commented Oct 1, 2021 at 13:04
• This all feels very odd as the entire idea of rounding is to introduce consistency either in number of places or number of significant figures. Certainly at present it's not built-in to siunitx, so you'd need to code up your own approach. Commented Oct 6, 2021 at 5:42

Here's a LuaLaTeX-based solution. It defines a utility macro called \mynum which, in turns, calls a Lua function to do the actual work.

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{siunitx}
\sisetup{round-precision=3,group-digits=false,round-mode=places}

\usepackage{luacode} % for '\luaexec' macro
%% Lua-side code:
\luaexec{%
function mynum ( n )
if n<0.001 then tex.sprint ( "\\num[round-mode=figures]{"..n.."}" )
else tex.sprint ( "\\num{"..n.."}" )
end
end
}
%% LaTeX-side code:
\newcommand\mynum[1]{\directlua{mynum(#1)}}

\begin{document}
\num{0.0437},   \mynum{0.0437}   % both give 0.044

\num{0.00437},  \mynum{0.00437}  % both give 0.004

\num{0.000437}, \mynum{0.000437} % only \mynum gives 0.000437
\end{document}


Using just expl3 functions, and assuming v3 of siunitx to allow us to do this using the code-level API, we might go for

\documentclass{article}
\usepackage{siunitx}
\sisetup{round-precision=3,group-digits=false}
\ExplSyntaxOn
\NewDocumentCommand \mynum { O { } m }
{
\mode_leave_vertical:
\group_begin:
\keys_set:nn { siunitx } {#1}
\fp_compare:nNnTF {#2} < { 0.001 }
{ \keys_set:nn { siunitx } { round-mode = none } }
{ \keys_set:nn { siunitx } { round-mode = places } }
\siunitx_number_format:nN {#2} \l___siunitx_number_tmp_tl
\siunitx_print_number:V \l___siunitx_number_tmp_tl
\group_end:
}
\ExplSyntaxOff
\begin{document}
\num{0.0437},   \mynum{0.0437}   % both give 0.044

\num{0.00437},  \mynum{0.00437}  % both give 0.004

\num{0.000437}, \mynum{0.000437} % only \mynum gives 0.000437
\end{document}


using the demo from Mico's answer.

Note that the fp function here is limited to IEEE754 range/precision (e.g. 16 digits of mantissa), which may be an issue in some cases. (The core siunitx functions can handle arbitrary precision rounding.)