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

Commit 22b61d6

Browse files
Reini Urbanrurban
Reini Urban
authored andcommitted
exact_arith: implement it
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.
1 parent 6c02d8a commit 22b61d6

17 files changed

+308
-43
lines changed

Configure

+28
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,7 @@ CONFIG=''
14241424
usecperl=''
14251425
fake_signatures=''
14261426
usenamedanoncv=''
1427+
useexactarith=''
14271428

14281429
: Detect odd OSs
14291430
define='define'
@@ -7584,6 +7585,32 @@ $define)
75847585
;;
75857586
esac
75867587

7588+
case "$useexactarith" in
7589+
$define|true|[yY]*) dflt='y' ;;
7590+
*) dflt='n' ;;
7591+
esac
7592+
cat <<EOM
7593+
7594+
Would you like to build Perl so that every builtin arithmetic overflow
7595+
does not promote to internal fast double/long double numbers but
7596+
instead to slow and precise bigint? So that exact_arith is enabled by default.
7597+
7598+
If this doesn't make any sense to you, just accept the default '$dflt'.
7599+
EOM
7600+
rp='Use exact arith, overflow to bigint as in perl6?'
7601+
. ./myread
7602+
case "$ans" in
7603+
y|Y) val="$define" ;;
7604+
*) val="$undef" ;;
7605+
esac
7606+
set useexactarith
7607+
eval $setvar
7608+
case "$useexactarith" in
7609+
$define)
7610+
echo "exact_arith selected." >&4
7611+
;;
7612+
esac
7613+
75877614
case "$usecperl" in
75887615
$define) usecperl='define'
75897616
echo "cperl variant selected." >&4
@@ -25924,6 +25951,7 @@ usecrosscompile='$usecrosscompile'
2592425951
usedevel='$usedevel'
2592525952
usedl='$usedl'
2592625953
usedtrace='$usedtrace'
25954+
useexactarith='$useexactarith'
2592725955
usefaststdio='$usefaststdio'
2592825956
useffi='$useffi'
2592925957
useithreads='$useithreads'

MANIFEST

+2
Original file line numberDiff line numberDiff line change
@@ -5690,6 +5690,8 @@ lib/dumpvar.pl A variable dumper
56905690
lib/dumpvar.t A variable dumper tester
56915691
lib/English.pm Readable aliases for short variables
56925692
lib/English.t See if English works
5693+
lib/exact_arith.pm Pragma to set exact arithmetic as in perl6
5694+
lib/exact_arith.t See if use exact_arith works
56935695
lib/ExtUtils/Embed.pm Utilities for embedding Perl in C programs
56945696
lib/ExtUtils/t/Embed.t See if ExtUtils::Embed and embedding works
56955697
lib/ExtUtils/typemap Extension interface types

Porting/Maintainers.pl

+1
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,7 @@ package Maintainers;
17321732
lib/DBM_Filter/
17331733
lib/DirHandle.{pm,t}
17341734
lib/English.{pm,t}
1735+
lib/exact_arith.{pm,t}
17351736
lib/ExtUtils/Embed.pm
17361737
lib/ExtUtils/XSSymSet.pm
17371738
lib/ExtUtils/t/Embed.t

config_h.SH

+8
Original file line numberDiff line numberDiff line change
@@ -5488,6 +5488,14 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
54885488
#$usesafehashiter USE_SAFE_HASHITER /**/
54895489
#endif
54905490
5491+
/* USE_EXACT_ARITH:
5492+
* This symbol, if defined, indicates that Perl uses exact_arith as default.
5493+
*/
5494+
#define PERL_EXACT_ARITH
5495+
#ifndef USE_EXACT_ARITH
5496+
#$useexactarith USE_EXACT_ARITH /**/
5497+
#endif
5498+
54915499
/* PERL_HASH_FUNC_*:
54925500
* This symbol defines the used perl hash function variant.
54935501
* It is set in Configure or via -Dhash_func=, but can be left blank.

embed.fnc

+1
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ pR |int |PerlSock_accept_cloexec|int listenfd \
528528
pR |int |PerlSock_socketpair_cloexec|int domain|int type|int protocol \
529529
|NN int *pairfd
530530
#endif
531+
AMp |void |bigint_arith |NN const char *op|NN SV *const left|NN SV *const right
531532
#if defined(PERL_IN_DOIO_C)
532533
s |IO * |openn_setup |NN GV *gv|NN char *mode|NN PerlIO **saveifp \
533534
|NN PerlIO **saveofp|NN int *savefd \

embed.h

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#define av_top_index(a) S_av_top_index(aTHX_ a)
6868
#define av_undef(a) Perl_av_undef(aTHX_ a)
6969
#define av_unshift(a,b) Perl_av_unshift(aTHX_ a,b)
70+
#define bigint_arith(a,b,c) Perl_bigint_arith(aTHX_ a,b,c)
7071
#define block_end(a,b) Perl_block_end(aTHX_ a,b)
7172
#define block_gimme() Perl_block_gimme(aTHX)
7273
#define block_start(a) Perl_block_start(aTHX_ a)

ext/Config/Config_xs.in

+1
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,7 @@ usecrosscompile, T_INV,0,ALN64I"@@usecrosscompile@@"
15031503
usedevel, T_INV,0,ALN64I"@@usedevel@@"
15041504
usedl, T_INV,0,ALN64I"@@usedl@@"
15051505
usedtrace, T_INV,0,ALN64I"@@usedtrace@@"
1506+
useexactarith, T_INV,0,ALN64I"@@useexactarith@@"
15061507
usefaststdio, T_INV,0,ALN64I"@@usefaststdio@@"
15071508
useffi, T_INV,0,ALN64I"@@useffi@@"
15081509
useithreads, T_INV,0,ALN64I"@@useithreads@@"

lib/exact_arith.pm

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package exact_arith;
2+
our $VERSION = '0.01';
3+
sub unimport { delete $^H{exact_arith}; }
4+
sub import { $^H{exact_arith} = 1; }
5+
6+
1;
7+
__END__
8+
9+
=head1 NAME
10+
11+
exact_arith - promote on overflow to bigint/num
12+
13+
=head1 SYNOPSIS
14+
15+
use exact_arith;
16+
print 18446744073709551614 * 2; # => 36893488147419103228, a bigint object
17+
18+
{ no exact_arith;
19+
print 18446744073709551614 * 2; # => 3.68934881474191e+19
20+
}
21+
22+
=head1 DESCRIPTION
23+
24+
This is a new lexical user-pragma since cperl5.24 to use exact
25+
arithmetic, without loosing precision on all builtin arithmetic ops.
26+
As in perl6.
27+
28+
It is of course a bit slower, than without.
29+
30+
=cut

lib/exact_arith.t

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!./perl -- -*- mode: cperl; cperl-indent-level: 4 -*-
2+
3+
BEGIN {
4+
chdir 't' if -d 't';
5+
@INC = ( '.', '../lib' );
6+
}
7+
8+
use strict;
9+
require '../t/test.pl';
10+
plan(4);
11+
12+
$|=1;
13+
14+
use exact_arith;
15+
my $n = 18446744073709551614 * 2; # => 36893488147419103228, a bigint object
16+
is(ref $n, 'bigint');
17+
is($n, 36893488147419103228);
18+
19+
{
20+
no exact_arith;
21+
my $m = 18446744073709551614 * 2;
22+
is(ref $n, '');
23+
is($n, 3.68934881474191e+19);
24+
}

perl.c

+6
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,9 @@ S_Internals_V(pTHX_ CV *cv)
19321932
# ifdef PERL_DONT_CREATE_GVSV
19331933
" PERL_DONT_CREATE_GVSV"
19341934
# endif
1935+
# ifdef PERL_EXACT_ARITH
1936+
" PERL_EXACT_ARITH"
1937+
# endif
19351938
# ifdef PERL_EXTERNAL_GLOB
19361939
" PERL_EXTERNAL_GLOB"
19371940
# endif
@@ -2034,6 +2037,9 @@ S_Internals_V(pTHX_ CV *cv)
20342037
# ifdef USE_CPERL
20352038
" USE_CPERL"
20362039
# endif
2040+
# ifdef USE_EXACT_ARITH
2041+
" USE_EXACT_ARITH"
2042+
# endif
20372043
# ifdef USE_FAST_STDIO
20382044
" USE_FAST_STDIO"
20392045
# endif

perl.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,11 @@
317317
RX_ENGINE(rx_sv)->dupe(aTHX_ (rx_sv),(param))
318318
#endif
319319

320-
321-
322-
320+
#ifdef PERL_EXACT_ARITH
321+
#define IS_EXACT_ARITH cop_hints_fetch_pvs(PL_curcop, "exact_arith", REFCOUNTED_HE_EXISTS)
322+
#else
323+
#define IS_EXACT_ARITH 0
324+
#endif
323325

324326
/*
325327
* Because of backward compatibility reasons the PERL_UNUSED_DECL

pod/perlcdelta.pod

+6
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,12 @@ release manager will have to investigate the situation carefully.)
551551

552552
=over 4
553553

554+
=item L<exact_arith> 0.01
555+
556+
Promote on overflow to bigint/bignum as in perl6, do not loose precision
557+
with all builtin arithmetic operators.
558+
L<[cperl #21]|https://github.com/perl11/cperl/issues/21>
559+
554560
=item L<ffi> 0.01c
555561

556562
ffi helpers and ffi types.

0 commit comments

Comments
 (0)