21
\$\begingroup\$

Introduction:

The sine of \$x\$ is given by the formula:

$$\sin(x) = x - \frac {x^3}{3!} + \frac {x^5}{5!} - \frac {x^7}{7!} + \frac {x^9}{9!} - \frac {x^{11}}{11!} + \cdots$$

The cosine of \$x\$ is given by the formula:

$$\cos(x) = 1 - \frac {x^2}{2!} + \frac {x^4}{4!} - \frac {x^6}{6!} + \frac {x^8}{8!} - \frac {x^{10}}{10!} + \cdots$$

Task:

Given the value of \$x\$ and \$n\$, write a program (no functions, etc.) to output the value of \$\sin(x)\$ and \$\cos(x)\$ correct up to \$n\$ terms of the formula above. Assume that \$x\$ is in radians.

Input:

x n

A decimal number \$x\$ (with up to 3 decimal places) and an integer \$n\$. Input must be on stdin or a prompt dialog box (iff your language doesn't support stdin)

Output:

[sin(x)]
[cos(x)]

The value of both \$\sin(x)\$ and \$\cos(x)\$ should be rounded to 6 decimal places. If \$\sin(x)\$ is \$0.5588558855\$ (10 decimal digits), it should be rounded to \$0.558856\$ (6 decimal digits). The rounding must take place to the nearest, as described in the fifth column, "Round to nearest", of the the table in this Wiki article.

Constraints:

1 <= x <= 20
1 <= n <= 20

Samples:

----
5 3

10.208333
14.541667
----
8.555 13

0.765431
-0.641092
----
9.26 10

-3.154677
-8.404354
----
6.54 12

0.253986
0.967147
----
5 1

5.000000
1.000000
----
20 20

-5364.411846
-10898.499385
----

Notes:

  1. Standard loopholes are prohibited.
  2. Built-in math functions and operators of trigonometry (sin, cos, tan, etc.), factorial, and exponentiation cannot be used. You are free to use a built-in rounding function for estimating the result of computing \$\sin(x)\$ and \$\cos(x)\$ to the 6-th decimal digit.
  3. No need to handle wrong inputs.
  4. Only ASCII characters can be used in the program, not the Chinese Unicode ones that allow code compression.
  5. Your program must terminate, and display the output, within 3 seconds of input.
  6. Your answer must accompany the ungolfed code, along with the explanation of the code (compulsory if the code is not immediately obvious to programmers-not-familiar-with-your-language, especially GolfScript, J, etc.).
  7. Please include a link to an online compiler where your program can be tested.

Scoring:

The answer with lowest code length in characters, including white space, tabs, etc. wins! Winner would be declared on 21 May 2014.

EDIT: 21/05/14 Winner is aditsu using CJam language. Runner up follows jpjacobs with J language, and second runner up is primo with Perl language. Congrats all!

\$\endgroup\$
9
  • \$\begingroup\$ (Mod note: comments nuked. Please ping me for any lost information that you might want; looks like after my warning in advance, everything made its way into the question though.) \$\endgroup\$
    – Doorknob
    Commented May 15, 2014 at 15:00
  • \$\begingroup\$ In the first paragraph, it should be "sine", not "sin" \$\endgroup\$ Commented May 15, 2014 at 18:03
  • \$\begingroup\$ Is "Round to nearest" still a requirement, or can we use any built-in rounding facilities? e.g. round towards zero? \$\endgroup\$ Commented May 15, 2014 at 18:04
  • \$\begingroup\$ Requiring the equivalent of a mod 2pi operation to make the inputs converge faster would be rather useful - it's one of many improvements that the real world uses when dealing with these functions. (actually mod pi and sign awareness). \$\endgroup\$
    – Floris
    Commented May 16, 2014 at 1:21
  • 1
    \$\begingroup\$ @Floris I never knew this. Well, we can't do anything now, the rules have already changed much, and I don't want to keep changing them to further annoy the answerers. Thanks for the suggestion though! \$\endgroup\$ Commented May 16, 2014 at 3:57

18 Answers 18

19
\$\begingroup\$

Perl - 72 bytes

$~=<>=~$"+$'*2;$_=1-$_*$`/$~--/$~*$`for($,,$;)x$';printf'%f
%f',$`*$,,$;

Or, counting command line options as 1 byte each, in 70 bytes:

#!perl -n
$-=/ /+$'*2;$_=1-$_*$`/$---/$-*$`for($,,$;)x$';printf'%f
%f',$`*$,,$;

Or, if you'll allow me Perl 5.8, in 63 bytes:

#!perl -p
$.+=$'<</ /;$_=1-$_*$`/$.--/$.*$`for($_=$#='%f
',$\)x$';$_*=$`

but why would you.

Edit: Compliance with the new rules. %f rounds to 6 places by default, how convenient!


Algorithm

Examining the Taylor series for sin(x):

it can be seen that each term evenly divides every successive term. Because of this, it can be transformed rather effortlessly into a nested expression:

cos(x) transforms similarly, without the leading x, and denominator terms one smaller.

Additionally, this nested expression can be reformulated as a reverse recursive expression:

with s = 0 and sin(x) = x·s1, which is ultimately what is used.


Ungolfed

<> =~ m/ /;          # read one line from stdin, match a space
                     # prematch ($`) is now x, postmatch ($') is now n
($x, $n) = ($`, $'); # reassign, for clarity
$i = 2*$n + 1;       # counting variable (denominators)

for (($s, $c)x$n) {  # iterate over $s and $c, n times each
  # compute the next term of the recursive expression
  # note: inside this loop $_ is not the _value_
  # of $s and $c alternately, it _is_ $s and $c

  $_ = 1 - $_ * $x**2 / $i-- / $i;
}

# formated output
printf("%f\n%f", $x*$s, $c);

Sample Usage

$ echo 5 3 | perl sin-cos.pl
10.208333
14.541667

$ echo 8.555 13 | perl sin-cos.pl
0.765431
-0.641092

$ echo 9.26 10 | perl sin-cos.pl
-3.154677
-8.404354

$ echo 6.54 12 | perl sin-cos.pl
0.253986
0.967147

$ echo 5 1 | perl sin-cos.pl
5.000000
1.000000

$ echo 20 20 | perl sin-cos.pl
-5364.411846
-10898.499385

If you want to test this online, I recommend using compileonline.com. Copy-Paste the code into main.pl, and the input into the STDIN box, then Execute Script.

\$\endgroup\$
8
  • 2
    \$\begingroup\$ What a devious way to parse the input... can I use that in my solution? :) \$\endgroup\$
    – Tal
    Commented May 14, 2014 at 12:22
  • \$\begingroup\$ @Tal Feel free. \$\endgroup\$
    – primo
    Commented May 14, 2014 at 12:25
  • 2
    \$\begingroup\$ I think perl (and especially your code) counts as "not immediately obvious to programmers-not-familiar-with-your-language" \$\endgroup\$ Commented May 15, 2014 at 1:35
  • 1
    \$\begingroup\$ @aditsu Agreed. I'll add some cleaner code, and an explanation of the algorithm. \$\endgroup\$
    – primo
    Commented May 15, 2014 at 3:08
  • 2
    \$\begingroup\$ This answer really was extremely educational! \$\endgroup\$
    – Tal
    Commented May 15, 2014 at 20:04
9
\$\begingroup\$

Python 3 (102) / Python 2 (104)

Python 3 (102)

x,n=map(float,input().split())
k=2*n
t=1
while k>1:k-=1;t=1+t*1j*x/k
print('%.6f\n'*2%(t.imag,t.real))

Python 2.7 (104)

x,n=map(float,raw_input().split())
k=2*n
t=1
while k>1:k-=1;t=1+t*1j*x/k
print'%.6f\n'*2%(t.imag,t.real)

Basically the same code. We save two characters from not needing parens for print but lose four from needing raw_input.

Sample run

You can run these here.

>>>
20 20
-5364.411846
-10898.499385

Code explanation

The main idea is to compute 2*n terms of e^(ix), and then take the imaginary and real part to get the sin and cos values approximated to n terms. We use the truncation of the Taylor series:

e^(ix)≈sum_{k=0}^{2n-1} (i*x)^k/k!

This is polynomial in i*x, but rather than compute its value by summing each term, we use a modified Horner's Method to compute the sequence (defined recursively in reverse)

t_{2n} = 1
t_k = 1 + t_{k+1}*i*x/k,

which gives t_1 equaling the desired value.

Python string formatting operations are used to get the values to display rounded up to 6 decimal digits.

Edit: Changed to round to 6 digits as per new rules. No other changes were needed.

\$\endgroup\$
3
  • \$\begingroup\$ Try ideone for an online py3 interpreter :) \$\endgroup\$ Commented May 14, 2014 at 7:05
  • \$\begingroup\$ @BritishColour Thanks! I've added it to the post. \$\endgroup\$
    – xnor
    Commented May 14, 2014 at 7:09
  • \$\begingroup\$ Please update your answer. See details in question. Thanks. \$\endgroup\$ Commented May 16, 2014 at 14:56
8
\$\begingroup\$

J 98 70 69 58

Though this can probably be shortened quite a bit using more fancy functions ... comments are welcome:

exit echo 0j6":,.-/(($%&(*/)1+i.@[)"0~i.@,&_2)/".}:stdin''

note 2: input ends when receiving EOF (ctrl-D in linux). Edit: join exponentiation and factorial into a nicer, more J-ish whole: ($ %&(*/) >:@i.@[ ). This boils down to take an array of x replications of y and an array of the numbers from 1 to y. Multiply each and divide the result. This gets rid of the duplicate */.

Thanks to algortihmshark, another 7 characters off.

Eliminated cut for getting rid of the trailing newline.

Longer version, for which knowing about forks is a must.

NB. recursive Factorial
f=: */@>:@i.      NB. multiply all from 1 to n
NB. Exponential
e=: */@$          NB. replicate y x times, take the product.
NB. the x t y is the Nth (general) term without sign of the joint series
t=: (e % f@[)"0  NB. pretty straight forward: divide by (x!) on the exponential

NB. Piece the parts together, from right to left:
NB. read from stdin, cut the linefeed off , make the 2 n terms in 2 columns, which
NB. effectively splits out pair and odd terms, put in the minuses, put in rows
NB. instead of columns, echo, exit
exit echo 0j6&": ,. (-/) (i.@(,&_2)@{: t {.) , (". ;. _2) stdin''

There is no online J interpreter, but it's open source since a few years; installation is easy with these instructions:

http://www.jsoftware.com/jwiki/System/Installation/J801

On #jsoftware on irc.freenode.org, there is a J bot too.

stdin works only when ran from a file, from the commandline, else replace stdin '' with 'a b;' where a and b are the numbers that would have been passed on the commandline.

\$\endgroup\$
7
  • 5
    \$\begingroup\$ I love that it starts with exit \$\endgroup\$ Commented May 15, 2014 at 4:09
  • \$\begingroup\$ Please update your answer. See details in question. Thanks. \$\endgroup\$ Commented May 16, 2014 at 14:57
  • \$\begingroup\$ Updated for the 6 decimal places. If there's something else, please specify. Thanks \$\endgroup\$
    – jpjacobs
    Commented May 19, 2014 at 20:49
  • \$\begingroup\$ You can remove the & from 0j6&": to save a char. Also, (i.@(,&_2)@{:($%&(*/)>:@i.@[)"0{.) can be rewritten (($%&(*/)1+i.@[)"0~i.@,&_2)/ for another 6. \$\endgroup\$ Commented May 19, 2014 at 21:29
  • \$\begingroup\$ This tasks screams for T. (approximate function by n-term Taylor series), but I think that's verboten as a standard loophole. \$\endgroup\$
    – FUZxxl
    Commented Feb 18, 2015 at 13:19
6
\$\begingroup\$

CJam - 42

rd:X;1_ri2*,1>{_2%2*(*/X*_}/;]2/z{:+6mO}/p

Try it online at http://cjam.aditsu.net

Explanation:

r reads a token from the input
d converts to double
:X assigns to the variable X
; pops the value from the stack
1 puts 1 on the stack (the first term)
_ duplicates the 1
r reads the next token (the n)
i converts to integer
2*,1>{...}/ is a kind of loop from 1 to 2*n - 1:
- 2* multiplies by 2
- , makes an array from 0 to (last value)-1
- 1> removes the first item of the array (0)
- {...}/ executes the block for each item in the array
_ duplicates the "loop variable" (let's call it k)
2%2*( converts from even/odd to -1/1:
- 2% is modulo 2 (-> 0/1)
- 2* multiplies by 2 (-> 0/2)
- ( decrements (-> -1/1)
* multiplies, thus changing the sign every second time
/ divides the term on the stack by k or -k; this is the "/k!" part of the calculation together with the sign change
X* multiplies by X; this is the "X^k" part of the calculation; we obtained the next term in the series
_ duplicates the term to be used for calculating the following term in the next iteration
; (after the loop) pops the last duplicated term
] collects the terms on the stack in an array
At this point we have an array [1 X -X^2/2! -X^3/3! X^4/4! X^5/5! ...] containing exactly all the terms we need for cos(x) and sin(x), interleaved
2/ splits this array into pairs
z transposes the matrix, resulting in the array with the terms for cos(x) and the array with the terms for sin(x), as "matrix rows"
{...}/ again executes the block for each array item (matrix row):
- :+ adds the elements of the matrix row together
- 6mO rounds to 6 decimals
At this point we have the desired cos(x) and sin(x) on the stack
p prints the representation of the last item on the stack (sin(x)) followed by a newline
At the end of the program, the remaining contents of the stack (cos(x)) are printed automatically.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ +1 for introducing me to a language I've never heard of and will probably never use. \$\endgroup\$
    – Alex A.
    Commented May 15, 2014 at 14:41
  • \$\begingroup\$ @Alex thanks, CJam is somewhat like GolfScript on steroids \$\endgroup\$ Commented May 15, 2014 at 15:00
  • \$\begingroup\$ I don't like changing rules after posting the question, but I have disallowed code-compression-allowing-Unicode characters, as I did not know Unicode characters could be used to compress code. Only ASCII characters can be used now. Please edit your post. Sorry for inconvenience. \$\endgroup\$ Commented May 15, 2014 at 17:46
  • \$\begingroup\$ @GaurangTandon I don't like that very much either. What else did you think Chinese characters could possibly be used for in this problem? Anyway, edited. \$\endgroup\$ Commented May 15, 2014 at 23:31
6
\$\begingroup\$

Fortran: 89 109 125 102 101 98 bytes

complex*16::t=1;read*,x,n;do k=2*n-1,1,-1;t=1+t*(0,1)*x/k;enddo;print'(f0.6)',aimag(t),real(t);end

I abuse implicit typing, but unfortunately no such implicit complex type exists, so I had to specify that & the complex i. Gfortran cuts output at 8 decimal places naturally, so we're good on that spec. Unfortunately, my original method of output, print*,t, did not meet specs so I had to add 16 characters to output the imaginary and real components & hit the required 8 decimal places.

Thanks to Ventero, I managed to save 23 bytes between output and the loop. And another character to get correct answers and formatted output. And 3 more on the read statement.

Ungolfed,

complex*16::t=1
read*,x,n
do k=2*n-1,1,-1
   t=1+t*(0,1)*x/k
enddo
print'(f0.6)',aimag(t),real(t)
end
\$\endgroup\$
4
  • \$\begingroup\$ Please update your answer. See details in question. Thanks! \$\endgroup\$ Commented May 16, 2014 at 14:57
  • 1
    \$\begingroup\$ @GaurangTandon: You probably should stop changing the details of the problem. \$\endgroup\$
    – Kyle Kanos
    Commented May 16, 2014 at 15:01
  • \$\begingroup\$ I know, and I don't want to, but I can't help it. Actually, after testing 5 answers, it turned out that almost all of them were giving different results (this was indeed completely unsuspected). I could have followed some other approach, but that would have requried the complete change of the algorithms of the current answers. This one is the best I could figure out. \$\endgroup\$ Commented May 16, 2014 at 15:03
  • 2
    \$\begingroup\$ Well I know that mine works perfectly, so I should totally get the check :D ;) \$\endgroup\$
    – Kyle Kanos
    Commented May 16, 2014 at 15:05
6
\$\begingroup\$

Perl, 120 108 104 89 85

<>=~/ /;$c=$t=1;for(1..2*$'-1){$t*=$`/$_;$_%2?$s:$c+=$_&2?-$t:$t}printf"%f\n"x2,$s,$c

Ungolfed:

<> =~ / /;
$cosine = $t = 1;
for (1.. 2*$' - 1){
  $t *= $` / $_;
  ($_%2 ? $sine : $cosine) += $_&2?-$t:$t
}
printf "%.6f\n" x2, $sine, $cosine

The first line reads the input and uses regex to find a space; this automatically puts the value before the space in $` and the value after it in $'.

Now we loop from 1 to 2*n-1. $t is our term, which the loop repeatedly multiplies by x and divides by the loop's index ($_). The loop starts at 1 rather than 0 because the cosine is initialized to 1, which saved me having to deal with dividing by zero.

After updating $t, the trinary operator returns either $sine or $cosine, depending on whether the index is odd or even, and adds $t's value to it. The magic formula $_&2?-$t:$t figures whether to add or subtract this value (basically using a bitwise-and on the index and 2 to generate the repeating sequence of "add, add, subtract, subtract").

You can test-run this code at compileonline.com.

\$\endgroup\$
7
  • \$\begingroup\$ Please correct your output for 20 20. \$\endgroup\$ Commented May 15, 2014 at 6:32
  • 1
    \$\begingroup\$ I think your for loop may need to go from 1..$n*2-1, instead of 1..$n. While I'm here... $s is perfectly fine left uninitialized, as undef evaluates to 0 in a numeric context. Ternary assignment doesn't need parentheses: $_&1?$s:$c+=$t. "%.8f\n%.8f" can be shortened to "%.8f\n"x2, at the consequence of adding a trailing newline. \$\endgroup\$
    – primo
    Commented May 15, 2014 at 9:15
  • \$\begingroup\$ @Primo Thanks, I didn't know about some of those. And now it even produces the correct result as well. \$\endgroup\$
    – Tal
    Commented May 15, 2014 at 10:38
  • \$\begingroup\$ @Tal My pleasure. Also, slightly better magic: $t*(1-($_&2)) => $_&2?-$t:$t. \$\endgroup\$
    – primo
    Commented May 15, 2014 at 10:53
  • \$\begingroup\$ Please update your answer. See details in question. Thanks. \$\endgroup\$ Commented May 16, 2014 at 14:56
4
\$\begingroup\$

C, 120

double s,c,r,x;main(i,n){for(scanf("%lf %d",&x,&n),r=1;i<n*2;s+=r,r*=-x/i++)c+=r,r*=x/i++;printf("%.8lf\n%.8lf\n",s,c);}

To save a byte, the statements that update the sine value are placed inside the for() statement, but are actually executed after the statements following the closing parenthesis that update the cosine value. (I guess I could also save a couple more bytes by removing the final newline character in the program's output.)

The global variables s, c, r and x are implicitly initialized to zero, and i will have a value of 1 as long as there are no arguments provided on the command line. Unfortunately printf() defaults to 6 places of decimals, so the output format is a bit verbose.

Ungolfed:

Here's the code with a bit of rearrangement to make the order in which things are done a bit clearer:

double s,c,r,x;
main(i,n) {
    scanf("%lf %d",&x,&n);
    r=1;
    for(;i<n*2;) {
        c+=r;
        r*=x/i++;
        s+=r;
        r*=-x/i++;
    }
    printf("%.8lf\n%.8lf\n",s,c);
}

Sample output:

$ echo 1.23 4 | ./sincos
0.94247129
0.33410995

Try it online:

http://ideone.com/URZWwo

\$\endgroup\$
3
\$\begingroup\$

Python >=2.7.3, 186 184 211 200 182 170 characters

Kinda simple as hell. Uses formula from the question parameterized for sine and cosine.

Online interpreter can be found here here

x,n=map(eval,raw_input().split())
f=lambda n:n<2and 1or n*f(n-1.)
for i in[1,0]:print"%.6f"%sum((1-j%2*2)*reduce(lambda o,p:o*p,[x]*(i+2*j),1)/f(i+2*j)for j in range(n))

Edit: Valid version with all the restrictions

Edit2: Changed online interpreter to ideone.com because of invalid round function output in Python 2.7.1

Edit3: Turned out that I used unnecessary inline lambda + changed rounding to string format (stolen from xnor :) )

Edit4: Replaced join with not functional main for loop

\$\endgroup\$
5
  • \$\begingroup\$ Hello avail, I have recently edited the rules which now do not allow the built-in operators for exponentiation (that is what the ** is doing I suppose). So, I think you will have to edit your answer. Sorry for inconvenience. Please correct me if I am wrong. \$\endgroup\$ Commented May 14, 2014 at 6:37
  • 1
    \$\begingroup\$ I guess further modifications are useless with xnor's answer :) \$\endgroup\$
    – avall
    Commented May 14, 2014 at 7:51
  • \$\begingroup\$ @avail On 20 20, I get output -5364.4118142500001. Might want to fix it to 8 decimals. \$\endgroup\$ Commented May 15, 2014 at 6:31
  • \$\begingroup\$ It is because of repl.it Python version 2.7.1. If you run it on ideone.com (Python 2.7.3) it works properly. ideone.com/JsYNNK \$\endgroup\$
    – avall
    Commented May 15, 2014 at 7:49
  • \$\begingroup\$ It works nice now! +1 \$\endgroup\$ Commented May 15, 2014 at 12:22
3
\$\begingroup\$

JavaScript - 114 chars

y=(z=prompt)().split(' ');for(x=l=s=+y[0],c=d=1;--y[1];c+=l*=-x/++d,s+=l*=x/++d);z(s.toFixed(6)+'\n'+c.toFixed(6))

Based on james' great answer. Same algorithm, first step avoided with initialization of c=1 and s=x. Using 2 vars instead of an array for output simplifies the loop.

Ungolfed

y = ( z = prompt)().split(' ');
for ( 
    x = l = s = +y[0], /* init to value x, note the plus sign to convert from string to number */
    c = d = 1;
    --y[1]; /* No loop variable, just decrement counter */
    c += (l *= -x / ++d), /* Change sign of multiplier on each loop */
    s += (l *= x / ++d) 
); /* for body is empty */
z(s.toFixed(6) + '\n' + c.toFixed(6))     
\$\endgroup\$
2
  • \$\begingroup\$ Minor typo: It would be s += (l *= x / ++d) and not s += (l* = x / ++d) in the ungolfed code. \$\endgroup\$ Commented May 15, 2014 at 12:50
  • 1
    \$\begingroup\$ @GaurangTandon fixed \$\endgroup\$
    – edc65
    Commented May 15, 2014 at 13:07
3
\$\begingroup\$

GNU bc, driven by bash, 128 bytes

Far too many bytes spent setting decimal places and to-nearest rounding. Oh well, here it is anyway:

bc -l<<<"m=1000000
w=s=$1
c=1
for(p=2;p/2<$2;s+=w){w*=-1*$1/p++
c+=w
w*=$1/p++}
s+=((s>0)-.5)/m
c+=((c>0)-.5)/m
scale=6
s/1
c/1"

Output:

$ ./trig.sh 5 3
10.208333
14.541667
$ ./trig.sh 8.555 13
.765431
-.641092
$ ./trig.sh 9.26 10
-3.154677
-8.404354
$ ./trig.sh 6.54 12
.253986
.967147
$ ./trig.sh 5 1
5.000000
1.000000
$ ./trig.sh 20 20
-5364.411846
-10898.499385
$ 

Linux command-line tools, 97 unicode characters

Unicode hack answer removed at OP's request. Look at the edit history if you interested.

\$\endgroup\$
4
  • \$\begingroup\$ I don't like changing rules after posting the question, but I have disallowed code-compression-allowing-Unicode characters, as I did not know Unicode characters could be used to compress code. Only ASCII characters can be used now. Please edit your post. Sorry for inconvenience \$\endgroup\$ Commented May 15, 2014 at 17:47
  • \$\begingroup\$ @GaurangTandon Its not really compression - the unicode version actually takes more bytes (but less characters). But I agree with your sentiment - I actually prefer scoring to strictly be done using byte count, but couldn't resist the bit about Chinese characters in your OP. \$\endgroup\$ Commented May 15, 2014 at 17:50
  • \$\begingroup\$ You use illegal exponential operator \$\endgroup\$
    – avall
    Commented May 15, 2014 at 21:27
  • \$\begingroup\$ @avall Oops. That cost me 4 bytes. \$\endgroup\$ Commented May 15, 2014 at 21:32
2
\$\begingroup\$

JavaScript (ECMAScript 6 Draft) - 97 96 Characters

A recursive solution:

f=(x,n,m=1,i=0,s=x,c=1)=>i<2*n?f(x,n,m*=-x*x/++i/++i,i,s+m*x/++i,c+m):[s,c].map(x=>x.toFixed(8))

Output:

f(0.3,1)
["0.29550000", "0.95500000"]

f(0.3,24)
["0.29552021", "0.95533649"]
\$\endgroup\$
4
  • \$\begingroup\$ That doesn't meet the spec regarding rounding though. \$\endgroup\$ Commented May 14, 2014 at 18:31
  • \$\begingroup\$ @m.buettner fixed \$\endgroup\$
    – MT0
    Commented May 14, 2014 at 19:07
  • 1
    \$\begingroup\$ It doesn't meet input format and no functions requirement. \$\endgroup\$
    – avall
    Commented May 15, 2014 at 6:11
  • \$\begingroup\$ Please update your answer. See details in question. Thanks. \$\endgroup\$ Commented May 16, 2014 at 15:08
2
\$\begingroup\$

C,114

Insufficient reputation to comment, but further to Squeamish Offisrage's C answer, 7 byte reduction by using float for double and removing spaces, and combining declaration and init of 'r' gives

float s,c,r=1,x;main(i,n){for(scanf("%f%d",&x,&n);i<n*2;s+=r,r*=-x/i++)c+=r,r*=x/i++;printf("%.8f\n%.8f\n",s,c);}

try here.

\$\endgroup\$
7
  • \$\begingroup\$ Welcome to programming puzzles and code golf. Well done for acknowledging that your answer is a minor improvement on @squeamishossifrage's (I still managed to spell it wrong in my edit.) Best not to refer to the answer "above" because the order changes every time there is an edit. BTW, I noticed the initialization of r in the declaration. I haven't tested to see if float gives the required precision. \$\endgroup\$ Commented May 15, 2014 at 12:36
  • \$\begingroup\$ @steveverrill Neither did I think float would give the required precision, but it does work :) And welcome to PPCG, user2702245 ! \$\endgroup\$ Commented May 15, 2014 at 12:54
  • \$\begingroup\$ Is it just me thats getting the wrong answers with float variables then? For x=5 and n=3, I get sin(x)=10.20833206 and cos(x)=14.54166412 :-( (Intel Core Duo, in case you were wondering) \$\endgroup\$
    – r3mainer
    Commented May 15, 2014 at 14:26
  • \$\begingroup\$ Would you like me to convert this to a comment on said answer? \$\endgroup\$
    – Doorknob
    Commented May 15, 2014 at 18:19
  • \$\begingroup\$ @Doorknob May as well leave it now :-) \$\endgroup\$
    – r3mainer
    Commented May 15, 2014 at 18:51
1
\$\begingroup\$

Ruby, 336

Probably the longest one here, but I'm sure it could be made shorter :(

def f(n)
n==0 ? 1: 1.upto(n).inject(:*)
end
def p(x,y)
i=1
return 1 if y==0 
y.times {i *= x}
i
end
def s(x,n)
a = 0.0
for k in 0...n
a += p(-1,k) * p(x.to_f, 1+2*k)/f(1+2*k)
end
a.round(8)
end
def c(x,n)
a= 0.0
for k in 0...n
a +=p(-1,k) * p(x.to_f, 2*k)/f(2*k)
end
a.round(8)
end
x = gets.chomp
n = gets.chomp.to_i
puts s(x,n), c(x,n)
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6) - 185 chars

i=(h,n)=>n?h*i(h,n-1):1;q=x=>x?x*q(x-1):1;p=(a,j,n)=>{for(c=b=0,e=1;c++<n;j+=2,e=-e)b+=e*i(a,j)/q(j);return b.toFixed(6)}
_=(y=prompt)().split(" ");y(p(_[0],1,_[1])+"\n"+p(_[0],0,_[1]))

Uses a function q for factorial, i for exponentiation, and p for performing both sin and cos. Run at jsbin.com. Uses exactly the formula without any modification.

EDIT: Changed 8 decimal places to 6 decimal places. 15/May/14

Ungolfed Code:

/*Note that `name=args=>function_body` is the same as `function name(args){function_body} */

// factorial
function fact(x) {
    return x > 1 ? x * fact(x - 1) : 1
}

// Exponentiation
function expo(number, power){
    return power > 0 ? number * expo(number, power - 1) : 1;
}

function sin_and_cos(number, starter, terms) {
    for (count = sum = 0, negater = 1;
            count++ < terms;
            starter += 2, negater = -negater) 

        sum += (negater * expo(number, starter)) / fact(starter);

    // to 6-decimal places
    return sum.toFixed(6);
}

input = (out = prompt)().split(" ");

out(sin_and_cos(input[0], 1,input[1]) 
        + "\n" +                
        sin_and_cos(input[0], 0, input[1]));
\$\endgroup\$
1
\$\begingroup\$

JavaScript - 133 chars

y=(z=prompt)().split(" "),s=[0,0],l=1;for(i=0;i<y[1]*2;i++){s[i%2]+=i%4>1?-1*l:l;l*=y[0]/(i+1)}z(s[1].toFixed(6));z(s[0].toFixed(6));

Ungolfed

var y = prompt().split(" ");

var out = [0,0]; // out[1] is sin(x), out[0] is cos(x)
var l = 1; // keep track of last term in series
for (var i=0; i < y[1] * 2; i++) {
    out[i % 2] += (i % 4 > 1) ? -1 * l : l;
    l *= y[0] / (i + 1);
}

prompt(out[1].toFixed(6));
prompt(out[0].toFixed(6));
\$\endgroup\$
2
  • \$\begingroup\$ Input has to be two space-separated integers, not in two different dialog boxes. Please fix that. \$\endgroup\$ Commented May 15, 2014 at 6:35
  • \$\begingroup\$ @GaurangTandon fixed - thanks for pointing it out \$\endgroup\$
    – James
    Commented May 15, 2014 at 14:55
1
\$\begingroup\$

Mathematica, 96 chars

{{x,n}}=ImportString[InputString[],"Table"];Column@{Im@#,Re@#}&@Fold[1+I#x/#2&,1,2n-Range[2n-1]]
\$\endgroup\$
3
  • \$\begingroup\$ How is the input format, seems x,n to me ? \$\endgroup\$ Commented May 16, 2014 at 3:58
  • \$\begingroup\$ @GaurangTandon It is x n. \$\endgroup\$
    – alephalpha
    Commented May 16, 2014 at 14:27
  • \$\begingroup\$ Ok, thanks for clarifying. \$\endgroup\$ Commented May 16, 2014 at 14:55
1
\$\begingroup\$

Ruby - 160 152 140 Chars

Using recursion and the fact that for this recursive implementation sin(x, 2n + 1) = 1 + cos(x, 2n - 1), being sin(x, n) and cos(x, n) the series defined above for cos x and sin x.

p=->x,n{n<1?1:x*p[x,n-1]}
f=->n{n<2?1:n*f[n-1]}
c=->x,n{n<1?1:p[x,n]/f[n]-c[x,n-2]}
x,n=gets.split.map &:to_f
n*=2
puts c[x,n-1]+1,c[x,n-2]

Edit: Contributed by commenters (read below).

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can save a lot of characters by using lambdas: p=->x,n{...}, f=->n{...} and so on, and then use square brackets instead of parentheses to call them, like p[x,n-1]. Also, I think collect is just an alias for map, which is much shorter, and since you're only mapping a member call, you can shorten that to gets.split.map &:to_f. \$\endgroup\$ Commented Feb 18, 2015 at 12:57
  • \$\begingroup\$ @MartinBüttner Thanks! Will add this! (hope your comment here stated that this solution is not only mine, but collab) To be honest: I'm also new to ruby (2 month only) :))) \$\endgroup\$
    – Boriel
    Commented Feb 18, 2015 at 12:59
1
\$\begingroup\$

APL(NARS), 109 chars

r←a F w;d;v;m;p
r←d←1+(2≠↑a)×w-1⋄m←w×wׯ1⋄p←2⊃a⋄v←0 1-2=↑a
→0×⍳0≥p-←1⋄r+←d×←m÷×/v+←2⋄→2

⍪{6⍕⍵a[2]F 1⊃a}¨⍳2⊣a←⎕

15+42+28+2+22=109

the last line call the function F that is a sin and cos function depend of first input on the left (it is ≠2 is sin input =2 is cos). Some test:

      ⍪{6⍕⍵a[2]F 1⊃a}¨⍳2⊣a←⎕
⎕:
      5 3
  10.208333 
  14.541667 
      ⍪{6⍕⍵a[2]F 1⊃a}¨⍳2⊣a←⎕
⎕:
      8.555 13
  0.765431  
  ¯0.641092 
      ⍪{6⍕⍵a[2]F 1⊃a}¨⍳2⊣a←⎕
⎕:
      9.26 10
  ¯3.154677 
  ¯8.404354 

OT it would be possible to calculate the exact answer using rationals and input rational for example of 1r4 (0.25=1/4)

      ⍪{6⍕⍵a[2]F 1⊃a}¨⍳2⊣a←⎕
⎕:
      1r4 10
  0.247404 
  0.968912 
      {⍵○1r4}¨⍳2
  0.2474039593 0.9689124217 
      {⍵○0.25}¨⍳2
  0.2474039593 0.9689124217 
      1 10 F 1r4      
  8264318085745811128158727r33404146443928530321408000 
      2 10 F 1r4 
  17051609536099989115458551r17598710837038136237752320   
        

these last 2 numbers both cut would be the decimals 0.2474039592 and 0.9689124217

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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