# Why are transcendental functions of large numbers inaccurate on computers?

For instance, why is it hard to accurately compute sin(1e99)? I suspect it has something to do with rounding error.

• log(1e99) is fairly simple though ;) – MSalters Oct 14 '15 at 9:04
• I don't agree with the title, as this isn't true for all transcendental functions (f.i. the logarithm and exponential have no such issue). It's probably more characteristic of oscillating functions. – Yves Daoust Oct 14 '15 at 9:05
• @YvesDaoust: I'd argue that the problem is fairly general. The logarithm is in fact the main exception, as the usual floating-point representation explicitly stores an exponent. And exp(x) can be approximated by exp(x/2) ^ 2. That said, any function that doesn't oscillate tends to have an asymptote or go to infinity, both of which make the implementation for large arguments trivial. – MSalters Oct 14 '15 at 9:17

There's nothing fundamentally hard about computing $\sin(10^{99})$. You simply compute $x = 10^{99} \bmod 2\pi$, then compute $\sin(x)$. (Why is this valid? It's because $\sin(x)=\sin(y)$ if $x\equiv y \pmod{2\pi}$.) It's not too hard to compute $x$ if you use a numerical representation that has enough digits of precision, and then to compute $\sin(x)$ using standard methods.

However, a standard double won't have enough precision to perform this computation. It only has about 53 bits of precision; that's a lot less than the $99 \lg 10 \approx 329$ bits of precision you'd need to be able to distinguish $10^{99}$ from $10^{99}+1$. (A standard IEEE float cannot even represent values in excess of $3*10^{38}$). Of course, $\sin(10^{99})$ is very different from $\sin(10^{99}+1)$. So, if you want to compute $\sin(10^{99})$, just stuffing $10^{99}$ into a float or double and then trying to invoke the $\sin(\cdot)$ function on that is not going to end well.

If you want to compute $x$ to at least $b$ bits of precision, you'll probably need a numerical representation that can represent $10^{99}$ to at least $329+b$ bits of precision (probably more than that, for intermediate values that arise during the modular reduction). A float or double ain't gonna be enough for that.

• Having implemented sin(x) myself (embedded platform), I can confirm sin(10^99) is easy. You need to check the exponent anyway, and for this case just return 0. The hard parts are around 2^24 (16 million) where the Least Significant Bit is in the order of π. – MSalters Oct 14 '15 at 7:41
• @MSalters "just return 0" -- are you claiming that $\sin(10^{99})=0$? That can't be correct, since $10^{99}$ isn't a multiple of $\pi$. If that's not what you're claiming, I don't understand your comment. – David Richerby Oct 14 '15 at 8:39
• @DavidRicherby: obviously standard floating-point implementations cannot compute $\sin(10^{99})$ with a single significant digit, as they are just unable to represent that number. Hence returning $0$ isn't worse than any other value. – Yves Daoust Oct 14 '15 at 8:54
• @DavidRicherby: 10^99 isn't even exactly representable in double precision. The actual number passed to sin(x) will be a 53 bit approximation (so about 16 digits), approximately 1.8287798260516400 * 2^328. The rounding error there is about 0.00000000000000000003 * 2^238, which is far, far larger than π. – MSalters Oct 14 '15 at 8:54
• @DavidRicherby: The actual implementation is if input.exponent > 26 return 0.0. When the possible rounding error exceeds the 2π period, the output is fully dependent on that unknown rounding error. 0 is simply the mean value of sin(x). – MSalters Oct 14 '15 at 9:27

Taking the sine of large numbers is a numerically unstable operation.

Considering an argument like $10^{99}$, you can get a completely different value of the sine by adding, say $1$ to it. Think that this is a relative change of $10^{-99}$ !

Indeed, $$|\sin(a+1)-\sin(a)|=|2\sin(\frac12)\cos(a+\frac12)|>0.95|\sin(a+\frac12)|,$$

so that you can find arbitrarily tiny $\epsilon=\dfrac1a$ such that

$$|\sin(a(1+\epsilon))-\sin(a)|>0.5.$$