############# Class : fract ##############
package Math::Cephes::Fraction;
use strict;
use vars qw(%OWNER @ISA %ITERATORS
@EXPORT_OK %EXPORT_TAGS $VERSION);
require Exporter;
*import = \&Exporter::import;
#my @fract = qw(radd rsub rmul rdiv euclid fract mixed_fract);
my @fract = qw(euclid fract mixed_fract);
@EXPORT_OK = (@fract);
%EXPORT_TAGS = ('fract' => [@fract]);
$VERSION = '0.47';
#use Math::Cephes qw(new_fract euclid);
require Math::Cephes;
@ISA = qw( Math::Cephes );
%OWNER = ();
%ITERATORS = ();
*swig_n_get = *Math::Cephesc::fract_n_get;
*swig_n_set = *Math::Cephesc::fract_n_set;
*swig_d_get = *Math::Cephesc::fract_d_get;
*swig_d_set = *Math::Cephesc::fract_d_set;
sub new {
my $pkg = shift;
my $self = Math::Cephesc::new_fract(@_);
bless $self, $pkg if defined($self);
}
sub DESTROY {
return unless $_[0]->isa('HASH');
my $self = tied(%{$_[0]});
return unless defined $self;
delete $ITERATORS{$self};
if (exists $OWNER{$self}) {
Math::Cephesc::delete_fract($self);
delete $OWNER{$self};
}
}
sub DISOWN {
my $self = shift;
my $ptr = tied(%$self);
delete $OWNER{$ptr};
}
sub ACQUIRE {
my $self = shift;
my $ptr = tied(%$self);
$OWNER{$ptr} = 1;
}
sub fract {
return Math::Cephes::Fraction->new(@_);
}
sub n {
my ($self, $value) = @_;
return $self->{n} unless $value;
$self->{n} = $value;
return $value;
}
sub d {
my ($self, $value) = @_;
return $self->{d} unless $value;
$self->{d} = $value;
return $value;
}
sub euclid {
return Math::Cephes::euclid($_[0], $_[1]);
}
sub mixed_fract {
my $f = shift;
my $nin = int($f->{n});
my $din = int($f->{d});
my $gcd;
if ($din < 0) {
$din *= -1;
$nin *= -1;
}
if (abs($nin) < abs($din)) {
if ( $nin == 0 ) {
return (0, 0, 0);
}
else {
($gcd, $nin, $din) = euclid($nin, $din);
return (0, $nin, $din);
}
}
else {
my $n = abs($nin) % $din;
my $w = int($nin / $din);
if ($n == 0) {
return ($w, 0, 1);
}
else {
($gcd, $n, $din) = euclid($n, $din);
return ($w, $n, $din);
}
}
}
sub as_string {
my $f = shift;
my ($gcd, $string);
my $num = int($f->{n});
my $den = int($f->{d});
if ( abs($num % $den) == 0) {
my $w = $num / $den;
$string = "$w";
}
elsif ($num == 0) {
$string = '0';
}
else {
if ($den < 0) {
$num *= -1;
$den *= -1;
}
($gcd, $num, $den) = euclid($num, $den);
$string = "$num/$den";
}
return $string;
}
sub as_mixed_string {
my $f = shift;
my ($gcd, $string);
my $num = int($f->{n});
my $den = int($f->{d});
if ($den < 0) {
$den *= -1;
$num *= -1;
}
if (abs($num) < abs($den)) {
if ( $num == 0 ) {
$string = '0';
}
else {
($gcd, $num, $den) = euclid($num, $den);
$string = "$num/$den";
}
}
else {
my $n = abs($num) % $den;
my $w = int($num / $den);
if ($n == 0) {
$string = "$w";
}
else {
($gcd, $num, $den) = euclid($num, $den);
$string = "$w $n/$den";
}
}
return $string;
}
sub radd {
my ($f1, $f2) = @_;
my $f = Math::Cephes::Fraction->new();
Math::Cephes::radd($f1, $f2, $f);
return $f;
}
sub rsub {
my ($f1, $f2) = @_;
my $f = Math::Cephes::Fraction->new();
Math::Cephes::rsub($f2, $f1, $f);
return $f;
}
sub rmul {
my ($f1, $f2) = @_;
my $f = Math::Cephes::Fraction->new();
Math::Cephes::rmul($f1, $f2, $f);
return $f;
}
sub rdiv {
my ($f1, $f2) = @_;
my $f = Math::Cephes::Fraction->new();
Math::Cephes::rdiv($f2, $f1, $f);
return $f;
}
1;
__END__
=head1 NAME
Math::Cephes::Fraction - Perl interface to the cephes math fraction routines
=head1 SYNOPSIS
use Math::Cephes::Fraction qw(fract);
my $f1 = fract(2,3); # $f1 = 2/3
my $f2 = fract(3,4); # $f2 = 3/4
my $f3 = $f1->radd($f2); # $f3 = $f1 + $f2
=head1 DESCRIPTION
This module is a layer on top of the basic routines in the
cephes math library to handle fractions. A fraction object
is created via any of the following syntaxes:
my $f = Math::Cephes::Fraction->new(3, 2); # $f = 3/2
my $g = new Math::Cephes::Fraction(5, 3); # $g = 5/3
my $h = fract(7, 5); # $h = 7/5
the last one being available by importing I<:fract>. If no arguments
are specified, as in
my $h = fract();
then the defaults $z = 0/1 are assumed. The numerator and
denominator of a fraction are represented respectively by
$f->{n}; $f->{d}
or, as methods,
$f->n; $f->d;
and can be set according to
$f->{n} = 4; $f->{d} = 9;
or, again, as methods,
$f->n(4) ; $f->(d) = 9;
The fraction can be printed out as
print $f->as_string;
or as a mixed fraction as
print $f->as_mixed_string;
These routines reduce the fraction to its basic form before printing.
This uses the I<euclid> routine which finds the greatest common
divisor of two numbers, as follows:
($gcd, $m_reduced, $n_reduced) = euclid($m, $n);
which returns the greatest common divisor of $m and $n, as well as
the result of reducing $m and $n by $gcd
A summary of the basic routines is as follows.
$x = fract(3, 4); # x = 3 / 4
$y = fract(2, 3); # y = 2 / 3
$z = $x->radd( $y ); # z = x + y
$z = $x->rsub( $y ); # z = x - y
$z = $x->rmul( $y ); # z = x * y
$z = $x->rdiv( $y ); # z = x / y
print $z->{n}, ' ', $z->{d}; # prints numerator and denominator of $z
print $z->as_string; # prints the fraction $z
print $z->as_mixed_string; # converts $z to a mixed fraction, then prints it
$m = 60;
$n = 144;
($gcd, $m_reduced, $n_reduced) = euclid($m, $n);
=head1 BUGS
Please report any to Randy Kobes <randy@theoryx5.uwinnipeg.ca>
=head1 SEE ALSO
For the basic interface to the cephes fraction routines, see
L<Math::Cephes>. See also L<Math::Fraction>
for a more extensive interface to fraction routines.
=head1 COPYRIGHT
The C code for the Cephes Math Library is
Copyright 1984, 1987, 1989, 2002 by Stephen L. Moshier,
and is available at http://www.netlib.org/cephes/.
Direct inquiries to 30 Frost Street, Cambridge, MA 02140.
The perl interface is copyright 2000, 2002 by Randy Kobes.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut