40

Coming from Maple I do not understand how the precision for numerical computations in Mathematica is specified. I understand that there are various options to commands such as WorkingPrecision and PrecisionGoal. But I would like to use the same precision (above machine precision) for a number of computations including matrix operations and the FindRoot command outside and inside of routines. Also I would like to specify the precision of the output.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
highsciguy
  • 1,700
  • 1
  • 16
  • 23
  • 2
    You can look at the documentation for the functions listed when you evaluate ?$*Precision. You can do fixed precision calculations with Block[{$MaxPrecision=..., $MinPrecision=...}, ...] or set these globally to affect all functions that rely on it – rm -rf Jun 04 '12 at 19:50
  • I tried setting $MinPrecision=20 already. Strangely I still get results with ScientificForm[%, 20] with just 16 digits. Do matrix computations and FindRoot depend on it? – highsciguy Jun 04 '12 at 20:02
  • 3
    @highsciguy yes, but you have to be careful not to introduce machine-precision numbers at any point, which "poison" the result. That is, all numbers specified as decimals should have a precision annotation, e.g. 1.0`20. Also, you should be aware that some matrix decompositions are done in machine precision using LAPACK. – Oleksandr R. Jun 04 '12 at 20:12
  • 2
    I see. How do I tell mathematica that all numbers e.g. 1.5 are actually 20 Digits precision? SetPrecision on all numbers or add the `20 everywhere? – highsciguy Jun 04 '12 at 20:16
  • 3
    You can use either approach. SetPrecision will take the machine-precision value and extend it with base-2 zeros up to the required precision, which may not be what you want (since zeros in base 2 are not necessarily so in base 10; e.g. SetPrecision[1.9, 20] gives a result slightly less than 1.9). If you use the annotation, the zeros are taken to be in base 10 instead. Another possible approach is to use Rationalize. – Oleksandr R. Jun 04 '12 at 21:53
  • @Oleksandr What do you mean when you say in the last comment here: "If you use the annotation, the zeros are taken to be in base 10 instead." Which "annotation" one should use? – Alexey Popkov Dec 01 '13 at 19:31
  • @AlexeyPopkov the number mark. For example, 1.9\100. ContrastSetPrecision[1.9, 100]`. – Oleksandr R. Dec 01 '13 at 19:42
  • @Oleksandr I think WRI should add an option for SetPrecision which specifies the base in which zeros will be added. It is inconvenient to use something like N[Rationalize[#, 0], 100] & just for keeping input in decimals. – Alexey Popkov Dec 01 '13 at 19:48
  • highsciguy, I note that you did not Accept my answer. If you find it lacking please tell me how it fails and I shall try to fix it. – Mr.Wizard Dec 23 '13 at 12:16

3 Answers3

24

How do I tell mathematica that all numbers e.g. 1.5 are actually 20 Digits precision? SetPrecision on all numbers or add the `20 everywhere?

You could force this with $PreRead. This naive definition is likely inefficient and probably breaks a number of corner cases I have not considered, but here is a rough demonstration:

$PreRead = (# /. 
     s_String /; 
       StringMatchQ[s, NumberString] && 
        Precision@ToExpression@s == MachinePrecision :> s <> "`20." &);

3/1.5 + Pi/7

Precision[%]
2.4487989505128276055

20.0879

As Alexey notes this breaks if the machine number string already has a "NumberMark" after it e.g. 1.23`. One could use a more precise string replacement to avoid this.

A different approach is to process at the expression rather than box level, though this simple first attempt probably fails in some cases as well:

$Pre = Function[Null, 
  Unevaluated[#] /. r_Real?MachineNumberQ :> RuleCondition@SetPrecision[r, 25], 
  HoldAllComplete]

Now:

MachineNumberQ[2.2]
ToString[3.14]
False

"3.140000000000000124344979"

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Your solution fails when the number entered has the NumberMark after digits, for example 1.5`. – Alexey Popkov Dec 01 '13 at 19:24
  • @Alexey I never thought it would be robust as written. Let me see if I can improve it some. – Mr.Wizard Dec 01 '13 at 20:42
  • 1
    Your second solution works in Mathematica 5.2 and 7.0.1 but not in v.8.0.4. Looks like a bug in $Pre in v.8.0.4. – Alexey Popkov Dec 01 '13 at 21:07
  • @Mr.Wizard: Your first solution also doesn't appear to work with numbers with 18 or more significant figures. For example: if you set the precision in your function equal to say, 50, then evaluate z = 1.2345678901234567 and then Precision[z], you get a precision of 50. By contrast, with z = 1.23456789012345678, you get a precision of 17.0915, which is equal to its native precision. – theorist Dec 29 '16 at 23:19
  • @theorist This code was designed to work with machine precision numbers only. Numbers entered with additional digits are automatically interpreted as arbitrary precision; I did not wish to override the precision those. If you leave out && Precision@ToExpression@s == MachinePrecision it should force those too. – Mr.Wizard Dec 31 '16 at 18:41
  • @Mr.Wizard It looks like I should stick with your original implementation, since what I wanted was to be able to increase the precision of all inexact numbers (regardless of whether they were arbitrary precision or machine precision) to a particular value (and seeing its attendant effect on the calculation), while leaving exact numbers alone. Your modification does the former, but also degrades exact numbers to the precision specified in the code (it doesn't, however, change the precision of exact symbols, like Pi). This creates lots of problems, e.g., indices in sums become inexact. – theorist Jan 02 '17 at 00:08
  • @Mr.Wizard Is there a way to set that precision functionally? Something like this fails to work: $PreRead=(#/.s_String/;StringMatchQ[s,NumberString]&&Precision@ToExpression@s==MachinePrecision:>s<>"\"<>ToString@prec<>"."&)withprec` set earlier. – Eli Lansey Feb 01 '21 at 16:50
  • @EliLansey Unless I misunderstand your code appears to work in version 10.1. Which version are you using and what behavior are you seeing? – Mr.Wizard Mar 06 '21 at 19:13
7

There is a quick-n-dirty solution. Set

$MinPrecision = 100

And then enter numbers something like

x = 1.01`2;

You will be getting warnings as

Precision::precsm: Requested precision 2.` is smaller than $MinPrecision.
    Using $MinPrecision instead.

but in this way you if you want to change precision you just change $MinPrecision value.

In[21]:= x

Out[21]= 1.\
0100000000000000000000000000000000000000000000000000000000000000000000\
00000000000000000000000000000
Yrogirg
  • 533
  • 6
  • 12
  • I don't even get the Precision::precsm warning message. However it does not work on machine numbers; the entry form as you rightly noted is critical. +1 for a simple method that may work in a number of applications. – Mr.Wizard Feb 10 '16 at 18:52
  • This is 10x easier than the accepted answer. – Paul Razvan Berg May 11 '21 at 12:45
0

First time posting, but for any googlers of this issue, the "global" precision of machine precision numbers can be set by:

Unprotect[$MachinePrecision];
$MachinePrecision = 100;
Protect[$MachinePrecision];
  • Does this setting affect any evaluations? – Ray Shadow Jun 01 '17 at 09:27
  • 1
    This does not affect MachinePrecision (no dollar sign) for example. I cannot imagine that it will do anything to change internals when a number like 3.3 is encountered (Try it: `In[20]:= Precision[3.3]

    Out[20]= MachinePrecision`). On top of which, it could have unpredictable effects which I would not view as a benefit.

    – Daniel Lichtblau Jun 01 '17 at 16:04