How to detect underflow/overflow (post 11.3)?

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.

Original answer

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.


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, Internal`CompileError[], 
            If[x != 0, Internal`CompileError[]]]]; 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.