3
$\begingroup$

One can constrain the precision of NIntegrate by setting PrecisionGoal:

NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}] // FullForm
(*==> 1.1045695042415091`*)

NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}, PrecisionGoal -> 2] // FullForm
(*==> 1.1052223748431014`*)

Since I have a lot of NIntegrate functions in my work, I want to set globally the PrecisionGoal to save the labor. Here is what I did:

$Pre = Function[{expr}, 
   expr /. NIntegrate -> (NIntegrate[##, PrecisionGoal -> 2] &), 
   HoldAll];

However, Trace shows that the above setting does not work as expected:

NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}] // Trace

{(NIntegrate[##1,PrecisionGoal->2]&)[1/Sqrt[x+y],{x,0,1},{y,0,1}],{{{Sqrt[x+y],Sqrt[x+y]},1/Sqrt[x+y],1/Sqrt[x+y]},1/Sqrt[x+y],1/Sqrt[x+y]},{{x,y}=.,{x=.,y=.},{x=.,Null},{y=.,Null},{Null,Null}},{x=.,Null},{x=.,Null},{y=.,Null},{{x,y}=.,{x=.,y=.},{x=.,Null},{y=.,Null},{Null,Null}},{Message[General::munfl,0.5 4.0326079252773842957465158527343513127923262375362274882806697019010^-330],Null},{Message[General::munfl,0.5 4.0326079252773842957465158527343513127923262375362274882806697019010^-330],Null},{Message[General::munfl,0.5 4.0326079252773842957465158527343513127923262375362274882806697019010^-330],{Message[General::stop,General::munfl],{General::stop,Further output of 1 will be suppressed during this calculation.},Null},Null},{Message[General::munfl,0.03125 2.5203799532983651848415724079589695704952038984601421801754185636910^-331],Null},{Message[General::munfl,0.03125 2.52037995329836518484157240795896957049520389846014218017541856369*10^-331],Null},..., 1.10457}

One can see that the numerical integration is still carried out with high precision, even though the first line in trace didn't ask for this. This claim can be verified by

$Pre=.
(NIntegrate[##1, PrecisionGoal -> 2] &)[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}]
(*==> 1.10522*)

Apart from this, there are many General::munfl warnings.

My question is how to understand the above behaviors?

$\endgroup$

1 Answer 1

3
$\begingroup$

Another story of evaluation order. You've only set one HoldAll for the pure function in $Pre, that's not enough. The function ReplaceAll (/.) doesn't have HoldAll attribute, either! Once the NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}] is passed to /., it'll immediately be evaluated, before the replacement happens. You need to stop this in some way, one possible solution is to use Unevaluated:

$Pre =.

$Pre = Function[{expr}, 
   Unevaluated@expr /. NIntegrate -> (NIntegrate[##, PrecisionGoal -> 2] &), 
   HoldAll];

NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}]
(* 1.10522 *)

"OK, then why do I see the strange output with Trace?" That's because all of the output of Trace is wrapped by HoldForm…:

$Pre =.
Trace[NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}]] // InputForm

enter image description here

So what really happens here is:

  1. The line NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}] // Trace evaluates before the replacement happens.

  2. The replacement happens on the output of Trace[…].

i.e. something amount to the following:

$Pre =.
Trace[NIntegrate[1/Sqrt[x + y], {x, 0, 1}, {y, 0, 1}]];
% /. NIntegrate -> (NIntegrate[##, PrecisionGoal -> 2] &)
$\endgroup$
1
  • $\begingroup$ Wooo, thank you so much! I didn't realize that in this particular case, the output of Trace could be distorted by the sneaky replacement due to HoldForm and ReplaceAll. $\endgroup$
    – luyuwuli
    Mar 20, 2023 at 11:51

Your Answer

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

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