Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Commit

Permalink
exact_arith: implement it
Browse files Browse the repository at this point in the history
Promote on overflow to bigint/num, and not to NV.
This is a new lexical user-pragma to use exact
arithmetic without loosing precision on all builtin arithmetic ops.
As in perl6.

It is of course a bit slower than without.

Closes #21.
  • Loading branch information
Reini Urban authored and rurban committed Jun 27, 2019
1 parent 178a393 commit f32233a
Show file tree
Hide file tree
Showing 17 changed files with 306 additions and 50 deletions.
28 changes: 28 additions & 0 deletions Configure
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,7 @@ CONFIG=''
usecperl=''
fake_signatures=''
usenamedanoncv=''
useexactarith=''

: Detect odd OSs
define='define'
Expand Down Expand Up @@ -7584,6 +7585,32 @@ $define)
;;
esac

case "$useexactarith" in
$define|true|[yY]*) dflt='y' ;;
*) dflt='n' ;;
esac
cat <<EOM

Would you like to build Perl so that every builtin arithmetic overflow
does not promote to internal fast double/long double numbers but
instead to slow and precise bigint? So that exact_arith is enabled by default.

If this doesn't make any sense to you, just accept the default '$dflt'.
EOM
rp='Use exact arith, overflow to bigint as in perl6?'
. ./myread
case "$ans" in
y|Y) val="$define" ;;
*) val="$undef" ;;
esac
set useexactarith
eval $setvar
case "$useexactarith" in
$define)
echo "exact_arith selected." >&4
;;
esac

case "$usecperl" in
$define) usecperl='define'
echo "cperl variant selected." >&4
Expand Down Expand Up @@ -25913,6 +25940,7 @@ usecrosscompile='$usecrosscompile'
usedevel='$usedevel'
usedl='$usedl'
usedtrace='$usedtrace'
useexactarith='$useexactarith'
usefaststdio='$usefaststdio'
useffi='$useffi'
useithreads='$useithreads'
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -5686,6 +5686,8 @@ lib/dumpvar.pl A variable dumper
lib/dumpvar.t A variable dumper tester
lib/English.pm Readable aliases for short variables
lib/English.t See if English works
lib/exact_arith.pm Pragma to set exact arithmetic as in perl6
lib/exact_arith.t See if use exact_arith works
lib/ExtUtils/Embed.pm Utilities for embedding Perl in C programs
lib/ExtUtils/t/Embed.t See if ExtUtils::Embed and embedding works
lib/ExtUtils/typemap Extension interface types
Expand Down
1 change: 1 addition & 0 deletions Porting/Maintainers.pl
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,7 @@ package Maintainers;
lib/DBM_Filter/
lib/DirHandle.{pm,t}
lib/English.{pm,t}
lib/exact_arith.{pm,t}
lib/ExtUtils/Embed.pm
lib/ExtUtils/XSSymSet.pm
lib/ExtUtils/t/Embed.t
Expand Down
8 changes: 8 additions & 0 deletions config_h.SH
Original file line number Diff line number Diff line change
Expand Up @@ -5488,6 +5488,14 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
#$usesafehashiter USE_SAFE_HASHITER /**/
#endif
/* USE_EXACT_ARITH:
* This symbol, if defined, indicates that Perl uses exact_arith as default.
*/
#define PERL_EXACT_ARITH
#ifndef USE_EXACT_ARITH
#$useexactarith USE_EXACT_ARITH /**/
#endif
/* PERL_HASH_FUNC_*:
* This symbol defines the used perl hash function variant.
* It is set in Configure or via -Dhash_func=, but can be left blank.
Expand Down
1 change: 1 addition & 0 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ pR |int |PerlSock_accept_cloexec|int listenfd \
pR |int |PerlSock_socketpair_cloexec|int domain|int type|int protocol \
|NN int *pairfd
#endif
AMp |void |bigint_arith |NN const char *op|NN SV *const left|NN SV *const right
#if defined(PERL_IN_DOIO_C)
s |IO * |openn_setup |NN GV *gv|NN char *mode|NN PerlIO **saveifp \
|NN PerlIO **saveofp|NN int *savefd \
Expand Down
1 change: 1 addition & 0 deletions embed.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#define av_top_index(a) S_av_top_index(aTHX_ a)
#define av_undef(a) Perl_av_undef(aTHX_ a)
#define av_unshift(a,b) Perl_av_unshift(aTHX_ a,b)
#define bigint_arith(a,b,c) Perl_bigint_arith(aTHX_ a,b,c)
#define block_end(a,b) Perl_block_end(aTHX_ a,b)
#define block_gimme() Perl_block_gimme(aTHX)
#define block_start(a) Perl_block_start(aTHX_ a)
Expand Down
1 change: 1 addition & 0 deletions ext/Config/Config_xs.in
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,7 @@ usecrosscompile, T_INV,0,ALN64I"@@usecrosscompile@@"
usedevel, T_INV,0,ALN64I"@@usedevel@@"
usedl, T_INV,0,ALN64I"@@usedl@@"
usedtrace, T_INV,0,ALN64I"@@usedtrace@@"
useexactarith, T_INV,0,ALN64I"@@useexactarith@@"
usefaststdio, T_INV,0,ALN64I"@@usefaststdio@@"
useffi, T_INV,0,ALN64I"@@useffi@@"
useithreads, T_INV,0,ALN64I"@@useithreads@@"
Expand Down
30 changes: 30 additions & 0 deletions lib/exact_arith.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package exact_arith;
our $VERSION = '0.01';
sub unimport { delete $^H{exact_arith}; }
sub import { $^H{exact_arith} = 1; }

1;
__END__
=head1 NAME
exact_arith - promote on overflow to bigint/num
=head1 SYNOPSIS
use exact_arith;
print 18446744073709551614 * 2; # => 36893488147419103228, a bigint object
{ no exact_arith;
print 18446744073709551614 * 2; # => 3.68934881474191e+19
}
=head1 DESCRIPTION
This is a new lexical user-pragma since cperl5.24 to use exact
arithmetic, without loosing precision on all builtin arithmetic ops.
As in perl6.
It is of course a bit slower, than without.
=cut
24 changes: 24 additions & 0 deletions lib/exact_arith.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!./perl -- -*- mode: cperl; cperl-indent-level: 4 -*-

BEGIN {
chdir 't' if -d 't';
@INC = ( '.', '../lib' );
}

use strict;
require '../t/test.pl';
plan(4);

$|=1;

use exact_arith;
my $n = 18446744073709551614 * 2; # => 36893488147419103228, a bigint object
is(ref $n, 'bigint');
is($n, 36893488147419103228);

{
no exact_arith;
my $m = 18446744073709551614 * 2;
is(ref $n, '');
is($n, 3.68934881474191e+19);
}
6 changes: 6 additions & 0 deletions perl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,9 @@ S_Internals_V(pTHX_ CV *cv)
# ifdef PERL_DONT_CREATE_GVSV
" PERL_DONT_CREATE_GVSV"
# endif
# ifdef PERL_EXACT_ARITH
" PERL_EXACT_ARITH"
# endif
# ifdef PERL_EXTERNAL_GLOB
" PERL_EXTERNAL_GLOB"
# endif
Expand Down Expand Up @@ -2031,6 +2034,9 @@ S_Internals_V(pTHX_ CV *cv)
# ifdef USE_CPERL
" USE_CPERL"
# endif
# ifdef USE_EXACT_ARITH
" USE_EXACT_ARITH"
# endif
# ifdef USE_FAST_STDIO
" USE_FAST_STDIO"
# endif
Expand Down
8 changes: 5 additions & 3 deletions perl.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,11 @@
RX_ENGINE(rx_sv)->dupe(aTHX_ (rx_sv),(param))
#endif




#ifdef PERL_EXACT_ARITH
#define IS_EXACT_ARITH cop_hints_fetch_pvs(PL_curcop, "exact_arith", REFCOUNTED_HE_EXISTS)
#else
#define IS_EXACT_ARITH 0
#endif

/*
* Because of backward compatibility reasons the PERL_UNUSED_DECL
Expand Down
11 changes: 4 additions & 7 deletions pod/perlcdelta.pod
Original file line number Diff line number Diff line change
Expand Up @@ -513,14 +513,11 @@ release manager will have to investigate the situation carefully.)

=over 4

=item L<ffi> 0.01c
=item L<exact_arith> 0.01

ffi helpers and ffi types.

=item L<hashiter>

Allow hash iterators changing keys for back-compat.
See L</Protected hash iterators>.
Promote on overflow to bigint/bignum as in perl6, do not loose precision
with all builtin arithmetic operators.
L<[cperl #21]|https://github.com/perl11/cperl/issues/21>

=item L<YAML::Safe> 0.80

Expand Down
Loading

0 comments on commit f32233a

Please sign in to comment.