turnstep / math-gmp Goto Github PK
View Code? Open in Web Editor NEWMath::GMP Perl module for high speed arbitrary size integer math
License: Other
Math::GMP Perl module for high speed arbitrary size integer math
License: Other
One of my long-running projects has recently reached new heights, dealing with integers greater than 1.8e308. That's fine in the core code where I deal with them as integers, but for some peripheral cases I need to do some float handling, and that code suddenly came crashing down.
I've now worked around that by injecting three extra Math::GMP methods, as below. I'm not sure whether some or all of these are appropriate to include in Math::GMP itself; if you think they would be, I'll put some effort into coming up with implementations that are more robust and efficient, and some tests. (And maybe a better name for bfdiv
).
I've also implemented a hack to let me get a sprintf("%g", $gmp)
that works for large values with string trickery, but I haven't come up with a way to do it more robustly. (I haven't yet tested it, but docs imply that gmp_sprintf
would not support a "%Zg"
format.)
Let me know what you think.
my $LONG = 300; # approximate
package Math::GMP {
sub log10 {
my($self) = @_;
my $s = "$self";
my $len = length($s);
return log($s) / log(10) if $len < $LONG;
$s =~ s/^(.)/$1./;
return log($s) / log(10) + $len - 1;
}
sub log {
my($self) = @_;
return log10($self) * log(10);
}
sub bfdiv {
my($self, $other) = @_;
my $sself = "$self";
# corrected from:
# return $self / "$other" if length($sself) < $LONG;
return $sself / "$other" if length($sself) < $LONG;
my $lother = ref($other) ? $other->log : CORE::log($other);
return exp($self->log - $lother);
}
}
sub long_sprintf {
# $format is expected to have a single %g or similar format specifier
my($format, $large) = @_;
my $s = sprintf $format, "$large";
if ($s =~ /inf/i) {
my $log = $large->log10;
my $exp = int($log);
my $rem = $log - $exp;
$s = sprintf $format, 10 ** $rem;
$s =~ s{e\d+|$}{e$exp};
}
return $s;
}
=head1 SYNOPSIS
my $large = Math::GMP->new(10) ** 1000;
my $smaller = $large * 2 / 3;
say $large->log10; # 1000
say $large->log; # 2302.58509299405
say $large->bfdiv($smaller); # 1.5-ish
say long_sprintf("%.2g", $large); # 1.00e1000
=head1 METHODS
=over 4
=head2 log10( )
Returns the base-10 logarithm of the invocant as a Perl float.
=head2 log( )
Returns the natural logarithm of the invocant as a Perl float.
=head2 bdfiv($n)
Returns the invocant divided by C<$n> as a Perl float. C<$n> may be a
C<Math::GMP> object or a standard Perl scalar value. Note that this
will use logarithms/exponentiation for large values, which will limit
its accuracy - use bigfloats instead if you need greater precision.
=back
=head1 FUNCTIONS
=over 4
=head2 long_sprintf($format, $value)
Given a sprintf-style format C<$format> with a single format specification
requesting a value in exponential notation, and a C<Math::GMP> object
C<$value>, returns a string displaying C<$value> in the requested manner.
=back
(edited to s/self/sself/
in bfdiv
)
Subsequent to Perl/perl5#19081, I suggest adding something like the following to the docs (probably only after 5.36 is released, though a reduced version could be added immediately).
--- a/lib/Math/GMP.pm 2020-02-09 19:08:42.000000000 +0000
+++ b/lib/Math/GMP.pm 2021-09-08 15:23:54.139606957 +0100
@@ -536,6 +536,31 @@
For internal use. B<Do not use directly>.
+=head1 DIVISION BY ZERO
+
+Whereas perl normally catches division by zero to provide a standard
+perl-level error message, C<libgmp> does not; the result is usually
+a SIGFPE (floating point exception) giving a core dump if you ever
+attempt to divide a C<Math::GMP> object by anything that evaluates
+to zero. This can make it hard to diagnose where the error has occurred
+in your perl code.
+
+As of perl-5.36.0, SIGFPE is delivered in a way that can be caught
+by a C<%SIG> handler. So you can get a stack trace with code like:
+
+ use Carp; # load it up front
+ local $SIG{FPE} = sub { confess(@_) };
+
+Before perl-5.36.0 this approach won't work: you'll need to use
+L<POSIX/sigaction> instead:
+
+ use Carp;
+ use POSIX qw{ sigaction SIGFPE };
+ sigaction(SIGFPE, POSIX::SigAction->new(sub { confess(@_) }));
+
+In either case, you should not attempt to return from the signal
+handler, since the signal will just be thrown again.
+
=head1 BUGS
As of version 1.0, Math::GMP is mostly compatible with the old
Hi, I am working with the git repo because I want to add some new functionality to Math::GMP, but there's no Makefile.PL and no info in README or in INSTALL how you might do that. I assume the dist.ini is something to do with it, but I'm also not seeing any clues there.
A link to an appropriate manpage would be welcome.
Hello! As pointed out in danaj/Math-Prime-Util#20, the intification of Math::GMP seems to return incorrect values for integers between 2^63 and 2^64 - 1.
Example:
use 5.010;
use Math::GMP;
my $n = 9223372036854775828; # 2^63 + 20
my $z = Math::GMP->new($n);
say $n; #=> 9223372036854775828
say $z; #=> 9223372036854775828
say int($n); #=> 9223372036854775828
say int($z); #=> 20 (incorrect)
Would be very nice if this can be fixed.
Thanks for your work,
Trizen
Hi,
I got ==> MALFORMED Signature file! <== from cpansign -v
This makes sense as the SIGNATURE's last line is
SHA256 dc5efc57dfb75d237226e738436163cf52c61d724e2dc595d97d7b95a1196352 xt/release/trailing-space.t
Would you regenerate the file please?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.