In some ways this is an extension of my answer here. To understand how Precision
, works it helps to understand how floating point numbers work and how error is propagated. I don't wish to give a full explanation of the subject. It can be sought out elsewhere, such as in a book on numerical analysis. But I will show how one can calculate the precision of an expression out for oneself.
As explained in the tutorial Numerical Precision, an arbitrary-precision Real
number in Mathematica represents a real value with a specified uncertainty encoded in its Precision
lying in a interval $[x - dx, x+ dx]$. The precision $p$ is related to the uncertainty $dx$ by
$$ p = -\log_{10}\left({dx \,\big/\,\left|x\right|} \right)\,.$$
The rules for computing the uncertainty of a calculation $y = f(x_1, x_2, \dots)$ basically come down to computing via differentials
$$dy = \left|{\partial f\over\partial x_1}(x_1,x_2,)\right|\;dx_1 +
\left| {\partial f\over\partial x_x}(x_1,x_2,\dots)\right|\;dx_2 +\cdots$$
At least computing the uncertainty this way seems to agree very closely with Mathematica.
Below are functions for calculating the uncertainty
and precision
of an expression evaluated at approximate real values passed as replacement rules in the argument x0
. Note that in Mathematica, MachinePrecision
corresponds to "complete unknown precision," at least in the sense that precision is not tracked. I represent that by a precision of Infinity,
which examples show is how MachinePrecision
is treated in the calculation of Precision
of expressions.
If for a simple example we take the expression x y
, the differential is given by
Dt[x y]
(*
y Dt[x] + x Dt[y]
*)
Filling in the absolute values ourselves, we can see that the uncertainty depends on the magnitudes of x
and y
and their uncertainties, represented by Dt[x]
and Dt[y]
. The precision, roughly speaking, is the relative error this represents, expressed as the number of decimal digits that are taken to be correct. One of the OP's examples is of the form x / Sqrt[y]
, whose differential is
Dt[x/Sqrt[y]]
(*
Dt[x]/Sqrt[y] - (x Dt[y])/(2 y^(3/2))
*)
Here, if we fill in the absolute values, we get
Dt[x/Sqrt[y]] /. Times[dx_Dt, rest__] :> Abs[Times[rest]] dx
(*
Dt[x]/Sqrt[Abs[y]] + 1/2 Abs[x/y^(3/2)] Dt[y]
*)
which again shows how the uncertainty, and hence the precision, depends on the numbers.
Clear[uncertainty, precision];
uncertainty[x_Real /; Precision[x] === MachinePrecision] := Infinity;
uncertainty[x_Real] := Abs[x] 10^-Precision[x];
uncertainty[x_ /; Precision[x] == Infinity] := 0;
uncertainty[expr_, x0_List] :=
Expand@Dt[expr] /. Times[dx_Dt, rest__] :> Abs[Times[rest]] dx /.
Thread[Dt /@ First /@ x0 -> (uncertainty /@ Last /@ x0)] /. x0;
precision[expr_,
x0_List] := -Log10[uncertainty[expr, x0]/ReplaceAll[expr, x0]];
The examples below verify that the uncertainty follows the formula for the differential,
2.0 * uncertainty[3.0`3] + 3.0 * uncertainty[2.0`2]
uncertainty[x y, {x -> 3.0`3, y -> 2.0`2}]
(*
0.066
0.066
*)
and if MachinePrecision
numbers enter into a calculation, the result has MachinePrecision
(that is, an unknown uncertainty or Infinity
).
uncertainty[x y, {x -> 3.0, y -> 2.0`2}]
(*
Infinity
*)
The calculations of precision
and the built-in Precision
agree.
precision[x y, {x -> 3.0`3, y -> 2.0`2}] // FullForm
Precision[3.0`3 * 2.0`2] // FullForm
(*
1.958607314841775`
1.958607314841775`
*)
They also agree in the x / Sqrt[y]
example,
precision[x/Sqrt[y], {x -> 0.9`15, y -> 3.`2}] // FullForm
Precision[x/Sqrt[y] /. {x -> 0.9`15, y -> 3.`2}] // FullForm
(*
2.301029995663894`
2.301029995663894`
*)
even when they appear not to agree.
precision[x/Sqrt[y], {x -> 0.9`15, y -> 3.`3}] // FullForm
Precision[x/Sqrt[y] /. {x -> 0.9`15, y -> 3.`3}] // FullForm
% === %%
(*
3.3010299956631126`
3.301029995663113`
True
*)
50]] == MachinePrecision but Precision[0.9
50*Sqrt[3]] == 50? The most significant odd case for me is that Precision[0.9*3.050] is also MachinePrecision but there is symmetry of form between 0.9 and 3.0 so why do 0.9
50 and 0.9*3.0`50 have different precisions? And for Precision[3.0*2.0] it doesn't matter where the precision spec is attached, the answer in both cases is MachinePrecision. Confused. $\endgroup$