8
\$\begingroup\$

There are 3 (commonly used) trigonometric functions sin cos and tan each of these functions has an inverse function

You goal is to write 3 programs or functions (one for each inverse trigonometric function asin acos atan) that take a (real) number a input and return the result of the corresponding inverse trigonometric function

Examples/Test-cases (rounded to four decimal places)

 x         asin(x)        acos(x)   atan(x)
 
 0         0              1.5708       0
 1         1.5708         0            0.7854
-1        -1.5708         3.1416      -0.7854
 0.2       0.2014         1.3694       0.1974
 0.4       0.4115         1.1593       0.3805
 0.6       0.6435         0.9273       0.5404
-0.5      -0.5236         2.0944      -0.4636
-0.7      -0.7754         2.3462      -0.6107
// you do not need to support these inputs for asin&acos
2      1.5708-1.317i      -1.317i      1.1071
5      1.5708-2.292i      -2.292i      1.3734
10     1.5708-2.993i      -2.993i      1.4711
15     1.5708-3.400i      -3.400i      1.5042
20     1.5708-3.688i      -3.688i      1.5208
100    1.5708-5.298i      -5.298i      1.5608

Rules

  • Please add built-in solutions to the community wiki
  • You may declare multiple functions in the same program, if you provide a way to choose which of the trigonometric functions is applied to the argument (e.g function names, a second argument)
  • It is allowed to return a tuple containing the results of multiple functions
  • You may take a second parameter, to distinguish between different functions
  • Your solutions for asin/acos only have to work for arguments between -1 and 1 (inclusive)
  • Your solution only has to be accurate up to three decimal places
  • Your score is the sum of the lengths of your program(s)/function(s)

Optional additional requirements

  • Also support inputs that give a complex result
  • Do not use the complex logarithm (see the Sandbox Post for how the complex logarithm might be useful)
\$\endgroup\$
9
  • \$\begingroup\$ I'm confused about the "three programs/functions" bit; should we have three separate submissions and add the scores? Should we have one program that defines three functions? \$\endgroup\$ Commented Aug 31, 2023 at 14:37
  • \$\begingroup\$ @noodleman You are allowed to declare your functions in the same program, or declare multiple different programs, depending on what is more convenient \$\endgroup\$
    – bsoelch
    Commented Aug 31, 2023 at 14:47
  • \$\begingroup\$ Is it acceptable to create a single function that returns a tuple with all 3 values? \$\endgroup\$
    – mousetail
    Commented Aug 31, 2023 at 14:57
  • 3
    \$\begingroup\$ What's the difference between myFunc(0.3)[1] vs myFunc(0.3, 1)? Why is the former banned but the latter allowed? \$\endgroup\$ Commented Aug 31, 2023 at 15:04
  • 2
    \$\begingroup\$ @mousetail Tuples are now allowed \$\endgroup\$
    – bsoelch
    Commented Aug 31, 2023 at 15:10

6 Answers 6

8
\$\begingroup\$

JavaScript (ES7), 94 bytes

Probably not the golfiest way, especially for edge cases.

Returns [atan(x), acos(x), asin(x)].

x=>[(p=1.571,g=x=>1/x?x/(h=k=>k+++k+(k>>9?0:k*k*x*x/h(k)))``:p)(x),c=2*g((1-x*x)**.5/++x),p-c]

Try it online!

Formulas

The arctangent is approximated with the continued fractions:

$$\arctan(x)=\dfrac{x}{1+\dfrac{(1x)^2}{3+\dfrac{(2x)^2}{5+\dfrac{(3x)^2}{7+\ddots}}}}$$

We then use:

$$\arccos(-1)=\pi\\\arccos(x)=2\arctan\left(\frac{\sqrt{1-x^2}}{1+x}\right),\:-1<x\le1$$

and:

$$\arcsin(x)=\frac{\pi}{2}-\arccos(x)$$

(source: Wikipedia)

\$\endgroup\$
8
\$\begingroup\$

R, 45 bytes

\(x,f,y=0:4e8/1e8)y[match(T,(f(y)-x)^2<1e-7)]

Attempt This Online! with slightly reduced precision to enable it to run with ATO's reduced memory allowance.

Single function with arguments x=input number, f=trigonometric function to inverse (one of sin, cos or tan). Just within the 3rd-decimal place precision limit, but precision can be increased by increasing the e8 & e-7 in the code to e9 & e-8.


R, 67 bytes

\(x,f){while((f(F/T)-x)^2>1e-8)T=`if`(T-1,T+F-(F=F+1),F+(F=1));F/T}

Attempt This Online!

Generalized "inverse" function, which, with arguments x=input number and f=any function, will output a non-negative real number (if it exists) corresponding to the inverse of f applied to x, within a precision of 1e-4 (in other words, the difference between f(inv(x,f)) and x is less than 1e-4).

\$\endgroup\$
8
\$\begingroup\$

Built-in solutions

APL(Dyalog Unicode), 1 bytes SBCS

Try it on APLgolf!

Left argument chooses function:

¯1○⍵ ⍝ asin
¯2○⍵ ⍝ acos
¯3○⍵ ⍝ atan

C, 31 Bytes

#include<math.h>
asin
acos
atan

C++, 30 Bytes

#include<cmath>
asin
acos
atan

Go

28 bytes (reals only)

import."math"
Asin
Acos
Atan

Attempt This Online!

34 bytes (includes complex numbers)

import."math/cmplx"
Asin
Acos
Atan

Attempt This Online!

JavaScript, 29 bytes

Math.asin
Math.acos
Math.atan

Attempt This Online!

Pascal, 6 bytes (only arctan)

arctan

Unfortunately, there is no built-in function to inverse the operations of sin and cos. See the Pascal submission for a full implementation of the task.

Python, 32 bytes (reals only)

from math import*
asin
acos
atan

Attempt This Online!

Python, 33 bytes (includes complex numbers)

from cmath import*
asin
acos
atan

Attempt This Online!

Rust, 29 bytes

f64::asin
f64::acos
f64::atan

sclin, 14 bytes

sin_
cos_
tan_

Try it on scline!

Thunno 2, 2 bytes each

Æs # arcsin
Æc # arccos
Æt # arctan

Try it online!

Vyxal, 2 bytes each

∆S # Arcsine
∆C # Arccosine
∆T # Arctangent

Try it Online!

PHP, 14 bytes

asin
acos
atan

Try it online!

Zsh, 36 bytes

zmodload zsh/mathfunc
asin
acos
atan

Try it online!

\$\endgroup\$
8
  • \$\begingroup\$ Any expression that creates a function counts \$\endgroup\$
    – mousetail
    Commented Aug 31, 2023 at 14:56
  • 7
    \$\begingroup\$ If the Python solution is allowed to just dump the functions into the global namespace, without ever actually typing the names of the functions, then how come other languages where the functions are already defined have to type out the names of the functions? Like in Vyxal surely one could argue that the solution is just 0 bytes long because the language already "provide[s] a way to choose which of the trigonometric functions is applied to the argument (e.g function names)", with the "function names" being ∆S etc.? \$\endgroup\$
    – Lecdi
    Commented Aug 31, 2023 at 23:30
  • 1
    \$\begingroup\$ @Lecdi “You goal is to write 3 programs or functions […]” I think the editors misunderstood the goal. You need to make certain functionality available but you do not have to apply the functions. Hence the scoring for programming languages that do not require a dedicated import can be indeed 0 bytes. \$\endgroup\$ Commented Sep 1, 2023 at 7:26
  • 1
    \$\begingroup\$ @infinitezero Yeah, I guess so. This will also aide comparability should one decide to provide a custom (non-built-in) implementation. Otherwise it’s like comparing apples with oranges. You know, this is code-golf, so the shortest code in bytes achieving the goal wins. The purpose of a community wiki post is probably also to exclude built-ins from code-golf competition since they almost always will be shorter. \$\endgroup\$ Commented Sep 1, 2023 at 12:06
  • 6
    \$\begingroup\$ Not that it matters too much for this CW builtin collection, but I do believe the scoring for imported functions is incorrect. The function names should be included (relevant meta consensus, quite old but didn't find anything newer) \$\endgroup\$
    – ovs
    Commented Sep 1, 2023 at 12:36
4
\$\begingroup\$

Pascal, 162 194 bytes

“Extended Pascal” (ISO standard 10206) defines that complex numbers are part of the language. When calling one of these functions, a real argument is automatically promoted to a complex value (because the formal parameter list says the function requires a complex number).

const i=cmplx(0,1);type r=complex;function s(x:r):r;begin s:=−i*ln(sqrt(1−x*x)+i*x);end;function c(x:r):r;begin c:=−i*ln(sqrt(x*x−1)+x);end;function t(x:r):r;begin t:=i/2*ln((1−i*x)/(1+i*x));end

Ungolfed:

    const
        i = cmplx(0, 1);
    
    function arcsin(protected x: complex): complex;
        begin
            arcsin := −i * ln(sqrt(1 − sqr(x)) + i * x);
        end;
    
    function arccos(protected x: complex): complex;
        begin
            arccos := −i * ln(sqrt(sqr(x) − 1) + x);
        end;
    
    function arctan(protected x: complex): complex;
        begin
            arctan := i / 2 * ln((1 − i * x) / (1 + i * x));
        end;

Arc tangent is actually already part of the language. Both in ISO standard 7185 (“Standard Pascal”) and ISO standard 10206 (“Extended Pascal”) the built-in function arctan is available. Since complex numbers are defined by EP, only the latter accepts and can return complex values.

\$\endgroup\$
7
  • \$\begingroup\$ can you also add a non built-in solution for the arctan function \$\endgroup\$
    – bsoelch
    Commented Aug 31, 2023 at 15:08
  • \$\begingroup\$ @bsoelch Certainly I can, but wouldn’t this defeat the purpose of code-golf? There is no benefit in defining a custom arctan anyway: the built-in trigonometric functions (sin, cos, and arctan) can take and output complex numbers. \$\endgroup\$ Commented Aug 31, 2023 at 15:15
  • \$\begingroup\$ Answers outside the community wiki should not only use non built-ins \$\endgroup\$
    – bsoelch
    Commented Aug 31, 2023 at 15:16
  • 2
    \$\begingroup\$ @bsoelch Not only do I (from a software engineering point of view) dislike reimplementing built-in functionality, but doesn’t this amount to a penalty? You know, I cannot add “Pascal” to the community wiki post, because only arctan is a built-in function. \$\endgroup\$ Commented Aug 31, 2023 at 15:30
  • \$\begingroup\$ Can't test, but would something like this work? arcsin := arctan(x / sqrt(1 − sqr(x))); (see en.wikipedia.org/wiki/…) \$\endgroup\$
    – corvus_192
    Commented Aug 31, 2023 at 15:42
3
\$\begingroup\$

Perl 5, 172 bytes

sub asin{n(@_,\&CORE::sin)}
sub acos{n(@_,\&CORE::cos)}
sub atan{n(@_,sub{sin(@_)/cos(pop)})}
sub n{$f=pop;$x=1;$x+=(&$f($x)-$_[0])/((&$f($x-1e-6)-&$f($x))*1e6)for 1..9;$x}

Try it online!

Uses Perl's builtin trig functions sin and cos. Since asin, acos and atan aren't builtin, they're rather found in the core lib Math::Trig, but here they're instead written in a Newton's method-ish solver in sub n.

Or 259 bytes:

sub si{my$x=pop;abs$x<1e-8?$x:2*si($x/2)*co($x/2)}
sub co{my$x=pop;abs$x<1e-8?1:co($x/2)**2-si($x/2)**2}
sub ta{&si/&co}
sub asi{n(@_,'si')}
sub aco{n(@_,'co')}
sub ata{n(@_,'ta')}
sub n{$f=pop;$x=1;$x+=(&$f($x)-$_[0])/((&$f($x-1e-6)-&$f($x))*1e6)for 1..9;$x}

Try it online!

...which replaces Perl's sin and cos with si and co that uses the property that sin(x) = x and cos(x) = 1 for small x and the formulas for half angles.

\$\endgroup\$
2
\$\begingroup\$

Charcoal, 132 125 bytes

NθNη⊞υ¹⊞υ∧›⁰ηθ≔⁰ζ≔²εF⁵⁰«≔₂⊕Xε²δ≔¹ιFχ«≔⊘⁺ιδι≔₂×ιδδ»≔∨⎇⊕η⁼›⁰§υη⎇η›θ§υ⁰›§υ¹θ›⁰§υ¹±¹δUMυ⁺κ×××δε§υ¬λ∨λ±¹≧⁺×∨η¹×δ∕ειζ≧×₂⊕×εεθ≦⊘ε»Iζ

Try it online! Link is to verbose version of code. Takes the function as the second argument where -1=atan, 0=asin and 1=acos. Explanation: Uses CORDIC to calculate the inverse functions. Edit: Switched to single-angle CORDIC for asin and acos to save 7 bytes.

Nθ

Input the real value.

Nη

Input the function code.

⊞υ¹

Start with z[0]=1.

⊞υ∧›⁰ηθ

Start with z[1]=0, except for atan, where the input is used.

≔⁰ζ

Start with a resulting angle of 0.

≔²ε

Start with 2 as the first power of 0.5. This is needed for acos to work with negative inputs, but doesn't affect asin or atan.

F⁵⁰«

Loop 50 times, as unfortunately 10 isn't accurate enough.

≔₂⊕Xε²δ≔¹ιFχ«≔⊘⁺ιδι≔₂×ιδδ»

Start calculating the atan of the power of 0.5. (Yes, I could do the atan separately, but that would duplicate code, increasing my byte count.)

≔∨⎇⊕η⁼›⁰§υη⎇η›θ§υ⁰›§υ¹θ›⁰§υ¹±¹δ

Determine whether we are increasing or decreasing the angle.

UMυ⁺κ×××δε§υ¬λ∨λ±¹

Rotate z by the atan of the power of 0.5.

≧⁺×∨η¹×δ∕ειζ

Update the angle.

≧×₂⊕×εεθ

Compensate for rotation's scaling factor (no effect for atan). Note that in a real FPGA you would approximate the square root but that doesn't help me here.

≦⊘ε

Get the next power of 0.5.

»Iζ

Output the final angle.

\$\endgroup\$

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