Skip to content

Commit

Permalink
- Added the Number.atan2() method
Browse files Browse the repository at this point in the history
- Implemented natively the plane angle conversion functions (such as rad2deg, deg2grad, etc...)
- Number.pi() and other constants will compute the value only once and will remember it when it's called again, therefore, Num.pi() is fast even when it's used as a method.
- Added the Number.tau() constant.
- PI and some other Math constats, are now available by they symbols.

Example:
	say Math::π	# prints: 3.14159...
	say Math::Φ	# prints: 1.61803...
	say Math::τ	# prints: 6.28318...
  • Loading branch information
trizen committed Dec 28, 2015
1 parent bd8c1da commit d67be5d
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 114 deletions.
92 changes: 6 additions & 86 deletions lib/Sidef/Math/Math.pm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ package Sidef::Math::Math {
state $table = {
"e" => sub { Sidef::Types::Number::Number->e },
"pi" => sub { Sidef::Types::Number::Number->pi },
"PI" => sub { Sidef::Types::Number::Number->pi },
"π" => sub { Sidef::Types::Number::Number->pi },
"tau" => sub { Sidef::Types::Number::Number->tau },
"τ" => sub { Sidef::Types::Number::Number->tau },
"phi" => sub { Sidef::Types::Number::Number->phi },
"Φ" => sub { Sidef::Types::Number::Number->phi },
"ln2" => sub { Sidef::Types::Number::Number->ln2 },
"G" => sub { Sidef::Types::Number::Number->G },
"Y" => sub { Sidef::Types::Number::Number->Y },
Expand All @@ -28,7 +33,7 @@ package Sidef::Math::Math {
"euler" => sub { Sidef::Types::Number::Number->Y },
};

my $key = lc($name);
my $key = "$name";
$cache{$key} //= exists($table->{$key}) ? $table->{$key}->() : do {
warn qq{[WARN] Inexistent Math constant "$name"!\n};
undef;
Expand Down Expand Up @@ -172,91 +177,6 @@ package Sidef::Math::Math {

*num2percent = \&number_to_percentage;

{
no strict 'refs';
foreach my $f (

# (Plane, 2-dimensional) angles may be converted with the following functions.
'rad2rad',
'deg2deg',
'grad2grad',
'rad2deg',
'deg2rad',
'grad2deg',
'deg2grad',
'rad2grad',
'grad2rad',

# The tangent
'tan',

# The cofunctions of the sine, cosine,
# and tangent (cosec/csc and cotan/cot are aliases)
'csc',
'cosec',
'sec',
'cot',
'cotan',

# The arcus (also known as the inverse) functions
# of the sine, cosine, and tangent
'asin',
'acos',
'atan',

# The principal value of the arc tangent of y/x
'atan2',

# The arcus cofunctions of the sine, cosine, and tangent (acosec/acsc and
# acotan/acot are aliases). Note that atan2(0, 0) is not well-defined.
'acsc',
'acosec',
'asec',
'acot',
'acotan',

# The hyperbolic sine, cosine, and tangent
'sinh',
'cosh',
'tanh',

# The cofunctions of the hyperbolic sine, cosine, and tangent
# (cosech/csch and cotanh/coth are aliases)
'csch',
'cosech',
'sech',
'coth',
'cotanh',

# The area (also known as the inverse) functions of the hyperbolic sine,
# cosine, and tangent
'asinh',
'acosh',
'atanh',

# The area cofunctions of the hyperbolic sine, cosine, and tangent
# (acsch/acosech and acoth/acotanh are aliases)
'acsch',
'acosech',
'asech',
'acoth',
'acotanh',

) {
*{__PACKAGE__ . '::' . $f} = sub {
my ($self, @rest) = @_;
state $x = require Math::Trig;
local $Sidef::Types::Number::Number::GET_PERL_VALUE = 1;
my $result = (\&{'Math::Trig::' . $f})->(map { $_->get_value } @rest);
(
ref($result) eq 'Math::Complex'
? 'Sidef::Types::Number::Complex'
: 'Sidef::Types::Number::Number'
)->new($result);
};
}
}

our $AUTOLOAD;

sub AUTOLOAD {
Expand Down
8 changes: 8 additions & 0 deletions lib/Sidef/Types/Number/Inf.pm
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ package Sidef::Types::Number::Inf {
*shift_right = \&inf;
*rand_int = \&inf;
*rand = \&inf;
*rad2deg = \&inf;
*rad2grad = \&inf;
*deg2grad = \&inf;
*deg2rad = \&inf;
*grad2rad = \&inf;
*grad2deg = \&inf;

sub zero { $ZERO }

Expand Down Expand Up @@ -223,6 +229,8 @@ package Sidef::Types::Number::Inf {
state $x = Sidef::Types::Number::Number->pi->div(Sidef::Types::Number::Number->new(2));
}

*atan2 = \&atan;

#
## atanh(-inf) = -pi/2*i
#
Expand Down
8 changes: 8 additions & 0 deletions lib/Sidef/Types/Number/Ninf.pm
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ package Sidef::Types::Number::Ninf {
*shift_right = \&ninf;
*rand_int = \&ninf;
*rand = \&ninf;
*rad2deg = \&ninf;
*rad2grad = \&ninf;
*deg2grad = \&ninf;
*deg2rad = \&ninf;
*grad2rad = \&ninf;
*grad2deg = \&ninf;

sub max { $_[1] }

Expand Down Expand Up @@ -221,6 +227,8 @@ package Sidef::Types::Number::Ninf {
state $x = Sidef::Types::Number::Number->pi->div(Sidef::Types::Number::Number->new(-2));
}

*atan2 = \&atan;

#
## atanh(-inf) = pi/2*i
#
Expand Down
166 changes: 142 additions & 24 deletions lib/Sidef/Types/Number/Number.pm
Original file line number Diff line number Diff line change
Expand Up @@ -223,47 +223,68 @@ package Sidef::Types::Number::Number {
#

sub pi {
my $pi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
_mpfr2rat($pi);
state $x = do {
my $pi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
_mpfr2rat($pi);
}
}

sub tau {
state $x = do {
my $tau = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($tau, $ROUND);
Math::MPFR::Rmpfr_mul_ui($tau, $tau, 2, $ROUND);
_mpfr2rat($tau);
}
}

sub ln2 {
my $ln2 = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_log2($ln2, $ROUND);
_mpfr2rat($ln2);
state $x = do {
my $ln2 = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_log2($ln2, $ROUND);
_mpfr2rat($ln2);
}
}

sub Y {
my $euler = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_euler($euler, $ROUND);
_mpfr2rat($euler);
state $x = do {
my $euler = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_euler($euler, $ROUND);
_mpfr2rat($euler);
}
}

sub G {
my $catalan = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_catalan($catalan, $ROUND);
_mpfr2rat($catalan);
state $x = do {
my $catalan = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_catalan($catalan, $ROUND);
_mpfr2rat($catalan);
}
}

sub e {
state $one_f = (Math::MPFR::Rmpfr_init_set_ui(1, $ROUND))[0];
my $e = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_exp($e, $one_f, $ROUND);
_mpfr2rat($e);
state $x = do {
state $one_f = (Math::MPFR::Rmpfr_init_set_ui(1, $ROUND))[0];
my $e = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_exp($e, $one_f, $ROUND);
_mpfr2rat($e);
}
}

sub phi {
state $one_f = (Math::MPFR::Rmpfr_init_set_ui(1, $ROUND))[0];
state $two_f = (Math::MPFR::Rmpfr_init_set_ui(2, $ROUND))[0];
state $five_f = (Math::MPFR::Rmpfr_init_set_ui(5, $ROUND))[0];
state $x = do {
state $one_f = (Math::MPFR::Rmpfr_init_set_ui(1, $ROUND))[0];
state $two_f = (Math::MPFR::Rmpfr_init_set_ui(2, $ROUND))[0];
state $five_f = (Math::MPFR::Rmpfr_init_set_ui(5, $ROUND))[0];

my $phi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_sqrt($phi, $five_f, $ROUND);
Math::MPFR::Rmpfr_add($phi, $phi, $one_f, $ROUND);
Math::MPFR::Rmpfr_div($phi, $phi, $two_f, $ROUND);
my $phi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_sqrt($phi, $five_f, $ROUND);
Math::MPFR::Rmpfr_add($phi, $phi, $one_f, $ROUND);
Math::MPFR::Rmpfr_div($phi, $phi, $two_f, $ROUND);

_mpfr2rat($phi);
_mpfr2rat($phi);
}
}

sub nan { state $x = Sidef::Types::Number::Nan->new }
Expand Down Expand Up @@ -663,6 +684,27 @@ package Sidef::Types::Number::Number {
_mpfr2rat($r);
}

sub atan2 {
my ($x, $y) = @_;

if (ref($y) eq 'Sidef::Types::Number::Inf') {
return $ZERO;
}
elsif (ref($y) eq 'Sidef::Types::Number::Ninf') {
if (Math::GMPq::Rmpq_sgn($$x) >= 0) {
return state $z = pi();
}
else {
return state $z = pi()->neg;
}
}

_valid($y);
my $r = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_atan2($r, _as_float($x), _as_float($y), $ROUND);
_mpfr2rat($r);
}

#
## Special functions
#
Expand Down Expand Up @@ -1643,6 +1685,82 @@ package Sidef::Types::Number::Number {
$block;
}

#
## Conversions
#

sub rad2deg {
my ($x) = @_;
state $f = do {
my $fr = Math::MPFR::Rmpfr_init2($PREC);
my $pi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
Math::MPFR::Rmpfr_ui_div($fr, 180, $pi, $ROUND);
_mpfr2rat($fr);
};
$f->mul($x);
}

sub deg2rad {
my ($x) = @_;
state $f = do {
my $fr = Math::MPFR::Rmpfr_init2($PREC);
my $pi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
Math::MPFR::Rmpfr_div_ui($fr, $pi, 180, $ROUND);
_mpfr2rat($fr);
};
$f->mul($x);
}

sub rad2grad {
my ($x) = @_;
state $factor = do {
my $fr = Math::MPFR::Rmpfr_init2($PREC);
my $pi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
Math::MPFR::Rmpfr_ui_div($fr, 200, $pi, $ROUND);
_mpfr2rat($fr);
};
$factor->mul($x);
}

sub grad2rad {
my ($x) = @_;
state $factor = do {
my $fr = Math::MPFR::Rmpfr_init2($PREC);
my $pi = Math::MPFR::Rmpfr_init2($PREC);
Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
Math::MPFR::Rmpfr_div_ui($fr, $pi, 200, $ROUND);
_mpfr2rat($fr);
};
$factor->mul($x);
}

sub grad2deg {
my ($x) = @_;
state $factor = do {
my $q = Math::GMPq::Rmpq_init();
Math::GMPq::Rmpq_set_ui($q, 9, 10);
$q;
};
my $r = Math::GMPq::Rmpq_init();
Math::GMPq::Rmpq_mul($r, $factor, $$x);
bless \$r, __PACKAGE__;
}

sub deg2grad {
my ($x) = @_;
state $factor = do {
my $q = Math::GMPq::Rmpq_init();
Math::GMPq::Rmpq_set_ui($q, 10, 9);
$q;
};
my $r = Math::GMPq::Rmpq_init();
Math::GMPq::Rmpq_mul($r, $factor, $$x);
bless \$r, __PACKAGE__;
}

{
no strict 'refs';

Expand Down
8 changes: 4 additions & 4 deletions scripts/RosettaCode/averages_mean_time_of_day.sf
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
#

func mean_angle(angles) {
Math.atan2(
angles.map { Math.sin(_ * Math::PI / 180) }.sum / angles.len,
angles.map { Math.cos(_ * Math::PI / 180) }.sum / angles.len,
) * 180 / Math::PI;
atan2(
Math.avg(angles.map { .deg2rad.sin }...),
Math.avg(angles.map { .deg2rad.cos }...),
).rad2deg;
}

func time2deg(t) {
Expand Down

0 comments on commit d67be5d

Please sign in to comment.