8
$\begingroup$

I use Mathematica mostly for numerical simulation, so most of the time double precision (or machine precision) is enough for me. Mathematica has this nice feature of automatically upgrade to arbitrary precision, but sometimes it costs problems for me.

For instance here is a compiled function that calculate a modulus of a vector

mymod = Compile[{{x, _Real, 1}}, x.x]

Now a vector has a Gaussian distribution

ListPlot[Array[Exp[-(#)^2./10.] &, 500, {-100., 100.}]]

enter image description here

and we want to calculate its modulus

mymod[Array[Exp[-(#)^2./10.]&,500,{-100.,100.}]]
(* 9.8885 *)

we get the right answer but with a warning saying that the argument type is incorrect:

Argument {5.075958897549*10^-435,1.513073408369*10^-431,4.367658965168*10^-428,<<45>>,5.42928*10^-284,3.46203*10^-281,<<450>>} at position 1 should be a rank 1 tensor of machine-size real numbers.

That's because Exp has upgraded the machine precision number we use to arbitrary precision. And thus the uncompiled function is invoked.

Consider the situation where we use extensively the numerical functions in a fairly large package, this automatic upgrading of precision may occur at multiple places. Although the final answer may probably be correct, invoking the uncompiled functions may greatly degrade the performance.

One solution point out by Daniel Lichtblau here is to turn off the tracking of the underflow by setting "CatchMachineUnderflow"->False to every function that uses arbitrary precision. But first we need to find those functions.

So my question are:

  1. Is it possible to tell Mathematica to generate a message when the upgrading to an arbitrary precision occurs? Just like we can have a message if the unpacking of an array occurs.
  2. This precision problem seems to be quite common for people dealing with numerical calculation in Mathematica. What do you think are good ways to deal with this problem?
$\endgroup$

2 Answers 2

7
$\begingroup$

... turn off the tracking of the underflow by setting "CatchMachineUnderflow"->False to every function that uses arbitrary precision. But first we need to find those functions.

This will take effect system-wide:

SetSystemOptions["CatchMachineUnderflow" -> False];

Then the following will underflow to a machine zero, instead of turning into a tiny bigreal:

    Exp[-800.]    

    (* 0. *)

This may become the default (and only) behavior in a future version.

$\endgroup$
3
  • $\begingroup$ Do you know (or could you help me find out) if using Shared passing is a reasonable way to return multiple results from a LibraryLink function? There are so many things that can go wrong that I am not confident about using this method. Maybe there is a caveat I have not thought of. For example, running Share[] will share the internal storage of some identical expressions. Can it share the storage of packed arrays too? If yes, that could make things go wrong in yet another way ... $\endgroup$
    – Szabolcs
    Commented Jan 26, 2018 at 10:34
  • $\begingroup$ With Version 11.3, your command results in the error message, $\endgroup$
    – bbgodfrey
    Commented Jun 2, 2018 at 18:22
  • $\begingroup$ Yes, not trapping machine underflow is the default (and only) behavior in 11.3 and later. Since there is no longer a choice, this system option has been removed. $\endgroup$
    – ilian
    Commented Jun 2, 2018 at 19:20
0
$\begingroup$

In your example it may be acceptable to merely Clip the input to mymod:

mymod[
 Clip[
  Array[Exp[-(#)^2./10.] &, 500, {-100., 100.}],
  {$MinMachineNumber, $MaxMachineNumber}
 ]
]
9.8885

In a form to reapply, along with Message generation:

catch::foo = "argument clipped";

catch[fn_][args__] := 
  With[{clipped = Clip[{args}, {$MinMachineNumber, $MaxMachineNumber}]},
    If[{args} =!= clipped, Message[catch::foo]];
    fn @@ clipped
  ]

Now:

catch[mymod] @ Array[Exp[-(#)^2./10.] &, 500, {-100., 100.}]

During evaluation of In[]:= catch::foo: argument clipped

9.8885
$\endgroup$
3
  • $\begingroup$ Thanks, but that requires to put that snippet of code to all the functions in a package, which seems a little bit tedious. I guess I'm trying to asking a event kind like message. For instance, giving some black box function, is it possible to catch that? $\endgroup$ Commented Jan 21, 2015 at 22:32
  • $\begingroup$ For example, giving this function f[n_] := Module[{mymod}, mymod = Compile[{{x, _Real, 1}}, x.x]; mymod[Array[Exp[-(#)^2./10.] &, n, {-100., 100.}]] ] is it possible to catch the even like catch[f[500]]? $\endgroup$ Commented Jan 21, 2015 at 22:36
  • $\begingroup$ @xslittlegrass I'll think about what you're trying to accomplish and update my answer if I come up with anything I consider actually serviceable. $\endgroup$
    – Mr.Wizard
    Commented Jan 22, 2015 at 4:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.