Natural Logarithm and the Integral of x^-1.0001

In calculus, the indefinite integral of x^n is x^(n+1)/(n+1) + C. For instance, the integral of x^2 is x^3/3 + C (where C is an arbitrary constant.) This does not apply to 1/x, aka x^-1, because that would cause a divide-by-zero error. Instead, the integral of x^-1 is ln(x) + C, where ln is the natural logarithm.

However, the standard formula should work on any value of n that is not -1, even if that value is arbitrarily close to -1. If you have x^-1.0001, the integral would be x^-.0001/-.0001. Does the limit actually converge to ln (x) from both the right and the left? If so, can you actually approximate the natural log by using x^(small number)/(small number)?

Not quite. For most integral problems, the indefinite integral evaluated at x is the same as the definite integral evaluated from 0 to x. We could choose any starting point we wanted; it would just lead to a different constant of integration. But if we try to do this for the integral of 1/x, we find that the necessary constant of integration would be infinite. To solve this, in this particular case, we instead define the indefinite integral to be equal to the definite integral starting at 1, instead of at 0.

The limit of x^(epsilon)/epsilon doesn’t actually converge to ln(x) directly; the problem is the additive constant.

Instead, let’s ignore the additive constant by looking at differences; look at ln(x) - ln(1) as compared to x^(epsilon)/epsilon - 1^(epsilon)/epsilon. Of course, the left side of this comparison is just ln(x) itself (since ln(1) is zero) and the right is [x^(epsilon) - 1]/epsilon. So the question is, does the right converge to the left?

The answer is yes; the right is [e^(ln(x) * epsilon) - 1]/epsilon. But this is the derivative of the function y |-> e^(ln(x)*y) at the input y = 0. By the chain rule and the fact that the function y |-> e^y is its own derivative, this comes out to ln(x) * e^(ln(x) * y) where y = 0, which is ln(x). Q.E.D.

(By y |-> [… y … y …], I mean the function which sends an input y to the output described by [… y … y …]; convenient notation when there are multiple variables flying around)

ETA: I didn’t see Chronos’s post when I started writing this, but he says essentially the same thing

(More directly than going through the detour, if you remember your differentiation rules for exponentiation with an arbitrary fixed base: [x^(epsilon) - 1]/epsilon is (or, rather, converges to) the derivative of epsilon |-> x^(epsilon) at the input 0. But this is ln(x) * x^(0), which is ln(x).)

This works in theory, but in practice you’ll end up dividing by a very small number, and that’s bad news with respect to numerical accuracy.

Ah, good point. I know very little about numerical analysis, but since we’re talking about dividing by an arbitrarily small number of our choosing, couldn’t we reformulate to multiply by arbitrarily large numbers of our choosing instead? I.e., if one reformulated as n * ([nth root of x] - 1), for large n, would that be ok or would the [nth root of x] portion be sufficiently bad news in itself from the standpoint of numerical accuracy?

(My naive assumption is that it’s not so bad; that the problem with dividing by small numbers is the discontinuity of division around the denominator of 0, but that this does not present itself with exponentiation, which is continuous around an exponent of 0. But I may be speaking out of my ass…)

I’m not totally convinced that this works, even in theory. The first problem you run into is that x^(-10^(-n))/-10^(-n) will be negative for any positive x, which is not the case for the logarithm. Second, it’s not immediately obvious to me that this family of functions is uniformly convergent, and if it’s not, then the integral doesn’t have to converge.

A couple quick tests suggest that this is numerically disastrous, but I have not had the chance to play around with it too much. If nobody comes in tomorrow I’ll mess around with it some more.

No, the problems aren’t mathematical in nature. Rather, they’re tied to the specifics of floating point arithmetic.

You forgot to subtract 1 in the numerator (the modification of the OP’s proposal which I pointed out was necessary). Once you do so, it will work out, as [x^(epsilon) - 1]/epsilon = [x^(0+epsilon) - x^0]/epsilon; by definition, as epsilon approaches 0, this approaches the derivative of the function epsilon |-> x^epsilon at 0, which is equal to ln(x). I am absolutely positive of this.

I assumed that the problems of floating-point arithmetic being discussed were, in some way, related to the discontinuity of division at a denominator of 0 (since, after all, this means small roundoff errors in the input cannot be constrained to small roundoff errors in the output), but I defer to your view otherwise. Still, and I have absolutely no idea how taking nth roots in floating point arithmetic is generally done in practice, would n * ([nth root of x] - 1) for large n work out to approximate ln(x) well in practice?

(Naturally, if one doesn’t subtract one in the numerator, we have x^epsilon/epsilon, which is approaching x^0/0 = 1/0, and thus will not converge to any real number [as you point out, it will be negative for negative epsilon and positive for positive epsilon; it approaches only the unsigned infinity of the projective reals])

In terms of floating-point arithmetic, the problem actually is that the exponentiation function is not exactly any easier than the logarithm function. Dividing by small numbers is not bad for precision, but it’s another lengthy operation.

Oh. Your comments (well, the comments you made before you edited) do remind me why it’s not so directly applicable to floating-point calculations to take the continuity of a function as a barometer for how small changes in input relate to small changes in output; what counts as “small” deviation with floating point numbers changes with the scale of the number being discussed [this being the “floating” aspect, I suppose]. :smack:

I should have addressed this:

It’s true that reasoning by “naive” commuting of limits and integrals won’t rigorously give us the OP’s desired result (questioning this was, after all, the OP’s purpose). But as it happens, we can quickly rigorously establish the desired result through different reasoning, as demonstrated above.

Here’s a quick Matlab script I put together to test this:



n = 20;
x = zeros(n, 2);
for i = 1:n
    epsilon = -10^(-i);
    estimate = (2^epsilon - 1)/epsilon;
    x(i, :) = [i, estimate];
end


And here are the contents of x afterwards:



    1.0000    0.6697
    2.0000    0.6908
    3.0000    0.6929
    4.0000    0.6931
    5.0000    0.6931
    6.0000    0.6931
    7.0000    0.6931
    8.0000    0.6931
    9.0000    0.6931
   10.0000    0.6931
   11.0000    0.6931
   12.0000    0.6931
   13.0000    0.6928
   14.0000    0.6883
   15.0000    0.6661
   16.0000    1.1102
   17.0000         0
   18.0000         0
   19.0000         0
   20.0000         0


For i = 12, the estimate agrees with Matlab’s log function out to five decimal places, which isn’t that accurate. As you can see, it starts falling apart pretty soon afterwards.

The problem with the floating-point computation isn’t dividing by epsilon; it’s the subtraction. When x is very close to zero, 2[sup]x[/sup] is very close to 1 (1+xlog(2)+O(x[sup]2[/sup])), and so 2[sup]x[/sup]-1 is very close to zero. But double-precision floating-point numbers only have about 15 digits of accuracy, so when xlog(2) approaches 1e-15 you start losing precision: at 1e-12 you have only about 3 digits, at 1e-13, only 2, and so on. This is what ultrafilter saw in his Matlab script.