7
$\begingroup$

I was recently trying to find a numerical solution to a thermodynamics problem and the expression $x\ln x$ appeared in one of the computations. I did not have to find its value very near $0$, so the computer managed fine, but it got me thinking - can one make a stable numerical algorithm to compute $x\ln x$ for values near 0?

It is easy to prove that $\lim\limits_{x\to 0^+} x\ln x=0$. However, simply multiplying $x$ by $\ln x$ is not a good solution for small $x$. The problem seems to be that we are multiplying a small number ($x$) by a large number ($\ln x$).

My first thought would be to approximate it somehow. But I quickly saw that Taylor series wouldn't work, as the derivative is $\ln x + 1$, which blows up (or rather down :-)) to $-\infty$. Some kind of iterative method like Newton's method does not seem to be the solution either, because the operations needed seem to be even more messy than what we are trying to compute.

So my question is - is there some numerically stable method to compute $x\ln x$ for small values of $x$? And preferably one that is more general, so that it could be used on functions like $x^n \ln x$ - but these at least have a finite first derivative at $0$ for $n>1$.

$\endgroup$
8
  • 1
    $\begingroup$ My guess is that you won't be able to do much better than the naive multiplication since $\ln x$ typically isn't very large. For a standard float for example it will never be larger than about $100$. Carlo's algorithm will get this wrong by about a factor $5$ or $6$ because $a+b = a$ until $b > 2^{-23} \approx \exp(-16)$. $\endgroup$ Commented Feb 18, 2022 at 23:24
  • 2
    $\begingroup$ There is no numerical instability involved in multiplying a small number by a large number. I don't see any reason why $x\log x$ would present a problem unless the logarithm function is poorly implemented. Here I'm assuming that $x$ is given exactly in floating point format. If instead $x$ is obtained by converting a double precision number to single precision, there will be a range in which $x$ is inaccurate due to partial underflow even if $x\log x$ is large enough to not partially underflow. Without knowing what code you are using, it is hard to say more. $\endgroup$ Commented Feb 19, 2022 at 3:51
  • 1
    $\begingroup$ On experiment, when $x$ is exact in floating point my computer gets precise answers in double precision down to the point of partial underflow, then answers as precise as partial underflow allows down to the point of underflow to 0. This might vary per hardware and compiler. $\endgroup$ Commented Feb 19, 2022 at 4:41
  • 2
    $\begingroup$ To add to Brendan McKay's comment, multiplying a small number by a large number can be numerically troublesome if the answer is close to 1. But here, the reason that $x\ln x$ approaches 0 as $x$ approaches 0 is that $x$ dominates. Maybe this is clearer if we write $x = e^t$ so that $x\ln x = te^t$ and we let $t\to -\infty$. Unless you happen to care about that narrow window just before the number becomes too small for you to handle anyway, there is not much of a numerical issue. $\endgroup$ Commented Feb 19, 2022 at 14:35
  • $\begingroup$ @TimothyChow I'm not aware of any numerical problem in multiplication when the the answer is close to 1. The absolute value of the last bit does change abruptly by the value of the radix (usually 2) when the exponent changes; is that what you mean? $\endgroup$ Commented Feb 20, 2022 at 1:29

3 Answers 3

8
$\begingroup$

Modern mathematics libraries should be able to find $\log x$ precisely for all floating-point numbers, as the algorithms for doing that have long been known and adopted. My experiments on a fairly recent Intel chip with gnu mathematics library and gcc 10 compiler confirm that.

Multiplication is even more definite: correct rounding of the last bit is guaranteed (though there can be different options available for what "correct rounding" means).

It might appear from the above that precise computation of $x\log x$ is guaranteed for any small $x>0$. However there is a reason why that doesn't happen for really tiny $x$ and there is no way to avoid it.

Floating-point numbers are usually stored with the mantissa normalized (leading bit 1, sometimes implicit). However, when the number is too small it may be impossible to normalize the number without the exponent underflowing. In this case (usually) the number is kept in unnormalized form and the number of bits of precision is reduced. This situation is called partial underflow and such numbers are subnormal or denormalized.

So, if you try to compute $x\log x$ when $x\log x$ is in the partial underflow range, $\log x$ will be computed precisely but the multiplication by $x$ cannot produce more bits of precision than numbers of the size of $x\log x$ have. Short of using different floating-point numbers, there is no solution.

If $x\log x$ is in the partial underflow range, then $x$ will be too, or maybe it will be so small as to underflow to 0. In practice $x$ will come from some earlier computation and the partial underflow means it may not be so precise as thought, which is another source of error. It isn't the fault of the function $x\log x$.

Incidentally I tested this explanation empirically and behaviour was exactly as predicted.

$\endgroup$
5
  • $\begingroup$ What happens when we try to evaluate $x\log x$ at $x=0.0$ or do you have the if-case $x==0.0$ then output $0.0$? $\endgroup$
    – rych
    Commented Feb 19, 2022 at 15:03
  • 1
    $\begingroup$ @rych For the most common combination of floating-point format and library, log(0.0) evaluates as ${-}\infty$, which is a special floating-point value. Then multiplying by 0.0 gives ${-}$NaN which is another special value that means "Not a Number". The moral is that the programmer should take responsibility for the case $x=0$ and provide 0.0 as the answer. $\endgroup$ Commented Feb 20, 2022 at 1:10
  • $\begingroup$ I tried a few systems and some give ${+}NaN$ rather than ${-}NaN$. Some computers (not sure which) don't even have NaN values. All the more reason for the programmer to test for $x=0$ explicitly. $\endgroup$ Commented Feb 20, 2022 at 1:38
  • $\begingroup$ Thanks, @Brendan. Perhaps we should dig out how $\log$ is actually implemented in various standard math C libraries, for small arguments perhaps even the method mentioned in Carlo's answer... and then modify accordingly to for the desired $x\log x$ avoiding uncertainty and errors $\endgroup$
    – rych
    Commented Feb 22, 2022 at 6:11
  • $\begingroup$ @rych It's complicated, see the glibc example at code.woboq.org/userspace/glibc/sysdeps/ieee754/dbl-64/… The implementers work hard to obtain the best accuracy for all possible arguments. $\endgroup$ Commented Feb 22, 2022 at 9:29
5
$\begingroup$

Since $\ln x = - \ln(1/x)$, to evaluate the logarithm near zero is equivalent to evaluating it for large argument. You can then use the result $$\ln y=\frac{\pi}{2a}\left(1+{\cal O}(y^{-2})\right),$$ with $a$ the arithmetic–geometric mean$^\ast$ of $a_0=1$ and $b_0=4/y$, see page 11 of Multiple-precision zero-finding methods and the complexity of elementary function evaluation.

$^\ast$ Starting from any two positive numbers $a_0$ and $b_0$, the arithmetic-geometric-mean iterate is $a_{i+1} = (a_i + b_i)/2$, $b_{i+1} = \sqrt{a_ib_i}$. For $a_0\gg b_0$ this converges rapidly to $a=\lim_{i\rightarrow\infty} a_i$.
$\endgroup$
0
$\begingroup$

If $x$ is represented in floating-point as $y \times 10^{-d}$, $0.1 < y \le 1$, $d \in \mathbb N$, note that

$$ x \ln(x) = y (\ln(y) - d \ln(10)) \times 10^{-d} $$

which shouldn't be a problem to evaluate accurately.

$\endgroup$
3
  • $\begingroup$ Doing a quick numerical check, this trick doesn't seem to improve the accuracy. Empirically, comparing standard double floating point precision against multiple precision calculations, the relative error in the direct calculation of $x\ln(x)$ starts to deviate from machine precision at about $10^{-308}$ and roughly has the size $10^{d-324}$ for $x=10^{-d}$. The smallest number that can be represented in double precision is roughly $10^{-324}$. Probably better to check if this level of accuracy is unacceptable before looking for something more robust. $\endgroup$ Commented Feb 18, 2022 at 23:27
  • 2
    $\begingroup$ @IgorKhavkine What you are seeing here is partial underflow, where the floating point form is too small to normalize but not small enough to underflow to zero. In this range fewer bits of precision are available. $\endgroup$ Commented Feb 19, 2022 at 3:54
  • 4
    $\begingroup$ The subtraction in this answer will increase the relative error in the computed value of $\log y$, so I don't think it is a good method. $\endgroup$ Commented Feb 19, 2022 at 3:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .