7
\$\begingroup\$

…without using any operator/function besides addition (+), subtraction (-), multiplication (*), division (/), modulo (%), exponent/power pow() or any of the standard C bitwise operators (<<, >>, ~, &, |, ^) or unary operators (—, ++) or assignment/comparison operators (=, ==).

If these symbols represent a different operation in your chosen language, go with the spirit of the question and don't use them.

Rules:

  • You cannot use any mathematical functions your language might offer (Mathematica, looking at you.)
  • You cannot use any operator besides the bitwise operators or the arithmetic operators listed above.
  • Your output should be a float and be correct to at least 2 decimal places when truncated/rounded.
  • You can use constants your language's standard libraries might provide.
  • You can hardcode the values, but your program should work correctly for all floats (up to 2 decimal places) between 0 and ;

This is code-golf, so the shortest answer wins.

Example:

Input: 3.141592653 / 2
Output: 1.00xxxxxx…

Please also post an ungolfed version of your code.

\$\endgroup\$
  • \$\begingroup\$ The tag code-challenge needs an objective winning criterion. \$\endgroup\$ – Howard Mar 7 '14 at 9:42
  • \$\begingroup\$ @Howard Updated the tags. \$\endgroup\$ – duci9y Mar 7 '14 at 9:43
  • 5
    \$\begingroup\$ The sandbox is too dormant The sandbox isn't dormant in any way. As you just notice yourself (after more than 10 edits in the last 30 minutes) it requires time and thought to produce a good challenge. The sandbox is just the right place to iron out any dents in your question. That's the purpose of the sandbox - to keep this noise from entering the main page. \$\endgroup\$ – Howard Mar 7 '14 at 10:20
  • 3
    \$\begingroup\$ Most of the current answers seem to violate the letter of the question without violating the spirit. In particular, with the exception of the APL one they all use one of <, >, or ^ meaning to-the-power-of rather than bitwise-XOR. Whether you prefer to comment on those answers and inform their submitters that they're invalid, or to edit the question to permit them, you could make things a lot clearer by listing the operators by name, not symbol in some unspecified language, and by grouping them with some kind of title or label (comparison, bitwise, arithmetic, assignment). \$\endgroup\$ – Peter Taylor Mar 7 '14 at 11:05
  • 1
    \$\begingroup\$ If I am not mistaken, even the sine function provided by libraries will not meet the trucation criterion: You can most likely find an x such that sin(x) = a.bc9999… (with a, b, c being some digits) and thus the output being a.bd0000… (with d = c+1). Therefore matching this criterion as it stands would be very nasty. Also, I would not know any language where exp is the exponent operator (or exponentiation) and not the exponential function. \$\endgroup\$ – Wrzlprmft Mar 7 '14 at 19:37

15 Answers 15

7
\$\begingroup\$

Python 83 69

Based on Bhaskara I's sine approximation formula

Implementation

def f(x):p=3.14;x,s=x%p,(4,-4,4)[int(x/p)];return s/(12.34/x/(p-x)-1)

Ungolfed

def apxsine(radian):
    pi = 3.14 # Approximate to 2 decimal places
    sign = (4,-4,4)[radian % pi]
    return sign / (12.34/radian/(pi - radian) - 1))

Deduction

enter image description here

Demo

>>> from math import pi, sin
>>> any(round(abs(f(e) - sin(e)), 2) for e in (e/180.*pi for e in range(0,360)))
False

JUst realized that if I would have opted for Euler's formula route, the code would be shorter (49 characters). But then it uses Complex numbers and am not sure if the call to the real method would be valid in the current question context.

f=lambda x:((2.72**(x*1j)-2.72**(-x*1j))/2j).real
\$\endgroup\$
  • \$\begingroup\$ Running f(3.141592653 / 2) returns 0.998…. Your answer should be valid to at least two decimal places (1.00…). Please tell me if I did something wrong. \$\endgroup\$ – duci9y Mar 7 '14 at 10:54
  • 1
    \$\begingroup\$ @duci9y: I believe, you need to round the result to two decimal place. round(f(3.141592653 / 2),2), instead of truncating \$\endgroup\$ – Abhijit Mar 7 '14 at 11:05
  • \$\begingroup\$ @duci9y Abhijit is right, you're truncating. The answer does give correct results. \$\endgroup\$ – devnull Mar 7 '14 at 11:08
  • 1
    \$\begingroup\$ @duci9y: Your question demanded a result which is precise to 2 decimal places Your output should be a float and be correct to at least 2 decimal places., so mathematically speaking that's rounding rather than truncating. \$\endgroup\$ – Abhijit Mar 7 '14 at 11:33
  • 4
    \$\begingroup\$ @duci9y His answer is accurate to two decimal places. 1.00 is the same as .998 to two decimal places. \$\endgroup\$ – McKay Mar 7 '14 at 13:59
5
\$\begingroup\$

MATLAB 35

Too bad e is not a constant in Matlab. That would have saved me 10 characters. I will see if I can come up with a solution for this.

@(x)(2.7183^(x*i)-2.7183^(-x*i))/2i
\$\endgroup\$
  • 1
    \$\begingroup\$ May be you can try the approximate value as 2.72? After all the question dictates that the precision could be within 2 decimal places. \$\endgroup\$ – Abhijit Mar 7 '14 at 11:15
  • \$\begingroup\$ I tried this, but for all values between 0 and 2pi, this was the minimum required definition of e in order to get the desired accuracy. \$\endgroup\$ – mmumboss Mar 7 '14 at 11:17
  • \$\begingroup\$ Strange, I tried your implementation in Python, and it seems to give me correct result. Unfortunately, I do not have Matlab to try this out :-) \$\endgroup\$ – Abhijit Mar 7 '14 at 11:18
  • \$\begingroup\$ And when you try it with an input of 6.28? \$\endgroup\$ – mmumboss Mar 7 '14 at 11:22
  • \$\begingroup\$ If I round the result to 2 decimal places it matches i.e. the formula with 2 decimal approximation of e gives -0.0031853017931379904 where as sin returns 0.0007829010740853711, which are both zero approximate to 2 decimal places. Refer ideone.com/I6Ifld \$\endgroup\$ – Abhijit Mar 7 '14 at 11:28
5
\$\begingroup\$

Javascript 114 77

Using Taylor Series expansion at 0:

function s(y){
    var p=2*Math.PI,
        // z = sign (y)
        z=(y>0?1:-1),
        // x = (abs(y) mod 2 PI - PI) * sign(y) => put x in [-PI, PI] range
        x=-z*((z*y)%p-p/2),
        // u = x^2
        u=x*x; 
        // return Taylor Expansion
        return x*(1-(1-(1-(1-u/72)*u/42)*u/20)*u/6);
}

Golfed (114):

function s(y){var z=(y>0?1:-1),p=2*Math.PI,x=-z*((z*y)%p-p/2),u=x*x; return x*(1-(1-(1-(1-u/72)*u/42)*u/20)*u/6);}

Edit

"Improved" for y in [0,2PI], golfed (77) :

function s(y){var x=3.14-y,u=x*x;return x*(1-(1-(1-(1-u/72)*u/42)*u/20)*u/6)}

Another version for more precision (varying k) :

function s(y){
    var p=2*Math.PI,
        // z = sign (y)
        z=(y>0?1:-1),
        // x = (abs(y) mod 2 PI - PI) * sign(y) => put x in [-PI, PI] range
        x=-z*((z*y)%p-p/2),
        // u = x^2
        u=x*x,
        // k = 2* expansion level +1
        k=9,
        // r = 1 initial value
        r = 1; 

        // Taylor Expansion
        // while k > 1
        for(;k>1;) { 
            r= 1 - r*u /k--/k--; 
        }
        return x*r;
 }

Golfed (114):

function s(y){var z=(y>0?1:-1),p=2*Math.PI,x=-z*((z*y)%p-p/2),u=x*x,k=9,r=1;for(;k>1;)r=1-r*u/k--/k--;return x*r;}
\$\endgroup\$
  • \$\begingroup\$ Please post an ungolfed version too. \$\endgroup\$ – duci9y Mar 7 '14 at 10:46
  • \$\begingroup\$ @duci9y ungolfed version given \$\endgroup\$ – Julien Ch. Mar 7 '14 at 11:02
4
\$\begingroup\$

APL - 21

{|{.5×⍵-+⍵}0J1*⍵÷○.5}

This uses the fact that sin pi*x/2 = Im[(-1)^x].

Example test on ngn APL

Previous answer: 26

{-/((×\9⍴⍵)÷×\1+⍳9)[2×⍳5]}

This uses the Taylor/Maclaurin series up to 9th term.

Example test on ngn APL

Note about operators: only operators used were /\⍴⍳ which don't have anything to do with arithmetic, and are mostly list manipulation tools, which is multiply by pi, and +-×÷* which are permitted by the rules

\$\endgroup\$
  • \$\begingroup\$ The 20 character line seems to give wrong answers? \$\endgroup\$ – mmumboss Mar 7 '14 at 13:25
  • \$\begingroup\$ @mmumboss Yeah, sorry, fixed \$\endgroup\$ – mniip Mar 7 '14 at 13:41
  • \$\begingroup\$ Your example link gives wrong result and does not match your post. Save nine bytes: 11○0J1*2÷○∘÷ \$\endgroup\$ – Adám Apr 25 '17 at 12:16
  • \$\begingroup\$ 11○ is just shorthand for |{.5×⍵-+⍵}. \$\endgroup\$ – Adám Apr 25 '17 at 12:18
4
\$\begingroup\$

C++ 80 68(excluding white-spaces + edit)

GOLFED

float S(float x){float z=x*x,y=x*(5040-(840+(42-z)*z)*z)/5040;return y;}  

UNGOLFED

both versions are different so that, it is easy to get output.

#include<iostream>
int main()
{
    float x,y,z;
    for(;;)
    {
        std::cin>>x;
        z=x*x;
        y=(x*(5040-840*z+42*z-z*z*z))/5040;
        std::cout<<y<<'\n';
    }
}  

Output

1.047197 ((pie)/3)
0.865096 (sin((pie)/3) = 1.73201/2 = 0.8660)
\$\endgroup\$
2
\$\begingroup\$

Javascript (56)

j=x=+prompt(r=0);for(i=1;i<99;j*=x/++i)r+=i&1?i&2?-j:j:0

Taylor series used here.
x is the input value, r is the result, j contains x^i/i!
The result is output in console.

x=prompt();
r=0;
j=1;
for(i=1;i<99;i++) {
  j=j*x/i;
  if (i%2) {
    if (i%4 == 1) r+=j;
    else r-=j;
  }
}
alert(r);

If evaluation is needed for input (for example 3.141592653 / 2) :

j=x=eval(prompt(r=0));for(i=1;i<99;j*=x/++i)r+=i&1?i&2?-j:j:0
\$\endgroup\$
  • \$\begingroup\$ Bravo... a lot more compact than my: f=n=>+!n||n*f(n-1);for(x=prompt(),y=s=0;9>=y;y++)s+=Math.pow(-1,y)*Math.pow(x,z=2*y+1)/f(z);alert(s) \$\endgroup\$ – WallyWest Mar 9 '14 at 11:28
2
\$\begingroup\$

Haskell

import Prelude hiding (sin)
import Data.Complex
sin x=(\(_:+y) -> y) $ exp (0 :+ x)

Uses Euler's formula. (y :+ z)=y+zi I think.

\$\endgroup\$
  • \$\begingroup\$ Is imagPart a mathematical function? \$\endgroup\$ – duci9y Mar 7 '14 at 12:14
  • \$\begingroup\$ I would consider complex arithmetics with exp cheating, as in complex, exp and trig are the same. Otherwise, there's an unfair advantage. \$\endgroup\$ – orion Mar 7 '14 at 17:19
  • \$\begingroup\$ Sorry, not a valid answer. \$\endgroup\$ – duci9y Mar 7 '14 at 17:31
  • \$\begingroup\$ Whoops, sorry, got rid of outside math function. (It wasn't much of a math function, but it is gone now.) \$\endgroup\$ – PyRulez Mar 7 '14 at 20:44
2
\$\begingroup\$

Python, 70 bytes

Using sin(x) = Im(exp(ix)) and the series for the exponential function:

def s(x):
    s,f=0,1
    for i in range(1,50):f*=1j*x/i;s+=f
    return s.imag

Note that imag is not a function here, strictly speaking.

Ungolfed:

def s(x):
    s = 0
    f = 1
    for i in range(1,50):
        f *= 1j*x/i
        s += f
    return s.imag
\$\endgroup\$
1
\$\begingroup\$

R, 80 chars

f=function(x){a=seq(1,99,2);sum((-1)^(0:49)*(x^a)/sapply(mapply(`:`,1,a),prod))}

Uses Taylor approximation at an order of 99. sapply and mapply are just functions to vectorize the operation, while sum and prod are just vectorized + and *.

> b=seq(0,2*pi,1e5)
> all((f(b)-sin(b))<.01)
[1] TRUE

If the *apply functions are a problem, here is a solution at 91 characters:

f=function(x){a=0:100;b=c();for(i in 1:50)b[i]=(-1)^(i-1)*(x^a[2*i])/prod(1:a[2*i]);sum(b)}
\$\endgroup\$
1
\$\begingroup\$

C 70

This one is not only golf but also useful in microcontrollers without floating point instructions or math libraries:

float S(float a){float x,y=1,h=1e-4;while(x+=h*(y-=h*x),(a-=h)>0);return x;}

Of course, the majority of the characters is taken by these annoyingly long type declarations and return. If the function declaration doesn't count, it's much shorter. If we take the value by pointer and overwrite it (removing the return statement), we get 71 characters.

S(float*x){float a=*x,y=1,h=1e-4;*x=0;while(*x+=h*(y-=h**x),(a-=h)>0);}

However, it complains about default return value.

EDIT: 70, for is shorter:

S(float*x){float a=*x,y=1,h=1e-4;*x=0;for(;(a-=h)>0;*x+=h*(y-=h**x));}

EDIT2: forgot ungolfed version

float fake_sin(float a){
   float x=0,y=1;
   float h=1e-4;//adjust for accuracy
   while(a>0){
      y-=h*x;
      x+=h*y;
      a-=h;
   }
   return x;//return y for cosine or y/x for tangent
}

It takes arbitrary positive angle, but doesn't work for negative.

\$\endgroup\$
1
\$\begingroup\$

Java - 108 / 81

float s(float p){for(float q=p-=3.14,d=p=-p,i=1,m=1;i<11;)p+=(q*=d*d)/(m*=++i*++i)*(((int)i&2)-1);return p;}

Without the function declaration, it's just doing p = sin(p):

for(float q=p-=3.14,d=p=-p,i=1,m=1;i<11;)p+=(q*=d*d)/(m*=++i*++i)*(((int)i&2)-1);

The error is max ±0.00201 in the range 0..2π, much worse in either direction.

Ungolfed:

float s(float p) {
    for (float q = p -= 3.14, d = p = -p, i = 1, m = 1; i < 11;)
        p += (q *= d * d) / (m *= ++i * ++i) * (((int)i & 2) - 1);
    return p;
}

Unobfuscated:

float sin(double ph) {
    float [] dividers = {-1, 6, -120, 5040, -362880, 39916800L};
    ph -= Math.PI;
    double d = 0;
    for (int i = 0; i < 6; i++)
        d += Math.pow(ph, i * 2 + 1) / dividers[i];
    return d;
}
\$\endgroup\$
1
\$\begingroup\$

C# - 115 103

This code uses an approximation of Maclaurin series calculation of the sine of x, and is accurate to 7 decimal places.

float x=0;for(int i=1;i<96;i+=2){float n=i,d=1,p=a;while(n>1){d*=n;n--;p*=a;}x+=((i+1)%4==0?-1:1)*p/d;}

Where a is the input in radians.

Here's the code with whitespaces:

float x = 0; for (int i = 1; i < 96; i += 2)
{
    float n = i, d = 1, p = a;
    while (n > 1)
    {
        d *= n;
        n--;
        p *= a;
    }
    x += ((i+1)%4==0?-1:1)*p / d;
}
\$\endgroup\$
0
\$\begingroup\$

TI-84 BASIC, 21 bytes

(e^(iAns)-e^(⁻iAns))/2i
\$\endgroup\$
0
\$\begingroup\$

Perl 6, 17 16 bytes

{(e**(i*$_)).im}
\$\endgroup\$
0
\$\begingroup\$

Axiom, 139 bytes

s(x:Float):Complex Float==(digits()>20=>%i;x>2*%pi=>s(x-2*%pi);x< -2*%pi=>s(x+2*%pi);imag(reduce(+,[(%i*x)^k/factorial(k)for k in 0..40])))

I see this formula in the other solutions and I inplemented it in Axiom... The formula i follow is this:

                               +oo
                               ----
                               \      (i*x)^k
sin(x)=ImPart(e^(i*x))=imPart( /     --------  )
                               ----k     k!
                                 0

ungolf

sin1(x:Float):Complex Float==
              digits()>20=>%i
              x>  2*%pi  =>sin1(x-2*%pi)
              x< -2*%pi  =>sin1(x+2*%pi)
              imag(reduce(+,[(%i*x)^k/factorial(k)for k in 0..40]))

there is some problem for the last 2 digits each number; some test cases:

(79) -> [-23, numeric(sin(-23)), s(-23) ]
   (79)  [- 23.0,0.8462204041 7517063524,0.8462204041 7517063514]
                                                 Type: List Complex Float
(80) -> [ 23, numeric(sin( 23)), s( 23) ]
   (80)  [23.0,- 0.8462204041 7517063524,- 0.8462204041 7517063536]
                                                 Type: List Complex Float
(81) -> [[x/2,numeric(sin(x/2)),s(x/2)] for x in 0..(7*2)]
   (81)
                  1
   [[0,0.0,0.0], [-,0.4794255386 0420300027,0.4794255386 0420300027],
                  2
    [1,0.8414709848 0789650665,0.8414709848 0789650665],
     3
    [-,0.9974949866 0405443094,0.9974949866 0405443093],
     2
    [2,0.9092974268 256816954,0.9092974268 256816954],
     5
    [-,0.5984721441 0395649405,0.5984721441 0395649405],
     2
    [3,0.1411200080 598672221,0.1411200080 5986722208],
     7
    [-,- 0.3507832276 8961984812,- 0.3507832276 8961984817],
     2
    [4,- 0.7568024953 0792825138,- 0.7568024953 0792825139],
     9
    [-,- 0.9775301176 6509705539,- 0.9775301176 6509705545],
     2
    [5,- 0.9589242746 6313846889,- 0.9589242746 6313846888],
     11
    [--,- 0.7055403255 7039190623,- 0.7055403255 7039190626],
      2
    [6,- 0.2794154981 9892587281,- 0.2794154981 9892587545],
     13
    [--,0.2151199880 878155243,0.2151199880 878155243],
      2
    [7,0.6569865987 187890904,0.6569865987 1878909041]]
                                                      Type: List List Any
\$\endgroup\$

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.