# How to format a number with an error?

I'm having a surprising amount of difficulty in trying to format some numbers with errors. I can't find any previous attempts to do this here or elsewhere and it would surely be of use to the community.

I have some number-error pairs: {12345.6789, 0.0012345} which I would like to convert to strings with both the number and the error rounded to the same number of decimal places, such that the error has a precision of two significant figures.

f[{12345.6789, 0.03456}]
f[{12345.6789, 3.456}]
f[{12345.6789, 345}]


"12345.679 ± 0.035"

"12345.7 ± 3.5"

"12340 ± 350"

I'm struggling to get this done with RealDigits, N, NumberForm, StringRiffle and others.

Can anyone produce a robust working implementation of f?

Edit: Additional test cases

There are quite a few subtly different behaviours when handling different number, including rounding, adding trailing zeros, handling precision = 0, and probably others. Therefore for the sake of comprehensively testing implementations here are a list of inputs and the required outputs (if you can think of any additional useful test cases then let me know / add them):

f[{12.3456, 0.0123}]     ->     "12.346 ± 0.012"
f[{12.3456, 0.123}]      ->     "12.35 ± 0.12"
f[{129.3456, 1.23}]      ->     "129.3 ± 1.2"
f[{-129.3456, 12.3}]     ->     "-129. ± 12."
f[{12.9999, 0.02}]       ->     "13.000 ± 0.020"
f[{1, 100}]              ->     "0 ± 100."
f[{-1, 100}]             ->     "0 ± 100."
f[{12345.6789, 345}]     ->     "12350. ± 340."
f[{12345.6789, 3456}]    ->     "12300. ± 3500."

• It seems this is a duplicate: Expression of uncertainty in measurement. but your answer here is far superior so I'd mark the old one as a duplicate. Do you agree? – Kuba Dec 1 '16 at 8:55
• at 12.0 ,just use Around – wuyudi Jan 22 '20 at 4:17

## 4 Answers

### Update

This seems to do what you want a bit more simply than your own solution.

f[{a_, b_}] :=
NumberForm[
SetAccuracy[a ± b, Accuracy @ SetPrecision[b, 2]],
ExponentFunction -> (Null &)
] // ToString // Quiet


Your test:

f[{12.3456, 0.0123}]
f[{12.3456, 0.123}]
f[{129.3456, 1.23}]
f[{-129.3456, 12.3}]
f[{12.9999, 0.02}]
f[{1, 100}]
f[{-1, 100}]
f[{12345.6789, 345}]
f[{12345.6789, 3456}]


"12.346 ± 0.012"

"12.35 ± 0.12"

"129.3 ± 1.2"

"-129. ± 12."

"13.000 ± 0.020"

"0. ± 100."

"0. ± 100."

"12350. ± 340."

"12300. ± 3500."

• Nice - you'd think this would be native by now though. – alancalvitti Dec 1 '16 at 1:19
• Thanks, that seems to get most of the way there. In a couple of cases the output is not quite as I would want, for example f[{12.6789, 0.00123}] -> "12.6789 \[PlusMinus] 0.0012000000000000001" and although the answer for f[{12.9999, 0.02}] is correct ("13. \[PlusMinus] 0.02"), I'd like to include the relevant trailing zeros, eg "13.000 \[PlusMinus] 0.020". I'll have a proper look with this and @corey979's code later and try to form a fully robust solution, there are a lot of edge cases! Also the 345 being rounded to 340 I'm ok with, that's the normal banker's rounding of Round. – Quantum_Oli Dec 1 '16 at 7:53
• Thanks Mr.W, this works nicely. The only time I've spotted it fail is with an input along the lines of {0,0.01} which produces an output " -4\n0. \[Times] 10 \[PlusMinus] 0.010", however this is due to a failing in NumberForm ask discussed and circumvented here: mathematica.stackexchange.com/q/133065/6588 – Quantum_Oli Dec 9 '16 at 11:29
f[{a_, b_}, prec_] :=
Block[{x = {a, b}, y}, y = SetAccuracy[x, prec];
ToString @ y[] <> " ± " <> ToString @ y[]]

f[{12345.6789, 0.0012345}, 4]


"12345.679 ± 0.001"

f[{12345.6789, 3.456}, 2]


"12345.7 ± 3.5"

f[{12345.6789, 345}, 1]


"12346. ± 345."

f[Round[#, 5]& @ {12345.6789, 345}, 1]


"12345. ± 345."

• I hadn't come across SetAccuracy before. I would want trailing zeros where needed, for example f[{12345.6789, 0.0012345}, 4] should be "12345.6790 ± 0.0010". Also it struggles with some precisions, eg: f[{12345.6789, 12.345}, 0] comes out at a mess. – Quantum_Oli Nov 30 '16 at 19:36
• Then do f[Round[#, 0.001] &@{12345.6789, 0.0012345}, 5] - yields "12345.6790 ± 0.0010". Rounding is one thing that can be done on the input itself; I focused on adressing the issue of displaying given number of digits. Also, SetAccuracy is probably designed differently than what you think. – corey979 Nov 30 '16 at 19:44

Building on @Mr.Wizard♦ 's answer I have come up with the following. I use SetPrecision to set the significant figures of the error to two (ala Mr.W). I then use RealDigits, which tells me about the number of significant figures either side of the decimal place, to calculate the necessary precision for the number, a. I can the use SetPrecision again, instead of Round, but I have to catch, using If, the cases where the required precision is $\le 0$.

I avoid using InputForm as I think this is what leads to the 0.0012000000000000001 problem. But I do use NumberForm to convert 1.*10^2 to 100.. The Quiet is there to turn off the warning about the presence of trailing zeros - which I actually want!

My function:

f[{a_, b_}] := Module[{aa, bb, p},
bb = SetPrecision[b, 2];
p = Last[RealDigits[a]] - Last[RealDigits[bb]] + 2;
aa = If[p > 0, SetPrecision[a, p], 0];
Quiet[
ToString@
NumberForm[PlusMinus @@ {aa, bb}, ExponentFunction -> (Null &)],
{NumberForm::sigz}
]
]


This passes all the test cases I have outlined so far above, please let me know if you find any tests you think it fails. And obviously if you find a more elegant implementation!

f[{12.3456, 0.0123}]
f[{12.3456, 0.123}]
f[{129.3456, 1.23}]
f[{-129.3456, 12.3}]
f[{12.9999, 0.02}]
f[{1, 100}]
f[{-1, 100}]
f[{12345.6789, 345}]
f[{12345.6789, 3456}]


"12.346 ± 0.012"

"12.35 ± 0.12"

"129.3 ± 1.2"

"-129. ± 12."

"13.000 ± 0.020"

"0 ± 100."

"0 ± 100."

"12350. ± 340."

"12300. ± 3500."

• Please see my updated answer. I borrowed your use of ExponentFunction to replace the poorly chosen InputForm. – Mr.Wizard Dec 2 '16 at 22:57

This extends Mr. Wizard's answer to handle large/small numbers:

printNumberError[a_, b_] :=
Block[{exponent = Floor[Log[10, Abs[a]]],
sas = SetAccuracy[#1, Accuracy[SetPrecision[#2, 2]]] &},
If[exponent < 6 && exponent > -4,
NumberForm[sas[Row[{a, "±", b}, " "], b],
ExponentFunction -> (Null &)],
Block[{aa = a/10^exponent, bb = b/10^exponent},
Row[{"(", sas[aa, bb], "±", sas[bb, bb], ")",
"×", Superscript[10, exponent]}, " "]]]];


For example:

printNumberError[-6.390809*10^-6, 3.4485*10^-8]


Gives:

$$(-6.391\pm0.034)\times10^{-6}$$

• Good addition; thanks. I suggest making the SetAccuracy[a, Accuracy[SetPrecision[b, 2]]] operation a function to reduce repetition in this code. I can edit that in if you like. – Mr.Wizard Jan 22 '20 at 15:51
• Good point ... updated my code. – Brett van de Sande Jan 24 '20 at 6:09
• @Mr.Wizard ... Also, I generally keep my Mma code in plain text (*.m) files so that I can use source control in a meaningful way. Thus, special characters like $\pm$ are problematic. – Brett van de Sande Jan 24 '20 at 6:17
• There is a difference between "private" Mathematica characters and standard characters that Mathematica uses. ± is part of the latter and it should work fine in plain text. Have you actually experienced problems or did you assume it would not work? – Mr.Wizard Jan 24 '20 at 9:37
• I did a test and git (on Ubuntu) does handle both "±" and "×" without issue. – Brett van de Sande Jan 25 '20 at 17:32