Use bigint and float perl - perl

I am extremely new to Perl, so I hope you will excuse my inexperience.
I have the following lines of code:
use warnings;
use strict;
use POSIX 'ceil';
use bigint;
my($g, $y, $n) = ($ARGV[0], $ARGV[1], $ARGV[2]);
my $z = ceil(sqrt($n-1));
my $entry;
print "list1: \n";
for my $v (0 .. $z) {
$entry = ($g ** $v) % $n;
$entry = ($entry ** ($n - 2)) % $n;
$entry = ($entry * $y) % $n;
print "$entry : $v\n";
}
print "list2: \n";
for my $u (0 .. $z) {
$entry = ($g ** ($u * $z)) % $n;
print "$entry: $u\n";
}
I need to use the bigint environment because of some following statements. Whenever I look into $z it evaluates to 6 instead of 7, when i call my program with $n = 41. It looks as if the bigint environment rounds the value of the sqrt method. I also tried to use BigFloat instead of bigint, but then the result of $entry = ($g ** ($u * $z)) % $n; gets calculated wrong (with ($g, $y, $n) = (15, 38, 41) the result is 3, when $u reached 3 in the for loop, but should be 26 instead).
Is there any option to avoid this rounding, so I can use float while calculating the square root and bigint in all following statements, so the pow operation works properly?
My call is perl program.pl 15 38 41. I try to implement the baby-step-giant-step algorithm.

you need to use bignum, not bigint:
$ cat bauer.pl
#!/usr/bin/perl
use warnings;
use strict;
use POSIX;
use bigint;
my($g, $y, $n) = ($ARGV[0], $ARGV[1], $ARGV[2]);
my $z = ceil(sqrt($n-1));
$ perl r.pl
1.41421356237309504880168872420969807857
With your program signature:
$ cat bauer.pl
#!/usr/bin/perl
use warnings;
use strict;
use POSIX;
use bignum;
my($g, $y, $n) = ($ARGV[0], $ARGV[1], $ARGV[2]);
my $z = ceil(sqrt($n-1));
print STDOUT "$z\n";
$ perl bauer.pl 1 2 48
7

I'd recommend Math::BigFloat and Math::BigInt over the bigint pragma, practically always.
The pragma is "just a thin wrapper around various modules of the Math::BigInt family" says the (linked) doc, but has very non-trivial actions (the "Description" conveys it). Instead, use the classes to set up what you want burdened with infinite precision support, itself non-trivial and costly.
use warnings;
use strict;
use feature 'say';
use Math::BigFloat;
my($g, $y, $n) = ($ARGV[0], $ARGV[1], $ARGV[2]);
my $z = sqrt($n-1);
say $z;
my $num = Math::BigFloat->new( $z );
say $num;
my $num_ceil = $num->bceil();
say $num_ceil;
Update The shown calculation has no need for a big-number exponent
use warnings;
use strict;
use feature 'say';
use POSIX 'ceil';
use Math::BigInt;
my ($g, $y, $n) = #ARGV;
my $z = ceil(sqrt($n-1));
my $bg = Math::BigInt->new($g);
my $e;
for my $u (0 .. $z) {
$e = $bg->copy->bmodpow($u*$rnd, $n);
say "$u: $e";
}
There happens to be a bmodpow method, doing exactly what's needed and being
"far superior" at it. Most arithmetic methods modify their operands, thus copy() is chained in to preserve $bg for the next iteration. See "Modifying and =" bullet under Caveats in docs.
I declare $e outside of the loop to avoid the (copy) constructor running every time in the loop as the variable becomes (is assigned) a BigInt object, returned by the method. (I am not certain that this is needed or that it helps though.)

Whenever I look into $z it evaluates to 6 instead of 7,
use bigint; causes numeric literals to be replaced with Math::BigInt objects. For example,
1
gets replaced with
Math::BigInt->new(1)
Math::BigInt in turn overrides a number of operators when a Math::BigInt object is used as an operand.
As such,
use bigint;
my $z = ceil(sqrt($n-1));
is equivalent to
use Math::BigInt;
my $z = ceil(sqrt($n-Math::BigInt->new(1)));
which is equivalent to
use Math::BigInt;
my $temp = Math::BigInt->new(1); # 1 [BigInt]
$temp->bneg; # -1 [BigInt]
$temp->badd($n); # 40 [BigInt]
$temp->bsqrt(); # 6 [BigInt] <--- XXX
$temp = $temp->numify; # 6 [Primitive]
my $z = ceil($temp); # 6 [Primitive]
So, you are using a Math::BigInt when you don't want to. Don't do that!!! Simply use
# No "use bigint;"!!!
my $z = ceil(sqrt($n-1));
Of course, the algorithm to which you linked actually calls for
# No "use bigint;"!!!
my $z = ceil(sqrt($n));
Because use bigint; can have large effects at a distance, I personally find use bigint; far too magical. I'd much rather use Math::BigInt->new(...) where appropriate rather than having use bigint; convert all my numerical constants into Math::BigInt objects. I'd also rather use Math::BigInt's methods instead of overloaded operators. Far less surprises that way (e.g. such as the loss of big number support when using ceil).
use warnings;
use strict;
use feature qw( say );
use Config qw( %Config );
use Math::BigInt qw( );
use POSIX qw( ceil );
# Each of the arguments is expected to be in [0, 2^32).
# Should use exponentiation by squaring instead of larger number support.
sub pow_m {
my ($base, $exp, $mod) = #_;
my $n = Math::BigInt->new($base);
$n->bpow($exp);
$n->bmod($mod);
return $n->numify();
}
# Each of the arguments is expected to be in [0, 2^32).
# Requires a 64-bit integers or $e might overflow.
sub babystep_giantstep {
my ($g, $h, $mod) = #_;
my $m = ceil(sqrt($mod));
my %table;
my $e = 1;
for my $i (0..$m-1) {
$table{$e} = $i;
$e = ($e * $g) % $mod;
}
my $factor = pow_m($g, $mod-$m-1, $mod);
$e = $h;
for my $i (0..$m-1) {
if (exists($table{$e})) {
return $i*$m + $table{$e};
}
$e = ($e * $factor) % $mod;
}
return undef;
}
{
$Config{uvsize} >= 8
or warn("Results may overflow\n");
my ($g, $h, $mod) = #ARGV;
my $log = babystep_giantstep($g, $h, $mod);
say $log;
my $test = Math::BigInt->new($g);
$test->bpow($log);
$test->bmod($mod);
$test = $test->numify;
say $test == $h ? "ok" : "not ok";
}

Related

How to overload operator in non-class package?

In my situation I don't need warnings Use of uninitialized value in string while comparing string equality. So I tought that instead silencing all such warnings in the scope with no warnings 'uninitialized' would be better to overload eq-operator with my own subroutine, like:
use overload 'eq' => \&undefined_equal;
sub undefined_equal {
my ( $left, $right ) = #_;
no warnings 'uninitialized';
if ( $left eq $right ) {
return 1;
}
return 0;
}
Of course, overloading does not work, because according to the docs, overload is meant to use with classes, but I have plain procedural packages.
So I did try with overloading built-in functions, like:
package REeq;
use strict; use warnings; use 5.014;
BEGIN {
use Exporter ();
#REeq::ISA = qw( Exporter );
#REeq::EXPORT = qw( eq );
}
sub eq {
my ( $left, $right ) = #_;
no warnings 'uninitialized';
if ( $left CORE::eq $right ) {
return 1;
}
return 0;
}
1;
I can call my eq but can't use it as operator.
I need it because I want instead
if ( defined $some_scalar && $some_scalar eq 'literal string' ){
....
}
to use just
if ( $some_scalar eq 'literal string' ){
....
}
How could I achieve my goal?
Changing the behaviour of eq is possible, but it requires writing an XS modules that creates an op checker that replaces the code perl executes for the eq ops in scope. This is the approach used by no autovivification;, for example.
Seems you can - I haven't tried this but the perl monks have
sure, if you see it that way... you just have to bless your variable,
just like you did with your Number-package.
use overload ...;
my $n = bless {number => 23}, "main";
print $n >> 2;
i think that's not what you want, just wanted to make clear that it's
not a problem of the package name but that you must have a blessed
object.
Edit: taking zdim's onboard...
use strict;
use warnings;
use overload 'eq' => \&undefined_equal;
sub undefined_equal {
my ( $left, $right ) = #_;
no warnings 'uninitialized';
if ( ${$left} eq $right ) {
return 1;
}
return 0;
}
my $a = "abcde";
my $n = bless \$a, "main";
print "a eq undef -->";
print $a eq undef;
print "<--\nn eq undef -->";
print $n eq undef;
print "<--\n";
which gives
$ perl overload.pl
Use of uninitialized value in string eq at overload.pl line 20.
a eq undef --><--
n eq undef -->0<--
Don't forget the double $$ in the sub or you disappear into recursion. And the scalar reference for bless as you can only bless references, it seems
It still has a bless but hey

Unexpected results for high order function

I have a higher order function that maps even position values in an array:
sub map_even(&#) {
my $block = shift;
my #res;
for $i (0..$#_) {
push #res, $i%2 ? $_[$i] : &$block($_[$i]);
}
#res;
}
print map_even {$_*$_} 1,2,3,4;
I am expecting the output to be 14316, but the actual output is
0204
Why does this happen and how can I fix this? And is there any improvement can be done to the code?
In your anonymous function you have to access first input argument via $_[0] (hint: #_ array).
use strict;
use warnings;
sub map_even(&#) {
my $block = shift;
my #res;
for my $i (0..$#_) {
push #res, $i%2 ? $block->($_[$i]) : $_[$i];
}
#res;
}
print join ",", map_even {$_[0]*$_[0]} 1,2,3,4;
output
1,4,3,16
Using $_,
sub map_even(&#) {
my $block = shift;
my #res;
for my $i (0..$#_) {
push #res, $i%2 ? $block->() : $_ for $_[$i];
# or
# local $_ = $_[$i];
# push #res, $i%2 ? $block->() : $_;
}
#res;
}
print join ",", map_even {$_*$_} 1,2,3,4;
In your map_even block, you use the special $_ variable. However, you have to set it inside your loop:
local $_ = $_[$i];
... $block->();
The $_ is a global variable and can be temporarily overridden with the local operator. The $_ has nothing to do with subroutine arguments.
About aliasing: Perls for, map and grep mostly alias $_ to the current element as a performance hack, not because this behavior would be particularly desirable. In order to perform an alias, you should localize the whole *_ typeglob which contains the $_ variable and then assign a scalar reference of the alias target to the glob:
local *_ = \$_[$i];
I would solve this one of two ways.
First, by using List::Utils's pairmap:
use strict;
use warnings;
use List::Util qw(pairmap);
my #x = (1 .. 4);
my #result = pairmap {$a, $b**2} #x;
print "#result\n";
Or more simply, by just using the indexes:
use strict;
use warnings;
my #x = (1 .. 4);
my #result = map {$_ % 2 ? $x[$_] ** 2 : $x[$_]} (0..$#x);
print "#result\n";
However, if you really wanted a new sub, I'd just setup a flip-flop:
use strict;
use warnings;
sub map_even(&#) {
my $block = shift;
my $even = 1;
map {($even ^= 1) ? $block->() : $_} #_;
}
print join " ", map_even {$_*$_} 1,2,3,4;
All output:
1 4 3 16

Routine as argument -- generic variables not working

I am working on writing a gaming system (wargames, etc.) and am creating the system for creating and displaying hex maps. I realized quickly that I am repeatedly doing a nested loop of x=(0..maxx) and y=(0..maxy). So I attempted to adapt some code I found somewhere (one of the advanced perl books, I forget where) to create an easier way to do this sort of looping thing. This is what I came up with:
sub fillmap (&#) {
my $code = shift;
no strict 'refs';
use vars qw($x $y);
my $caller = caller;
local(*{$caller."::x"}) = \my $x;
local(*{$caller."::y"}) = \my $y;
foreach $x (0..5) {
foreach $y (0..3) {
warn "fillmap $x,$y\n";
&{$code}($x,$y);
}
}
}
It's suppose to work like sort, but using $x and $y instead of $a and $b.
Note: the warn statement is for debugging. I also simplified the x and y ranges (the array passed in determines the maxx and maxy values, but I didn't want to muddy this discussion with the routines for calculating them... I just hard-coded them to maxx=5 and maxy=3)
So, this execution of this routine like so:
fillmap {warn "$x,$y\n";} #map;
should yield a list of the x,y pairs. But instead, it gives me this:
fillmap 0,0
,
fillmap 0,1
,
fillmap 0,2
,
fillmap 0,3
,
fillmap 1,0
,
...
Note, the "fillmap" lines are from the subroutine for debugging. But instead of each x,y pair, I just get the comma ($x and $y are undefined).
What am I doing wrong?
The problem is that for $x does its own localisation. The $x inside the loop isn't the $x that's aliased to $caller::x.
You need to do one of the following:
Copy $x into $caller::x inside the loop.
Alias $caller::x to $x inside the loop.
The following does the latter:
use strict;
use warnings;
sub fillmap(&#) {
my $code = shift;
my $caller = caller();
my $xp = do { no strict 'refs'; \*{$caller.'::x'} }; local *$xp;
my $yp = do { no strict 'refs'; \*{$caller.'::y'} }; local *$yp;
for my $x (0..1) {
*$xp = \$x;
for my $y (0..2) {
*$yp = \$y;
$code->();
}
}
}
our ($x, $y);
fillmap { warn "$x,$y\n"; } '...';
You could avoid the need for our ($x, $y); by using $a and $b instead of $x and $y. You can't solve the problem by moving it (or use vars qw( $x $y );) into fillmap because you obviously intend fillmap to be used in a different package and lexical scope than the caller.

Why is my for loop an illegal declaration

I created two subs one to do Fibonacci and the other to test even numbers. When I call it though it is saying my for loop in line 7 the sub Fibonacci is illegal why?
#!/usr/bin/perl
use strict;
use warnings;
my ($x,$y);
my $num = 0;
sub Fibs($start,$stop){
for ($start..$stop){
($x, $y) = ($y, $x+$y);
my $total += $y;
}
print "$total \n"
}
sub even($num){
if ($num % 2 == 0){
return $num;}
}
my $big_total = Fibs(even($num), 3999999)
Edited from suggestions below.
Clearly I am missing something. From feedback updated to new version.
#!/usr/bin/perl
use strict;
use warnings;
my ($x,$y);
my $num = 0;
sub Fibs{
my ($start, $stop) = #_ ;
for ($start..$stop){
my ($x, $y) = (0,2);
if ($x % 2 == 0){
($x, $y) = ($y, $x+$y);
my $total += $y;
}
}
my $big_total = Fibs(0, 3999999)
In addition to the missing opening braces, Perl doesn't support that kind of declaration for subroutine parameters.
Rather than
sub Fibs($start, $stop) {
...
}
you need to write something like:
sub Fibs {
my($start, $stop) = #_;
...
}
(Perl does have prototypes, but they're not really intended for declaring the types of parameters, and they don't provide names. See this article for a discussion.)
Other problems:
You should add
use strict;
use warnings;
You never use the $x and $y that you declare in the outer scope.
Your even function appears to be incomplete. It doesn't (explicitly) return a value if its argument is an odd number. What exactly is it intended to do?

Find all possible starting positions of a regular expression match in perl, including overlapping matches?

Is there a way to find all possible start positions for a regex match in perl?
For example, if your regex was "aa" and the text was "aaaa", it would return 0, 1, and 2, instead of, say 0 and 2.
Obviously, you could just do something like return the first match, and then delete all characters up to and including that starting character, and perform another search, but I'm hoping for something more efficient.
Use lookahead:
$ perl -le 'print $-[0] while "aaaa" =~ /a(?=a)/g'
In general, put everything except the first character of the regex inside of the (?=...).
Update:
I thought about this one a bit more, and came up with this solution using an embedded code block, which is nearly three times faster than the grep solution:
use 5.010;
use warnings;
use strict;
{my #pos;
my $push_pos = qr/(?{push #pos, $-[0]})/;
sub with_code {
my ($re, $str) = #_;
#pos = ();
$str =~ /(?:$re)$push_pos(?!)/;
#pos
}}
and for comparison:
sub with_grep { # old solution
my ($re, $str) = #_;
grep {pos($str) = $_; $str =~ /\G(?:$re)/} 0 .. length($str) - 1;
}
sub with_while { # per Michael Carman's solution, corrected
my ($re, $str) = #_;
my #pos;
while ($str =~ /\G.*?($re)/) {
push #pos, $-[1];
pos $str = $-[1] + 1
}
#pos
}
sub with_look_ahead { # a fragile "generic" version of Sean's solution
my ($re, $str) = #_;
my ($re_a, $re_b) = split //, $re, 2;
my #pos;
push #pos, $-[0] while $str =~ /$re_a(?=$re_b)/g;
#pos
}
Benchmarked and sanity checked with:
use Benchmark 'cmpthese';
my #arg = qw(aa aaaabbbbbbbaaabbbbbaaa);
my $expect = 7;
for my $sub qw(grep while code look_ahead) {
no strict 'refs';
my #got = &{"with_$sub"}(#arg);
"#got" eq '0 1 2 11 12 19 20' or die "$sub: #got";
}
cmpthese -2 => {
grep => sub {with_grep (#arg) == $expect or die},
while => sub {with_while (#arg) == $expect or die},
code => sub {with_code (#arg) == $expect or die},
ahead => sub {with_look_ahead(#arg) == $expect or die},
};
Which prints:
Rate grep while ahead code
grep 49337/s -- -20% -43% -65%
while 61293/s 24% -- -29% -56%
ahead 86340/s 75% 41% -- -38%
code 139161/s 182% 127% 61% --
I know you asked for a regex, but there is actually a simple builtin function that does something quite similar, the function index (perldoc -f index). From that we can build up a simple solution to your direct question, though if you really need a more complicated search than your example this will not work as it only looks for substrings (after an index given by the third parameter).
#!/usr/bin/env perl
use strict;
use warnings;
my $str = 'aaaa';
my $substr = 'aa';
my $pos = -1;
while (1) {
$pos = index($str, $substr, $pos + 1);
last if $pos < 0;
print $pos . "\n";
}
You can use global matching with the pos() function:
my $s1 = "aaaa";
my $s2 = "aa";
while ($s1 =~ /aa/g) {
print pos($s1) - length($s2), "\n";
}