12
\$\begingroup\$

Given input \$x \in \left\{0,3,6,...,90\right\}\$, output \$\sin\left(x°\right)\$ using integer and \$+ - \times \div ( ) \sqrt{\cdot}\$(square root), e.g. \$\sin(45°)=\sqrt{1\div 2}\$.

Flexible output format. You needn't do any simplification to output, aka. it's fine to output \$\sin(0°)=\sqrt{42}-\sqrt{6\sqrt{-9+58}}\$. Complex intermediate value is fine but please mention.

Shortest code wins.

\$\endgroup\$
3
  • \$\begingroup\$ What exactly is the output format? Especially for square root, how would that be represented, as I understand we're supposed to output a string of some sort. \$\endgroup\$ Nov 3 at 21:39
  • 6
    \$\begingroup\$ May we use square roots to produce complex numbers in intermediate steps? \$\endgroup\$
    – xnor
    Nov 4 at 1:14
  • 2
    \$\begingroup\$ May we use - as both subtraction and as negation? Your example shows it as subtraction. (Ideally we shouldn't have to guess the pattern from examples). \$\endgroup\$
    – Wheat Wizard
    Nov 4 at 2:27

6 Answers 6

15
\$\begingroup\$

Python, 89 bytes

c='s-1*'
y='/s+2/s++7s5s*6+5s522'
f=lambda d:d and'+*'+y+(x:=f(d-3))+'*'+c+x*2+c+y*2or'0'

Attempt This Online!

It times out when trying to run it in ATO when trying to run it for large degrees, but it should work in theory. It outputs in prefix notation, where s is the unary square root operator; all other operators are binary. Furthermore, in this notation, there are only single digits (e.g. 20 represents a 2 then a 0).

It works by repeatedly applying the formula $$ \sin(a+3^{\circ}) = \sin(a) \cos(3^{\circ}) + \cos(a) \sin(3^{\circ}) \\ = \sin(a) \cos(3^{\circ}) + \sqrt{1-\sin(a)\sin(a)} \sqrt{1-\cos(3^{\circ})\cos(3^{\circ})}$$

where \$\cos(3^\circ) = \sin(87^\circ)\$ equals $$\frac12 \sqrt{2+\frac12 \sqrt{7+\sqrt{5}+\sqrt{6(5+\sqrt{5})}}}$$

(according to Wolfram-Alpha).

\$\endgroup\$
7
  • 1
    \$\begingroup\$ You could golf your notation slightly by only allowing single digits, which would save thee bytes \$\endgroup\$
    – emanresu A
    Nov 3 at 23:01
  • \$\begingroup\$ @emanresuA Is that definitely valid? \$\endgroup\$ Nov 3 at 23:04
  • 1
    \$\begingroup\$ It's a perfectly valid and unambiguous representation, and I don't think it's particularly overoptimised for this challenge (which would probably fall under a loophole) \$\endgroup\$
    – emanresu A
    Nov 3 at 23:12
  • \$\begingroup\$ What's the ^ in output? \$\endgroup\$
    – l4m2
    Nov 3 at 23:23
  • 1
    \$\begingroup\$ y+y or'0' => y*2or'0' \$\endgroup\$
    – l4m2
    Nov 3 at 23:29
13
\$\begingroup\$

Python 3, 75 bytes

lambda x:f"(1-1{(s:=x//3*'*(1+S(5)+S(S(20)-10))/(S(12)+S(-4))')})/S(-4{s})"

Try it online!

This produces an expression with complex numbers as intermediates that can be evaluated in Python with S=cmath.sqrt. For instance, x=3 gives:

(1*S(1+S(5)+S(2*S(5)-10))/S(S(12)+S(-4))-1/(1*S(1+S(5)+S(2*S(5)-10))/S(S(12)+S(-4))))/S(-4)

The main idea is to work with complex numbers, in particular roots of unity. Since \$e^{i \theta}\ = \cos(\theta) + i\sin(\theta)\$ where \$i = \sqrt{-1}\$, we can work with multiples of \$\theta\$ as

$$\ \cos(k\theta) + i\sin(k\theta)= e^{i k\theta}\ = \left(e^{i \theta}\right)^k = \left( \cos(\theta) + i\sin(\theta)\right)^k$$

From there, we can extract just the sine with:

$$\sin(k \theta) = \frac{\left(e^{i \theta}\right)^k-1/\left(e^{i \theta}\right)^k}{2i}$$

We can take the \$k\$ power by multiplying \$k\$ times, that is concatenating \$k\$ copies of *stuff in the expression, since the challenge doesn't allow exponents in the formula.

So we express \$e^{i \theta}\$ for \$\theta = 3^{\circ}\$ (three degrees), and take its \$k\$-th power by multiplying it \$k\$ times, using string repetition.

It remains to express \$e^{i \theta}\$ for \$\theta = 3^{\circ}\$. We could directly write out its sine and cosine, but it's a bit shorter to express it in terms of 36 and 30 degrees:

$$e^{i (3^\circ)} = \sqrt{e^{i (6^\circ)}} = \sqrt{e^{i (36^\circ)}e^{i (-30^\circ)}} = \sqrt{(\cos(36^\circ)+i \sin (36^\circ))(\cos(30^\circ)-i \sin (30^\circ))}$$

These angles have relatively nice sines and cosines. A bit of tweaking and combining terms gives this in the code's notation as:

S((1+S(5)+S(2*S(5)-10))/(S(12)+S(-4)))

If we call S(c) the value above, the value we want to output is:

(S(c) - 1/S(c))/S(-4)

using that \$\sqrt{-4} = 2i\$. Finally, an improvement from @loopwalt that saved 6 bytes is to simplify this to

(1-c)/S(-4c)
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Bit of a different answer, but you can save quite a few bytes by using a prefix notation similar to 97.100.67.109's answer \$\endgroup\$
    – emanresu A
    Nov 4 at 9:55
  • 2
    \$\begingroup\$ Can't you write S(20) for 2*S(5)? \$\endgroup\$
    – loopy walt
    Nov 4 at 15:53
  • 1
    \$\begingroup\$ -6 I believe lambda x:f"(1-1{(s:=x//3*'*(1+S(5)+S(S(20)-10))/(S(12)+S(-4))')})/S(-4{s})" \$\endgroup\$
    – loopy walt
    Nov 5 at 11:58
5
\$\begingroup\$

Vyxal, 39 bitsv2, 4.875 bytes

∆R∆sS

Try it Online!

Bitstring:

000100111011111001011001001010111111101

Outputs square root as sqrt(...), and division as /. Uses sympy to calculate the exact sine value, and then casts to string.

Explained

∆R∆sS­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣‏⁠‎⁡⁠⁤‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌­
∆R     # ‎⁡Convert the input to radians
  ∆s   # ‎⁢find sine of that
    S  # ‎⁣cast to string, which stops conversion to float. Instead, it uses the exact representation, which is expressed in terms of integers.
💎

Created with the help of Luminespire.

\$\endgroup\$
2
  • \$\begingroup\$ I always feel a little bit silly when I write a solution in the triple-digit byte counts, then see a solution in a golfing language in under a dozen bytes :P \$\endgroup\$ Nov 3 at 23:13
  • 6
    \$\begingroup\$ @97.100.97.109 I feel, if anything, the opposite. Meaning I'll sometimes feel the builtin is just a cheat. Not that I am against golfing languages by a longshot. They certainly have their own beauty and finding the exact right tool or builtin for the job is undoubtedly a skill, can require broad knowledge of many languages in some cases, and is its own sort of satisfaction. But I also often feel the more work you are doing as a programmer, from a pure problem-solving perspective, the more impressive. TLDR: don't feel silly, it's apples and oranges. \$\endgroup\$
    – Jonah
    Nov 4 at 1:21
4
\$\begingroup\$

Python 3 + SymPy, 41 39 bytes

lambda n:sin(rad(n))
from sympy import*

Try it online! Link outputs all results from to 90°. Edit: Saved 2 bytes thanks to @loopywalt.

\$\endgroup\$
1
  • \$\begingroup\$ You can use sympy.rad to save two bytes. \$\endgroup\$
    – loopy walt
    Nov 4 at 9:20
4
\$\begingroup\$

Ruby, 132 110 bytes

f=->x{(x%60-24).abs==6?%w{(s5-1)/4 1/2 (s(30+s180)+s5-1)/8 1}[x/30]:"s(1/2+#{q=x<=>45}*(#{f[q*(x*2-90)]})/2)"}

Try it online!

While existing answers are very clever (and shorter than this!), the output expressions are rather long. This recursive function uses the half-angle formulas to produce expressions that fit on a single line in all cases.

Half angle formulas (rules for determining correct sign in all quadrants are unnecessary and omitted):

cos(a/2)=sqrt(1/2+(cos a)/2) or cos x=sqrt(1/2+(cos x*2)/2)

sin(a/2)=sqrt(1/2-(cos a)/2) or sin x=sqrt(1/2-(cos x*2)/2)

Below is a development version of the code, showing how the half angle formula is used to recursively derive expressions for all inputs. There are four infinite cycles as follows: 30>30, 90>90, 18>54>18, 78>66>42>6>78. These are broken with explicit values for 30,90,18 and 78 (note even the fairly complex base expression for 78 is much simpler than the base expression for 3 used in other answers.)

Development code with table showing how each value is derived by recursion

f=->x{m=x%60
m==30?"1/2"[0,90/x]:m==18?"(sqrt5-1)/4/-2+(sqrt(30+sqrt180)/8"[0,x/13*11]:"sqrt(1/2+#{s=x<=>45}sin(#{s*(x*2-90)})/2)"}

Try it online!

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

Mathematica/Wolfram, 27 bytes

f=FunctionExpand@Sin[#*°]&

Try it online (thx to @noodle man)

This is a function solution - # introduces a placeholder for argument and & says whatever comes before is a pure function. ° is builtin for number of radians in a degree, @ is function application without brackets. Beyond that just relying on the underlying symbolic computation engine.

The full list of answers can be generated via:

Table[f[i * 3], {i, 0, 30}]

enter image description here

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Welcome to Code Golf, and nice first submission! Mathematica is actually on TIO: Try it online! \$\endgroup\$
    – noodle man
    Nov 6 at 18:20
  • \$\begingroup\$ @noodleman thanks! I was kind of assuming Wolfram would never license it, so I didn't bother to actually check - apparently my assumptions were incorrect. \$\endgroup\$ Nov 6 at 20:35

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