Approximate the Dottie number

13

3

The Dottie number is the fixed point of the cosine function, or the solution to the equation cos(x)=x.1

Your task will be to make code that approximates this constant. Your code should represent a function that takes an integer as input and outputs a real number. The limit of your function as the input grows should be the Dottie number.

You may output as a fraction, a decimal, or an algebraic representation of a number. Your output should be capable of being arbitrarily precise, floats and doubles are not sufficient for this challenge. If your language is not capable of arbitrary precision numbers, then you must either implement them or choose a new language.

This is a question so answers will be scored in bytes, with fewer bytes being better.

Tips

One way of calculating the constant is to take any number and repeatedly apply the cosine to it. As the number of applications tends towards infinity the result tends towards the fixed point of cosine.

Here is a fairly accurate approximation of the number.

0.739085133215161

1: Here we will take cosine in radians

Post Rock Garf Hunter

Posted 2017-08-04T15:21:21.067

Reputation: 55 382

So, if we are using Python, we must implement our own type or import Decimal? – Mr. Xcoder – 2017-08-04T15:28:56.867

How accurate must our submissions be? – Mr. Xcoder – 2017-08-04T15:30:34.223

Goes to Jelly tutorial to steal ÆẠȷ¡ realizes it's invalid. Tries Brachylog; oh no Brachylog doesn't even do floats. – Erik the Outgolfer – 2017-08-04T15:30:38.463

@Mr.Xcoder They must only be asymptotically accurate. – Post Rock Garf Hunter – 2017-08-04T15:31:00.190

I feel like the "arbitrarily precise" requirement is a bit too stringent. Why not consider an answer valid once x=cos(x)? – kamoroso94 – 2017-08-04T16:58:35.790

@kamoroso94 Because then answers can output the value without calculation. The arbitrarily precise requirement requires that answers actually be calculated as opposed to simply stored in the source. – Post Rock Garf Hunter – 2017-08-04T17:26:52.040

Ah I see, that is quite an unfortunate loophole. Thanks for explaining. – kamoroso94 – 2017-08-04T19:06:09.687

Possible duplicate of Approximate the plastic number (instead of x^3-1=x we have cos(x)=x)

– Sanchises – 2017-08-04T21:17:43.383

@Sanchises I don't believe this is a duplicate. In some languages, those with equation solvers, the two tasks are very similar. However the majority of languages don't have these. The most common algorithm for solving here simply doesn't work on the other question. – Post Rock Garf Hunter – 2017-08-04T21:44:56.857

For a computer "arbitrary precise" is it too much, because each number use memory, and memory is limited. Perhaps better "arbitrary precise until one upper bound", for example digits until 10^4 or until memory of PC allow that calculation – RosLuP – 2017-08-05T08:45:27.010

1I would like to see this in Haskell, APL, and some Lisp flavor. – Mark C – 2017-10-25T08:50:55.407

Answers

6

MATL, 34 30 19 bytes

11 bytes off thanks to Sanchises!

48i:"'cos('wh41hGY$

The last decimal figures in the output may be off. However, the number of correct figures starting from the left increases with the input, and the result converges to the actual constant.

Try it online!

Explanation

For input n, and starting at x=1, this applies the function

              x ↦ cos(x)

with n-digit variable-precision arithmetic n times.

48         % Push 48, which is ASCII for '1': initial value for x as a string
i:"        % Do n times, where n is the input
  'cos('   %   Push this string
  w        %   Swap. Moves current string x onto the top of the stack
  h        %   Concatenate
  41       %   Push 41, which is ASCII for ')'
  h        %   Concatenate. This gives the string 'cos(x)', where x is the
           %   current number
  GY$      %   Evaluate with variable-prevision arithmetic using n digits
           %   The result is a string, which represents the new x
           % End (implicit). Display (implicit). The stack contains the last x

Luis Mendo

Posted 2017-08-04T15:21:21.067

Reputation: 87 464

Why not just apply it n times at n digits precision? This seems overly complicated. – Sanchises – 2017-08-04T21:13:13.523

This is incredible. I want to see it in APL. – Mark C – 2017-10-25T08:48:10.093

5

Python 3, 58 bytes

lambda n:S('cos('*n+'0'+')'*n).evalf(n)
from sympy import*

Try it online!

Dennis

Posted 2017-08-04T15:21:21.067

Reputation: 196 637

2A version in Python 2 that doesn't memory error as quickly. – notjagan – 2017-08-04T15:42:54.260

No evalf in M :o

– Jonathan Allan – 2017-08-04T21:34:22.010

3

PHP, 50 bytes

$a=$argv[1];$i=$j=0;while($i<$a){$j=cos($j);$i++;}

Try it online!

Alex Neises

Posted 2017-08-04T15:21:21.067

Reputation: 61

Welcome to the site! :) – James – 2017-08-04T18:13:35.153

I believe that for($a=$argv[1];$a--;)$j=cos($j);echo$j; (40 bytes) is enough. – Ismael Miguel – 2017-08-05T11:44:28.637

3

GNU bc -l, 30

Score includes +1 for -l flag to bc.

for(a=1;a/A-b/A;b=c(a))a=b
a

The final newline is significant and necessary.

Try it online.

-l does 2 things:

  • enable the "math" library, including c() for cos(x)
  • sets precision (scale) to 20 decimal places (bc has arbitrary precision calculation)

I'm not really clear on the precision requirement. As it is, this program calculates to 20 decimal places. If a different precision is required, then scale=n; needs to be inserted at the start of the program, where n is the number of decimal places. I don't know if I should add this to my score or not.

Note also that for some numbers of decimal places (e.g. 21, but not 20), the calculation oscillates either side of the solution in the last digit. Thus in the comparison of current and previous iterations, I divide both sides by 10 (A) to erase the last digit.

Digital Trauma

Posted 2017-08-04T15:21:21.067

Reputation: 64 644

3

Mathematica, 22 bytes

Nest[Cos@#&,0,9#]~N~#&

input

[100]

output

0.73908513321516064165531208767387340401341175890075746496568063577328\ 46548835475945993761069317665318

J42161217

Posted 2017-08-04T15:21:21.067

Reputation: 15 931

2

R (+Rmpfr), 55 bytes

function(n,b=Rmpfr::mpfr(1,n)){for(i in 1:n)b=cos(b);b}

Dennis has now added Rmpfr to TIO so this will work; added some test cases.

Explanation:

Takes the code I wrote from this challenge to evaluate cos n times starting at 1, but first I specify the precision I want the values to be in by creating an object b of class mpfr with value 1 and precision n, n>=2, so we get more precision as we go along.

Try it online!

Giuseppe

Posted 2017-08-04T15:21:21.067

Reputation: 21 077

3

Try again. :) In the future, if anything is missing from TIO, don't hesitate to drop a message in http://talk.tryitonline.net.

– Dennis – 2017-08-04T16:05:05.677

@Dennis Thank you! I'll keep that in mind in the future! – Giuseppe – 2017-08-04T16:08:34.157

2

Octave, 42 bytes

@(n)digits(n)*0+vpasolve(sym('cos(x)-x'));

Try it online!

Pretty much a duplicate of my answer to Approximate the Plastic Number, but somewhat shorter due to more relaxed requirements.

Sanchises

Posted 2017-08-04T15:21:21.067

Reputation: 8 530

1

Mathics or Mathematica, 46 bytes

{$MaxPrecision=#}~Block~Cos~FixedPoint~N[1,#]&

Try it online!

notjagan

Posted 2017-08-04T15:21:21.067

Reputation: 4 011

1

K: 6 bytes

  _cos/1
0.7390851

f/ applies f until it reaches a fixed point.

tangentstorm

Posted 2017-08-04T15:21:21.067

Reputation: 111

0

Python - 89 bytes

Uses decimal module.

from decimal import*
import math
lambda n:reduce(lambda a,b:Decimal(math.cos(a)),[1]*n,1)

Maltysen

Posted 2017-08-04T15:21:21.067

Reputation: 25 023

84 bytes by combining imports. – Arnold Palmer – 2017-08-04T19:48:38.157

0

Perl 5, 41 Bytes

use bignum;sub f{$_[0]?cos(f($_[0]-1)):0}

Bignum is required for the arbitrary precision. Defines a function f that recursively applies cosine to 0 N times.

TIO doesn't seem to have bignum so no link :(

theLambGoat

Posted 2017-08-04T15:21:21.067

Reputation: 119

0

Mathematica 44 Bytes

FindRoot[Cos@x-x,{x,0},WorkingPrecision->#]&

FindRoot uses Newton's method by default.

Kelly Lowder

Posted 2017-08-04T15:21:21.067

Reputation: 3 225

0

Python 2, 86 bytes

import math as m,decimal as d
def f(x,n):return f(d.Decimal(m.cos(x)),n-1)if n else x

New version using the tip provided.

Python 2, 105 bytes

import math as m,decimal as d
def f(x,n):return d.Decimal(f(x+(m.cos(x)-x)/(m.sin(x)+1),n-1))if n else x

Uses Newton's method and recursive function to calculate the value. x is initial value and n is the recursion limit.

SydB

Posted 2017-08-04T15:21:21.067

Reputation: 31

Python's builtin float type does have indefinite precision, thus your function is not actually asymptotic. – Post Rock Garf Hunter – 2017-08-04T22:39:19.570

Thanks, good to know. Fixed I guess, not very short anymore tho :) – SydB – 2017-08-04T22:54:54.473

The tip provided in the question would probably be shorter than Newton's method. – Post Rock Garf Hunter – 2017-08-04T22:55:33.753

Thanks again, seems like I was too carried away with fancy mathematics. – SydB – 2017-08-04T23:13:28.967

0

Axiom, 174 bytes

f(n:PI):Complex Float==(n>10^4=>%i;m:=digits(n+10);e:=10^(-n-7);a:=0;repeat(b:=a+(cos(a)-a)/(sin(a)+1.);if a~=0 and a-b<e then break;a:=b);a:=floor(b*10^n)/10.^n;digits(m);a)

ungolfed and commented

-- Input: n:PI numero di cifre
-- Output la soluzione x a cos(x)=x con n cifre significative dopo la virgola
-- Usa il metodo di Newton a_0:=a  a_(n+1)=a_n-f(a_n)/f'(a_n)
fo(n:PI):Complex Float==
  n>10^4=>%i
  m:=digits(n+10)
  e:=10^(-n-7)
  a:=0     -- Punto iniziale
  repeat
     b:=a+(cos(a)-a)/(sin(a)+1.)
     if a~=0 and a-b<e then break
     a:=b
  a:=floor(b*10^n)/10.^n
  digits(m)
  a

results:

(3) -> for i in 1..10 repeat output[i,f(i)]
   [1.0,0.7]
   [2.0,0.73]
   [3.0,0.739]
   [4.0,0.739]
   [5.0,0.73908]
   [6.0,0.739085]
   [7.0,0.7390851]
   [8.0,0.73908513]
   [9.0,0.739085133]
   [10.0,0.7390851332]
                                                               Type: Void
           Time: 0.12 (IN) + 0.10 (EV) + 0.12 (OT) + 0.02 (GC) = 0.35 sec
(4) -> f 300
   (4)
  0.7390851332 1516064165 5312087673 8734040134 1175890075 7464965680 635773284
  6 5488354759 4599376106 9317665318 4980124664 3987163027 7149036913 084203157
  8 0440574620 7786885249 0389153928 9438845095 2348013356 3127677223 158095635
  3 7765724512 0437341993 6433512538 4097800343 4064670047 9402143478 080271801
  8 8377113613 8204206631
                                                      Type: Complex Float
                                   Time: 0.03 (IN) + 0.07 (OT) = 0.10 sec

I would use the Newton method because it would be faster than 'repeated cos(x) method'

 800   92x
1000  153x
2000  379x

where in the first column there is the number of digit and in the second column there is how much Newton method is faster than use repeated cos(x) method, here. Good Morning

RosLuP

Posted 2017-08-04T15:21:21.067

Reputation: 3 036