# How to detect underflow/overflow (post 11.3)?

This old trick used to work before 11.3:

SetSystemOptions["CheckMachineUnderflow" -> True]


But no longer... so how can we explicitly check for this in v12+??

CompiledFunctionTools.m:115:
(* clear the CatchMachineUnderflow bit which might be set,
but is no longer supported *)


Example code:

f = Compile[{{x, _Real}}, x/2,
RuntimeOptions -> {"CatchMachineUnderflow" -> True}
];
f[$MinMachineNumber] 1.11254*10^-308 (*no General::munfl message*)  • I asked a similar but not identical question here. Nov 26 '19 at 1:17 • Genuinely curious question: Are you cherry picking edge cases, or have you had this bite you in a real world scenario since the change? The only times I've experienced this as an issue was when I found myself writing quick and sloppy code... – ktm Nov 26 '19 at 18:25 ## 2 Answers It is certainly possible to detect whether machine underflow has occurred, but you would have to do the checking yourself. For example, something like this will check specifically if there was an underflow in the compiled function f after the multiplication by 0.5 Clear[munderflowQ, f]; munderflowQ = With[{mmn =$MinMachineNumber},
Compile[{{num, _Real}}, Abs[num] < mmn]];

f = Compile[{{x, _Real}},
Module[{res = x/2},
If[munderflowQ[res],
If[res != 0, InternalCompileError[],
If[x != 0, InternalCompileError[]]]]; res],
CompilationOptions -> {"InlineExternalDefinitions" -> True},
RuntimeOptions -> {"RuntimeErrorHandler" ->
Function[Message[CompiledFunction::cfne]; Evaluate[#]]}];


Of course in general this kind of checking would have to be done after each and every arithmetic operation that may possibly underflow.

You would also have to decide what to do in case underflow is detected and write code to handle it if and as desired -- the above example just gives a message and switches to uncompiled evaluation, but that does not change the final result in any way.

Update

I think your updated question shows exactly why the check for machine underflow was removed. In M11.1 we get:

f=Compile[{{x,_Real}},x/2,RuntimeOptions->{"CatchMachineUnderflow"->True}];
f[\$MinMachineNumber]


CompiledFunction::cfn: Numerical error encountered at instruction 3; proceeding with uncompiled evaluation.

1.112536929253601*10^-308

Notice that the error message says "proceeding with uncompiled evaluation".

Mathematica currently uses many libraries that support machine precision computations, and I expect many more to be added. Any time "uncompiled evaluation" occurs because of machine underflow, these libraries can no longer be used. Not only that, it is generally not possible to detect whether machine underflow might have occurred in these libraries, and so the "CatchMachineUnderflow"->True rule would not work.

I believe it is for these reasons that the "CatchMachineUnderflow" feature was removed.

Basically, to be able to use these new libraries, it is necessary that inputting a machine number into a function will always produce a machine number (or some other compilable type), especially within Compile.

Since your z is not a machine number, the "CheckMachineUnderflow" system option does not play any role in your example. And there is a well documented way (Accuracy) to check the accuracy of a number:

z = 1.00000000000000000;
Do[z = 2*z - z, 50];

Accuracy[z]


-6.85606

Note that the your example behaves in exactly the same way in M12 and M11.3, so talking about a change in behavior in M12 is misleading at best.

• Right, but I was looking for an answer that doesn't entail explicitly checking all values for negative accuracies
– M.R.
Nov 26 '19 at 5:11
• That example was supposed to be for a different question lol
– M.R.
Nov 26 '19 at 13:53