use
5.006;
our
@ISA
=
qw< Math::BigInt::Lib >
;
our
$VERSION
=
'1.24'
;
my
$bits
= 32;
my
$chunk
= 32;
my
$zero
= Bit::Vector->new_Dec(
$bits
, 0);
my
$one
= Bit::Vector->new_Dec(
$bits
, 1);
my
$two
= Bit::Vector->new_Dec(
$bits
, 2);
my
$ten
= Bit::Vector->new_Dec(
$bits
, 10);
sub
api_version { 2; }
sub
import
{ }
sub
__dump {
my
(
$class
,
$x
) =
@_
;
my
$str
=
$class
-> _as_bin(
$x
);
my
$nbits_alloc
=
$x
-> Size();
my
$imax
=
$x
-> Max();
my
$nbits_min
=
$imax
< 0 ? 1 :
$imax
+ 2;
my
$nbits_exp
=
$chunk
* __ceil(
$nbits_min
/
$chunk
);
return
"$str ($nbits_min/$nbits_exp/$nbits_alloc)"
;
}
sub
_new {
my
(
$class
,
$str
) =
@_
;
my
$ndec
=
length
(
$str
);
my
$nbin
= 1 + __ceil(3.32192809488736 *
$ndec
);
$nbin
=
$chunk
* __ceil(
$nbin
/
$chunk
);
my
$u
= Bit::Vector->new_Dec(
$nbin
,
$str
);
$class
->__reduce(
$u
)
if
$nbin
>
$bits
;
$u
;
}
sub
_from_hex {
my
(
$class
,
$str
) =
@_
;
$str
=~ s/^0[xX]//;
my
$bits
= 1 + 4 *
length
(
$str
);
$bits
=
$chunk
* __ceil(
$bits
/
$chunk
);
my
$x
= Bit::Vector->new_Hex(
$bits
,
$str
);
$class
->__reduce(
$x
);
}
sub
_from_bin {
my
$str
=
$_
[1];
$str
=~ s/^0[bB]//;
my
$bits
= 1 +
length
(
$str
);
$bits
=
$chunk
* __ceil(
$bits
/
$chunk
);
Bit::Vector->new_Bin(
$bits
,
$str
);
}
sub
_zero {
Bit::Vector->new_Dec(
$bits
, 0);
}
sub
_one {
Bit::Vector->new_Dec(
$bits
, 1);
}
sub
_two {
Bit::Vector->new_Dec(
$bits
, 2);
}
sub
_ten {
Bit::Vector->new_Dec(
$bits
, 10);
}
sub
_copy {
$_
[1]->Clone();
}
sub
_str {
my
$x
=
$_
[1]->to_Dec();
$x
;
}
sub
_num {
0 +
$_
[1]->to_Dec();
}
sub
_as_hex {
my
$x
=
lc
$_
[1]->to_Hex();
$x
=~ s/^0*([\da-f])/0x$1/;
$x
;
}
sub
_as_bin {
my
$x
=
$_
[1]->to_Bin();
$x
=~ s/^0*(\d)/0b$1/;
$x
;
}
sub
_add {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
= __max(
$xs
,
$ys
) + 2;
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
$x
->add(
$x
,
$y
, 0);
$class
->__reduce(
$x
)
if
$ns
!=
$xs
;
$class
->__reduce(
$y
)
if
$ns
!=
$ys
;
$x
;
}
sub
_sub {
my
(
$class
,
$x
,
$y
,
$z
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
= __max(
$xs
,
$ys
);
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
if
(
$z
) {
$y
->subtract(
$x
,
$y
, 0);
$class
->__reduce(
$y
);
$class
->__reduce(
$x
)
if
$ns
!=
$xs
;
}
else
{
$x
->subtract(
$x
,
$y
, 0);
$class
->__reduce(
$y
)
if
$ns
!=
$ys
;
$class
->__reduce(
$x
);
}
return
$x
unless
$z
;
$y
;
}
sub
_mul {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
=
$xs
+
$ys
+ 2;
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
$x
->Multiply(
$x
,
$y
);
$class
->__reduce(
$y
)
if
$ns
!=
$ys
;
$class
->__reduce(
$x
)
if
$ns
!=
$xs
;
$x
;
}
sub
_div {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Max();
my
$ys
=
$y
->Max();
if
(
$xs
< 0 ||
$xs
<
$ys
) {
my
$r
=
$x
->Clone();
$x
= Bit::Vector->new_Hex(
$chunk
, 0);
return
wantarray
? (
$x
,
$r
) :
$x
;
}
else
{
my
$ns
=
$x
->Size();
my
$ys
=
$y
->Size();
$y
->Resize(
$ns
)
if
$ys
<
$ns
;
my
$r
= Bit::Vector->new_Hex(
$ns
, 0);
$x
->Divide(
$x
,
$y
,
$r
);
$class
->__reduce(
$y
)
if
$ys
<
$ns
;
$class
->__reduce(
$x
);
return
wantarray
? (
$x
,
$class
->__reduce(
$r
)) :
$x
;
}
}
sub
_inc {
my
(
$class
,
$x
) =
@_
;
my
$xs
=
$x
->Size();
if
(
$x
->bit_test(
$xs
-2) &
$x
->bit_test(0)) {
$x
->Resize(
$xs
+
$chunk
);
$x
->increment();
$class
->__reduce(
$x
);
}
else
{
$x
->increment();
}
$x
;
}
sub
_dec {
my
(
$class
,
$x
) =
@_
;
$x
->decrement();
$class
->__reduce(
$x
);
}
sub
_and {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
= __max(
$xs
,
$ys
);
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
$x
->And(
$x
,
$y
);
$class
->__reduce(
$y
)
if
$ns
!=
$xs
;
$class
->__reduce(
$x
);
$x
;
}
sub
_xor {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
= __max(
$xs
,
$ys
);
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
$x
->Xor(
$x
,
$y
);
$class
->__reduce(
$y
)
if
$ns
!=
$xs
;
$class
->__reduce(
$x
);
$x
;
}
sub
_or {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
= __max(
$xs
,
$ys
);
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
$x
->Or(
$x
,
$y
);
$class
->__reduce(
$y
)
if
$ns
!=
$xs
;
$class
->__reduce(
$x
)
if
$ns
!=
$xs
;
$x
;
}
sub
_gcd {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
->Size();
my
$ys
=
$y
->Size();
my
$ns
= __max(
$xs
,
$ys
);
$x
->Resize(
$ns
)
if
$xs
!=
$ns
;
$y
->Resize(
$ns
)
if
$ys
!=
$ns
;
$x
->GCD(
$x
,
$y
);
$class
->__reduce(
$y
)
if
$ys
!=
$ns
;
$class
->__reduce(
$x
);
$x
;
}
sub
_acmp {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xm
=
$x
->Size();
my
$ym
=
$y
->Size();
my
$diff
= (
$xm
-
$ym
);
return
$diff
<=> 0
if
$diff
!= 0;
$x
->Lexicompare(
$y
);
}
sub
_len {
length
(
$_
[1]->to_Dec());
}
sub
_alen {
my
$nb
=
$_
[1] -> Max();
return
1
if
$nb
< 0;
int
(0.5 + 3.32192809488736 * (
$nb
+ 1));
}
sub
_digit {
my
(
$class
,
$x
,
$n
) =
@_
;
substr
(
$x
->to_Dec(), -(
$n
+1), 1);
}
sub
_fac {
my
(
$class
,
$x
) =
@_
;
if
(
$class
->_is_zero(
$x
)) {
$x
=
$class
->_one();
return
$x
;
}
my
$n
=
$class
->_copy(
$x
);
$x
=
$class
->_one();
while
(!
$class
->_is_one(
$n
)) {
$class
->_mul(
$x
,
$n
);
$class
->_dec(
$n
);
}
$x
;
}
sub
_pow {
my
(
$class
,
$x
,
$y
) =
@_
;
return
$class
-> _one()
if
$class
-> _is_zero(
$y
);
return
$class
-> _zero()
if
$class
-> _is_zero(
$x
);
my
$ns
= 1 + (
$x
-> Max() + 1) *
$y
-> to_Dec();
$ns
=
$chunk
* __ceil(
$ns
/
$chunk
);
my
$z
= Bit::Vector -> new(
$ns
);
$z
-> Power(
$x
,
$y
);
return
$class
->__reduce(
$z
);
}
sub
_rsft {
my
(
$class
,
$x
,
$n
,
$b
) =
@_
;
if
(
$b
== 2) {
$x
->Move_Right(
$class
->_num(
$n
));
}
else
{
$b
=
$class
->_new(
$b
)
unless
ref
(
$b
);
$x
=
$class
->_div(
$x
,
$class
->_pow(
$b
,
$n
));
}
$class
->__reduce(
$x
);
}
sub
_lsft {
my
(
$class
,
$x
,
$n
,
$b
) =
@_
;
if
(
$b
== 2) {
$n
=
$class
->_num(
$n
);
my
$size
=
$x
->Size() + 1 +
$n
;
my
$ns
= (
int
(
$size
/
$chunk
)+1)
*$chunk
;
$x
->Resize(
$ns
);
$x
->Move_Left(
$n
);
$class
->__reduce(
$x
);
}
else
{
$b
=
$class
->_new(
$b
);
$class
->_mul(
$x
,
$class
->_pow(
$b
,
$n
));
}
return
$x
;
}
sub
_is_zero {
my
$x
=
$_
[1];
return
$x
-> is_empty() ? 1 : 0;
}
sub
_is_one {
my
$x
=
$_
[1];
return
0
if
$x
->Size() !=
$bits
;
$x
->equal(
$one
);
}
sub
_is_two {
my
$x
=
$_
[1];
return
0
if
$x
->Size() !=
$bits
;
$x
->equal(
$two
);
}
sub
_is_ten {
my
$x
=
$_
[1];
return
0
if
$x
->Size() !=
$bits
;
$_
[1]->equal(
$ten
);
}
sub
_is_even {
$_
[1]->bit_test(0) ? 0 : 1;
}
sub
_is_odd {
$_
[1]->bit_test(0) ? 1 : 0;
}
sub
_check {
my
$x
=
$_
[1];
return
"Undefined"
unless
defined
$x
;
return
"$x is not a reference to Bit::Vector"
if
ref
(
$x
) ne
'Bit::Vector'
;
return
"$x is negative"
if
$x
->Sign() < 0;
my
$xs
=
$x
-> Size();
my
$ns
=
$chunk
*
int
(
$xs
/
$chunk
);
if
(
$xs
!=
$ns
) {
return
"Size($x) is $x bits, expected a multiple of $chunk."
;
}
my
$imax
=
$x
-> Max();
my
$nmin
=
$imax
< 0 ? 1 :
$imax
+ 2;
$ns
=
$chunk
* __ceil(
$nmin
/
$chunk
);
if
(
$xs
!=
$ns
) {
return
"Size($x) is $xs bits, but only $ns bits are needed."
;
}
0;
}
sub
_mod {
my
(
$class
,
$x
,
$y
) =
@_
;
my
$xs
=
$x
-> Size();
my
$ys
=
$y
-> Size();
my
$ns
= __max(
$xs
,
$ys
);
$x
-> Resize(
$ns
)
if
$xs
<
$ns
;
$y
-> Resize(
$ns
)
if
$ys
<
$ns
;
my
$quo
= Bit::Vector -> new(
$ns
);
my
$rem
= Bit::Vector -> new(
$ns
);
$quo
-> Divide(
$x
,
$y
,
$rem
);
$y
-> Resize(
$ys
)
if
$ys
<
$ns
;
$class
-> __reduce(
$rem
);
}
sub
__reduce {
my
(
$class
,
$x
) =
@_
;
my
$bits_allocated
=
$x
->Size();
return
$x
if
$bits_allocated
<=
$chunk
;
my
$imax
=
$x
->Max();
my
$bits_needed
=
$imax
< 0 ? 1 : 2 +
$imax
;
$bits_needed
=
$chunk
* __ceil(
$bits_needed
/
$chunk
);
if
(
$bits_allocated
>
$bits_needed
) {
$x
->Resize(
$bits_needed
);
}
$x
;
}
sub
__max {
my
(
$m
,
$n
) =
@_
;
$m
>
$n
?
$m
:
$n
;
}
sub
__ceil {
my
$x
=
shift
;
my
$ix
=
int
$x
;
(
$ix
>=
$x
) ?
$ix
:
$ix
+ 1;
}
1;