3
$\begingroup$

I am struggling with some puzzling machine-underflow errors that I can't reduce to a form that makes sense to me, and I would like some help understanding what Mathematica is doing and what it is (or I am) getting wrong.

This comes from a bigger problem, but I've tried to reduce it as much as possible and this is the simplest instance that I can find:

Block[{ζ = 200},
 {#, N[#]} &[
  ζ^(3/2) Sqrt[1/( -1 + (E^(4 ζ)) )] 
  ]
 ]

On my machine, the instance itself evaluates reasonably well (to 2000 Sqrt[2/(-1 + E^800)]), but the N[#]'d version produces a General::munfl error and returns a value of 0.. This error goes away if:

  • I eliminate the -1 from the denominator, which makes sense; but also
  • if I remove the factor of ζ^(3/2) and
  • if I change the ζ = 200 assignment to ζ = 200.,

and the latter two make no sense to me.

Could one of you wizards shed some light on this weird stuff? What is causing this behaviour, and how do I avoid it?

(And more generally: This comes from a function that is defined via a symbolic integration. (More details available if they are relevant.) The best outcome would be a numerical-handling procedure that I can apply to the results of that symbolic integration that will prevent errors like these from creeping in.)


Edit: OK, I've been able (I think) to narrow down the source of the flagged error (or at least one of them). The N[#] evaluation seems to be going through a multiplication of the form

(8.`*^6 )*(3.6`2*^-348)

(where the 3.6`2 is actually to precision $\sim$13.05..., but that seems not to affect the output) which produces the error message

General::munfl: $8.\times 10^6 \ 3.6\times 10^{-348}$ is too small to represent as a normalized machine number; precision may be lost.

and returns the value 0.. This feels completely bonkers to me: if 3.6`2*^-348 is a perfectly fine number, why would making it bigger by a factor of a million suddenly make it too small to handle?

Zooming out a bit, the problem seems to be that the factor of 8.`*^6 (which for this example ultimately comes from the $\zeta^{3/2}$, but in general could be anything that multiplied the 3.6`2*^-348) is at machine precision, whereas the result of the exponential,

InputForm[Exp[800.]]
(*2.726374572112566567364779546367269757967`13.051499783199061*^347*)

is not. How can this be avoided?

$\endgroup$
5
  • 3
    $\begingroup$ Your best shot for working around this would be to use arbitrary precision arithmetic, e.g. N[...,20]. $\endgroup$ Mar 18, 2022 at 14:59
  • $\begingroup$ @DanielLichtblau Yes, it does look like it comes down to precision considerations. I don't particularly care for high-precision calculations (machine precision is just fine), but I do want it to retain that level of precision even if it needs to temporarily hop through some numbers that have very high or very low exponents. $\endgroup$ Mar 18, 2022 at 16:24
  • $\begingroup$ Note that Exp[800.] cannot be, and is not according to the InputForm, represented at machine precision. On overflow such as this, the number is promoted to arbitrary precision. However, on underflow, the result becomes machine zero (since V11.3). Compare {1/Exp[800.], Exp[-800.]}. -- If the factors are positive reals, try Block[{ζ = 200}, {#, Exp@N[PowerExpand@Log@#]} &[ζ^(3/2) Sqrt[1/(-1 + (E^(4 ζ)))]]]. I cannot guarantee it will always work, though, but it works on your expression. $\endgroup$
    – Michael E2
    Mar 18, 2022 at 16:34
  • $\begingroup$ If you don't want an arbitrary-precision result, you can use N twice; first with arbitrary precision then with machine precision. For example, Block[{ζ = 200}, {#, N[#, 20] // N} &[ζ^(3/2) Sqrt[1/(-1 + (E^(4 ζ)))]]] $\endgroup$
    – Bob Hanlon
    Mar 18, 2022 at 17:21
  • 1
    $\begingroup$ Since we now automatically underflow-to-machine-zero, there really is no chance for doing the computation in machine arithmetic and avoiding that situation. $\endgroup$ Mar 18, 2022 at 21:45

1 Answer 1

1
$\begingroup$

3.6`2*^-348 is a "perfectly fine" controlled-precision number, but it cannot be represented in machine precision. If, in an arithmetic operation, one operand has machine precision, Mathematica generally converts the others to machine precision before performing the operation. That's usually what you want for efficiency. So, (8.`*^6 )*(3.6`2*^-348) underflows.

If you need to "temporarily hop through some numbers that have very high or very low exponents" you'll need to code that in terms of arbitrary precision or logarithms. You cannot force machine numbers to directly represent quantities beyond their design limits.

$\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.