5

I'd like to understand why one of these inputs gives me an error and the other doesn't:

s1 = 
 NDSolve[
   {x'[t] == x[t], x[0] == SetPrecision[1., 10]}, 
   {x}, {t, 0, 1}, 
   WorkingPrecision -> $MachinePrecision
 ][[1]]

NDSolve::precw: The precision of the differential equation ({{(x^[Prime])[t]==x[t],x[0]==1.000000000},{},{},{},{}}) is less than WorkingPrecision (15.954589770191003`). >>

(* Out: {x -> InterpolatingFunction[{{0, 1.000000000000000}}, <>]} *)

versus

s2 = 
 NDSolve[
   {x'[t] == x[t], x[0] == SetPrecision[1., 10]}, 
   {x}, {t, 0, 1}, 
   WorkingPrecision -> MachinePrecision
 ][[1]]

(* Out: {x -> InterpolatingFunction[{{0., 1.}}, <>]} *)

Notice that the only difference is the fact that $MachinePrecision got changed to MachinePrecision. Also, oddly enough, the resulting answers are not identical:

x1[t_] = Evaluate[x[t] /. s1];
x2[t_] = Evaluate[x[t] /. s2];

Plot[x1[t] - x2[t], {t, 0, 1}]

plot

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Max
  • 1,050
  • 6
  • 14
  • 3
    Using $MachinePrecision in the current version of Mathematica forces the (admittedly counterintuitive in this case) use of the arbitrary-precision numerics. MachinePrecision is the right setting to use if you want to stay within machine precision computations, but you do run the risk of hitting instabilities if you are the unlucky sort. – J. M.'s missing motivation Jun 08 '16 at 05:13
  • If that's the case, why does changing the precision to 20 eliminate the error? Do you mean to switch those two statements? – Max Jun 08 '16 at 05:19
  • Again: the symbol with the dollar sign uses arbitrary precision, while the other one is the switch to use machine precision. Mull on this for a bit. Your use of SetPrecision[1., 10] is unfortunate in the former case, since 10 < $MachinePrecision, which is why you get the error observed. – J. M.'s missing motivation Jun 08 '16 at 05:24
  • 1
    This confused me for a bit as well. Here is how I understand it now; perhaps it will help you too. $MachinePrecision is the number of digits of precision that is roughly equivalent to running a native machine-precision calculation on your system. You can evaluate it, and it will return a real number, on my system for instance ca. 15.9. Now think of it this way: WorkingPrecision -> someNumber forces the use of the arbitrary precision engine, with someNumber digits of precision. ... – MarcoB Jun 08 '16 at 06:22
  • 1
    ... Similarly WorkingPrecision -> $MachinePrecision triggers the use of the arbitrary precision system, with a number of digits of precision that mimics the native machine's precision, but now with error tracking thanks to the arbitrary precision engine. A comparative example can be found in the "Possible Issues" section of the docs on $MachinePrecision. – MarcoB Jun 08 '16 at 06:24
  • 3
    Additionally arb.-prec. numbers use extra guard bits, so that rounding error is different with MachinePrecision & $MachinePrecision. – Michael E2 Jun 08 '16 at 07:02
  • I think I've stepped out of my depth here haha. @MarcoB's reference to the Possible Issues section of $MachinePrecision helped me formulate what it is I'm confused about: what's the difference between "machine number computations" and "machine number resolution"? Also, if I were to simply use WorkingPrecision -> 15.9546 (which =$MachinePrecision on my computer), would the internal behavior be the same as using $MachinePrecision, MachinePrecision, or neither? – Max Jun 08 '16 at 17:18
  • @Max I think there is no difference between the two, at least in the way I would use them. They both refer to fast, machine-precision calculations. Since $MachinePrecision evaluates to that number (15.9..), I fully expect that WorkingPrecision -> 15.9546 and WorkingPrecision -> $MachinePrecision will lead to the same results on your machine. – MarcoB Jun 08 '16 at 17:32

1 Answers1

6

I was looking for a previous question of which this might be a duplicate; although many previous discussions hinge on precision issues, and the difference has been mentioned in comments, I could not dredge up an explicit discussion of $MachinePrecision vs MachinePrecision through the SE search engine, so I thought I might sum up the discussion in comments, in hopes that it may be useful as an easier-to-find future reference.


The difference between MachinePrecision and $MachinePrecision took me some time to grasp at first. I also find that the documentation does a poor job of explaining the difference between the two. Here is how I understand it now; perhaps it will help others too.

$MachinePrecision is the number of digits of precision that is equivalent to running a native machine-precision calculation on your system (i.e. using machine numbers). You can evaluate it, and it will return a machine-precision real number:

$MachinePrecision
(* Out: 15.9546 *)

On the one hand, MachinePrecision is a switch to indicate that numerical functions should use machine numbers as implemented in the hardware of your particular computer, and no precision tracking. This is by far the fastest option, and it is chosen by default.

Now consider that setting WorkingPrecision -> someNumber forces the use of the arbitrary precision engine, with someNumber digits of precision and error tracking.

Similarly, then, WorkingPrecision -> $MachinePrecision triggers the use of the arbitrary precision system, with a number of digits of precision that mimics the native machine's precision, but now with error tracking thanks to the arbitrary precision engine.

A comparative example can be found in the "Possible Issues" section of the docs on $MachinePrecision.

Michael also mentioned in his comment that arbitrary-precision numbers use extra guard bits, so that rounding error is different between MachinePrecision and $MachinePrecision.


Here are a few relevant previous discussions from this site:

MarcoB
  • 67,153
  • 18
  • 91
  • 189
  • 1
    A historical note: in versions before 5, N[x, $MachinePrecision] was the way to produce a machine precision evaluation of a number. For some reason, version 5 introduced MachinePrecision as a separate entity which effectively did what $MachinePrecision used to do, and now $MachinePrecision is then left to produce arbitrary-precision results. – J. M.'s missing motivation Jun 08 '16 at 17:26
  • 1
    @J.M. As though the situation was not complicated enough already :-) More seriously, if you (or anybody) have any corrections / additions to what I wrote above, please feel free to edit away! I was surprised not to find an authoritative answer on this subject already, so I wonder if I might have simply missed it in my search. – MarcoB Jun 08 '16 at 17:30