Skip to content

Commit

Permalink
- Added the Fraction(a,b) built-in class.
Browse files Browse the repository at this point in the history
Represents a symbolic fraction: a/b, where `a` and `b` can be any objects.

- Implemented division of two polynomials, by using the `Fraction()` newly added class.

Example:

	var a = Poly([1,2,3])
	var b = Poly([3,4,5])

	say a/b

Outputs:

	Fraction(x^2 + 2*x + 3, 3*x^2 + 4*x + 5)
  • Loading branch information
trizen committed Aug 27, 2021
1 parent 5db0b7d commit a7a9bd7
Show file tree
Hide file tree
Showing 13 changed files with 831 additions and 61 deletions.
3 changes: 3 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ lib/Sidef/Types/Null/Null.pm
lib/Sidef/Types/Null/Null.pod
lib/Sidef/Types/Number/Complex.pm
lib/Sidef/Types/Number/Complex.pod
lib/Sidef/Types/Number/Fraction.pm
lib/Sidef/Types/Number/Fraction.pod
lib/Sidef/Types/Number/Gauss.pm
lib/Sidef/Types/Number/Gauss.pod
lib/Sidef/Types/Number/Mod.pm
Expand Down Expand Up @@ -779,6 +781,7 @@ scripts/Tests/for_in_with_user_objects.sf
scripts/Tests/for_two_vars.sf
scripts/Tests/for_var_in_array.sf
scripts/Tests/forward_difference.sf
scripts/Tests/fraction_class.sf
scripts/Tests/func_scoping.sf
scripts/Tests/function_composition.sf
scripts/Tests/functional_modules.sf
Expand Down
1 change: 1 addition & 0 deletions lib/Sidef/Deparse/Perl.pm
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ package Sidef::Deparse::Perl {
Sidef::DataTypes::Number::Quaternion Sidef::Types::Number::Quaternion
Sidef::DataTypes::Number::Complex Sidef::Types::Number::Complex
Sidef::DataTypes::Number::Polynomial Sidef::Types::Number::Polynomial
Sidef::DataTypes::Number::Fraction Sidef::Types::Number::Fraction
Sidef::DataTypes::Range::Range Sidef::Types::Range::Range
Sidef::DataTypes::Range::RangeNumber Sidef::Types::Range::RangeNumber
Sidef::DataTypes::Range::RangeString Sidef::Types::Range::RangeString
Expand Down
1 change: 1 addition & 0 deletions lib/Sidef/Deparse/Sidef.pm
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ package Sidef::Deparse::Sidef {
Sidef::DataTypes::Number::Quaternion Quaternion
Sidef::DataTypes::Number::Complex Complex
Sidef::DataTypes::Number::Polynomial Polynomial
Sidef::DataTypes::Number::Fraction Fraction
Sidef::DataTypes::Range::Range Range
Sidef::DataTypes::Range::RangeNumber RangeNum
Sidef::DataTypes::Range::RangeString RangeStr
Expand Down
2 changes: 2 additions & 0 deletions lib/Sidef/Parser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ package Sidef::Parser {
| Quadratic\b (?{ state $x = bless({}, 'Sidef::DataTypes::Number::Quadratic') })
| Quaternion\b (?{ state $x = bless({}, 'Sidef::DataTypes::Number::Quaternion') })
| Poly(?:nomial)?\b (?{ state $x = bless({}, 'Sidef::DataTypes::Number::Polynomial') })
| Frac(?:tion)?\b (?{ state $x = bless({}, 'Sidef::DataTypes::Number::Fraction') })
| Inf\b (?{ state $x = Sidef::Types::Number::Number->inf })
| NaN\b (?{ state $x = Sidef::Types::Number::Number->nan })
| Infi\b (?{ state $x = Sidef::Types::Number::Complex->new(0, Sidef::Types::Number::Number->inf) })
Expand Down Expand Up @@ -208,6 +209,7 @@ package Sidef::Parser {
Str String
Num Number
Poly Polynomial
Frac Fraction
Mod
Gauss
Quadratic
Expand Down
243 changes: 243 additions & 0 deletions lib/Sidef/Types/Number/Fraction.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package Sidef::Types::Number::Fraction {

use utf8;
use 5.016;

use parent qw(
Sidef::Types::Number::Number
);

use overload
q{bool} => \&to_n,
q{0+} => \&to_n,
q{""} => \&__stringify__,
q{${}} => \&to_n;

sub new {
my (undef, $n, $m) = @_;

$n //= Sidef::Types::Number::Number::ZERO;
$m //= Sidef::Types::Number::Number::ONE;

bless {a => $n, b => $m};
}

*call = \&new;

sub to_n {
my ($x) = @_;
my $r = $x->{a}->to_n->div($x->{b}->to_n);

if (ref($r) eq __PACKAGE__) { # probably should die here?
return Sidef::Types::Number::Number->new($x->{a})->div(Sidef::Types::Number::Number->new($x->{b}));
}

return $r;
}

*lift = \&to_n;
*__boolify__ = \&to_n;
*__numify__ = \&to_n;

sub __stringify__ {
my ($x) = @_;
"Fraction($x->{a}, $x->{b})";
}

sub to_s {
my ($x) = @_;
Sidef::Types::String::String->new($x->__stringify__);
}

*dump = \&to_s;

sub nu {
$_[0]->{a};
}

*numerator = \ν

sub de {
$_[0]->{b};
}

*denominator = \&de;

sub nude {
($_[0]->{a}, $_[0]->{b});
}

sub neg {
my ($x) = @_;
__PACKAGE__->new($x->{a}->neg, $x->{b});
}

sub dec {
my ($x) = @_;
__PACKAGE__->new($x->{a}->sub($x->{b}), $x->{b},);
}

sub inc {
my ($x) = @_;
__PACKAGE__->new($x->{a}->add($x->{b}), $x->{b},);
}

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

if (ref($y) eq __PACKAGE__) {
return __PACKAGE__->new($x->{a}->mul($y->{b})->add($y->{a}->mul($x->{b})), $x->{b}->mul($y->{b}));
}

__PACKAGE__->new($x->{a}->add($y->mul($x->{b})), $x->{b});
}

sub sub {
my ($x, $y) = @_;
$x->add($y->neg);
}

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

if (ref($y) eq __PACKAGE__) {
return __PACKAGE__->new($x->{a}->mul($y->{a}), $x->{b}->mul($y->{b}),);
}

__PACKAGE__->new($x->{a}->mul($y), $x->{b});
}

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

if (ref($y) eq __PACKAGE__) {
return __PACKAGE__->new($x->{a}->mul($y->{b}), $x->{b}->mul($y->{a}),);
}

__PACKAGE__->new($x->{a}, $x->{b}->mul($y));
}

sub pow {
my ($x, $n) = @_;

if ($n->is_neg) {
my $abs_n = $n->neg;
return __PACKAGE__->new($x->{b}->pow($abs_n), $x->{a}->pow($abs_n),);
}

__PACKAGE__->new($x->{a}->pow($n), $x->{b}->pow($n));
}

sub lsft {
my ($x, $n) = @_;
__PACKAGE__->new($x->{a}->lsft($n), $x->{b});
}

sub rsft {
my ($x, $n) = @_;
__PACKAGE__->new($x->{a}, $x->{b}->lsft($n));
}

sub floor {
my ($x) = @_;

my $y = $x->{a}->div($x->{b});

if (ref($y) ne __PACKAGE__) {
return $y->floor;
}

$x->{a}->idiv_floor($x->{b});
}

sub ceil {
my ($x) = @_;

my $y = $x->{a}->div($x->{b});

if (ref($y) ne __PACKAGE__) {
return $y->ceil;
}

$x->{a}->idiv_ceil($x->{b});
}

sub round {
my ($x) = @_;

my $y = $x->{a}->div($x->{b});

if (ref($y) ne __PACKAGE__) {
return $y->round;
}

$x->{a}->idiv_round($x->{b});
}

sub trunc {
my ($x) = @_;

my $y = $x->{a}->div($x->{b});

if (ref($y) ne __PACKAGE__) {
return $y->trunc;
}

$x->{a}->idiv_trunc($x->{b});
}

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

if (ref($y) ne __PACKAGE__) {
return __PACKAGE__->new(
Sidef::Types::Number::Mod->new($x->{a}, $y),
Sidef::Types::Number::Mod->new($x->{b}, $y),
);
}

$x->sub($y->mul($x->div($y)->floor));
}

{
no strict 'refs';

foreach my $method (qw(eq ne lt le gt ge cmp or xor and)) {
*{__PACKAGE__ . '::' . $method} = sub {
my ($x, $y) = @_;

if (ref($y) ne __PACKAGE__) {
$y = __PACKAGE__->new($y);
}

$x->{a}->mul($y->{b})->$method($x->{b}->mul($y->{a}));
};
}

*{__PACKAGE__ . '::' . '%'} = \&mod;
*{__PACKAGE__ . '::' . '/'} = \÷
*{__PACKAGE__ . '::' . '÷'} = \÷
*{__PACKAGE__ . '::' . '*'} = \&mul;
*{__PACKAGE__ . '::' . '+'} = \&add;
*{__PACKAGE__ . '::' . '-'} = \⊂
*{__PACKAGE__ . '::' . '**'} = \&pow;
*{__PACKAGE__ . '::' . '++'} = \&inc;
*{__PACKAGE__ . '::' . '--'} = \&dec;
*{__PACKAGE__ . '::' . '<'} = \&lt;
*{__PACKAGE__ . '::' . '>'} = \&gt;
*{__PACKAGE__ . '::' . '&'} = \&and;
*{__PACKAGE__ . '::' . '|'} = \&or;
*{__PACKAGE__ . '::' . '^'} = \&xor;
*{__PACKAGE__ . '::' . '<<'} = \&lsft;
*{__PACKAGE__ . '::' . '>>'} = \&rsft;
*{__PACKAGE__ . '::' . '<=>'} = \&cmp;
*{__PACKAGE__ . '::' . '<='} = \&le;
*{__PACKAGE__ . '::' . ''} = \&le;
*{__PACKAGE__ . '::' . '>='} = \&ge;
*{__PACKAGE__ . '::' . ''} = \&ge;
*{__PACKAGE__ . '::' . '=='} = \&eq;
*{__PACKAGE__ . '::' . '!='} = \&ne;
}
}

1
Loading

0 comments on commit a7a9bd7

Please sign in to comment.