Math-BigInt

 view release on metacpan or  search on metacpan

lib/Math/BigRat.pm  view on Meta::CPAN

    # If called as a class method, initialize a new object.

    $self = bless {}, $class unless $selfref;

    $self -> {sign} = $nan;
    $self -> {_n}   = $LIB -> _zero();
    $self -> {_d}   = $LIB -> _one();

    # If rounding parameters are given as arguments, use them. If no rounding
    # parameters are given, and if called as a class method initialize the new
    # instance with the class variables.

    #return $self -> round(@r);  # this should work, but doesnt; fixme!

    if (@r) {
        if (@r >= 2 && defined($r[0]) && defined($r[1])) {
            carp "can't specify both accuracy and precision";
            return $self -> bnan();
        }
        $self->{accuracy} = $r[0];
        $self->{precision} = $r[1];
    } else {
        unless($selfref) {
            $self->{accuracy} = $class -> accuracy();
            $self->{precision} = $class -> precision();
        }
    }

    return $self;
}

sub bpi {
    my $self    = shift;
    my $selfref = ref $self;
    my $class   = $selfref || $self;
    my @r       = @_;                   # rounding paramters

    # Make "require" work.

    $class -> import() if $IMPORT == 0;

    # Don't modify constant (read-only) objects.

    return $self if $selfref && $self -> modify('bpi');

    # If called as a class method, initialize a new object.

    $self = bless {}, $class unless $selfref;

    ($self, @r) = $self -> _find_round_parameters(@r);

    # The accuracy, i.e., the number of digits. Pi has one digit before the
    # dot, so a precision of 4 digits is equivalent to an accuracy of 5 digits.

    my $n = defined $r[0] ? $r[0]
          : defined $r[1] ? 1 - $r[1]
          : $self -> div_scale();

    # The algorithm below creates a fraction from a floating point number. The
    # worst case is the number (1 + sqrt(5))/2 (golden ratio), which takes
    # almost 2.4*N iterations to find a fraction that is accurate to N digits,
    # i.e., the relative error is less than 10**(-N).
    #
    # This algorithm might be useful in general, so it should probably be moved
    # out to a method of its own. XXX

    my $max_iter = $n * 2.4;

    my $x = Math::BigFloat -> bpi($n + 10);

    my $tol = $class -> new("1/10") -> bpow("$n") -> bmul($x);

    my $n0 = $class -> bzero();
    my $d0 = $class -> bone();

    my $n1 = $class -> bone();
    my $d1 = $class -> bzero();

    my ($n2, $d2);

    my $xtmp = $x -> copy();

    for (my $iter = 0 ; $iter <= $max_iter ; $iter++) {
        my $t = $xtmp -> copy() -> bint();

        $n2 = $n1 -> copy() -> bmul($t) -> badd($n0);
        $d2 = $d1 -> copy() -> bmul($t) -> badd($d0);

        my $err = $n2 -> copy() -> bdiv($d2) -> bsub($x);
        last if $err -> copy() -> babs() -> ble($tol);

        $xtmp -> bsub($t);
        last if $xtmp -> is_zero();
        $xtmp -> binv();

        ($n1, $n0) = ($n2, $n1);
        ($d1, $d0) = ($d2, $d1);
    }

    my $mbr = $n2 -> bdiv($d2);
    %$self = %$mbr;
    return $self;
}

sub copy {
    my $self    = shift;
    my $selfref = ref $self;
    my $class   = $selfref || $self;

    # If called as a class method, the object to copy is the next argument.

    $self = shift() unless $selfref;

    my $copy = bless {}, $class;

    $copy->{sign} = $self->{sign};
    $copy->{_d} = $LIB->_copy($self->{_d});
    $copy->{_n} = $LIB->_copy($self->{_n});
    $copy->{accuracy} = $self->{accuracy} if defined $self->{accuracy};
    $copy->{precision} = $self->{precision} if defined $self->{precision};



( run in 1.022 second using v1.01-cache-2.11-cpan-71847e10f99 )