Il coseno del pedante


29

Il mio capo mi ha appena detto di scrivere una funzione coseno. Essendo un bravo appassionato di matematica, la mia mente ha immediatamente evocato la serie Taylor appropriata.

cos(x) = 1 / 0! - x^2 / 2! + x^4 / 4! - x^6 / 6! + ... + (-1)^k x^(2k) / (2k)! + ...

Tuttavia, il mio capo è molto esigente. Vorrebbe essere in grado di specificare esattamente quanti termini della serie Taylor calcolare. Potete aiutarmi a scrivere questa funzione?

Il tuo compito

Dato un valore in virgola mobile xda 0a 2 pie un numero intero positivo ninferiore a 100, calcolare la somma dei primi ntermini della serie di Taylor fornita sopra cos(x).

Questo è , quindi vince il codice più corto. Input e output possono essere acquisiti in uno dei modi standard. Sono vietate le scappatoie standard.

Gli appunti

  • L'input può essere preso in qualsiasi forma ragionevole, purché vi sia una chiara separazione tra xe n.
  • L'input e l'output dovrebbero essere valori in virgola mobile, almeno accurati come il calcolo della formula utilizzando numeri in virgola mobile IEEE a precisione singola con alcune regole di arrotondamento standard.
  • Se ha senso per il linguaggio utilizzato, i calcoli possono essere eseguiti usando quantità razionali esatte, ma l'input e l'output devono comunque essere in forma decimale.

Esempi

 x  |  n | Output
----+----+--------------
0.0 |  1 | 1.0
0.5 |  1 | 1.0
0.5 |  2 | 0.875
0.5 |  4 | 0.87758246...
0.5 |  9 | 0.87758256...
2.0 |  2 | -1.0
2.0 |  5 | -0.4158730...

1
Suppongo che nsia anche maggiore di 0?
GamrCorps,

8
Direi che tecnicamente non è ciò che significa pedante, ma sarebbe troppo meta.
PyRulez,

8
Se il tuo capo vuole che tu scriva una funzione buona o almeno leggibile, sei nel posto sbagliato.
Roman Gräf,

2
Un capo veramente esigente vorrebbe calcolare il coseno usando qualcosa di un po 'più efficiente (e preciso) rispetto alla serie Taylor ...
PM 2Ring

6
@ PM2Ring Non sarebbe pignolo, sarebbe ragionevole. La serie Taylor è davvero l'opzione più cruda.
user1997744,

Risposte:


64

Linguaggio di scripting dell'operazione Flashpoint , 165 157 byte

F={x=_this select 0;n=_this select 1;i=0;r=0;while{i<n*2}do{r=r+x^i/(i call{c=_this;j=c-1;while{j>0}do{c=c*j;j=j-1};if(c<1)then{c=1};c})*(-1)^(i/2);i=i+2};r}

Chiama con:

hint format["%1\n%2\n%3\n%4\n%5\n%6\n%7",
    [0.0, 1] call f,
    [0.5, 1] call f,
    [0.5, 2] call f,
    [0.5, 4] call f,
    [0.5, 9] call f,
    [2.0, 2] call f,
    [2.0, 5] call f]

Produzione:

enter image description here

L'input e l'output dovrebbero essere valori in virgola mobile, almeno accurati come il calcolo della formula utilizzando numeri in virgola mobile IEEE a precisione singola con alcune regole di arrotondamento standard.

Sono abbastanza sicuro che i numeri siano numeri in virgola mobile IEEE a precisione singola, anche se nell'output stampato i decimali più lunghi non sono così precisi. È la stampa che arrotonda i numeri in questo modo, in realtà i numeri sono più precisi.

Ad esempio, a=1.00001;b=1.000011;hint format["%1\n%2\n%3", a, b, a==b]produrrà questo:

1.00001
1.00001
false

Quindi chiaramente la precisione effettiva dei numeri è maggiore della precisione stampata.



16
@orlp Perché no?
Steadybox

3
@orlp Penso che la domanda più appropriata da porsi sia: perché il linguaggio di scripting Operation Flashpoint non è una variante di ArnoldC ?
plafoniera

2
Mmm ... entri nell'input sparando un dato numero di round [n] nella direzione data della bussola [x]? 😍 Operazione Flashpoint!
Mormegil,

14
@Mormegil Bene, generalmente no, ma questo può essere fatto con questo pezzo di codice: dir=-1;num=1;player addEventHandler ["fired", {_dir=getdir (nearestObject [_this select 0, _this select 4]);if (dir < 0) then {dir = _dir} else {if (abs(dir - _dir) < 5) then {num = num + 1} else {hint format["%1", [dir*(pi/180), num] call F];dir=-1;num=1}}}]- Tirare in una direzione aumenta il contatore, quindi sparare in un'altra direzione chiama la funzione coseno con la direzione precedente e il numero di colpi in quella direzione.
Steadybox,

13

05AB1E , 14 11 byte

FIn(NmN·!/O

Provalo online!

Spiegazione

F                # for N in [0 ... n] do
 In              # push (x^2)
   (             # negate
    Nm           # raise to the Nth power
      N·!        # push (2*N)!
         /       # divide
          O      # sum

@JamesHolderness: Sì, la lingua ha subito una revisione piuttosto importante da allora. Un bizzarro bug sembra essersi afflitto ², ma può invece essere sostituito da I.
Emigna,

10

MATL , 14 byte

U_iqE:2ep/YpsQ

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione con esempio

Tutti i numeri hanno una doppia precisione (questa è l'impostazione predefinita).

Considerate ingressi x = 2.0, n = 5.

U_     % Implicitly input x. Square and negate
       % STACK: -4
iqE    % Input n. Subtract 1, multiply by 2
       % STACK: -4, 8
:      % Range
       % STACK: -4, [1 2 3 4 5 6 7 8]
2e     % Reshape into a 2-row matrix
       % STACK: -4, [1 3 5 7;
       %             2 4 6 8]
p      % Product of each column
       % STACK: -4, [2 12 30 56]
/      % Divide, element-wise
       % STACK: [-2 -0.333333333333333 -0.133333333333333 -0.0714285714285714]
Yp     % Cumulative product of array
       % STACK: [-2 0.666666666666667 -0.0888888888888889 0.00634920634920635]
s      % Sum of array
       % STACK: -1.41587301587302
Q      % Add 1. Implicitly display
       % STACK: -0.41587301587302

10

Mathematica, 49 41 39 31 byte

Sum[(-#^2)^k/(2k)!,{k,0,#2-1}]&

Vecchia versione più "divertente": (39 byte)

Normal@Series[Cos@k,{k,0,2#2-2}]/.k->#&

Risparmio di 10 byte grazie a @Pavel e 8 grazie a @Greg Martin!


9
Mentre la Seriescapacità di Mathematica è davvero fantastica e divertente, si scopre che l'implementazione manuale Sum[(-#^2)^k/(2k)!,{k,0,#2-1}]&è più breve qui.
Greg Martin,

9

Gelatina , 12 11 byte

ḶḤµ⁹*÷!_2/S

Provalo online!

Come?

ḶḤµ⁹*÷!_2/S - Main link: n, x           e.g. 5, 2.0
Ḷ           - lowered range(n)              [0,1,2,3,4]
 Ḥ          - double (vectorises)           [0,2,4,6,8]
  µ         - monadic chain separation (call that i)
   ⁹        - link's right argument         2.0
    *       - exponentiate(i) (vectorises)  [1.0,4.0,16.0,64.0,256.0]
      !     - factorial(i) (vectorises)     [1,  2,  24,  720, 40320]
     ÷      - divide (vectorises)           [1.0,2.0,0.6666666666666666,0.08888888888888889,0.006349206349206349]
        2/  - pairwise reduce by:
       _    -     subtraction               [-1.0,0.5777777777777777,0.006349206349206349]
         S  - sum                           -0.41587301587301617

8

Gelatina, 22 byte

-*ð×ø⁹*⁸²ð÷ø⁸Ḥ!
⁸R’Ç€S

Questo è un programma completo che accetta n come primo argomento e x come secondo.

Spiegazione:

              Creates a function to compute each term in the series. 
Its argument we will call k, eg k=3 computes 3rd term. Take x=2 for example.
-*           Computes (-1)^k. Eg -1
ð×ø        Multiplies by the quantity of
⁹             x.  
*             to the power of
⁸             k
²             ...squared. Eg -1 × (2³)² 
ð÷ø        divides by the quantity of
⁸              k
Ḥ             doubled
!               ...factorial. Eg -1 × (2³)²/(6!).


                Main link, first argument n and second argument n. Eg n=4, x=2.
⁸R            Creates range(n). Eg [1,2,3,4]
’                Decrements each element. Eg [0,1,2,3]
Ç€            Maps the above function over each element. Eg [1,-2,0.666,-0.0889]
S               Sum all all of the elements.  Eg -0.422.

7
Benvenuti in PPCG!
Martin Ender,

6

Python, 54 byte

f=lambda x,n,t=1,p=1:n and t+f(x,n-1,-t*x*x/p/-~p,p+2)

Se usi Python 2, assicurati di passare x come float, non come numero intero, ma la mia comprensione è che non importa se stai usando Python 3.


5

TI-Basic, 41 40 byte

Prompt X,N
sum(seq((-(X+1E-49)2)^Q/((2Q)!),Q,0,N-1
1E-49 viene aggiunto all'angolo perché TI-Basic genera un errore per 0 ^ 0, è abbastanza grande da non causare l'errore e non è abbastanza grande da cambiare la risposta.


4

C, 96 byte

Ricorsivo dal vivo

f(n){return n?n*f(n-1):1;}float c(n,x)float x;{return n?c(n-1,x)+pow(-1,n)*pow(x,2*n)/f(2*n):1;}

dettagliata

f(n) // factorial(n)
{
    return n ?   // n != 0 ?
        n*f(n-1) // n! = n * (n-1)!
    : 1;         // 0! = 1
}

float c(n,x)float x; // cos(x) with n+1 terms
{
    return n ?        // n != 0 ?
        c(n-1, x)     // cos(x) (n-1)th term
        + pow(-1, n)  // + (-1)^n
        * pow(x, 2*n) // * x^(2n)
        / f(2 * n)    // / (2n)!
    : 1;              // cos(x) at n=0
}

Progressivo ricorsivo, 133 byte in diretta

#define F float
#define c(x,n) 1+g(1,n,x,1,1,1)
F g(F i,F n,F x,F s,F p,F f){s=-s;p*=x*x;f*=i;return i<n?g(i+1,n,x,s,p,f)+s/2*p/f:0;}

dettagliata

#define F float // shorthand float

#define c(x,n) 1+g(1,n,x,1,1,1) // macro function

F g(F i,F n,F x,F s,F p,F f)
{
    s = -s;   // (-1)^n = (-1) * (-1)^(n-1)
    p *= x*x; // x^(2n) =  x^2 * x^(2(n-1))
    f *= i;   //    2n! =    2 * (1*2*..*n)

    return i < n ?       // i = 0 .. n-1
        g(i+1,n,x,s,p,f) // next term
        + s / 2 * p / f  // s*p/2f = s/2*p/f
        : 0;             // don't compute nth term
}

Versione 96b c(0.5, 80)=> NaN, per overflowf(80)=0
l4m2

Le funzioni ricorsive di @l4m2 sono qui ai fini del golf, ma sono poco pratiche in quanto possono facilmente traboccare poiché il numero di chiamate supera il limite dello stack di chiamate, e anche con limiti più alti è uno spreco di risorse, per la soluzione sopra provare numeri più piccoli.
Khaled.K,

1
Il problema dice direttamente, n<100quindi almeno non andare così lontano nel range. Non overflow dello stack
l4m2

Se il problema dice n<100e utilizzi la O(2^n)soluzione, immagino che vada bene, purché alla fine riesegua il risultato
l4m2

1
Cordiali saluti, il risultato NaN non ha nulla a che fare con la ricorsione - è un overflow del calcolo fattoriale che sta usando numeri interi quando dovrebbe usare float (198! Non si inserirà mai in un int).
James Holderness,

4

JavaScript (ES6), 46 byte

f=
x=>g=(n,t=1,p=0)=>n&&t+g(--n,-t*x*x/++p/++p,p)
<div oninput=o.textContent=f(x.value)(n.value)><input id=x><input type=number min=1 value=1 id=n><pre id=o>1

Accetta input al curry (x) (n).


Perché non renderlo un frammento?
Arjun,

4

C, 71 byte

usando lo schema Horner

float f(n,x)float x;{float y;for(n+=n;n;)y=1-(y*x*x/n--)/n--;return y;}

Versione non golfata:

float f(n,x) float x;
{
  float y = 0.0;
  for(n = 2*n; n>0; n -= 2)
  {
    y = 1-y*x*x/n/(n-1);
  }
  return y;
}

Su quale piattaforma funziona?
anatolyg

4

R, 70 64 byte

function(x,n)sum(sapply(1:n-1,function(y)(-x^2)^y/gamma(2*y+1)))

salvato 6 byte grazie alla risposta di pizzapants184 con il trucco (-x ^ 2) ^ y

65 byte:

function(x,n)Reduce(function(a,b)a+(-x^2)^b/gamma(2*b+1),1:n-1,0)

praticamente l'implementazione ingenua di questo, ma un po 'golfato; restituisce una funzione anonima che calcola la serie di Taylor al n specificato

  • l'utilizzo di un Riduci richiede un altro byte poiché initdeve essere impostato su 0
  • usi gamma(n+1) invece difactorial(n)
  • 1:n-1 è equivalente a 0:(n-1)

3

ok , 38 byte

Questo funziona anche in k , ma richiede 39 byte perché uno 'deve essere scritto come /:invece (almeno, in kmac 2016.06.28 lo fa).

{+/(y#1 -1)*{(*/y#x)%*/1+!y}.'x,'2*!y}

Spiegazione:

Cominciamo con il bit centrale. (*/y#x)è esponenziazione, è equivalente a x^y. */1+!ysarebbe y!, o yfattoriale. %è divisione. Pertanto la funzione nel mezzo èmiddle(x,y) = (x^y)/(y!) .

Ora il bit a destra, a cui viene applicata la funzione sopra. 2*!yè{0, 2, 4, ..., 2*(y-1)} . x,'antepone xad ogni elemento in quell'elenco, trasformandolo in {(x, 0), (x, 2), (x, 4), ..., (x, 2*(y-1))}. L' .'poi applica middlead ogni coppia di numeri (map essenzialmente).

Finalmente, (y#1 -1)* moltiplica il risultato per 1 o -1 (alternando) e +/prende la somma.


3

Haskell, 71 byte

f x n=sum$map(\i->(-1)^i*x^(2*i)/fromIntegral(product[1..2*i]))[0..n-1]

Questa è una risposta piuttosto noiosa che non è troppo difficile da decifrare. I fromIntegralmorsi davvero, però. (L' /operatore richiede operandi dello stesso tipo numerico in Haskell e la coercizione tra tipi numerici non è consentita senza una funzione wordy.)


1
Una comprensione dell'elenco può farti risparmiare alcuni morsi:f x n=sum[(-1)^i*x^(2*i)/fromIntegral(product[1..2*i])|i<-[0..n-1]]
Julian Wolf,

1
Benvenuti in particolare al golf PPCG e Haskell!
Laikoni,

3

Gelatina , 12 byte

²N*Ḷ}©÷®Ḥ!¤S

Provalo online!

Come funziona

²N*Ḷ}©÷®Ḥ!¤S  Main link. Left argument: x. Right argument: n

²             Square; yield x².
 N            Negate; yield -x².
     ©         Call the link to the left and copy the result to the register.
   Ḷ}          Call unlength on the right argument, yielding [0, 1, ..., n-1].
  *           Yield [1, -x², ..., (-x²)**(n-1)].
          ¤   Combine the three links to the left into a niladic chain.
       ®        Yield the value in the register, [0, 1, ..., n-1].
        Ḥ       Unhalve; yield [0, 2, ..., 2n-2].
         !      Factorial; yield [0!, 2!, ..., (2n-2)!].
      ÷         Division; yield [1/0!, -x²/2!, ..., (-x²)**(n-1)/(2n-2)!].
           S  Take the sum.


3

Haskell , 61 byte

x#n=sum[(-1*x^2)^i/fromIntegral(product[1..2*i])|i<-[0..n-1]]

Sembrava abbastanza diverso dall'altra soluzione Haskell da giustificare una risposta separata. L'implementazione dovrebbe essere piuttosto autoesplicativa: chiamare con x#ndov'è xil numero di cui calcolare il coseno ed nè l'ordine della somma parziale da prendere.


Puoi salvare parecchi byte rimuovendo fromIntegrale usando **al posto di ^, come questo
B. Mehta

x#n=sum[(-x*x)**i/product[1..2*i]|i<-[0..n-1]]salva altri 3 byte.
Lynn,

3

Pyt , 37 34 33 byte

←←ĐĐ↔3Ș1~⇹ř⁻^04Ș⇹ř⁻^²*0↔ř⁻2*!+/+Ʃ

3

J, 26 24 byte

+/@:(!@]%~^*_1^2%~])2*i.

-2 byte grazie a @cole

Inizialmente avevo pianificato di usare un gerundio ciclico per alternare tra l'aggiunta e la sottrazione, ma non riuscivo a farlo funzionare.

Spiegazione:

                    2*i.     | Integers from 0 to 2(n-1)
    (              )         | Dyadic train:
            _1^-:@]          | -1 to the power of the left argument
          ^*                 | Times left arg to the power of right arg
     !@]%~                   | Divided by the factorial of the right arg
+/@:                         | Sum

1
24 byte: +/@:(!@]%~^*_1^2%~])2*i.indagherò su un gerundio ciclico: probabilmente ha fallito poiché J valuta da /destra a sinistra, quindi è necessario utilizzarlo |.(o forse hai tenuto conto di questo e hai ancora difficoltà).
Cole

3

Perl 6 , 53 byte

{(sum (1,*i*$^x...*)[^2*$^n] »/»(1,|[\*] 1..*)).re}

Provalo online!

Questo in realtà calcola il complesso esponenziale e per il doppio del numero di termini richiesti e quindi prende la parte reale.


2

MATLAB con Symbolic Math Toolbox, 57 byte

@(x,n)eval(subs(taylor(sym('cos(x)'),'Order',2*n),'x',x))

Ciò definisce una funzione anonima con che prende doubleingressi x, ned emette il risultato comedouble .

Esempio (testato su R2015b):

>> @(x,n)eval(subs(taylor(sym('cos(x)'),'Order',2*n),'x',x))
ans = 
    @(x,n)eval(subs(taylor(sym('cos(x)'),'Order',2*n),'x',x))
>> f = ans; format long; f(0,1), f(0.5,1), f(0.5,2), f(0.5,4), f(0.5,9), f(2,2), f(2,5)
ans =
     1
ans =
     1
ans =
   0.875000000000000
ans =
   0.877582465277778
ans =
   0.877582561890373
ans =
    -1
ans =
  -0.415873015873016

2

JavaScript ES7 60 byte

x=>a=n=>--n?(-1)**n*x**(2*n)/(f=m=>m?m*f(m-1):1)(2*n)+a(n):1


x=>a=n=>                                                         // Curry-d function, it basically returns another function
        --n?                                              :1  // subtract one from n. If n - 1 is 0, return 1
            (-1)**n*                                             // This generates the sign of the number
                    x**(2*n)/                                    // This creates the part before the division, basicaly x^2n
                             (f=m=>m?m*f(m-1):1)(2*n)            // This creates a recursive factorial function and calls it with 2n
                                                     +a(n)    // Recursively call the function. This adds the elements of the taylor series together

Per usarlo:

Premere F12, digitare la funzione e quindi fare

c(x)(n)

2

C 144 130 byte

F(m){int u=1;while(m)u*=m--;return u;}float f(float x,n){float s;for(int i=1;i<n;i++)s+=pow(-1,i)*pow(x,2*i)/(F(2*i));return 1+s;}

Versione Ungolfed:

//Function to calculate factorial
int F(int m)
{
  int u=1;

  while(m>1)
   u*=m--; 

  return u;
}

//actual function called in main function   
float f(float x, int n)
{

  float s=0.0;

  for(int i=1;i<=n-1;i++)
     s+=pow(-1,i)*pow(x,2*i)/(F(2*i)); 

  return 1+s;
 }

Grazie Kevin per aver salvato alcuni byte!


È possibile salvare alcuni byte massaggiando le definizioni delle funzioni:F(m){...}f(x,n)float x;{...}
Kevin,

Poiché u * 1 == u, puoi eseguire il loop nella prima funzione while(m)u*=m--o u=m;while(--m)u*=m( o stessa lunghezza)
Kevin,

i<=n-1è lo stesso dii<n
Kevin,

@Kevin Grazie, hai perfettamente ragione, non gioco a golf da un po 'di tempo. :)
Abel Tom,



2

Stax , 12 byte

ü┘·.ⁿYeò≥Vîû

Esegui ed esegui il debug

Disimballato, ungolfed e commentato, sembra così.

            Input is `x n`
Z           Push a zero underneath the top.  The stack is now `x 0 n` 
D           Run the rest of the program n times.
  xJNi|*    (-x*x)^i where i is the iteration index
  iH|F/     divide that by factorial(2i)
  +         add to the running total so far
            final result is implicitly printed

Esegui questo



1

PHP, 76 byte

for($f=1;$i<$argv[2]*2;$f*=++$i)$i&1?:$s+=(-1)**$k++*$argv[1]**$i/$f;echo$s;

prende Xe Ndagli argomenti della riga di comando; Corri con-r .

cappio $ida 0a N*2-1, tenere fac($i)in $f; se $iè pari, aggiungi il termine alla somma $s. somma di stampa.


Vorrei avere numeri complessi (con M_Icome unità immaginaria);
Mi limiterei semplicemente $faM_I*++$i e Salva 7 byte.

Forse Mathematica può farlo. Ma Mathematica non deve.

Ho potuto salvare due byte con cos(M_PI*$i/2)invece di $i&1?:e (-1)**$k++;
ma sarebbe strano usare un coseno incorporato per costruire una funzione coseno.


1

Assioma, 36 byte

g(a,n)==eval(taylor(cos(x)),a).(2*n)

Costruisci l'infinito (nel senso finito ma si può chiedere di costruire l'elenco di 2 * n elementi se il PC ha memoria sufficiente) elenco di somme parziali per la serie di Taylor per cos (x) calcolare in 'a', in "eval ( taylor (cos (x)), a) "; ottiene l'elemento 2 * n dell'elenco in ". (2 * n)". Casi test:

(47) -> g(0,1)
   (47)  1
                                                 Type: Expression Integer
(48) -> g(0.5,1)
   (48)  1.0
                                                   Type: Expression Float
(49) -> g(0.5,2)
   (49)  0.875
                                                   Type: Expression Float
(50) -> g(0.5,4)
   (50)  0.8775824652 7777777778
                                                   Type: Expression Float
(51) -> g(0.5,9)
   (51)  0.8775825618 9037271611
                                                   Type: Expression Float
(52) -> g(2.0,5)
   (52)  - 0.4158730158 7301587302
                                                   Type: Expression Float
(53) -> g(2.0,800)
   (53)  - 0.4161468365 471423870

1

J , 17 byte

4 :'2&o.T.(+:y)x'

Provalo online!

Utilizza un built-in , che presumo sia OK.

Sfortunatamente, non so davvero come lavorare bene con le funzioni che accettano argomenti tramite il curry in questo modo, quindi ho dovuto farlo esplicitamente. Sono sicuro che esiste un modo per farlo tacitamente o in modo più breve.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.