17
$\begingroup$

When thinking on the workaround for this LogLogPlot bug suggested by halirutan I noticed that CompiledFunction actually can return machine numbers smaller than $MinMachineNumber. Consider:

f = Compile[{{t, _Real}}, Exp[-9 t^2]];
num = f[8.872]
num < $MinMachineNumber
MachineNumberQ[num]
MachineNumberQ[num2 = ToExpression[ToString[num, StandardForm]]]

2.191864698767832`*^-308

True

True

False

As you see, num is smaller than $MinMachineNumber BUT MachineNumberQ returns True. Conversion of this number into String and backward returns arbitrary-precision number.

Moreover, CompiledFunction accepts such numbers and works with them correctly:

f2 = Compile[{{x, _Real}}, Sqrt@x];
f2[num]

1.480494747970364`*^-154

How this behavior could be explained? Does it mean that CompiledFunction actually CAN work with arbitrary-precision numbers?

P.S. I use Mathematica 8.0.4 under Windows 7 x64.

$\endgroup$

2 Answers 2

18
$\begingroup$

Congratulations! You find one of subnormal positive double :)

Another example

f = Compile[{{t, _Real}}, 2.0^t];

f[-1074]
f[-1075]
5.*10^-324
0
MachineNumberQ@f[-1074]
True

This doesn't mean that CompiledFunction can work with arbitrary-precision numbers.

Update

Normally Mathematica prevents such numbers

2.^-1074.
% // MachineNumberQ
4.940656458413*10^-324
False

But after a "hack" we can create subnormal positive double manually

SetSystemOptions["CatchMachineUnderflow" -> False];
2.^-1074.
% // MachineNumberQ
5.*10^-324
True

See also Improving speed of Exp[].

Note that Mathematica displays only the first digit of this number (a little bug). All digits:

RealDigits[%%]
{{4, 9, 4, 0, 6, 5, 6, 4, 5, 8, 4, 1, 2, 4, 6, 5}, -323}
$\endgroup$
6
  • $\begingroup$ Good old floating-point magic :) $\endgroup$
    – ssch
    Nov 25, 2013 at 15:03
  • 3
    $\begingroup$ @AlexeyPopkov Yes, they are machine numbers (they satisfy IEEE 754 double-precision standard). Therefore, MachineNumberQ returns True. $\endgroup$
    – ybeltukov
    Nov 25, 2013 at 15:39
  • $\begingroup$ How can I enter a subnormal positive double by hands? Entering 5.*^-324 gives arbitrary-precision number. $\endgroup$ Nov 25, 2013 at 15:48
  • $\begingroup$ @AlexeyPopkov It doesn't fit in the comment so I post it in the update of my answer. $\endgroup$
    – ybeltukov
    Nov 25, 2013 at 15:59
  • 3
    $\begingroup$ Subnormals are normally handled (slowly) by microcode or in software rather than by the floating-point unit directly. I wonder, is there any way to switch on flush-to-zero? $\endgroup$ Nov 25, 2013 at 23:15
5
$\begingroup$

In addition to @ybeltukov's excellent answer, I thought it would be worth noting the behaviour of RuntimeOptions, when compiling to either the Wolfram Virtual Machine (WVM) or to C, for these subnormal positive doubles.

f = Compile[{{t, _Real}}, Exp[-9 t^2]];

Needs["GeneralUtilities`"]
f[1.]    (* = 0.00012341 *)
f[8.872] (* = 2.191*10^-308 *)

Do[f[1.], {i, 10000}] // AccurateTiming
(* 0.0066 seconds *)

Do[f[8.872], {i, 10000}] // AccurateTiming
(* 0.0652 seconds *)

The difference in timings is an interesting one because of the subnormal result of f[8.872] - take a look at this plot to see.

range = {6., 7., 8., 8.871, 8.872, 9., 10., 11., 12.};
times = AccurateTiming[Do[f[#], {i, 10000}]] & /@ range;
ListPlot[Transpose[{range,times}]]

enter image description here

The default for "RuntimeOptions" is to not catch machine underflow. This can be turned on e.g.

f2 = Compile[{{t, _Real}}, Exp[-9 t^2],
                RuntimeOptions -> {"CatchMachineUnderflow" -> True}];
f2[1.]    (* all fine as before *)
f2[8.872] (* uh-oh! CompiledFunction::cfne *)

CompiledFunction::cfne: Numerical error encountered; proceeding with uncompiled evaluation.

This error has an associated performance hit, as it jumps out to uncompiled evaluation.

Do[f2[1.], {i, 10000}] // AccurateTiming
(* 0.0063 seconds *)

Do[f2[8.872], {i, 10000}] // AccurateTiming
(* 0.3324 seconds *)

Now look at the timing performance when the underflow is caught. Again, the sub-normal f2[8.872] is a tricky one to handle compared to subsequent results.

enter image description here

$\endgroup$

Your Answer

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

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