From 7e8a161385dd4e3211516f0f1e654e39f1005435 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 16 2020 10:39:53 +0000 Subject: perl-bignum-0.49 base --- diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..70fe309 --- /dev/null +++ b/BUGS @@ -0,0 +1,26 @@ +For an updated list of bugs, see + + https://rt.cpan.org/Public/Dist/Display.html?Name=bignum + +The following list is not up to date: + +Known bugs: + +* print 2 + 4.5,"\n"; # produces "6.5" but should be actually 65/10 + +* perl -Mbignum=t -le 'print 2.0' + Loading Math::BigInt::Trace + MBI import Math::BigInt::Trace :constant upgrade Math::BigFloat::Trace lib Calc + Loading Math::BigFloat::Trace + MBF import Math::BigFloat::Trace :constant downgrade Math::BigInt::Trace + MBI new '2' => '2' (Math::BigInt::Trace) + MBF new '2.0' => '2' (Math::BigInt::Trace) + 2 + +The order of MBI and MBF is reversed, since the output is done *after* the new, +but the new of MBF downgrades internally to MBI. No solution yet. + +Please send me test-reports, your experiences with this and your ideas - I love +to hear about my work! + +Tels diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..862c137 --- /dev/null +++ b/CHANGES @@ -0,0 +1,373 @@ +2018-02-03 v0.49 pjacklam + + * Improve specification of required modules in Makefile.PL. + + * Fix typo in CHANGES file. + +2018-01-31 v0.48 pjacklam + + * According to the CPAN testers reports, Perl v5.10 or later is required, so + make Perl v5.10 the minimum required version. + + * Verify that CPAN RT #102006 is fixed. + +2016-12-13 v0.47 pjacklam + + * Add more logic to Makefile.PL regarding INSTALLDIRS (CPAN RT #119199 + and #119225). + +2016-12-11 v0.46 pjacklam + + * Fix Makefile.PL so that this module installs over the core version. + +2016-12-03 v0.45 pjacklam + + * Use ExtUtils::MakeMaker rather than Module::Install in Makefile.PL + + * Remove INSTALL file. The information is in the README file. + + * Improve documentation in BUGS and SUPPORT sections in POD in bignum.pm, + bigint.pm, and bigrat.pm. + + * Remove unused variables in Math/BigInt/Trace.pm and Math/BigFloat/Trace.pm + + * Update README and BUGS files. + + * Remove code that was accidentally left in t/infnan.inc after debugging. + + * Remove author information in LICENSE file. + + * Trim whitespace. + + * CHANGES file now has the same formatting as other Math::BigInt-related + distributions. + +2016-11-15 v0.44 pjacklam + + * Update bundled Module::Install from version 1.16 to version 1.17. + + * Replace function calls with method calls. + + * Include patch for CPAN RT #116506. + +2016-07-09 v0.43 pjacklam + + * Replace function calls with method calls. + +2016-01-05 v0.42 pjacklam + + * "use strict" and "use warnings" everywhere. + + * Reformat some if the code according to the "perlstyle" man page. It makes + the code easier for read, for me at least. + + * Add descriptions to tests. + + * Reorder CHANGES to chronological order. + + * Use bpi() as a class method, not a function. + + * Replace "use vars ..." with "our ...". + + * More descriptive variable names. + + * Start POD sections with =pod + + * Allow "nan", "inf", and "infinity", and ingore case, since core Perl allows + these. We want to be compatible. Add tests to "infnan.inc". + +2015-09-25 v0.41 pjacklam + + * hex() and oct() now have the same semantics as the corresponding core + functions. E.g., hex("cat") returns 202 and a warning "Illegal hexadecimal + digit 't' ignored at ..." rather than NaN. + + * Added test files auth-bigint-hex.t and auth-bigint-oct.t. + + * Minimum required version of the Math-BigInt distro is now 1.992. + +2015-09-22 v0.40 pjacklam + + * Sync with blead. + + * Update author information in Makefile.PL. + +2015-09-14 v0.39 pjacklam + + * bignum tests: use eval-block instead of eval-string + + * bignum tests: use eval block to load Math::BigInt::Lite + + * Set version number in all .pm files to 0.39. + + * Display information about module versions in 01load.t. + +2015-08-28 v0.38 pjacklam + + * Synchronise with blead perl. + + * Minimum required Math-BigInt is v1.88. + + * Update bundled Module::Install from v1.08 to v1.16. + +2014-04-03 v0.37 pjacklam + + * Synchronise with blead perl. + + * Added new '00sig.t', '01load.t', '02pod.t', and '03pod_cov.t'. + + * Removed old 'pod.t' and 'podcov.t' + +2012-09-11 rafl 0.30 302 tests + + * Synchronise with blead perl. + +2011-08-08 rafl 0.29 302 tests + + * Synchronise with blead perl. + +2011-07-09 rafl 0.28 302 tests + + * Synchronise with blead perl. + +2010-09-15 rafl 0.25 302 tests + + * Synchronise with blead perl + Only changes in the tests. + +2010-09-04 rafl 0.24 301 tests + + * Apply changes from blead perl + Mostly POD fixes and minor test tweaks. + +2008-04-05 Tels 0.23 301 tests + + * require Math::BigInt v1.88 + + * require Math::BigRat v0.21 + + * update bundles Module::Install + + * require Perl 5.006 (vs. 5.006002), should work with that + +2007-06-30 Tels 0.22 301 tests + + * make the pragmas lexical, so that "no bigint;" etc. works + + * make "use bigint; use bignum;" not warn about redefining "inf" and "NaN" + This also means a "use bigint;" will not override any already existing + "inf" or "NaN" routine + + * require Math::BigInt v1.87 + + * fix #27059: t/option_l.t fails + + * on Perl 5.9.4 or later: "overload" hex() and oct() with lexical routines + that also handle arbitrary big integers + + * for all Perls: make "use bigint qw/hex oct/" export global hex() and oct() + routines that work with big integers + + * make bignum.pm and bigrat.pm re-use code from bigint.pm + + * add exportable bpi() and bexp() methods + + * add exportable PI and e constants + +2007-04-17 Tels 0.21 205 tests + + * require Math::BigInt v1.83 + + * require Math::BigRat v0.19 + + * add support for "try" and "only" + + * fix licence field back to "perl" + +2007-04-09 Tels 0.20 198 tests + + * require Math::BigInt v1.82 + + * require Math::BigRat v0.18 + + * add a test for bug #18025: + "bignum/bigrat can lead to a number that is both 1 and 0" + + * POD test needs Test::Pod::Coverage 1.08 to work + +2007-02-03 Tels 0.19 194 tests + + * require Math::BigInt v1.79 + + * require Perl v5.6.2 + + * add Build.PL + + * use Module::Install + + * remove PREREQ_FATAL since the toolchain is broken + + * apply spelling fixes to POD + +2007-01-27 Tels 0.18 194 tests + + * require Math::BigInt 1.78 + + * add support for octal constants + + * use PREREQ_FATAL + + * add POD tests + +2005-04-03 Tels 0.17 184 tests + + * remove the default library 'Calc', and let Bigint et. al. decide instead + which library to load as default + +2005-01-01 Tels 0.16 184 tests + + * option "l", "a", and "p" did not work under -Mbigrat + + * little doc fixes + + * add more tests, convert some testfiles to Test::More + +2004-03-12 Tels 0.15 175 tests + + * small nitpick fix for Math::BigInt v1.70 + +2003-07-04 Tels 0.14 175 tests (released) + + * small nits fixed + + * allow parameters a and p for bigrat + +2002-12-12 Tels 0.14a 175 tests (not released) + + * added doc about shallow copies like $x = $y and method calls + + * precision()/accuracy()/round_mode() save now one call and are thus faster + + * bigrat() now calls Math::BigRat->precision|accuracy|round_mode, too + + * distribution is now signed, go to http://bloodgate.com/tels.asc for key + +2002-08-24 v0.13 Tels + + * added a LOT to the documentation + + * tests don't go "huh" anymore + + * bninfnan.t has the correct setup for testing in the core + +2002-08-13 v0.12 Tels + + * INSTALLDIRS => perl + + * document that use bignum/bigint/bigrat is global, not only in current block + + * added default exported inf() and NaN() routines to fix the second example: + perl -Mbignum -e 'print 1 + inf,"\n"' + perl -Mbignum -e 'print inf + inf,"\n"' + + * tests for inf()/NaN() + +2002-03-25 v0.11 Tels + + * testsuite failed under Lite due to specific tests for MBI + + * removed the printing of "Loading ..." to STDERR (interfered w/ something) + + * more tests for bigrat and bignum + + * trace.t remvoed due to VMS problems + +2002-03-17 v0.10 Tels + + * bigint: handle floating point constants like '4.5', '45e-1', '4.56e1' by + truncating them to integer, so: + perl -Mbigint -le 'print 4.5+4.5' + 8 + +2002-03-12 v0.09 Tels + + * added bigint.pm as a better way of perl -MMath::BigInt=:constant + + * tests for that + + * bigrat: some typos + +2002-03-11 v0.08 Tels + + * doc fixes/types and 'l' is equal to 'lib' (thanx to Dan Sullivan) + + * added tests for l, lib, and foo (the latter is expected to die) + + * uses Math::BigInt::Lite when it finds it, otherwise just plain M::BI + + * added tests for loading of Lite + + * version output includes Math::BigInt::Lite when it was used + + * rewritten README and INSTALL document + +2002-03-05 v0.07 Tels + + * new options: a (accuracy) and p (precision) + + * doc and tests improved quite a lot + +2002-02-26 v0.06 Tels + + * options can now be in short (one letter) or long form + + * new option: t or trace + + * old option: v or version + + * included Math::BigInt::Trace for trace + +2002-02-24 v0.05 Tels + + * Comes now in two flavours: Normal (bignum) and Rat-flavoured (bigrat) + te@null:~ > perl -Mbignum=v + Math::BigInt v1.52 lib => Math::BigInt::Calc v0.23 + Math::BigFloat v1.29 + te@null:~ > perl -Mbigrat=v + Math::BigInt v1.52 lib => Math::BigInt::Calc v0.23 + Math::BigFloat v1.29 + Math::BigRat v0.02 + +2002-02-21 v0.04 Tels + + * added :constant to Math::BigFloat loading and tests for it + + * added v to import to print version and exit: + + te@null:~ > perl -Mbignum=v + Math::BigInt v1.51 lib => Math::BigInt::Calc v0.22 + Math::BigFloat v1.28 + Math::BigRat v0.02 + te@null:~ > perl -Mbignum=v,lib,Pari + Math::BigInt v1.51 lib => Math::BigInt::Pari v1.07 + Math::BigFloat v1.28 + Math::BigRat v0.02 + +2002-02-10 v0.03 Tels + + * renamed to bignum + + * added dependency and loading of Math::BigRat + +2002-01-29 v0.02 Tels + + * AUTOLOAD, cleaned up a bit + +2002-01-29 v0.01 Tels + + * first version + +Please send me test-reports, your experiences with this and your ideas - I love +to hear about my work! + +Tels diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1eedfda --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..41ed4fb --- /dev/null +++ b/MANIFEST @@ -0,0 +1,44 @@ +BUGS +CHANGES +lib/bigint.pm +lib/bignum.pm +lib/bigrat.pm +lib/Math/BigFloat/Trace.pm +lib/Math/BigInt/Trace.pm +LICENSE +Makefile.PL +MANIFEST This list of files +MANIFEST.SKIP +README +t/00sig.t +t/01load.t +t/02pod.t +t/03podcov.t +t/author-bigint-hex.t +t/author-bigint-oct.t +t/big_e_pi.t +t/bigexp.t +t/bigint.t +t/bignum.t +t/bigrat.t +t/bii_e_pi.t +t/biinfnan.t +t/bir_e_pi.t +t/bn_lite.t +t/bninfnan.t +t/br_lite.t +t/brinfnan.t +t/in_effect.t +t/infnan.inc +t/option_a.t +t/option_l.t +t/option_p.t +t/overrides.t +t/ratopt_a.t +t/scope_f.t +t/scope_i.t +t/scope_r.t +TODO +META.yml Module YAML meta-data (added by MakeMaker) +META.json Module JSON meta-data (added by MakeMaker) +SIGNATURE Public-key signature (added by MakeMaker) diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 0000000..f399291 --- /dev/null +++ b/MANIFEST.SKIP @@ -0,0 +1,12 @@ +.*\.tar\.gz +^blib.* +^\w+\.(html|txt|png|dot|pl|svg|old|bak|org) +^Makefile\z +^Makefile.(old|bak)\z +^MANIFEST.(old|bak)\z +^MYMETA\.(yml|json)\z +\.*tmp +.*\.patch\z +pm_to_blib +\.git.* +^bignum-[0-9] diff --git a/META.json b/META.json new file mode 100644 index 0000000..abd2be8 --- /dev/null +++ b/META.json @@ -0,0 +1,49 @@ +{ + "abstract" : "unknown", + "author" : [ + "Peter John Acklam " + ], + "dynamic_config" : 1, + "generated_by" : "ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010", + "license" : [ + "perl_5" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : 2 + }, + "name" : "bignum", + "no_index" : { + "directory" : [ + "t", + "inc" + ] + }, + "prereqs" : { + "build" : { + "requires" : { + "ExtUtils::MakeMaker" : "6.64" + } + }, + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "6.64" + } + }, + "runtime" : { + "requires" : { + "Math::BigInt" : "1.999718", + "Math::BigRat" : "0.12", + "perl" : "5.01" + } + }, + "test" : { + "requires" : { + "Test::More" : "0.47" + } + } + }, + "release_status" : "stable", + "version" : "0.49", + "x_serialization_backend" : "JSON::PP version 2.97000" +} diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..87057f5 --- /dev/null +++ b/META.yml @@ -0,0 +1,26 @@ +--- +abstract: unknown +author: + - 'Peter John Acklam ' +build_requires: + ExtUtils::MakeMaker: '6.64' + Test::More: '0.47' +configure_requires: + ExtUtils::MakeMaker: '6.64' +dynamic_config: 1 +generated_by: 'ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: '1.4' +name: bignum +no_index: + directory: + - t + - inc +requires: + Math::BigInt: '1.999718' + Math::BigRat: '0.12' + perl: '5.01' +version: '0.49' +x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..d39d729 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,39 @@ +#!perl + +use strict; +use warnings; +use ExtUtils::MakeMaker; + +my %WriteMakefileArgs = + ( + 'NAME' => 'bignum', + 'VERSION_FROM' => 'lib/bignum.pm', + 'AUTHOR' => 'Peter John Acklam ', + 'MIN_PERL_VERSION' => 5.010, + 'CONFIGURE_REQUIRES' => { + 'ExtUtils::MakeMaker' => 6.64, + }, + 'BUILD_REQUIRES' => { + 'ExtUtils::MakeMaker' => 6.64, + }, + 'PREREQ_PM' => { + 'Math::BigInt' => 1.999718, + 'Math::BigRat' => 0.12, + #'Math::BigInt::Lite' => 0.09, # optional + }, + 'TEST_REQUIRES' => { + 'Test::More' => 0.47, + }, + 'LICENSE' => 'perl_5', + 'LIBS' => [''], # e.g., '-lm' + 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' + 'INC' => '', # e.g., '-I/usr/include/other' + 'SIGN' => 1, + ); + +# Install over the core version? (Cf. CPAN RT #119199 and #119225.) + +$WriteMakefileArgs{INSTALLDIRS} = 'perl' + if $] >= 5.008 && $] < 5.012; + +WriteMakefile(%WriteMakefileArgs); diff --git a/README b/README new file mode 100644 index 0000000..62b5e6a --- /dev/null +++ b/README @@ -0,0 +1,43 @@ +bignum + +bignum - transparent big number support + +INSTALLATION + +To install this module, unpack the distribution file, and run the following +commands: + + perl Makefile.PL + make + make test + make install + +SUPPORT AND DOCUMENTATION + +After installing, you can find documentation for these modules with the +perldoc command. + + perldoc bignum + +You can also look for information at: + + RT, CPAN's request tracker + http://rt.cpan.org/NoAuth/Bugs.html?Dist=bignum + + AnnoCPAN, Annotated CPAN documentation + http://annocpan.org/dist/bignum + + CPAN Ratings + http://cpanratings.perl.org/d/bignum + + Search CPAN + http://search.cpan.org/dist/bignum + +COPYRIGHT AND LICENCE + +Copyright 2002-2007 Tels, L. + +Copyright 2014- Peter John Acklam L. + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. diff --git a/SIGNATURE b/SIGNATURE new file mode 100644 index 0000000..a12a26f --- /dev/null +++ b/SIGNATURE @@ -0,0 +1,69 @@ +This file contains message digests of all files listed in MANIFEST, +signed via the Module::Signature module, version 0.81. + +To verify the content in this distribution, first make sure you have +Module::Signature installed, then type: + + % cpansign -v + +It will check each file's integrity, as well as the signature's +validity. If "==> Signature verified OK! <==" is not displayed, +the distribution may already have been compromised, and you should +not run its Makefile.PL or Build.PL. + +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +SHA1 3ee135c08dc6dda71c7381f1a2495df461458e03 BUGS +SHA1 3735d390ff81bd72f0ddf3e0e06084b6956189c8 CHANGES +SHA1 d7c83d8f89b92a3262a01eb2778d39402e77263a LICENSE +SHA1 53ff562ba2eecd551ef6aee56f6f391031a3c912 MANIFEST +SHA1 4d036a4cde22d6d80f1e4aa41b6951e81c657325 MANIFEST.SKIP +SHA1 e521e597387984481c6d4af68c84f39d2d4513a9 META.json +SHA1 18879630e7a5350647183fa793bde0f1786ac5cf META.yml +SHA1 dad19971982e551df2316fbebbb880d1bc6e3c3d Makefile.PL +SHA1 fa6d74767423bf79cfaedb3e461160d1faeab91e README +SHA1 0070e1ca5b12be8948c08e62e62c98a2df7410d4 TODO +SHA1 60f923ec155ecde0bececc6c24dbaf81ddc941e8 lib/Math/BigFloat/Trace.pm +SHA1 7a03dd82a6167cf5c95d99f65409faba5adee302 lib/Math/BigInt/Trace.pm +SHA1 48b15b4262a9c86ceff7aa2d12a2bcb59bda2bde lib/bigint.pm +SHA1 fdd77e3d004c5cc40fbc9666458c9b8c3a0ee701 lib/bignum.pm +SHA1 cc9732a5ecbdc486349e30e8abdf37800c70d540 lib/bigrat.pm +SHA1 a2d393f9d265801f8ef022725d03f83b616b2fe1 t/00sig.t +SHA1 4564e2c5605e7568738286358e4a49c8f27c38e6 t/01load.t +SHA1 237e24044b9cc602f739d4eff3f6f1bd3b51f16e t/02pod.t +SHA1 51ca22f1945595e0272dbc26bca2c1d4f8231568 t/03podcov.t +SHA1 af0aa4628e18d980b985a4bd22db6b4f0467125b t/author-bigint-hex.t +SHA1 c3bc8706bef21cdf96564bae9b7a4a1f1a8b5f2c t/author-bigint-oct.t +SHA1 ed3e805322e1f1799e2e68b65a1c0c34d5e78b71 t/big_e_pi.t +SHA1 06ba8137ea1136b3a86862effd90bd23c60360ee t/bigexp.t +SHA1 6ec6c37fd18ec538940a90c3cb4f7ea438b50817 t/bigint.t +SHA1 2935aa58821ff53327399329dbcf8194e92e5772 t/bignum.t +SHA1 799432d401aeba8bf84b4ea93adda6ebcc7ce9ee t/bigrat.t +SHA1 ac5e242ec0cc96d203760eb54eb5cf3e26cb4bb5 t/bii_e_pi.t +SHA1 c2eeb2e8a74025f651ae8eeecab41854dd100c7f t/biinfnan.t +SHA1 a3d5829a255fbb24126be4728efd245356d4d436 t/bir_e_pi.t +SHA1 e2066465a1aa0369487e45af4fed469b5d7915bc t/bn_lite.t +SHA1 ed6ff44bd1c726f1c87cb39e200116c5472d2550 t/bninfnan.t +SHA1 00679525b4719dabd088a7f7c8d8e758cefbc140 t/br_lite.t +SHA1 6480aa7520b00b34c78c84963ce972348627265c t/brinfnan.t +SHA1 39c5a2b06ca0299cbc5c846e9347194610e8ec1c t/in_effect.t +SHA1 65215b3093ffbbbdc432d62abac0e1768eb34969 t/infnan.inc +SHA1 9995d3788a1561f0a6e30178e9f93a425726ff0d t/option_a.t +SHA1 602522ad22998581c2b5f5a7e0cfc26343b6e1a0 t/option_l.t +SHA1 6474ca84364a126496999f2d6c47e6c0e740092b t/option_p.t +SHA1 bccfe0521ab0c46fb0f175485fa6ea889bc64d82 t/overrides.t +SHA1 523dddeb99a76738db6b91d2dae8cd5eda365537 t/ratopt_a.t +SHA1 b1bc1bd4ff2fc69322b132b7154c86b15b1f0f62 t/scope_f.t +SHA1 6fb36d527514933d0a7457c95c13e863543250ef t/scope_i.t +SHA1 e0aa84c76b7c2167b53f36147f752adf9d26f1e6 t/scope_r.t +-----BEGIN PGP SIGNATURE----- + +iQEcBAEBAgAGBQJads5cAAoJEGcmPl2fr166qg4IAIU562zug4+fVo5OuoocGLTK +EEbCiyUSso+xu1dqdS8ztUHQGGOCEVDm/QlJIHexnecB+fBYN0ufix87cBoQvHuk +u0PiNrkTZKDyIDrmSntb520hHH2cIYz9Tyw9bDIzGKGsZTgGSYlzo233jSnMlYhE +MogKuArBjmNjsGpFCRAo9DhoTZ6Wa9i9QQnZk5UrKhlFi6Lj09LCc54x5SJAxtDc +aaxOM9ocR/Em2L+iSRoMG6FWX+d2I4DK7UcluaTfcTO0/41P5SYI0xp77tQkJUUj +9Q/QRT6ew8urKxz6FuAyRbK+1acv39F0e0dHgjS1J0kvrygrnQCvSOHdmKsXS80= +=ci/j +-----END PGP SIGNATURE----- diff --git a/TODO b/TODO new file mode 100644 index 0000000..ec02696 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +Pretty much done, but there might be new ideas worth adding. + +Please send me test-reports, your experiences with this and your ideas - I love +to hear about my work! + +Tels diff --git a/lib/Math/BigFloat/Trace.pm b/lib/Math/BigFloat/Trace.pm new file mode 100644 index 0000000..04dec98 --- /dev/null +++ b/lib/Math/BigFloat/Trace.pm @@ -0,0 +1,58 @@ +#!perl + +package Math::BigFloat::Trace; + +require 5.010; +use strict; +use warnings; + +use Exporter; +use Math::BigFloat; + +our ($accuracy, $precision, $round_mode, $div_scale); + +our @ISA = qw(Exporter Math::BigFloat); + +our $VERSION = '0.49'; + +use overload; # inherit overload from Math::BigFloat + +# Globals +$accuracy = $precision = undef; +$round_mode = 'even'; +$div_scale = 40; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + + my $value = shift; + my $a = $accuracy; + $a = $_[0] if defined $_[0]; + my $p = $precision; + $p = $_[1] if defined $_[1]; + my $self = Math::BigFloat->new($value, $a, $p, $round_mode); + + # remember, downgrading may return a BigInt, so don't meddle with class + # bless $self, $class; + + print "MBF new '$value' => '$self' (", ref($self), ")"; + return $self; +} + +sub import { + print "MBF import ", join(' ', @_); + my $self = shift; + + # we catch the constants, the rest goes go BigFloat + my @a = (); + foreach (@_) { + push @a, $_ if $_ ne ':constant'; + } + overload::constant float => sub { $self->new(shift); }; + + Math::BigFloat->import(@a); # need it for subclasses +# $self->export_to_level(1,$self,@_); # need this ? +} + +1; diff --git a/lib/Math/BigInt/Trace.pm b/lib/Math/BigInt/Trace.pm new file mode 100644 index 0000000..5f83c79 --- /dev/null +++ b/lib/Math/BigInt/Trace.pm @@ -0,0 +1,48 @@ +#!perl + +package Math::BigInt::Trace; + +require 5.010; +use strict; +use warnings; + +use Exporter; +use Math::BigInt; + +our ($accuracy, $precision, $round_mode, $div_scale); + +our @ISA = qw(Exporter Math::BigInt); + +our $VERSION = '0.49'; + +use overload; # inherit overload from Math::BigInt + +# Globals +$accuracy = $precision = undef; +$round_mode = 'even'; +$div_scale = 40; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + + my $value = shift; + my $a = $accuracy; + $a = $_[0] if defined $_[0]; + my $p = $precision; + $p = $_[1] if defined $_[1]; + my $self = Math::BigInt->new($value, $a, $p, $round_mode); + bless $self, $class; + print "MBI new '$value' => '$self' (", ref($self), ")"; + return $self; +} + +sub import { + print "MBI import ", join(' ', @_); + my $self = shift; + Math::BigInt::import($self, @_); # need it for subclasses +# $self->export_to_level(1, $self, @_); # need this ? + @_ = (); +} + +1; diff --git a/lib/bigint.pm b/lib/bigint.pm new file mode 100644 index 0000000..92aeae8 --- /dev/null +++ b/lib/bigint.pm @@ -0,0 +1,822 @@ +package bigint; + +use 5.010; +use strict; +use warnings; + +our $VERSION = '0.49'; + +use Exporter; +our @ISA = qw( Exporter ); +our @EXPORT_OK = qw( PI e bpi bexp hex oct ); +our @EXPORT = qw( inf NaN ); + +use overload; + +############################################################################## + +# These are all alike, and thus faked by AUTOLOAD + +my @faked = qw/round_mode accuracy precision div_scale/; +our ($AUTOLOAD, $_lite); # _lite for testsuite + +sub AUTOLOAD { + my $name = $AUTOLOAD; + + $name =~ s/.*:://; # split package + no strict 'refs'; + foreach my $n (@faked) { + if ($n eq $name) { + *{"bigint::$name"} = + sub { + my $self = shift; + no strict 'refs'; + if (defined $_[0]) { + return Math::BigInt->$name($_[0]); + } + return Math::BigInt->$name(); + }; + return &$name; + } + } + + # delayed load of Carp and avoid recursion + require Carp; + Carp::croak ("Can't call bigint\-\>$name, not a valid method"); +} + +sub upgrade { + $Math::BigInt::upgrade; +} + +sub _binary_constant { + # this takes a binary/hexadecimal/octal constant string and returns it + # as string suitable for new. Basically it converts octal to decimal, and + # passes every thing else unmodified back. + my $string = shift; + + return Math::BigInt->new($string) if $string =~ /^0[bx]/; + + # so it must be an octal constant + Math::BigInt->from_oct($string); +} + +sub _float_constant { + # this takes a floating point constant string and returns it truncated to + # integer. For instance, '4.5' => '4', '1.234e2' => '123' etc + my $float = shift; + + # some simple cases first + return $float if ($float =~ /^[+-]?[0-9]+$/); # '+123','-1','0' etc + return $float + if ($float =~ /^[+-]?[0-9]+\.?[eE]\+?[0-9]+$/); # 123e2, 123.e+2 + return '0' if ($float =~ /^[+-]?[0]*\.[0-9]+$/); # .2, 0.2, -.1 + if ($float =~ /^[+-]?[0-9]+\.[0-9]*$/) { # 1., 1.23, -1.2 etc + $float =~ s/\..*//; + return $float; + } + my ($mis, $miv, $mfv, $es, $ev) = Math::BigInt::_split($float); + return $float if !defined $mis; # doesn't look like a number to me + my $ec = int($$ev); + my $sign = $$mis; + $sign = '' if $sign eq '+'; + if ($$es eq '-') { + # ignore fraction part entirely + if ($ec >= length($$miv)) { # 123.23E-4 + return '0'; + } + return $sign . substr($$miv, 0, length($$miv) - $ec); # 1234.45E-2 = 12 + } + # xE+y + if ($ec >= length($$mfv)) { + $ec -= length($$mfv); + return $sign.$$miv.$$mfv if $ec == 0; # 123.45E+2 => 12345 + return $sign.$$miv.$$mfv.'E'.$ec; # 123.45e+3 => 12345e1 + } + $mfv = substr($$mfv, 0, $ec); + $sign.$$miv.$mfv; # 123.45e+1 => 1234 +} + +sub unimport { + $^H{bigint} = undef; # no longer in effect + overload::remove_constant('binary', '', 'float', '', 'integer'); +} + +sub in_effect { + my $level = shift || 0; + my $hinthash = (caller($level))[10]; + $hinthash->{bigint}; +} + +############################################################################# +# the following two routines are for "use bigint qw/hex oct/;": + +use constant LEXICAL => $] > 5.009004; + +# Internal function with the same semantics as CORE::hex(). This function is +# not used directly, but rather by other front-end functions. + +sub _hex_core { + my $str = shift; + + # Strip off, clean, and parse as much as we can from the beginning. + + my $x; + if ($str =~ s/ ^ (0?[xX])? ( [0-9a-fA-F]* ( _ [0-9a-fA-F]+ )* ) //x) { + my $chrs = $2; + $chrs =~ tr/_//d; + $chrs = '0' unless CORE::length $chrs; + $x = Math::BigInt -> from_hex($chrs); + } else { + $x = Math::BigInt -> bzero(); + } + + # Warn about trailing garbage. + + if (CORE::length($str)) { + require Carp; + Carp::carp(sprintf("Illegal hexadecimal digit '%s' ignored", + substr($str, 0, 1))); + } + + return $x; +} + +# Internal function with the same semantics as CORE::oct(). This function is +# not used directly, but rather by other front-end functions. + +sub _oct_core { + my $str = shift; + + $str =~ s/^\s*//; + + # Hexadecimal input. + + return _hex_core($str) if $str =~ /^0?[xX]/; + + my $x; + + # Binary input. + + if ($str =~ /^0?[bB]/) { + + # Strip off, clean, and parse as much as we can from the beginning. + + if ($str =~ s/ ^ (0?[bB])? ( [01]* ( _ [01]+ )* ) //x) { + my $chrs = $2; + $chrs =~ tr/_//d; + $chrs = '0' unless CORE::length $chrs; + $x = Math::BigInt -> from_bin($chrs); + } + + # Warn about trailing garbage. + + if (CORE::length($str)) { + require Carp; + Carp::carp(sprintf("Illegal binary digit '%s' ignored", + substr($str, 0, 1))); + } + + return $x; + } + + # Octal input. Strip off, clean, and parse as much as we can from the + # beginning. + + if ($str =~ s/ ^ ( [0-7]* ( _ [0-7]+ )* ) //x) { + my $chrs = $1; + $chrs =~ tr/_//d; + $chrs = '0' unless CORE::length $chrs; + $x = Math::BigInt -> from_oct($chrs); + } + + # Warn about trailing garbage. CORE::oct() only warns about 8 and 9. + + if (CORE::length($str)) { + my $chr = substr($str, 0, 1); + if ($chr eq '8' || $chr eq '9') { + require Carp; + Carp::carp(sprintf("Illegal octal digit '%s' ignored", $chr)); + } + } + + return $x; +} + +{ + my $proto = LEXICAL ? '_' : ';$'; + eval ' +sub hex(' . $proto . ') {' . <<'.'; + my $str = @_ ? $_[0] : $_; + _hex_core($str); +} +. + + eval ' +sub oct(' . $proto . ') {' . <<'.'; + my $str = @_ ? $_[0] : $_; + _oct_core($str); +} +. +} + +############################################################################# +# the following two routines are for Perl 5.9.4 or later and are lexical + +my ($prev_oct, $prev_hex, $overridden); + +if (LEXICAL) { eval <<'.' } +sub _hex(_) { + my $hh = (caller 0)[10]; + return $prev_hex ? &$prev_hex($_[0]) : CORE::hex($_[0]) + unless $$hh{bigint}||$$hh{bignum}||$$hh{bigrat}; + _hex_core($_[0]); +} + +sub _oct(_) { + my $hh = (caller 0)[10]; + return $prev_oct ? &$prev_oct($_[0]) : CORE::oct($_[0]) + unless $$hh{bigint}||$$hh{bignum}||$$hh{bigrat}; + _oct_core($_[0]); +} +. + +sub _override { + return if $overridden; + $prev_oct = *CORE::GLOBAL::oct{CODE}; + $prev_hex = *CORE::GLOBAL::hex{CODE}; + no warnings 'redefine'; + *CORE::GLOBAL::oct = \&_oct; + *CORE::GLOBAL::hex = \&_hex; + $overridden++; +} + +sub import { + my $self = shift; + + $^H{bigint} = 1; # we are in effect + + # for newer Perls always override hex() and oct() with a lexical version: + if (LEXICAL) { + _override(); + } + # some defaults + my $lib = ''; + my $lib_kind = 'try'; + + my @import = (':constant'); # drive it w/ constant + my @a = @_; + my $l = scalar @_; + my $j = 0; + my ($ver, $trace); # version? trace? + my ($a, $p); # accuracy, precision + for (my $i = 0; $i < $l; $i++, $j++) { + if ($_[$i] =~ /^(l|lib|try|only)$/) { + # this causes a different low lib to take care... + $lib_kind = $1; + $lib_kind = 'lib' if $lib_kind eq 'l'; + $lib = $_[$i + 1] || ''; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } elsif ($_[$i] =~ /^(a|accuracy)$/) { + $a = $_[$i + 1]; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } elsif ($_[$i] =~ /^(p|precision)$/) { + $p = $_[$i + 1]; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } elsif ($_[$i] =~ /^(v|version)$/) { + $ver = 1; + splice @a, $j, 1; + $j--; + } elsif ($_[$i] =~ /^(t|trace)$/) { + $trace = 1; + splice @a, $j, 1; + $j--; + } elsif ($_[$i] !~ /^(PI|e|bpi|bexp|hex|oct)\z/) { + die ("unknown option $_[$i]"); + } + } + my $class; + $_lite = 0; # using M::BI::L ? + if ($trace) { + require Math::BigInt::Trace; + $class = 'Math::BigInt::Trace'; + } else { + # see if we can find Math::BigInt::Lite + if (!defined $a && !defined $p) { # rounding won't work to well + local @INC = @INC; + pop @INC if $INC[-1] eq '.'; + if (eval { require Math::BigInt::Lite; 1 }) { + @import = (); # :constant in Lite, not MBI + Math::BigInt::Lite->import(':constant'); + $_lite = 1; # signal okay + } + } + require Math::BigInt if $_lite == 0; # not already loaded? + $class = 'Math::BigInt'; # regardless of MBIL or not + } + push @import, $lib_kind => $lib if $lib ne ''; + # Math::BigInt::Trace or plain Math::BigInt + $class->import(@import); + + bigint->accuracy($a) if defined $a; + bigint->precision($p) if defined $p; + if ($ver) { + print "bigint\t\t\t v$VERSION\n"; + print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite; + print "Math::BigInt\t\t v$Math::BigInt::VERSION"; + my $config = Math::BigInt->config(); + print " lib => $config->{lib} v$config->{lib_version}\n"; + exit; + } + # we take care of floating point constants, since BigFloat isn't available + # and BigInt doesn't like them: + overload::constant float => + sub { + Math::BigInt->new(_float_constant(shift)); + }; + # Take care of octal/hexadecimal constants + overload::constant binary => + sub { + _binary_constant(shift); + }; + + # if another big* was already loaded: + my ($package) = caller(); + + no strict 'refs'; + if (!defined *{"${package}::inf"}) { + $self->export_to_level(1, $self, @a); # export inf and NaN, e and PI + } +} + +sub inf () { Math::BigInt->binf(); } +sub NaN () { Math::BigInt->bnan(); } + +sub PI () { Math::BigInt->new(3); } +sub e () { Math::BigInt->new(2); } +sub bpi ($) { Math::BigInt->new(3); } +sub bexp ($$) { + my $x = Math::BigInt->new($_[0]); + $x->bexp($_[1]); +} + +1; + +__END__ + +=pod + +=head1 NAME + +bigint - Transparent BigInteger support for Perl + +=head1 SYNOPSIS + + use bigint; + + $x = 2 + 4.5,"\n"; # BigInt 6 + print 2 ** 512,"\n"; # really is what you think it is + print inf + 42,"\n"; # inf + print NaN * 7,"\n"; # NaN + print hex("0x1234567890123490"),"\n"; # Perl v5.10.0 or later + + { + no bigint; + print 2 ** 256,"\n"; # a normal Perl scalar now + } + + # Import into current package: + use bigint qw/hex oct/; + print hex("0x1234567890123490"),"\n"; + print oct("01234567890123490"),"\n"; + +=head1 DESCRIPTION + +All operators (including basic math operations) except the range operator C<..> +are overloaded. Integer constants are created as proper BigInts. + +Floating point constants are truncated to integer. All parts and results of +expressions are also truncated. + +Unlike L, this pragma creates integer constants that are only +limited in their size by the available memory and CPU time. + +=head2 use integer vs. use bigint + +There is one small difference between C and C: the +former will not affect assignments to variables and the return value of +some functions. C truncates these results to integer too: + + # perl -Minteger -wle 'print 3.2' + 3.2 + # perl -Minteger -wle 'print 3.2 + 0' + 3 + # perl -Mbigint -wle 'print 3.2' + 3 + # perl -Mbigint -wle 'print 3.2 + 0' + 3 + + # perl -Mbigint -wle 'print exp(1) + 0' + 2 + # perl -Mbigint -wle 'print exp(1)' + 2 + # perl -Minteger -wle 'print exp(1)' + 2.71828182845905 + # perl -Minteger -wle 'print exp(1) + 0' + 2 + +In practice this makes seldom a difference as B of +expressions will be truncated anyway, but this can, for instance, affect the +return value of subroutines: + + sub three_integer { use integer; return 3.2; } + sub three_bigint { use bigint; return 3.2; } + + print three_integer(), " ", three_bigint(),"\n"; # prints "3.2 3" + +=head2 Options + +bigint recognizes some options that can be passed while loading it via use. +The options can (currently) be either a single letter form, or the long form. +The following options exist: + +=over 2 + +=item a or accuracy + +This sets the accuracy for all math operations. The argument must be greater +than or equal to zero. See Math::BigInt's bround() function for details. + + perl -Mbigint=a,2 -le 'print 12345+1' + +Note that setting precision and accuracy at the same time is not possible. + +=item p or precision + +This sets the precision for all math operations. The argument can be any +integer. Negative values mean a fixed number of digits after the dot, and +are ignored since all operations happen in integer space. +A positive value rounds to this digit left from the dot. 0 or 1 mean round to +integer and are ignore like negative values. + +See Math::BigInt's bfround() function for details. + + perl -Mbignum=p,5 -le 'print 123456789+123' + +Note that setting precision and accuracy at the same time is not possible. + +=item t or trace + +This enables a trace mode and is primarily for debugging bigint or +Math::BigInt. + +=item hex + +Override the built-in hex() method with a version that can handle big +integers. This overrides it by exporting it to the current package. Under +Perl v5.10.0 and higher, this is not so necessary, as hex() is lexically +overridden in the current scope whenever the bigint pragma is active. + +=item oct + +Override the built-in oct() method with a version that can handle big +integers. This overrides it by exporting it to the current package. Under +Perl v5.10.0 and higher, this is not so necessary, as oct() is lexically +overridden in the current scope whenever the bigint pragma is active. + +=item l, lib, try or only + +Load a different math lib, see L. + + perl -Mbigint=lib,GMP -e 'print 2 ** 512' + perl -Mbigint=try,GMP -e 'print 2 ** 512' + perl -Mbigint=only,GMP -e 'print 2 ** 512' + +Currently there is no way to specify more than one library on the command +line. This means the following does not work: + + perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512' + +This will be hopefully fixed soon ;) + +=item v or version + +This prints out the name and version of all modules used and then exits. + + perl -Mbigint=v + +=back + +=head2 Math Library + +Math with the numbers is done (by default) by a module called +Math::BigInt::Calc. This is equivalent to saying: + + use bigint lib => 'Calc'; + +You can change this by using: + + use bignum lib => 'GMP'; + +The following would first try to find Math::BigInt::Foo, then +Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: + + use bigint lib => 'Foo,Math::BigInt::Bar'; + +Using C warns if none of the specified libraries can be found and +L did fall back to one of the default libraries. +To suppress this warning, use C instead: + + use bignum try => 'GMP'; + +If you want the code to die instead of falling back, use C instead: + + use bignum only => 'GMP'; + +Please see respective module documentation for further details. + +=head2 Internal Format + +The numbers are stored as objects, and their internals might change at anytime, +especially between math operations. The objects also might belong to different +classes, like Math::BigInt, or Math::BigInt::Lite. Mixing them together, even +with normal scalars is not extraordinary, but normal and expected. + +You should not depend on the internal format, all accesses must go through +accessor methods. E.g. looking at $x->{sign} is not a good idea since there +is no guaranty that the object in question has such a hash key, nor is a hash +underneath at all. + +=head2 Sign + +The sign is either '+', '-', 'NaN', '+inf' or '-inf'. +You can access it with the sign() method. + +A sign of 'NaN' is used to represent the result when input arguments are not +numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively +minus infinity. You will get '+inf' when dividing a positive number by 0, and +'-inf' when dividing any negative number by 0. + +=head2 Method calls + +Since all numbers are now objects, you can use all functions that are part of +the BigInt API. You can only use the bxxx() notation, and not the fxxx() +notation, though. + +But a warning is in order. When using the following to make a copy of a number, +only a shallow copy will be made. + + $x = 9; $y = $x; + $x = $y = 7; + +Using the copy or the original with overloaded math is okay, e.g. the +following work: + + $x = 9; $y = $x; + print $x + 1, " ", $y,"\n"; # prints 10 9 + +but calling any method that modifies the number directly will result in +B the original and the copy being destroyed: + + $x = 9; $y = $x; + print $x->badd(1), " ", $y,"\n"; # prints 10 10 + + $x = 9; $y = $x; + print $x->binc(1), " ", $y,"\n"; # prints 10 10 + + $x = 9; $y = $x; + print $x->bmul(2), " ", $y,"\n"; # prints 18 18 + +Using methods that do not modify, but test that the contents works: + + $x = 9; $y = $x; + $z = 9 if $x->is_zero(); # works fine + +See the documentation about the copy constructor and C<=> in overload, as +well as the documentation in BigInt for further details. + +=head2 Methods + +=over 2 + +=item inf() + +A shortcut to return Math::BigInt->binf(). Useful because Perl does not always +handle bareword C properly. + +=item NaN() + +A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always +handle bareword C properly. + +=item e + + # perl -Mbigint=e -wle 'print e' + +Returns Euler's number C, aka exp(1). Note that under bigint, this is +truncated to an integer, and hence simple '2'. + +=item PI + + # perl -Mbigint=PI -wle 'print PI' + +Returns PI. Note that under bigint, this is truncated to an integer, and hence +simple '3'. + +=item bexp() + + bexp($power,$accuracy); + +Returns Euler's number C raised to the appropriate power, to +the wanted accuracy. + +Note that under bigint, the result is truncated to an integer. + +Example: + + # perl -Mbigint=bexp -wle 'print bexp(1,80)' + +=item bpi() + + bpi($accuracy); + +Returns PI to the wanted accuracy. Note that under bigint, this is truncated +to an integer, and hence simple '3'. + +Example: + + # perl -Mbigint=bpi -wle 'print bpi(80)' + +=item upgrade() + +Return the class that numbers are upgraded to, is in fact returning +C<$Math::BigInt::upgrade>. + +=item in_effect() + + use bigint; + + print "in effect\n" if bigint::in_effect; # true + { + no bigint; + print "in effect\n" if bigint::in_effect; # false + } + +Returns true or false if C is in effect in the current scope. + +This method only works on Perl v5.9.4 or later. + +=back + +=head1 CAVEATS + +=over 2 + +=item Operator vs literal overloading + +C works by overloading handling of integer and floating point +literals, converting them to L objects. + +This means that arithmetic involving only string values or string +literals will be performed using Perl's built-in operators. + +For example: + + use bignum; + my $x = "900000000000000009"; + my $y = "900000000000000007"; + print $x - $y; + +will output C<0> on default 32-bit builds, since C never sees +the string literals. To ensure the expression is all treated as +C objects, use a literal number in the expression: + + print +(0+$x) - $y; + +=item ranges + +Perl does not allow overloading of ranges, so you can neither safely use +ranges with bigint endpoints, nor is the iterator variable a bigint. + + use 5.010; + for my $i (12..13) { + for my $j (20..21) { + say $i ** $j; # produces a floating-point number, + # not a big integer + } + } + +=item in_effect() + +This method only works on Perl v5.9.4 or later. + +=item hex()/oct() + +C overrides these routines with versions that can also handle +big integer values. Under Perl prior to version v5.9.4, however, this +will not happen unless you specifically ask for it with the two +import tags "hex" and "oct" - and then it will be global and cannot be +disabled inside a scope with "no bigint": + + use bigint qw/hex oct/; + + print hex("0x1234567890123456"); + { + no bigint; + print hex("0x1234567890123456"); + } + +The second call to hex() will warn about a non-portable constant. + +Compare this to: + + use bigint; + + # will warn only under Perl older than v5.9.4 + print hex("0x1234567890123456"); + +=back + +=head1 MODULES USED + +C is just a thin wrapper around various modules of the Math::BigInt +family. Think of it as the head of the family, who runs the shop, and orders +the others to do the work. + +The following modules are currently used by bigint: + + Math::BigInt::Lite (for speed, and only if it is loadable) + Math::BigInt + +=head1 EXAMPLES + +Some cool command line examples to impress the Python crowd ;) You might want +to compare them to the results under -Mbignum or -Mbigrat: + + perl -Mbigint -le 'print sqrt(33)' + perl -Mbigint -le 'print 2*255' + perl -Mbigint -le 'print 4.5+2*255' + perl -Mbigint -le 'print 3/7 + 5/7 + 8/3' + perl -Mbigint -le 'print 123->is_odd()' + perl -Mbigint -le 'print log(2)' + perl -Mbigint -le 'print 2 ** 0.5' + perl -Mbigint=a,65 -le 'print 2 ** 0.2' + perl -Mbignum=a,65,l,GMP -le 'print 7 ** 7777' + +=head1 BUGS + +For information about bugs and how to report them, see the BUGS section in the +documentation available with the perldoc command. + + perldoc bignum + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc bigint + +For more information, see the SUPPORT section in the documentation available +with the perldoc command. + + perldoc bignum + +=head1 LICENSE + +This program is free software; you may redistribute it and/or modify it under +the same terms as Perl itself. + +=head1 SEE ALSO + +L and L. + +L, L, L and L as well as +L, L and L. + +=head1 AUTHORS + +=over 4 + +=item * + +(C) by Tels L in early 2002 - 2007. + +=item * + +Maintained by Peter John Acklam Epjacklam@gmail.com, 2014-. + +=back + +=cut diff --git a/lib/bignum.pm b/lib/bignum.pm new file mode 100644 index 0000000..e052aab --- /dev/null +++ b/lib/bignum.pm @@ -0,0 +1,731 @@ +package bignum; + +use 5.010; +use strict; +use warnings; + +our $VERSION = '0.49'; + +use Exporter; +our @ISA = qw( bigint ); +our @EXPORT_OK = qw( PI e bpi bexp hex oct ); +our @EXPORT = qw( inf NaN ); + +use overload; +use bigint (); + +############################################################################## + +BEGIN { + *inf = \&bigint::inf; + *NaN = \&bigint::NaN; + *hex = \&bigint::hex; + *oct = \&bigint::oct; +} + +# These are all alike, and thus faked by AUTOLOAD + +my @faked = qw/round_mode accuracy precision div_scale/; +our ($AUTOLOAD, $_lite); # _lite for testsuite + +sub AUTOLOAD { + my $name = $AUTOLOAD; + + $name =~ s/.*:://; # split package + no strict 'refs'; + foreach my $n (@faked) { + if ($n eq $name) { + *{"bignum::$name"} = + sub { + my $self = shift; + no strict 'refs'; + if (defined $_[0]) { + Math::BigInt->$name($_[0]); + return Math::BigFloat->$name($_[0]); + } + return Math::BigInt->$name(); + }; + return &$name; + } + } + + # delayed load of Carp and avoid recursion + require Carp; + Carp::croak ("Can't call bignum\-\>$name, not a valid method"); +} + +sub unimport { + $^H{bignum} = undef; # no longer in effect + overload::remove_constant('binary', '', 'float', '', 'integer'); +} + +sub in_effect { + my $level = shift || 0; + my $hinthash = (caller($level))[10]; + $hinthash->{bignum}; +} + +############################################################################# + +sub import { + my $self = shift; + + $^H{bignum} = 1; # we are in effect + + # for newer Perls override hex() and oct() with a lexical version: + if ($] > 5.009004) { + bigint::_override(); + } + + # some defaults + my $lib = ''; + my $lib_kind = 'try'; + my $upgrade = 'Math::BigFloat'; + my $downgrade = 'Math::BigInt'; + + my @import = (':constant'); # drive it w/ constant + my @a = @_; + my $l = scalar @_; + my $j = 0; + my ($ver, $trace); # version? trace? + my ($a, $p); # accuracy, precision + for (my $i = 0; $i < $l; $i++, $j++) { + if ($_[$i] eq 'upgrade') { + # this causes upgrading + $upgrade = $_[$i + 1]; # or undef to disable + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } elsif ($_[$i] eq 'downgrade') { + # this causes downgrading + $downgrade = $_[$i + 1]; # or undef to disable + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } elsif ($_[$i] =~ /^(l|lib|try|only)$/) { + # this causes a different low lib to take care... + $lib_kind = $1; + $lib_kind = 'lib' if $lib_kind eq 'l'; + $lib = $_[$i + 1] || ''; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } + elsif ($_[$i] =~ /^(a|accuracy)$/) { + $a = $_[$i + 1]; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } + elsif ($_[$i] =~ /^(p|precision)$/) { + $p = $_[$i + 1]; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } + elsif ($_[$i] =~ /^(v|version)$/) { + $ver = 1; + splice @a, $j, 1; + $j--; + } + elsif ($_[$i] =~ /^(t|trace)$/) { + $trace = 1; + splice @a, $j, 1; + $j--; + } + elsif ($_[$i] !~ /^(PI|e|bexp|bpi|hex|oct)\z/) { + die ("unknown option $_[$i]"); + } + } + my $class; + $_lite = 0; # using M::BI::L ? + if ($trace) { + require Math::BigInt::Trace; + $class = 'Math::BigInt::Trace'; + $upgrade = 'Math::BigFloat::Trace'; + } + else { + # see if we can find Math::BigInt::Lite + if (!defined $a && !defined $p) { # rounding won't work to well + local @INC = @INC; + pop @INC if $INC[-1] eq '.'; + if (eval { require Math::BigInt::Lite; 1 }) { + @import = (); # :constant in Lite, not MBI + Math::BigInt::Lite->import(':constant'); + $_lite = 1; # signal okay + } + } + require Math::BigInt if $_lite == 0; # not already loaded? + $class = 'Math::BigInt'; # regardless of MBIL or not + } + push @import, $lib_kind => $lib if $lib ne ''; + # Math::BigInt::Trace or plain Math::BigInt + $class->import(@import, upgrade => $upgrade); + + if ($trace) { + require Math::BigFloat::Trace; + $class = 'Math::BigFloat::Trace'; + $downgrade = 'Math::BigInt::Trace'; + } + else { + require Math::BigFloat; + $class = 'Math::BigFloat'; + } + $class->import(':constant', 'downgrade', $downgrade); + + bignum->accuracy($a) if defined $a; + bignum->precision($p) if defined $p; + if ($ver) { + print "bignum\t\t\t v$VERSION\n"; + print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite; + print "Math::BigInt\t\t v$Math::BigInt::VERSION"; + my $config = Math::BigInt->config(); + print " lib => $config->{lib} v$config->{lib_version}\n"; + print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n"; + exit; + } + + # Take care of octal/hexadecimal constants + overload::constant binary => + sub { + bigint::_binary_constant(shift); + }; + + # if another big* was already loaded: + my ($package) = caller(); + + no strict 'refs'; + if (!defined *{"${package}::inf"}) { + $self->export_to_level(1, $self, @a); # export inf and NaN + } +} + +sub PI () { Math::BigFloat->new('3.141592653589793238462643383279502884197'); } +sub e () { Math::BigFloat->new('2.718281828459045235360287471352662497757'); } +sub bpi ($) { Math::BigFloat->bpi(@_); } +sub bexp ($$) { + my $x = Math::BigFloat->new($_[0]); + $x->bexp($_[1]); +} + +1; + +__END__ + +=pod + +=head1 NAME + +bignum - Transparent BigNumber support for Perl + +=head1 SYNOPSIS + + use bignum; + + $x = 2 + 4.5,"\n"; # BigFloat 6.5 + print 2 ** 512 * 0.1,"\n"; # really is what you think it is + print inf * inf,"\n"; # prints inf + print NaN * 3,"\n"; # prints NaN + + { + no bignum; + print 2 ** 256,"\n"; # a normal Perl scalar now + } + + # for older Perls, import into current package: + use bignum qw/hex oct/; + print hex("0x1234567890123490"),"\n"; + print oct("01234567890123490"),"\n"; + +=head1 DESCRIPTION + +All operators (including basic math operations) are overloaded. Integer and +floating-point constants are created as proper BigInts or BigFloats, +respectively. + +If you do + + use bignum; + +at the top of your script, Math::BigFloat and Math::BigInt will be loaded +and any constant number will be converted to an object (Math::BigFloat for +floats like 3.1415 and Math::BigInt for integers like 1234). + +So, the following line: + + $x = 1234; + +creates actually a Math::BigInt and stores a reference to in $x. +This happens transparently and behind your back, so to speak. + +You can see this with the following: + + perl -Mbignum -le 'print ref(1234)' + +Don't worry if it says Math::BigInt::Lite, bignum and friends will use Lite +if it is installed since it is faster for some operations. It will be +automatically upgraded to BigInt whenever necessary: + + perl -Mbignum -le 'print ref(2**255)' + +This also means it is a bad idea to check for some specific package, since +the actual contents of $x might be something unexpected. Due to the +transparent way of bignum C should not be necessary, anyway. + +Since Math::BigInt and BigFloat also overload the normal math operations, +the following line will still work: + + perl -Mbignum -le 'print ref(1234+1234)' + +Since numbers are actually objects, you can call all the usual methods from +BigInt/BigFloat on them. This even works to some extent on expressions: + + perl -Mbignum -le '$x = 1234; print $x->bdec()' + perl -Mbignum -le 'print 1234->copy()->binc();' + perl -Mbignum -le 'print 1234->copy()->binc->badd(6);' + perl -Mbignum -le 'print +(1234)->copy()->binc()' + +(Note that print doesn't do what you expect if the expression starts with +'(' hence the C<+>) + +You can even chain the operations together as usual: + + perl -Mbignum -le 'print 1234->copy()->binc->badd(6);' + 1241 + +Under bignum (or bigint or bigrat), Perl will "upgrade" the numbers +appropriately. This means that: + + perl -Mbignum -le 'print 1234+4.5' + 1238.5 + +will work correctly. These mixed cases don't do always work when using +Math::BigInt or Math::BigFloat alone, or at least not in the way normal Perl +scalars work. + +If you do want to work with large integers like under C, try +C: + + perl -Mbigint -le 'print 1234.5+4.5' + 1238 + +There is also C which gives you big rationals: + + perl -Mbigrat -le 'print 1234+4.1' + 12381/10 + +The entire upgrading/downgrading is still experimental and might not work +as you expect or may even have bugs. You might get errors like this: + + Can't use an undefined value as an ARRAY reference at + /usr/local/lib/perl5/5.8.0/Math/BigInt/Calc.pm line 864 + +This means somewhere a routine got a BigFloat/Lite but expected a BigInt (or +vice versa) and the upgrade/downgrad path was missing. This is a bug, please +report it so that we can fix it. + +You might consider using just Math::BigInt or Math::BigFloat, since they +allow you finer control over what get's done in which module/space. For +instance, simple loop counters will be Math::BigInts under C and +this is slower than keeping them as Perl scalars: + + perl -Mbignum -le 'for ($i = 0; $i < 10; $i++) { print ref($i); }' + +Please note the following does not work as expected (prints nothing), since +overloading of '..' is not yet possible in Perl (as of v5.8.0): + + perl -Mbignum -le 'for (1..2) { print ref($_); }' + +=head2 Options + +bignum recognizes some options that can be passed while loading it via use. +The options can (currently) be either a single letter form, or the long form. +The following options exist: + +=over 2 + +=item a or accuracy + +This sets the accuracy for all math operations. The argument must be greater +than or equal to zero. See Math::BigInt's bround() function for details. + + perl -Mbignum=a,50 -le 'print sqrt(20)' + +Note that setting precision and accuracy at the same time is not possible. + +=item p or precision + +This sets the precision for all math operations. The argument can be any +integer. Negative values mean a fixed number of digits after the dot, while +a positive value rounds to this digit left from the dot. 0 or 1 mean round to +integer. See Math::BigInt's bfround() function for details. + + perl -Mbignum=p,-50 -le 'print sqrt(20)' + +Note that setting precision and accuracy at the same time is not possible. + +=item t or trace + +This enables a trace mode and is primarily for debugging bignum or +Math::BigInt/Math::BigFloat. + +=item l or lib + +Load a different math lib, see L. + + perl -Mbignum=l,GMP -e 'print 2 ** 512' + +Currently there is no way to specify more than one library on the command +line. This means the following does not work: + + perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512' + +This will be hopefully fixed soon ;) + +=item hex + +Override the built-in hex() method with a version that can handle big +numbers. This overrides it by exporting it to the current package. Under +Perl v5.10.0 and higher, this is not so necessary, as hex() is lexically +overridden in the current scope whenever the bignum pragma is active. + +=item oct + +Override the built-in oct() method with a version that can handle big +numbers. This overrides it by exporting it to the current package. Under +Perl v5.10.0 and higher, this is not so necessary, as oct() is lexically +overridden in the current scope whenever the bigint pragma is active. + +=item v or version + +This prints out the name and version of all modules used and then exits. + + perl -Mbignum=v + +=back + +=head2 Methods + +Beside import() and AUTOLOAD() there are only a few other methods. + +Since all numbers are now objects, you can use all functions that are part of +the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not +the fxxx() notation, though. This makes it possible that the underlying object +might morph into a different class than BigFloat. + +=head2 Caveats + +But a warning is in order. When using the following to make a copy of a number, +only a shallow copy will be made. + + $x = 9; $y = $x; + $x = $y = 7; + +If you want to make a real copy, use the following: + + $y = $x->copy(); + +Using the copy or the original with overloaded math is okay, e.g. the +following work: + + $x = 9; $y = $x; + print $x + 1, " ", $y,"\n"; # prints 10 9 + +but calling any method that modifies the number directly will result in +B the original and the copy being destroyed: + + $x = 9; $y = $x; + print $x->badd(1), " ", $y,"\n"; # prints 10 10 + + $x = 9; $y = $x; + print $x->binc(1), " ", $y,"\n"; # prints 10 10 + + $x = 9; $y = $x; + print $x->bmul(2), " ", $y,"\n"; # prints 18 18 + +Using methods that do not modify, but test the contents works: + + $x = 9; $y = $x; + $z = 9 if $x->is_zero(); # works fine + +See the documentation about the copy constructor and C<=> in overload, as +well as the documentation in BigInt for further details. + +=over 2 + +=item inf() + +A shortcut to return Math::BigInt->binf(). Useful because Perl does not always +handle bareword C properly. + +=item NaN() + +A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always +handle bareword C properly. + +=item e + + # perl -Mbignum=e -wle 'print e' + +Returns Euler's number C, aka exp(1). + +=item PI() + + # perl -Mbignum=PI -wle 'print PI' + +Returns PI. + +=item bexp() + + bexp($power,$accuracy); + +Returns Euler's number C raised to the appropriate power, to +the wanted accuracy. + +Example: + + # perl -Mbignum=bexp -wle 'print bexp(1,80)' + +=item bpi() + + bpi($accuracy); + +Returns PI to the wanted accuracy. + +Example: + + # perl -Mbignum=bpi -wle 'print bpi(80)' + +=item upgrade() + +Return the class that numbers are upgraded to, is in fact returning +C<$Math::BigInt::upgrade>. + +=item in_effect() + + use bignum; + + print "in effect\n" if bignum::in_effect; # true + { + no bignum; + print "in effect\n" if bignum::in_effect; # false + } + +Returns true or false if C is in effect in the current scope. + +This method only works on Perl v5.9.4 or later. + +=back + +=head2 Math Library + +Math with the numbers is done (by default) by a module called +Math::BigInt::Calc. This is equivalent to saying: + + use bignum lib => 'Calc'; + +You can change this by using: + + use bignum lib => 'GMP'; + +The following would first try to find Math::BigInt::Foo, then +Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: + + use bignum lib => 'Foo,Math::BigInt::Bar'; + +Please see respective module documentation for further details. + +Using C warns if none of the specified libraries can be found and +L did fall back to one of the default libraries. +To suppress this warning, use C instead: + + use bignum try => 'GMP'; + +If you want the code to die instead of falling back, use C instead: + + use bignum only => 'GMP'; + +=head2 INTERNAL FORMAT + +The numbers are stored as objects, and their internals might change at anytime, +especially between math operations. The objects also might belong to different +classes, like Math::BigInt, or Math::BigFloat. Mixing them together, even +with normal scalars is not extraordinary, but normal and expected. + +You should not depend on the internal format, all accesses must go through +accessor methods. E.g. looking at $x->{sign} is not a bright idea since there +is no guaranty that the object in question has such a hashkey, nor is a hash +underneath at all. + +=head2 SIGN + +The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored separately. +You can access it with the sign() method. + +A sign of 'NaN' is used to represent the result when input arguments are not +numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively +minus infinity. You will get '+inf' when dividing a positive number by 0, and +'-inf' when dividing any negative number by 0. + +=head1 CAVEATS + +=over 2 + +=item Operator vs literal overloading + +C works by overloading handling of integer and floating point +literals, converting them to L or L +objects. + +This means that arithmetic involving only string values or string +literals will be performed using Perl's built-in operators. + +For example: + + use bignum; + my $x = "900000000000000009"; + my $y = "900000000000000007"; + print $x - $y; + +will output C<0> on default 32-bit builds, since C never sees +the string literals. To ensure the expression is all treated as +C or C objects, use a literal number in the +expression: + + print +(0+$x) - $y; + +=item in_effect() + +This method only works on Perl v5.9.4 or later. + +=item hex()/oct() + +C overrides these routines with versions that can also handle +big integer values. Under Perl prior to version v5.9.4, however, this +will not happen unless you specifically ask for it with the two +import tags "hex" and "oct" - and then it will be global and cannot be +disabled inside a scope with "no bigint": + + use bigint qw/hex oct/; + + print hex("0x1234567890123456"); + { + no bigint; + print hex("0x1234567890123456"); + } + +The second call to hex() will warn about a non-portable constant. + +Compare this to: + + use bigint; + + # will warn only under older than v5.9.4 + print hex("0x1234567890123456"); + +=back + +=head1 MODULES USED + +C is just a thin wrapper around various modules of the Math::BigInt +family. Think of it as the head of the family, who runs the shop, and orders +the others to do the work. + +The following modules are currently used by bignum: + + Math::BigInt::Lite (for speed, and only if it is loadable) + Math::BigInt + Math::BigFloat + +=head1 EXAMPLES + +Some cool command line examples to impress the Python crowd ;) + + perl -Mbignum -le 'print sqrt(33)' + perl -Mbignum -le 'print 2*255' + perl -Mbignum -le 'print 4.5+2*255' + perl -Mbignum -le 'print 3/7 + 5/7 + 8/3' + perl -Mbignum -le 'print 123->is_odd()' + perl -Mbignum -le 'print log(2)' + perl -Mbignum -le 'print exp(1)' + perl -Mbignum -le 'print 2 ** 0.5' + perl -Mbignum=a,65 -le 'print 2 ** 0.2' + perl -Mbignum=a,65,l,GMP -le 'print 7 ** 7777' + +=head1 BUGS + +Please report any bugs or feature requests to +C, or through the web interface at +L (requires login). +We will be notified, and then you'll automatically be notified of +progress on your bug as I make changes. + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc bignum + +You can also look for information at: + +=over 4 + +=item * RT: CPAN's request tracker + +L + +=item * AnnoCPAN: Annotated CPAN documentation + +L + +=item * CPAN Ratings + +L + +=item * Search CPAN + +L + +=item * CPAN Testers Matrix + +L + +=back + +=head1 LICENSE + +This program is free software; you may redistribute it and/or modify it under +the same terms as Perl itself. + +=head1 SEE ALSO + +L and L. + +L, L, L and L as well as +L, L and L. + +=head1 AUTHORS + +=over 4 + +=item * + +(C) by Tels L in early 2002 - 2007. + +=item * + +Maintained by Peter John Acklam Epjacklam@gmail.com, 2014-. + +=back + +=cut diff --git a/lib/bigrat.pm b/lib/bigrat.pm new file mode 100644 index 0000000..45682f7 --- /dev/null +++ b/lib/bigrat.pm @@ -0,0 +1,595 @@ +package bigrat; + +use 5.010; +use strict; +use warnings; + +our $VERSION = '0.49'; + +use Exporter; +our @ISA = qw( bigint ); +our @EXPORT_OK = qw( PI e bpi bexp hex oct ); +our @EXPORT = qw( inf NaN ); + +use overload; +use bigint (); + +############################################################################## + +BEGIN { + *inf = \&bigint::inf; + *NaN = \&bigint::NaN; + *hex = \&bigint::hex; + *oct = \&bigint::oct; +} + +# These are all alike, and thus faked by AUTOLOAD + +my @faked = qw/round_mode accuracy precision div_scale/; +our ($AUTOLOAD, $_lite); # _lite for testsuite + +sub AUTOLOAD { + my $name = $AUTOLOAD; + + $name =~ s/.*:://; # split package + no strict 'refs'; + foreach my $n (@faked) { + if ($n eq $name) { + *{"bigrat::$name"} = + sub { + my $self = shift; + no strict 'refs'; + if (defined $_[0]) { + Math::BigInt->$name($_[0]); + Math::BigFloat->$name($_[0]); + return Math::BigRat->$name($_[0]); + } + return Math::BigInt->$name(); + }; + return &$name; + } + } + + # delayed load of Carp and avoid recursion + require Carp; + Carp::croak ("Can't call bigrat\-\>$name, not a valid method"); +} + +sub unimport { + $^H{bigrat} = undef; # no longer in effect + overload::remove_constant('binary', '', 'float', '', 'integer'); +} + +sub in_effect { + my $level = shift || 0; + my $hinthash = (caller($level))[10]; + $hinthash->{bigrat}; +} + +############################################################################# + +sub import { + my $self = shift; + + # see also bignum->import() for additional comments + + $^H{bigrat} = 1; # we are in effect + + # for newer Perls always override hex() and oct() with a lexical version: + if ($] > 5.009004) { + bigint::_override(); + } + # some defaults + my $lib = ''; + my $lib_kind = 'try'; + my $upgrade = 'Math::BigFloat'; + + my @import = (':constant'); # drive it w/ constant + my @a = @_; + my $l = scalar @_; + my $j = 0; + my ($a, $p); + my ($ver, $trace); # version? trace? + for (my $i = 0; $i < $l ; $i++, $j++) { + if ($_[$i] eq 'upgrade') { + # this causes upgrading + $upgrade = $_[$i + 1]; # or undef to disable + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + } + elsif ($_[$i] =~ /^(l|lib|try|only)$/) { + # this causes a different low lib to take care... + $lib_kind = $1; + $lib_kind = 'lib' if $lib_kind eq 'l'; + $lib = $_[$i + 1] || ''; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } + elsif ($_[$i] =~ /^(a|accuracy)$/) { + $a = $_[$i + 1]; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } + elsif ($_[$i] =~ /^(p|precision)$/) { + $p = $_[$i + 1]; + my $s = 2; + $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." + splice @a, $j, $s; + $j -= $s; + $i++; + } + elsif ($_[$i] =~ /^(v|version)$/) { + $ver = 1; + splice @a, $j, 1; + $j--; + } + elsif ($_[$i] =~ /^(t|trace)$/) { + $trace = 1; + splice @a, $j, 1; + $j--; + } + elsif ($_[$i] !~ /^(PI|e|bpi|bexp|hex|oct)\z/) { + die ("unknown option $_[$i]"); + } + } + my $class; + $_lite = 0; # using M::BI::L ? + if ($trace) { + require Math::BigInt::Trace; + $class = 'Math::BigInt::Trace'; + $upgrade = 'Math::BigFloat::Trace'; + } + else { + # see if we can find Math::BigInt::Lite + if (!defined $a && !defined $p) { # rounding won't work to well + local @INC = @INC; + pop @INC if $INC[-1] eq '.'; + if (eval { require Math::BigInt::Lite; 1 }) { + @import = (); # :constant in Lite, not MBI + Math::BigInt::Lite->import(':constant'); + $_lite = 1; # signal okay + } + } + require Math::BigInt if $_lite == 0; # not already loaded? + $class = 'Math::BigInt'; # regardless of MBIL or not + } + push @import, $lib_kind => $lib if $lib ne ''; + # Math::BigInt::Trace or plain Math::BigInt + $class->import(@import, upgrade => $upgrade); + + require Math::BigFloat; + Math::BigFloat->import(upgrade => 'Math::BigRat', ':constant'); + require Math::BigRat; + Math::BigRat->import(@import); + + bigrat->accuracy($a) if defined $a; + bigrat->precision($p) if defined $p; + if ($ver) { + print "bigrat\t\t\t v$VERSION\n"; + print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite; + print "Math::BigInt\t\t v$Math::BigInt::VERSION"; + my $config = Math::BigInt->config(); + print " lib => $config->{lib} v$config->{lib_version}\n"; + print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n"; + print "Math::BigRat\t\t v$Math::BigRat::VERSION\n"; + exit; + } + + # Take care of octal/hexadecimal constants + overload::constant binary => + sub { + bigint::_binary_constant(shift); + }; + + # if another big* was already loaded: + my ($package) = caller(); + + no strict 'refs'; + if (!defined *{"${package}::inf"}) { + $self->export_to_level(1, $self, @a); # export inf and NaN + } +} + +sub PI () { Math::BigFloat->new('3.141592653589793238462643383279502884197'); } +sub e () { Math::BigFloat->new('2.718281828459045235360287471352662497757'); } + +sub bpi ($) { + local $Math::BigFloat::upgrade; + Math::BigFloat->bpi(@_); +} + +sub bexp ($$) { + local $Math::BigFloat::upgrade; + my $x = Math::BigFloat->new($_[0]); + $x->bexp($_[1]); +} + +1; + +__END__ + +=pod + +=head1 NAME + +bigrat - Transparent BigNumber/BigRational support for Perl + +=head1 SYNOPSIS + + use bigrat; + + print 2 + 4.5,"\n"; # BigFloat 6.5 + print 1/3 + 1/4,"\n"; # produces 7/12 + + { + no bigrat; + print 1/3,"\n"; # 0.33333... + } + + # Import into current package: + use bigrat qw/hex oct/; + print hex("0x1234567890123490"),"\n"; + print oct("01234567890123490"),"\n"; + +=head1 DESCRIPTION + +All operators (including basic math operations) are overloaded. Integer and +floating-point constants are created as proper BigInts or BigFloats, +respectively. + +Other than L, this module upgrades to Math::BigRat, meaning that +instead of 2.5 you will get 2+1/2 as output. + +=head2 Modules Used + +C is just a thin wrapper around various modules of the Math::BigInt +family. Think of it as the head of the family, who runs the shop, and orders +the others to do the work. + +The following modules are currently used by bignum: + + Math::BigInt::Lite (for speed, and only if it is loadable) + Math::BigInt + Math::BigFloat + Math::BigRat + +=head2 Math Library + +Math with the numbers is done (by default) by a module called +Math::BigInt::Calc. This is equivalent to saying: + + use bigrat lib => 'Calc'; + +You can change this by using: + + use bignum lib => 'GMP'; + +The following would first try to find Math::BigInt::Foo, then +Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: + + use bigrat lib => 'Foo,Math::BigInt::Bar'; + +Using C warns if none of the specified libraries can be found and +L did fall back to one of the default libraries. +To suppress this warning, use C instead: + + use bignum try => 'GMP'; + +If you want the code to die instead of falling back, use C instead: + + use bignum only => 'GMP'; + +Please see respective module documentation for further details. + +=head2 Sign + +The sign is either '+', '-', 'NaN', '+inf' or '-inf'. + +A sign of 'NaN' is used to represent the result when input arguments are not +numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively +minus infinity. You will get '+inf' when dividing a positive number by 0, and +'-inf' when dividing any negative number by 0. + +=head2 Methods + +Since all numbers are not objects, you can use all functions that are part of +the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not +the fxxx() notation, though. This makes you independent on the fact that the +underlying object might morph into a different class than BigFloat. + +=over 2 + +=item inf() + +A shortcut to return Math::BigInt->binf(). Useful because Perl does not always +handle bareword C properly. + +=item NaN() + +A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always +handle bareword C properly. + +=item e + + # perl -Mbigrat=e -wle 'print e' + +Returns Euler's number C, aka exp(1). + +=item PI + + # perl -Mbigrat=PI -wle 'print PI' + +Returns PI. + +=item bexp() + + bexp($power,$accuracy); + +Returns Euler's number C raised to the appropriate power, to +the wanted accuracy. + +Example: + + # perl -Mbigrat=bexp -wle 'print bexp(1,80)' + +=item bpi() + + bpi($accuracy); + +Returns PI to the wanted accuracy. + +Example: + + # perl -Mbigrat=bpi -wle 'print bpi(80)' + +=item upgrade() + +Return the class that numbers are upgraded to, is in fact returning +C<$Math::BigInt::upgrade>. + +=item in_effect() + + use bigrat; + + print "in effect\n" if bigrat::in_effect; # true + { + no bigrat; + print "in effect\n" if bigrat::in_effect; # false + } + +Returns true or false if C is in effect in the current scope. + +This method only works on Perl v5.9.4 or later. + +=back + +=head2 MATH LIBRARY + +Math with the numbers is done (by default) by a module called + +=head2 Caveat + +But a warning is in order. When using the following to make a copy of a number, +only a shallow copy will be made. + + $x = 9; $y = $x; + $x = $y = 7; + +If you want to make a real copy, use the following: + + $y = $x->copy(); + +Using the copy or the original with overloaded math is okay, e.g. the +following work: + + $x = 9; $y = $x; + print $x + 1, " ", $y,"\n"; # prints 10 9 + +but calling any method that modifies the number directly will result in +B the original and the copy being destroyed: + + $x = 9; $y = $x; + print $x->badd(1), " ", $y,"\n"; # prints 10 10 + + $x = 9; $y = $x; + print $x->binc(1), " ", $y,"\n"; # prints 10 10 + + $x = 9; $y = $x; + print $x->bmul(2), " ", $y,"\n"; # prints 18 18 + +Using methods that do not modify, but testthe contents works: + + $x = 9; $y = $x; + $z = 9 if $x->is_zero(); # works fine + +See the documentation about the copy constructor and C<=> in overload, as +well as the documentation in BigInt for further details. + +=head2 Options + +bignum recognizes some options that can be passed while loading it via use. +The options can (currently) be either a single letter form, or the long form. +The following options exist: + +=over 2 + +=item a or accuracy + +This sets the accuracy for all math operations. The argument must be greater +than or equal to zero. See Math::BigInt's bround() function for details. + + perl -Mbigrat=a,50 -le 'print sqrt(20)' + +Note that setting precision and accuracy at the same time is not possible. + +=item p or precision + +This sets the precision for all math operations. The argument can be any +integer. Negative values mean a fixed number of digits after the dot, while +a positive value rounds to this digit left from the dot. 0 or 1 mean round to +integer. See Math::BigInt's bfround() function for details. + + perl -Mbigrat=p,-50 -le 'print sqrt(20)' + +Note that setting precision and accuracy at the same time is not possible. + +=item t or trace + +This enables a trace mode and is primarily for debugging bignum or +Math::BigInt/Math::BigFloat. + +=item l or lib + +Load a different math lib, see L. + + perl -Mbigrat=l,GMP -e 'print 2 ** 512' + +Currently there is no way to specify more than one library on the command +line. This means the following does not work: + + perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512' + +This will be hopefully fixed soon ;) + +=item hex + +Override the built-in hex() method with a version that can handle big +numbers. This overrides it by exporting it to the current package. Under +Perl v5.10.0 and higher, this is not so necessary, as hex() is lexically +overridden in the current scope whenever the bigrat pragma is active. + +=item oct + +Override the built-in oct() method with a version that can handle big +numbers. This overrides it by exporting it to the current package. Under +Perl v5.10.0 and higher, this is not so necessary, as oct() is lexically +overridden in the current scope whenever the bigrat pragma is active. + +=item v or version + +This prints out the name and version of all modules used and then exits. + + perl -Mbigrat=v + +=back + +=head1 CAVEATS + +=over 2 + +=item Operator vs literal overloading + +C works by overloading handling of integer and floating point +literals, converting them to L or L +objects. + +This means that arithmetic involving only string values or string +literals will be performed using Perl's built-in operators. + +For example: + + use bigrat; + my $x = "900000000000000009"; + my $y = "900000000000000007"; + print $x - $y; + +will output C<0> on default 32-bit builds, since C never sees +the string literals. To ensure the expression is all treated as +C or C objects, use a literal number in +the expression: + + print +(0+$x) - $y; + +=item in_effect() + +This method only works on Perl v5.9.4 or later. + +=item hex()/oct() + +C overrides these routines with versions that can also handle +big integer values. Under Perl prior to version v5.9.4, however, this +will not happen unless you specifically ask for it with the two +import tags "hex" and "oct" - and then it will be global and cannot be +disabled inside a scope with "no bigint": + + use bigint qw/hex oct/; + + print hex("0x1234567890123456"); + { + no bigint; + print hex("0x1234567890123456"); + } + +The second call to hex() will warn about a non-portable constant. + +Compare this to: + + use bigint; + + # will warn only under Perl older than v5.9.4 + print hex("0x1234567890123456"); + +=back + +=head1 EXAMPLES + + perl -Mbigrat -le 'print sqrt(33)' + perl -Mbigrat -le 'print 2*255' + perl -Mbigrat -le 'print 4.5+2*255' + perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3' + perl -Mbigrat -le 'print 12->is_odd()'; + perl -Mbignum=l,GMP -le 'print 7 ** 7777' + +=head1 BUGS + +For information about bugs and how to report them, see the BUGS section in the +documentation available with the perldoc command. + + perldoc bignum + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc bigrat + +For more information, see the SUPPORT section in the documentation available +with the perldoc command. + + perldoc bignum + +=head1 LICENSE + +This program is free software; you may redistribute it and/or modify it under +the same terms as Perl itself. + +=head1 SEE ALSO + +L and L. + +L, L, L and L as well as +L, L and L. + +=head1 AUTHORS + +=over 4 + +=item * + +(C) by Tels L in early 2002 - 2007. + +=item * + +Peter John Acklam Epjacklam@gmail.com, 2014-. + +=back + +=cut diff --git a/t/00sig.t b/t/00sig.t new file mode 100644 index 0000000..125c979 --- /dev/null +++ b/t/00sig.t @@ -0,0 +1,36 @@ +#!/usr/bin/perl -w + +use strict; # restrict unsafe constructs + +use Test::More; + +if (!$ENV{TEST_SIGNATURE}) { + plan skip_all => + "Set the environment variable TEST_SIGNATURE to enable this test."; +} +elsif (!eval { require Module::Signature; 1 }) { + plan skip_all => + "Next time around, consider installing Module::Signature, ". + "so you can verify the integrity of this distribution."; +} +elsif (!-e 'SIGNATURE') { + plan skip_all => "SIGNATURE not found"; +} +elsif (!-s 'SIGNATURE') { + plan skip_all => "SIGNATURE file empty"; +} +elsif (!eval { require Socket; Socket::inet_aton('pool.sks-keyservers.net') }) { + plan skip_all => "Cannot connect to the keyserver to check module ". + "signature"; +} +else { + plan tests => 1; +} + +my $ret = Module::Signature::verify(); +SKIP: { + skip "Module::Signature cannot verify", 1 + if $ret eq Module::Signature::CANNOT_VERIFY(); + + cmp_ok $ret, '==', Module::Signature::SIGNATURE_OK(), "Valid signature"; +} diff --git a/t/01load.t b/t/01load.t new file mode 100644 index 0000000..acd289c --- /dev/null +++ b/t/01load.t @@ -0,0 +1,32 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 3; + +BEGIN { + use_ok('bignum'); + use_ok('bigint'); + use_ok('bigrat'); +}; + +my @mods = ('bignum', + 'bigint', + 'bigrat', + 'Math::BigInt', + 'Math::BigRat', + 'Math::BigInt::Lite', + ); + +diag(""); +diag("Testing with Perl $], $^X"); +diag(""); +diag(sprintf("%12s %s\n", 'Version', 'Module')); +diag(sprintf("%12s %s\n", '-------', '------')); +for my $mod (@mods) { + eval "require $mod"; + my $ver = $@ ? '-' : $mod -> VERSION(); + diag(sprintf("%12s %s\n", $ver, $mod)); +} +diag(""); diff --git a/t/02pod.t b/t/02pod.t new file mode 100644 index 0000000..f61daf0 --- /dev/null +++ b/t/02pod.t @@ -0,0 +1,14 @@ +#!perl + +use strict; +use warnings; + +use Test::More; + +# Ensure a recent version of Test::Pod + +my $min_tp = 1.22; +eval "use Test::Pod $min_tp"; +plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; + +all_pod_files_ok(); diff --git a/t/03podcov.t b/t/03podcov.t new file mode 100644 index 0000000..af098d4 --- /dev/null +++ b/t/03podcov.t @@ -0,0 +1,33 @@ +#!perl + +use strict; +use warnings; + +use Test::More; + +# Ensure a recent version of Test::Pod::Coverage + +my $min_tpc = 1.08; +eval "use Test::Pod::Coverage $min_tpc"; +plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage" + if $@; + +# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version, +# but older versions don't recognize some common documentation styles + +my $min_pc = 0.18; +eval "use Pod::Coverage $min_pc"; +plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage" + if $@; + +plan tests => 3; + +my $trustme; + +$trustme = { + trustme => [ 'unimport' ], + }; + +for my $mod (qw/bignum bigint bigrat/) { + pod_coverage_ok($mod, $trustme, "$mod is covered"); +} diff --git a/t/author-bigint-hex.t b/t/author-bigint-hex.t new file mode 100644 index 0000000..01b004f --- /dev/null +++ b/t/author-bigint-hex.t @@ -0,0 +1,50 @@ +#!perl + +BEGIN { + unless ($ENV{AUTHOR_TESTING}) { + require Test::More; + Test::More::plan(skip_all => + 'these tests are for testing by the author'); + } +} + +use strict; +use warnings; + +use Test::More tests => 507068; + +use Algorithm::Combinatorics qw< variations >; + +use bigint; + +use Test::More; + +my $elements = ['0', 'b', 'x', '1', '1', '_', '_', '9', 'z']; + +for my $k (0 .. @$elements) { + my $seen = {}; + for my $variation (variations($elements, $k)) { + my $str = join "", @$variation; + next if $seen -> {$str}++; + print qq|#\n# hex("$str")\n#\n|; + + my $i; + my @warnings; + local $SIG{__WARN__} = sub { + my $warning = shift; + $warning =~ s/ at .*\z//s; + $warnings[$i] = $warning; + }; + + $i = 0; + my $want_val = CORE::hex("$str"); + my $want_warn = $warnings[$i]; + + $i = 1; + my $got_val = bigint::hex("$str"); + my $got_warn = $warnings[$i]; + + is($got_val, $want_val, qq|hex("$str") (output)|); + is($got_warn, $want_warn, qq|hex("$str") (warning)|); + } +} diff --git a/t/author-bigint-oct.t b/t/author-bigint-oct.t new file mode 100644 index 0000000..bbed212 --- /dev/null +++ b/t/author-bigint-oct.t @@ -0,0 +1,50 @@ +#!perl + +BEGIN { + unless ($ENV{AUTHOR_TESTING}) { + require Test::More; + Test::More::plan(skip_all => + 'these tests are for testing by the author'); + } +} + +use strict; +use warnings; + +use Test::More tests => 507068; + +use Algorithm::Combinatorics qw< variations >; + +use bigint; + +use Test::More; + +my $elements = ['0', 'b', 'x', '1', '1', '_', '_', '9', 'z']; + +for my $k (0 .. @$elements) { + my $seen = {}; + for my $variation (variations($elements, $k)) { + my $str = join "", @$variation; + next if $seen -> {$str}++; + print qq|#\n# oct("$str")\n#\n|; + + my $i; + my @warnings; + local $SIG{__WARN__} = sub { + my $warning = shift; + $warning =~ s/ at .*\z//s; + $warnings[$i] = $warning; + }; + + $i = 0; + my $want_val = CORE::oct("$str"); + my $want_warn = $warnings[$i]; + + $i = 1; + my $got_val = bigint::oct("$str"); + my $got_warn = $warnings[$i]; + + is($got_val, $want_val, qq|hex("$str") (output)|); + is($got_warn, $want_warn, qq|hex("$str") (warning)|); + } +} diff --git a/t/big_e_pi.t b/t/big_e_pi.t new file mode 100644 index 0000000..06b4b08 --- /dev/null +++ b/t/big_e_pi.t @@ -0,0 +1,17 @@ +#!perl + +############################################################################### +# test for e() and PI() exports + +use strict; +use warnings; + +use Test::More tests => 4; + +use bignum qw/e PI bexp bpi/; + +is(e, "2.718281828459045235360287471352662497757", 'e'); +is(PI, "3.141592653589793238462643383279502884197", 'PI'); + +is(bexp(1, 10), "2.718281828", 'bexp(1, 10)'); +is(bpi(10), "3.141592654", 'bpi(10)'); diff --git a/t/bigexp.t b/t/bigexp.t new file mode 100644 index 0000000..61d39b2 --- /dev/null +++ b/t/bigexp.t @@ -0,0 +1,19 @@ +#!perl + +############################################################################### +# test for bug #18025: bignum/bigrat can lead to a number that is both 1 and 0 + +use strict; +use warnings; + +use Test::More tests => 4; + +use bignum; + +my $ln_ev = -7 / (10 ** 17); +my $ev = exp($ln_ev); +is(sprintf('%0.5f', $ev), '1.00000', '($ev) is approx. 1'); +is(sprintf('%0.5f', 1 - $ev), '0.00000', '(1-$ev) is approx. 0'); +is(sprintf('%0.5f', 1 - "$ev"), '0.00000', '(1-"$ev") is approx. 0'); + +cmp_ok($ev, '!=', 0, '$ev should not equal 0'); diff --git a/t/bigint.t b/t/bigint.t new file mode 100644 index 0000000..4af592f --- /dev/null +++ b/t/bigint.t @@ -0,0 +1,108 @@ +#!perl + +############################################################################### + +use strict; +use warnings; + +use Test::More tests => 51; + +use bigint qw/hex oct/; + +############################################################################### +# _constant tests + +foreach (qw/ + 123:123 + 123.4:123 + 1.4:1 + 0.1:0 + -0.1:0 + -1.1:-1 + -123.4:-123 + -123:-123 + 123e2:123e2 + 123e-1:12 + 123e-4:0 + 123e-3:0 + 123.345e-1:12 + 123.456e+2:12345 + 1234.567e+3:1234567 + 1234.567e+4:1234567E1 + 1234.567e+6:1234567E3 + /) +{ + my ($x, $y) = split /:/; + is(bigint::_float_constant("$x"), "$y", + qq|bigint::_float_constant("$x") = $y|); +} + +foreach (qw/ + 0100:64 + 0200:128 + 0x100:256 + 0b1001:9 + /) +{ + my ($x, $y) = split /:/; + is(bigint::_binary_constant("$x"), "$y", + qq|bigint::_binary_constant("$x") = "$y")|); +} + +############################################################################### +# general tests + +my $x = 5; +like(ref($x), qr/^Math::BigInt/, '$x = 5 makes $x a Math::BigInt'); # :constant + +# todo: is(2 + 2.5, 4.5); # should still work +# todo: $x = 2 + 3.5; is(ref($x), 'Math::BigFloat'); + +$x = 2 ** 255; +like(ref($x), qr/^Math::BigInt/, '$x = 2 ** 255 makes $x a Math::BigInt'); + +is(12->bfac(), 479001600, '12->bfac() = 479001600'); +is(9/4, 2, '9/4 = 2'); + +is(4.5 + 4.5, 8, '4.5 + 4.5 = 2'); # truncate +like(ref(4.5 + 4.5), qr/^Math::BigInt/, '4.5 + 4.5 makes a Math::BigInt'); + +############################################################################### +# accuracy and precision + +is(bigint->accuracy(), undef, 'get accuracy'); +is(bigint->accuracy(12), 12, 'set accuracy to 12'); +is(bigint->accuracy(), 12, 'get accuracy again'); + +is(bigint->precision(), undef, 'get precision'); +is(bigint->precision(12), 12, 'set precision to 12'); +is(bigint->precision(), 12, 'get precision again'); + +is(bigint->round_mode(), 'even', 'get round mode'); +is(bigint->round_mode('odd'), 'odd', 'set round mode'); +is(bigint->round_mode(), 'odd', 'get round mode again'); + +############################################################################### +# hex() and oct() + +my $class = 'Math::BigInt'; + +is(ref(hex(1)), $class, qq|ref(hex(1)) = $class|); +is(ref(hex(0x1)), $class, qq|ref(hex(0x1)) = $class|); +is(ref(hex("af")), $class, qq|ref(hex("af")) = $class|); +is(ref(hex("0x1")), $class, qq|ref(hex("0x1")) = $class|); + +is(hex("af"), Math::BigInt->new(0xaf), + qq|hex("af") = Math::BigInt->new(0xaf)|); + +is(ref(oct("0x1")), $class, qq|ref(oct("0x1")) = $class|); +is(ref(oct("01")), $class, qq|ref(oct("01")) = $class|); +is(ref(oct("0b01")), $class, qq|ref(oct("0b01")) = $class|); +is(ref(oct("1")), $class, qq|ref(oct("1")) = $class|); +is(ref(oct(" 1")), $class, qq|ref(oct(" 1")) = $class|); +is(ref(oct(" 0x1")), $class, qq|ref(oct(" 0x1")) = $class|); + +is(ref(oct(0x1)), $class, qq|ref(oct(0x1)) = $class|); +is(ref(oct(01)), $class, qq|ref(oct(01)) = $class|); +is(ref(oct(0b01)), $class, qq|ref(oct(0b01)) = $class|); +is(ref(oct(1)), $class, qq|ref(oct(1)) = $class|); diff --git a/t/bignum.t b/t/bignum.t new file mode 100644 index 0000000..6bdd5bb --- /dev/null +++ b/t/bignum.t @@ -0,0 +1,83 @@ +#!/usr/bin/perl -w + +############################################################################### + +use strict; +use Test::More tests => 35; + +use bignum qw/oct hex/; + +############################################################################### +# general tests + +my $x = 5; +like(ref($x), qr/^Math::BigInt/, '$x = 5 makes $x a Math::BigInt'); # :constant + +is(2 + 2.5, 4.5, '2 + 2.5 = 4.5'); +$x = 2 + 3.5; +is(ref($x), 'Math::BigFloat', '$x = 2 + 3.5 makes $x a Math::BigFloat'); + +is(2 * 2.1, 4.2, '2 * 2.1 = 4.2'); +$x = 2 + 2.1; +is(ref($x), 'Math::BigFloat', '$x = 2 + 2.1 makes $x a Math::BigFloat'); + +$x = 2 ** 255; +like(ref($x), qr/^Math::BigInt/, '$x = 2 ** 255 makes $x a Math::BigInt'); + +# see if Math::BigInt constant and upgrading works +is(Math::BigInt::bsqrt("12"), '3.464101615137754587054892683011744733886', + 'Math::BigInt::bsqrt("12")'); +is(sqrt(12), '3.464101615137754587054892683011744733886', + 'sqrt(12)'); + +is(2/3, "0.6666666666666666666666666666666666666667", '2/3'); + +#is(2 ** 0.5, 'NaN'); # should be sqrt(2); + +is(12->bfac(), 479001600, '12->bfac() = 479001600'); + +# see if Math::BigFloat constant works + +# 0123456789 0123456789 <- default 40 +# 0123456789 0123456789 +is(1/3, '0.3333333333333333333333333333333333333333', '1/3'); + +############################################################################### +# accuracy and precision + +is(bignum->accuracy(), undef, 'get accuracy'); +is(bignum->accuracy(12), 12, 'set accuracy to 12'); +is(bignum->accuracy(), 12, 'get accuracy again'); + +is(bignum->precision(), undef, 'get precision'); +is(bignum->precision(12), 12, 'set precision to 12'); +is(bignum->precision(), 12, 'get precision again'); + +is(bignum->round_mode(), 'even', 'get round mode'); +is(bignum->round_mode('odd'), 'odd', 'set round mode'); +is(bignum->round_mode(), 'odd', 'get round mode again'); + +############################################################################### +# hex() and oct() + +my $class = 'Math::BigInt'; + +is(ref(hex(1)), $class, qq|ref(hex(1)) = $class|); +is(ref(hex(0x1)), $class, qq|ref(hex(0x1)) = $class|); +is(ref(hex("af")), $class, qq|ref(hex("af")) = $class|); +is(ref(hex("0x1")), $class, qq|ref(hex("0x1")) = $class|); + +is(hex("af"), Math::BigInt->new(0xaf), + qq|hex("af") = Math::BigInt->new(0xaf)|); + +is(ref(oct("0x1")), $class, qq|ref(oct("0x1")) = $class|); +is(ref(oct("01")), $class, qq|ref(oct("01")) = $class|); +is(ref(oct("0b01")), $class, qq|ref(oct("0b01")) = $class|); +is(ref(oct("1")), $class, qq|ref(oct("1")) = $class|); +is(ref(oct(" 1")), $class, qq|ref(oct(" 1")) = $class|); +is(ref(oct(" 0x1")), $class, qq|ref(oct(" 0x1")) = $class|); + +is(ref(oct(0x1)), $class, qq|ref(oct(0x1)) = $class|); +is(ref(oct(01)), $class, qq|ref(oct(01)) = $class|); +is(ref(oct(0b01)), $class, qq|ref(oct(0b01)) = $class|); +is(ref(oct(1)), $class, qq|ref(oct(1)) = $class|); diff --git a/t/bigrat.t b/t/bigrat.t new file mode 100644 index 0000000..ac6fc0c --- /dev/null +++ b/t/bigrat.t @@ -0,0 +1,84 @@ +#!perl + +############################################################################### + +use strict; +use warnings; + +use Test::More tests => 40; + +use bigrat qw/oct hex/; + +############################################################################### +# general tests + +my $x = 5; +like(ref($x), qr/^Math::BigInt/, '$x = 5 makes $x a Math::BigInt'); # :constant + +# todo: is(2 + 2.5, 4.5); # should still work +# todo: $x = 2 + 3.5; is(ref($x), 'Math::BigFloat'); + +$x = 2 ** 255; +like(ref($x), qr/^Math::BigInt/, '$x = 2 ** 255 makes $x a Math::BigInt'); + +# see if Math::BigRat constant works +is(1/3, '1/3', qq|1/3 = '1/3'|); +is(1/4+1/3, '7/12', qq|1/4+1/3 = '7/12'|); +is(5/7+3/7, '8/7', qq|5/7+3/7 = '8/7'|); + +is(3/7+1, '10/7', qq|3/7+1 = '10/7'|); +is(3/7+1.1, '107/70', qq|3/7+1.1 = '107/70'|); +is(3/7+3/7, '6/7', qq|3/7+3/7 = '6/7'|); + +is(3/7-1, '-4/7', qq|3/7-1 = '-4/7'|); +is(3/7-1.1, '-47/70', qq|3/7-1.1 = '-47/70'|); +is(3/7-2/7, '1/7', qq|3/7-2/7 = '1/7'|); + +# fails ? +# is(1+3/7, '10/7', qq|1+3/7 = '10/7'|); + +is(1.1+3/7, '107/70', qq|1.1+3/7 = '107/70'|); +is(3/7*5/7, '15/49', qq|3/7*5/7 = '15/49'|); +is(3/7 / (5/7), '3/5', qq|3/7 / (5/7) = '3/5'|); +is(3/7 / 1, '3/7', qq|3/7 / 1 = '3/7'|); +is(3/7 / 1.5, '2/7', qq|3/7 / 1.5 = '2/7'|); + +############################################################################### +# accuracy and precision + +is(bigrat->accuracy(), undef, 'get accuracy'); +is(bigrat->accuracy(12), 12, 'set accuracy to 12'); +is(bigrat->accuracy(), 12, 'get accuracy again'); + +is(bigrat->precision(), undef, 'get precision'); +is(bigrat->precision(12), 12, 'set precision to 12'); +is(bigrat->precision(), 12, 'get precision again'); + +is(bigrat->round_mode(), 'even', 'get round mode'); +is(bigrat->round_mode('odd'), 'odd', 'set round mode'); +is(bigrat->round_mode(), 'odd', 'get round mode again'); + +############################################################################### +# hex() and oct() + +my $class = 'Math::BigInt'; + +is(ref(hex(1)), $class, qq|ref(hex(1)) = $class|); +is(ref(hex(0x1)), $class, qq|ref(hex(0x1)) = $class|); +is(ref(hex("af")), $class, qq|ref(hex("af")) = $class|); +is(ref(hex("0x1")), $class, qq|ref(hex("0x1")) = $class|); + +is(hex("af"), Math::BigInt->new(0xaf), + qq|hex("af") = Math::BigInt->new(0xaf)|); + +is(ref(oct("0x1")), $class, qq|ref(oct("0x1")) = $class|); +is(ref(oct("01")), $class, qq|ref(oct("01")) = $class|); +is(ref(oct("0b01")), $class, qq|ref(oct("0b01")) = $class|); +is(ref(oct("1")), $class, qq|ref(oct("1")) = $class|); +is(ref(oct(" 1")), $class, qq|ref(oct(" 1")) = $class|); +is(ref(oct(" 0x1")), $class, qq|ref(oct(" 0x1")) = $class|); + +is(ref(oct(0x1)), $class, qq|ref(oct(0x1)) = $class|); +is(ref(oct(01)), $class, qq|ref(oct(01)) = $class|); +is(ref(oct(0b01)), $class, qq|ref(oct(0b01)) = $class|); +is(ref(oct(1)), $class, qq|ref(oct(1)) = $class|); diff --git a/t/bii_e_pi.t b/t/bii_e_pi.t new file mode 100644 index 0000000..d9e20b5 --- /dev/null +++ b/t/bii_e_pi.t @@ -0,0 +1,18 @@ +#!perl + +############################################################################### +# test for e() and PI() exports + +use strict; +use warnings; + +use Test::More tests => 5; + +use bigint qw/e PI bpi bexp/; + +is(e, "2", 'e'); +is(PI, "3", 'PI'); + +is(bexp(1, 10), "2", 'e'); +is(bexp(3, 10), "20", 'e'); +is(bpi(10), "3", 'PI'); diff --git a/t/biinfnan.t b/t/biinfnan.t new file mode 100644 index 0000000..c334917 --- /dev/null +++ b/t/biinfnan.t @@ -0,0 +1,22 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 66; + +use bigint; + +#require "t/infnan.inc"; + +# The 'bigint'/'bignum'/'bigrat' pragma is lexical, so we can't 'require' or +# 'do' the included file. Slurp the whole thing and 'eval' it. + +my $file = "t/infnan.inc"; + +open FILE, $file or die "$file: can't open file for reading: $!"; +my $data = do { local $/; }; +close FILE or die "$file: can't close file after reading: $!"; + +eval $data; +die $@ if $@; diff --git a/t/bir_e_pi.t b/t/bir_e_pi.t new file mode 100644 index 0000000..8305580 --- /dev/null +++ b/t/bir_e_pi.t @@ -0,0 +1,20 @@ +#!perl + +############################################################################### +# test for e() and PI() exports + +use strict; +use warnings; + +use Test::More tests => 4; + +use bigrat qw/e PI bexp bpi/; + +is(e, "2.718281828459045235360287471352662497757", 'e'); +is(PI, "3.141592653589793238462643383279502884197", 'PI'); + +# These tests should actually produce big rationals, but this is not yet +# implemented. + +is(bexp(1, 10), "2.718281828", 'bexp(1, 10)'); +is(bpi(10), "3.141592654", 'bpi(10)'); diff --git a/t/bn_lite.t b/t/bn_lite.t new file mode 100644 index 0000000..d26fe5c --- /dev/null +++ b/t/bn_lite.t @@ -0,0 +1,20 @@ +#!perl + +############################################################################### + +use strict; +use warnings; + +use Test::More; + +if (eval { require Math::BigInt::Lite; 1 }) { + plan tests => 1; + # can use Lite, so let bignum try it + require bignum; + bignum->import(); + # can't get to work a ref(1+1) here, presumable because :constant phase + # already done + is($bignum::_lite, 1, '$bignum::_lite is 1'); +} else { + plan skip_all => "no Math::BigInt::Lite"; +} diff --git a/t/bninfnan.t b/t/bninfnan.t new file mode 100644 index 0000000..e437ca1 --- /dev/null +++ b/t/bninfnan.t @@ -0,0 +1,22 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 66; + +use bignum; + +#require "t/infnan.inc"; + +# The 'bigint'/'bignum'/'bigrat' pragma is lexical, so we can't 'require' or +# 'do' the included file. Slurp the whole thing and 'eval' it. + +my $file = "t/infnan.inc"; + +open FILE, $file or die "$file: can't open file for reading: $!"; +my $data = do { local $/; }; +close FILE or die "$file: can't close file after reading: $!"; + +eval $data; +die $@ if $@; diff --git a/t/br_lite.t b/t/br_lite.t new file mode 100644 index 0000000..79ac2c6 --- /dev/null +++ b/t/br_lite.t @@ -0,0 +1,20 @@ +#!perl + +############################################################################### + +use strict; +use warnings; + +use Test::More; + +if (eval { require Math::BigInt::Lite; 1 }) { + plan tests => 1; + # can use Lite, so let bignum try it + require bigrat; + bigrat->import(); + # can't get to work a ref(1+1) here, presumable because :constant phase + # already done + is($bigrat::_lite, 1, '$bigrat::_lite is 1'); +} else { + plan skip_all => "no Math::BigInt::Lite"; +} diff --git a/t/brinfnan.t b/t/brinfnan.t new file mode 100644 index 0000000..1be8164 --- /dev/null +++ b/t/brinfnan.t @@ -0,0 +1,22 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 66; + +use bigrat; + +#require "t/infnan.inc"; + +# The 'bigint'/'bignum'/'bigrat' pragma is lexical, so we can't 'require' or +# 'do' the included file. Slurp the whole thing and 'eval' it. + +my $file = "t/infnan.inc"; + +open FILE, $file or die "$file: can't open file for reading: $!"; +my $data = do { local $/; }; +close FILE or die "$file: can't close file after reading: $!"; + +eval $data; +die $@ if $@; diff --git a/t/in_effect.t b/t/in_effect.t new file mode 100644 index 0000000..b4507ea --- /dev/null +++ b/t/in_effect.t @@ -0,0 +1,35 @@ +#!perl + +############################################################################### +# Test in_effect() + +use strict; +use warnings; + +use Test::More tests => 9; + +use bigint; +use bignum; +use bigrat; + +can_ok('bigint', qw/in_effect/); +can_ok('bignum', qw/in_effect/); +can_ok('bigrat', qw/in_effect/); + +SKIP: { + skip('Need at least Perl v5.9.4', 3) if $] < "5.009005"; + + is(bigint::in_effect(), 1, 'bigint in effect'); + is(bignum::in_effect(), 1, 'bignum in effect'); + is(bigrat::in_effect(), 1, 'bigrat in effect'); +} + +{ + no bigint; + no bignum; + no bigrat; + + is(bigint::in_effect(), undef, 'bigint not in effect'); + is(bignum::in_effect(), undef, 'bignum not in effect'); + is(bigrat::in_effect(), undef, 'bigrat not in effect'); +} diff --git a/t/infnan.inc b/t/infnan.inc new file mode 100644 index 0000000..5ecc7b5 --- /dev/null +++ b/t/infnan.inc @@ -0,0 +1,91 @@ +#!perl + +use strict; +use warnings; + +my $x; + +############################################################################### +# inf tests + +$x = 1 + inf; +like(ref($x), qr/^Math::BigInt/, '$x = 1 + inf makes a Math::BigInt'); +is($x->bstr(), 'inf', qq|$x = 1 + inf; $x->bstr() = 'inf'|); + +$x = 1 * inf; +like(ref($x), qr/^Math::BigInt/, '$x = 1 * inf makes a Math::BigInt'); +is($x->bstr(), 'inf', qq|$x = 1 * inf; $x->bstr() = 'inf'|); + +# these don't work without exporting inf() +$x = inf; +like(ref($x), qr/^Math::BigInt/, '$x = inf makes a Math::BigInt'); +is($x->bstr(), 'inf', qq|$x = inf; $x->bstr() = 'inf'|); + +$x = inf + inf; +like(ref($x), qr/^Math::BigInt/, '$x = inf + inf makes a Math::BigInt'); +is($x->bstr(), 'inf', qq|$x = inf + inf; $x->bstr() = 'inf'|); + +$x = inf * inf; +like(ref($x), qr/^Math::BigInt/, '$x = inf * inf makes a Math::BigInt'); +is($x->bstr(), 'inf', qq|$x = inf * inf; $x->bstr() = 'inf'|); + +############################################################################### +# NaN tests + +$x = 1 + NaN; +like(ref($x), qr/^Math::BigInt/, '$x = 1 + NaN makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = 1 + NaN; $x->bstr() = 'NaN'|); + +$x = 1 * NaN; +like(ref($x), qr/^Math::BigInt/, '$x = 1 * NaN makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = 1 * NaN; $x->bstr() = 'NaN'|); + +# these don't work without exporting NaN() +$x = NaN; +like(ref($x), qr/^Math::BigInt/, '$x = NaN makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = NaN; $x->bstr() = 'NaN'|); + +$x = NaN + NaN; +like(ref($x), qr/^Math::BigInt/, '$x = NaN + NaN makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = NaN + NaN; $x->bstr() = 'NaN'|); + +$x = NaN * NaN; +like(ref($x), qr/^Math::BigInt/, '$x = NaN * NaN makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = NaN * NaN; $x->bstr() = 'NaN'|); + +############################################################################### +# mixed tests + +# these don't work without exporting NaN() or inf() + +$x = NaN + inf; +like(ref($x), qr/^Math::BigInt/, '$x = NaN + inf makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = NaN + inf; $x->bstr() = 'NaN'|); + +$x = NaN * inf; +like(ref($x), qr/^Math::BigInt/, '$x = NaN * inf makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = NaN * inf; $x->bstr() = 'NaN'|); + +$x = inf * NaN; +like(ref($x), qr/^Math::BigInt/, '$x = inf * NaN makes a Math::BigInt'); +is($x->bstr(), 'NaN', qq|$x = inf * NaN; $x->bstr() = 'NaN'|); + +############################################################################### +# inf and NaN as strings. + +for my $nan (qw/ nan naN nAn nAN Nan NaN NAn NAN /) { + my $x = 1 + $nan; + is($x->bstr(), "NaN", qq|\$x = 1 + "$nan"; \$x->bstr() = "NaN"|); + isa_ok($x, "Math::BigInt"); +} + +for my $inf (qw/ inf inF iNf iNF Inf InF INf INF + infinity Infinity InFiNiTy iNfInItY + /) +{ + my $x = 1 + $inf; + is($x->bstr(), "inf", qq|\$x = 1 + "$inf"; \$x->bstr() = "inf"|); + isa_ok($x, "Math::BigInt"); +} + +1; diff --git a/t/option_a.t b/t/option_a.t new file mode 100644 index 0000000..2a9d171 --- /dev/null +++ b/t/option_a.t @@ -0,0 +1,22 @@ +#!perl + +############################################################################### + +use strict; +use warnings; + +use Test::More tests => 4; + +use bignum a => '12'; + +my @CLASSES = qw/Math::BigInt Math::BigFloat/; + +foreach my $class (@CLASSES) { + is($class->accuracy(),12, "$class accuracy = 12"); +} + +bignum->import(accuracy => '23'); + +foreach my $class (@CLASSES) { + is($class->accuracy(), 23, "$class accuracy = 23"); +} diff --git a/t/option_l.t b/t/option_l.t new file mode 100644 index 0000000..4744ded --- /dev/null +++ b/t/option_l.t @@ -0,0 +1,53 @@ +#!perl + +# test the "l", "lib", "try" and "only" options: + +use strict; +use warnings; + +use Test::More tests => 19; + +use bignum; + +my @WARNINGS; +{ + # catch warnings: + require Carp; + no warnings 'redefine'; + *Carp::carp = sub { push @WARNINGS, $_[0]; }; +} + +my $rc; + +$rc = eval { bignum->import( "l" => "foo" ) }; +is($@, '', # shouldn't die + qq|eval { bignum->import( "l" => "foo" ) }|); +is(scalar(@WARNINGS), 1, 'one warning'); +like($WARNINGS[0], qr/fallback to Math::/, 'got fallback'); + +$rc = eval { bignum->import( "lib" => "foo" ) }; +is($@, '', # ditto + qq|eval { bignum->import( "lib" => "foo" ) }|); +is(scalar @WARNINGS, 2, 'two warnings'); +like($WARNINGS[1], qr/fallback to Math::/, 'got fallback'); + +$rc = eval { bignum->import( "try" => "foo" ) }; +is($@, '', # shouldn't die + qq|eval { bignum->import( "try" => "foo" ) }|); + +$rc = eval { bignum->import( "try" => "foo" ) }; +is($@, '', # ditto + qq|eval { bignum->import( "try" => "foo" ) }|); + +$rc = eval { bignum->import( "foo" => "bar" ) }; +like($@, qr/^Unknown option foo/i, 'died'); # should die + +$rc = eval { bignum->import( "only" => "bar" ) }; +like($@, qr/fallback disallowed/i, 'died'); # should die + +# test that options are only lowercase (don't see a reason why allow UPPER) + +foreach (qw/L LIB Lib T Trace TRACE V Version VERSION/) { + $rc = eval { bignum->import( $_ => "bar" ) }; + like($@, qr/^Unknown option $_/i, 'died'); # should die +} diff --git a/t/option_p.t b/t/option_p.t new file mode 100644 index 0000000..6f57c92 --- /dev/null +++ b/t/option_p.t @@ -0,0 +1,20 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 4; + +my @CLASSES = qw/Math::BigInt Math::BigFloat/; + +use bignum p => '12'; + +foreach my $class (@CLASSES) { + is($class->precision(), 12, "$class precision = 12"); +} + +bignum->import(p => '42'); + +foreach my $class (@CLASSES) { + is($class->precision(), 42, "$class precision = 42"); +} diff --git a/t/overrides.t b/t/overrides.t new file mode 100644 index 0000000..371d91d --- /dev/null +++ b/t/overrides.t @@ -0,0 +1,114 @@ +#!perl + +use strict; +use warnings; + +# Test behaviour of hex and oct overrides in detail, and also how the three +# modules interact. + +use Test::More tests => 35; + +my $hex_called; +my $oct_called; + +# For testing that existing CORE::GLOBAL overrides are not clobbered +BEGIN { + if ($] > 5.009004) { + no warnings 'syntax'; + *CORE::GLOBAL::hex = sub(_) { ++$hex_called; CORE::hex(@_?$_[0]:$_) }; + *CORE::GLOBAL::oct = sub(_) { ++$oct_called; CORE::oct(@_?$_[0]:$_) }; + } else { + *CORE::GLOBAL::hex = sub(;$) { ++$hex_called; CORE::hex(@_?$_[0]:$_) }; + *CORE::GLOBAL::oct = sub(;$) { ++$oct_called; CORE::oct(@_?$_[0]:$_) }; + } +} + +{ + use bigint; + $_ = "20"; + is hex, "32", 'bigint hex override without arguments infers $_'; + is oct, "16", 'bigint oct override without arguments infers $_'; + @_ = 1..20; + is hex(@_), "32", 'bigint hex override provides scalar context'; + is oct(@_), "16", 'bigint oct override provides scalar context'; + SKIP: + { + skip "no lexical hex/oct", 2 unless $] > do { no bigint; 5.009004 }; + is ref hex(1), 'Math::BigInt', + 'bigint hex() works when bignum and bigrat are loaded'; + is ref oct(1), 'Math::BigInt', + 'bigint oct() works when bignum and bigrat are loaded'; + } +} +{ + use bignum; + $_ = "20"; + is hex, "32", 'bignum hex override without arguments infers $_'; + is oct, "16", 'bignum oct override without arguments infers $_'; + @_ = 1..20; + is hex(@_), "32", 'bignum hex override provides scalar context'; + is oct(@_), "16", 'bignum oct override provides scalar context'; + SKIP: + { + skip "no lexical hex/oct", 2 unless $] > 5.009004; + is ref hex(1), 'Math::BigInt', + 'bignum hex() works when bigint and bigrat are loaded'; + is ref oct(1), 'Math::BigInt', + 'bignum oct() works when bigint and bigrat are loaded'; + } +} +{ + use bigrat; + $_ = "20"; + is hex, "32", 'bigrat hex override without arguments infers $_'; + is oct, "16", 'bigrat oct override without arguments infers $_'; + @_ = 1..20; + is hex(@_), "32", 'bigrat hex override provides scalar context'; + is oct(@_), "16", 'bigrat oct override provides scalar context'; + SKIP: + { + skip "no lexical hex/oct", 2 unless $] > 5.009004; + is ref hex(1), 'Math::BigInt', + 'bigrat hex() works when bignum and bigint are loaded'; + is ref oct(1), 'Math::BigInt', + 'bigrat oct() works when bignum and bigint are loaded'; + } +} + +$hex_called = 0; +() = hex 0; +is $hex_called, 1, 'existing hex overrides are called'; +$oct_called = 0; +() = oct 0; +is $oct_called, 1, 'existing oct overrides are called'; + +{ + package _importer; + { + use bigint 'hex', 'oct'; + ::is \&hex, \&bigint::hex, 'exported hex function'; + ::is \&oct, \&bigint::oct, 'exported oct function'; + } + ::ok ref hex(), 'exported hex function returns ref outside pragma scope'; + ::ok ref oct(), 'exported oct function returns ref outside pragma scope'; + ::is oct("20"), "16", 'exported oct function works with "decimal"'; + # (used to return 20 because it thought it was decimal) +} +{ + package _importer2; + use bignum 'hex', 'oct'; + ::is \&hex, \&bignum::hex, 'bignum exports hex'; + ::is \&oct, \&bignum::oct, 'bignum exports oct'; + ::is \&hex, \&bigint::hex, 'bignum exports same hex as bigint'; + ::is \&oct, \&bigint::oct, 'bignum exports same oct as bigint'; +} +{ + package _importer3; + use bigrat 'hex', 'oct'; + ::is \&hex, \&bigrat::hex, 'bigrat exports hex'; + ::is \&oct, \&bigrat::oct, 'bigrat exports oct'; + ::is \&hex, \&bigint::hex, 'bigrat exports same hex as bigint'; + ::is \&oct, \&bigint::oct, 'bigrat exports same oct as bigint'; +} +is ref(hex 0), "", 'hex export is not global'; +is ref(oct 0), "", 'oct export is not global'; diff --git a/t/ratopt_a.t b/t/ratopt_a.t new file mode 100644 index 0000000..e5ee13b --- /dev/null +++ b/t/ratopt_a.t @@ -0,0 +1,25 @@ +#!perl + +############################################################################### + +use strict; +use warnings; + +use Test::More tests => 7; + +my @CLASSES = qw/Math::BigInt Math::BigFloat Math::BigRat/; + +# bigrat (bug until v0.15) +use bigrat a => 2; + +foreach my $class (@CLASSES) { + is($class->accuracy(), 2, "$class accuracy = 2"); +} + +eval { bigrat->import(accuracy => '42') }; + +is($@, '', 'no error'); + +foreach my $class (@CLASSES) { + is($class->accuracy(), 42, "$class accuracy = 42"); +} diff --git a/t/scope_f.t b/t/scope_f.t new file mode 100644 index 0000000..e932ea2 --- /dev/null +++ b/t/scope_f.t @@ -0,0 +1,34 @@ +#!perl + +############################################################################### +# Test "no bignum;" and overloading of hex()/oct() for newer Perls + +use strict; +use warnings; + +use Test::More tests => 10; + +# no :hex and :oct means these do not get overloaded for older Perls: +use bignum; + +isnt (ref(1), '', 'is in effect'); +isnt (ref(2.0), '', 'is in effect'); +isnt (ref(0x20), '', 'is in effect'); + +SKIP: { + skip ('Need at least Perl v5.9.4', 2) if $] < 5.009004; + + is (ref(hex(9)), 'Math::BigInt', 'hex is overloaded'); + is (ref(oct(07)), 'Math::BigInt', 'oct is overloaded'); + } + +{ + no bignum; + + is (ref(1), '', 'is not in effect'); + is (ref(2.0), '', 'is not in effect'); + is (ref(0x20), '', 'is not in effect'); + + isnt (ref(hex(9)), 'Math::BigInt', 'hex is not overloaded'); + isnt (ref(oct(07)), 'Math::BigInt', 'oct is not overloaded'); +} diff --git a/t/scope_i.t b/t/scope_i.t new file mode 100644 index 0000000..e76ceee --- /dev/null +++ b/t/scope_i.t @@ -0,0 +1,35 @@ +#!perl + +############################################################################### +# Test "no bigint;" and overloading of hex()/oct() for newer Perls + +use strict; +use warnings; + +use Test::More tests => 10; + +# no :hex and :oct means these do not get overloaded for older Perls: +use bigint; + +isnt(ref(1), '', 'is in effect'); +isnt(ref(2.0), '', 'is in effect'); +isnt(ref(0x20), '', 'is in effect'); + +SKIP: { + # Quote version number due to "use bigint;" + skip('Need at least Perl v5.9.4', 2) if $] < "5.009004"; + + is(ref(hex(9)), 'Math::BigInt', 'hex is overloaded'); + is(ref(oct(07)), 'Math::BigInt', 'oct is overloaded'); +} + +{ + no bigint; + + is(ref(1), '', 'is not in effect'); + is(ref(2.0), '', 'is not in effect'); + is(ref(0x20), '', 'is not in effect'); + + isnt(ref(hex(9)), 'Math::BigInt', 'hex is not overloaded'); + isnt(ref(oct(07)), 'Math::BigInt', 'oct is not overloaded'); +} diff --git a/t/scope_r.t b/t/scope_r.t new file mode 100644 index 0000000..8ad2626 --- /dev/null +++ b/t/scope_r.t @@ -0,0 +1,34 @@ +#!perl + +############################################################################### +# Test "no bigrat;" and overloading of hex()/oct() for newer Perls + +use strict; +use warnings; + +use Test::More tests => 10; + +# no :hex and :oct means these do not get overloaded for older Perls: +use bigrat; + +isnt(ref(1), '', 'is in effect'); +isnt(ref(2.0), '', 'is in effect'); +isnt(ref(0x20), '', 'is in effect'); + +SKIP: { + skip('Need at least Perl v5.9.4', 2) if $] < 5.009004; + + is(ref(hex(9)), 'Math::BigInt', 'hex is overloaded'); + is(ref(oct(07)), 'Math::BigInt', 'oct is overloaded'); +} + +{ + no bigrat; + + is(ref(1), '', 'is not in effect'); + is(ref(2.0), '', 'is not in effect'); + is(ref(0x20), '', 'is not in effect'); + + isnt(ref(hex(9)), 'Math::BigInt', 'hex is not overloaded'); + isnt(ref(oct(07)), 'Math::BigInt', 'oct is not overloaded'); +}