26
$\begingroup$

I want to calculate cosine of 452175521116192774 radians (it is around $4.52\cdot10^{17}$)
Here is what different calculators say:

Wolframalpha WolframAlpha

Desmos

Desmos

Geogebra

Geogebra

Python 3.9 (standard math module)

Python

Python 3.9 (mpmath library)

Python3

Obviously there is only one solution. There could be errors in floating point precision for these calculators, but this stumbles me. My calculator (TI-30XIS) says domain error (which is weird because cosine of, for example, a billion works just fine). How can I get the cosine of very large integers?

$\endgroup$
7
  • $\begingroup$ I trust WolframAlpha the most, but it even gives the message that it assumes radians instead of degrees. See: wolframalpha.com/… $\endgroup$ May 28 at 17:03
  • $\begingroup$ What is even weirder about this is that if you scroll down in WolframAlpha, it says $\cos(452175521116192774) \approx -0.263905$. If you input $\cos(452175521116192774 \bmod 2\pi)$ though, you get $\approx -0.5229$ which I think is the true value. $\endgroup$ May 28 at 17:37
  • $\begingroup$ @DietrichBurde Pretty sure WA means radians. $\endgroup$
    – lulu
    May 28 at 17:54
  • $\begingroup$ Pari gives $-0.52290347839611852148341607857971042099$, like WA. $\endgroup$ May 28 at 17:57
  • 1
    $\begingroup$ I am surprised no-one has asked: why do you want that result? $\endgroup$
    – PJTraill
    Jun 1 at 22:26

3 Answers 3

56
$\begingroup$

The problem is that your integer $$n=452175521116192774$$ can't be stored exactly as a standard 64-bit IEEE double precision floating point number. The closest double happens to be $$x=452175521116192768,$$ as can be seen from the binary representation $$ \begin{aligned} n &= 11001000110011100110011110110100000010000100000000000\color{red}{000110}_2 \\ x &= 11001000110011100110011110110100000010000100000000000\color{red}{000000}_2 \end{aligned} $$ where those last few bits in $n$ are lost, since the double format only stores the first 52 digits after the leading “1”.

So in systems that use standard floating point (like Desmos, Geogebra, and the Python math module) you will actually get $x$ when you enter $n$ in a place where a double is expected; in Python you can verify this as follows:

> print("%.310g" % 452175521116192774)
452175521116192768

Conseqently, when you ask for $\cos n$ these systems will answer with $$\cos x = -0.2639 \ldots$$ (which in itself is computed correctly; it's just that the input is not what you thought).

In contrast, Wolfram Alpha and mpmath work with the exact number $n$, and give the correct answer $$\cos n = -0.5229 \ldots$$

$\endgroup$
1
  • 5
    $\begingroup$ You can get around this in a language that uses lower precision by splitting your number into a low precision and high precision sections (in this case 452175521116192768 and 6, although other combinations work) and using the angle sum identity. $\endgroup$ May 29 at 6:52
4
$\begingroup$

As Hans Lundmark pointed out, the problem is caused by converting the argument to a C double before doing the calculation.

But if you don't want to bring in a high-precision math library, there's a way (at least in Python) to calculate a more accurate value by using the sum-of-angles identities.

from math import cos, sin

def cossin(x):
    '''
    Return (cos(x), sin(x)) more accurately.
    '''
    if abs(x) < 2 ** 53:
        # All integers below this threshold are represented exactly,
        # so just use the normal math module functions.
        return (cos(x), sin(x))
    else:
        a = float(x)
        b = x - int(a)  # the approximation error
        # a is a float, so use the normal math functions.
        cos_a = cos(a)
        sin_a = sin(a)
        # for b, call recursively in case *it* can't be represented as float
        cos_b, sin_b = cossin(b)
        return (cos_a * cos_b - sin_a * sin_b, cos_a * sin_b + sin_a * cos_b)

This agrees pretty closely with WolframAlpha's result.

>>> cossin(452175521116192774)
(-0.5229034783961185, -0.8523919006426797)

An alternative approach is to use a high-precision approximation of π to reduce the argument modulo 2π. (In Python, you can use the Fraction class to store your approximation. This gives you:

$$452175521116192774 \approx 71965969330795778 \times 2\pi + 4.162135302888925$$

And taking the cosine of the reduced argument will give you the correct result.

>>> cos(4.162135302888925)
-0.5229034783961188
$\endgroup$
-2
$\begingroup$

Your Texas Instruments calculator is probably an inferior model created by engineers did their best while under severe time and budget constraints, overseen by brutal capitalist managers who only care about meeting certain milestones in a Gantt chart.

My WP-34S (in double precision mode) is able to represent your number with a digit to spare. Pushing our luck, the cosine function in radian mode yields -0.52290347840 in the display. Alas, this calculator was too good, so HP discontinued the HP 30b Business Professional platform it was built on. But you can download a free emulator for your iPhone. That emulator runs long programs MUCH faster than the original calculator hardware.

How would YOU compute such a monster? Subtract an appropriate multiple of 2 pi to get the argument into a range the calculator can handle? Sorry, you don't have enough digits to do that.

I think your best bet would be to divide the argument by some large power of 2, then use the double angle formulas repeatedly to get the trig function of your desired angle. Alas, the largest power of 2 that divides your argument is 2. After that, further division by two adds more digits than your machine can hold. You need quad precision floating point to represent your argument in a computer, and much more than that to represent the argument divided by a large power of two. And if you can't even represent it, you can't calculate the cosine.

$\endgroup$
3
  • $\begingroup$ Actually you cannot even divide by $4$ evenly; the prime factorization is $2\times 151\times 1497269937470837$ according to Wolfram Alpha. $\endgroup$
    – David K
    Jun 1 at 0:56
  • 2
    $\begingroup$ Even if it were $2^n$ the result of the repeated double angle formula would be wrong: the error doubles at each step, so it is still $2^n$ times the machine precision and you have no real advantage over subtracting a multiple of $2\pi$. $\endgroup$
    – fedja
    Jun 1 at 2:03
  • $\begingroup$ @DavidK The lack of divisibility by $2$ is actually not an obstacle: if you know $e^{it}$ for $t=k,k+1$, you can compute it for $t=2k,2k+1,2k+2$, so you can go down keeping four real values instead of one. Unfortunately, this doesn't help in the slightest unless you increase the calculation precision. $\endgroup$
    – fedja
    Jun 1 at 2:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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