7
$\begingroup$

I use Mathematica mostly for numerical calculations, and sometimes the performance of numerical calculations can be greatly improved if the high-precision arithmetic can be switched off by

Developer`SetSystemOptions["CatchMachineUnderflow" -> False]

As suggested in this post, when one want to switch off the high-precision arithmetic, one can usually do something like

With[{cmuopt = SystemOptions["CatchMachineUnderflow"]},
 Internal`WithLocalSettings[
  SetSystemOptions["CatchMachineUnderflow" -> False],
  (* put your own code here; for example: *)
  SetSystemOptions[cmuopt]
 ]
]

Consider now I have a package that I want to run at the machine precision. This is fine for one function, but for a package containing many functions, adding those pieces of code to each function would be a pain. So I'm wondering whether there are ways to switch off the high precision at package wise, for all the functions in the package. Or in other words, can we change the "CatchMachineUnderflow" settings by context?

$\endgroup$
  • 2
    $\begingroup$ While it might possible to create something which would do that packagewise I don't think it would be wise to do so. What I'd recommend is to just write a wrapper for the above code fragment and then define your functions using that wrapper like: f[x_]:=ignoreUnderflow[Exp[-x]] where ignoreUnderflow would be said wrapper. That would be straightforward to implement, easy to read/understand and save you almost completely from any redundancy without making your functions rely on some hidden obscure mechanisms... $\endgroup$ – Albert Retey Jan 10 '15 at 16:57
4
$\begingroup$

If you're willing to overload SetDelayed (and/or Set) inside the package for the sake of defining functions inside the package, you could automatically add a wrapper offCMU that turns off "CatchMachineUnderflow" if it is on. This is quite like what Albert Retey recommended in a comment. The main difference is that SetDelayed is changed to do the wrapping. A minor difference is that a Condition is added to the wrapper so that the underflow option is turned off only once.

Here's the idea applied to a dummy package:

BeginPackage["foo`"];

minsquared::usage = "minsquared[] yields 0. if underflow";
expmax::usage = "expmax[] yields 0. if underflow";

Begin["`Private`"];

ClearAll[offCMU];
SetAttributes[offCMU, HoldAll];
offCMU[expr_] := 
  With[{cmuopt = SystemOptions["CatchMachineUnderflow"]}, 
   Internal`WithLocalSettings[
     SetSystemOptions["CatchMachineUnderflow" -> False],
     expr,
     SetSystemOptions[cmuopt]
     ] /; ("CatchMachineUnderflow" /. cmuopt)];
offCMU[expr_] := expr;  (* CMU already off *)

Internal`InheritedBlock[{SetDelayed},

  Unprotect@SetDelayed;
  SetDelayed[lhs_, rhs_] /; ! TrueQ[$in] := Block[{$in = True},
    SetDelayed[lhs, offCMU@rhs]
    ];

  minsquared[] := $MinMachineNumber^2;
  expmax[] := Exp[-$MaxMachineNumber];

  ];

End[ ];

EndPackage[ ]

Examples:

minsquared[]
$MinMachineNumber^2
(*
  0.
  4.95095367581213*10^-616
*)
expmax[]
Exp[-$MaxMachineNumber]
(*  0.  *)

General::unfl: Underflow occurred in computation. >>

(*  Underflow[]  *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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