# Problem with machine number precision in compiled functions

When I compile a very big function and give it input the function returns error. I realized that this is because the value of the function becomes smaller than the smallest machine number. Is it possible to tell MMA that when I compile a function if the output of the function becomes smaller than the smallest machine number it should return the smallest machine number or zero?

-
Try applying Chop before returning the value. – Emilio Pisanty Aug 22 '14 at 22:13
Please edit your question to clarify the issue Michael raises below. – Mr.Wizard Aug 23 '14 at 3:14

As @episanty says in a comment, try applying Chop to your data before you return the value. It's compilable, according to List of compilable functions, which means it is appropriate for you here.

Chop[expr] replaces approximate real numbers in expr that are close to zero by the exact integer 0.

The default tolerance is $10^{-10}$. You can use an extra argument if numbers smaller than this are important to you, e.g.

Chop[expr, $MachineEpsilon]  will only replace numbers smaller than$MachineEpsilon.

list = 1.*10^-# & /@ Range[1, 20]
(* {0.1, 0.01, 0.001, 0.0001, 0.00001, 1.*10^-6, 1.*10^-7, 1.*10^-8,
1.*10^-9, 1.*10^-10, 1.*10^-11, 1.*10^-12, 1.*10^-13, 1.*10^-14,
1.*10^-15, 1.*10^-16, 1.*10^-17, 1.*10^-18, 1.*10^-19, 1.*10^-20} *)

Chop[list]
(* {0.1, 0.01, 0.001, 0.0001, 0.00001, 1.*10^-6, 1.*10^-7, 1.*10^-8,
1.*10^-9, 1.*10^-10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} *)

$MachineEpsilon (* 2.22045*10^-16 *) Chop[list,$MachineEpsilon]
(* {0.1, 0.01, 0.001, 0.0001, 0.00001, 1.*10^-6, 1.*10^-7, 1.*10^-8,
1.*10^-9, 1.*10^-10, 1.*10^-11, 1.*10^-12, 1.*10^-13, 1.*10^-14,
1.*10^-15, 0, 0, 0, 0, 0} *)

-

By default, in compiled functions, underflow is not caught and becomes zero automatically.

cf = Compile[x,
Module[{z = x, y = x},
While[y > 0, z = y; y = y/2]; {y, z}]];

cf[1.]
(* {0., 5.*10^-324} *)


Such a number as the number 5.*10^-324 achieved just before underflow is a subnormal machine number. The minimum machine number with full machine precision of almost 16 decimal places is $MinMachineNumber or 2.22507*10^-308. I merely wish to point out that there is a little ambiguity in the question as to what is meant by the "smallest machine number." On the one hand, compiled functions automatically convert underflow to zero. On the other hand, they also allow subnormal numbers with the accompanying loss of precision, which loss could be detrimental to the accuracy of some functions. I don't know of a convenient way to check at each step in a computation whether a result is less than $MinMachineNumber; however, the OP asks about only the final result, which may be done as @blochwave points out.

-
This question is related to this one mathematica.stackexchange.com/questions/57388/… See your comment there. I compiled a function and it returned an error. I checked and I think that the function does not return big numbers and you told that the minimum of the output may exceeds a machine number. – MOON Aug 23 '14 at 15:33
@yashar Doesn't this comment belong to the other question, then? – Michael E2 Aug 23 '14 at 18:44
The other question was closed so I thought better to ask it as a new question. – MOON Aug 23 '14 at 20:37