{
our
$VERSION
=
'0.004'
; }
'/'
=>
'divided_by'
,
'=='
=>
'equal_to'
,
'eq'
=>
'equal_to'
,
'-'
=>
'minus'
,
'!='
=>
'not_equal_to'
,
'+'
=>
'plus'
,
'""'
=>
'stringify'
,
'*'
=>
'times'
,
'**'
=>
'to_power'
;
has
field
=> (
is
=>
'ro'
,
required
=> 1,
isa
=>
sub
{
my
$F
=
shift
;
(blessed(
$F
) &&
$F
->isa(
'Math::GF'
))
or ouch 500,
'field is not a valid Math::GF instance'
;
return
1;
},
);
has
p
=> (
is
=>
'ro'
,
init_arg
=>
undef
,
lazy
=> 1,
default
=>
sub
{
shift
->field->p },
);
has
n
=> (
is
=>
'ro'
,
init_arg
=>
undef
,
lazy
=> 1,
default
=>
sub
{
shift
->field->n },
);
has
sum_table
=> (
is
=>
'ro'
,
init_arg
=>
undef
,
lazy
=> 1,
default
=>
sub
{
shift
->field->sum_table },
);
has
prod_table
=> (
is
=>
'ro'
,
init_arg
=>
undef
,
lazy
=> 1,
default
=>
sub
{
shift
->field->prod_table },
);
has
v
=> (
is
=>
'ro'
,
default
=> 0,
);
has
i
=> (
is
=>
'ro'
,
lazy
=> 1,
builder
=>
'BUILD_multiplicative_inverse'
,
);
has
o
=> (
is
=>
'ro'
,
lazy
=> 1,
builder
=>
'BUILD_additive_inverse'
,
);
sub
assert_compatibility {
my
(
$self
,
$other
) =
@_
;
(blessed(
$other
) &&
$other
->isa(
'Math::GF::Extension'
))
|| ouch 500,
'one of the ops is not a Math::GF::Extension object'
;
my
$order
=
$self
->field->order;
$order
==
$other
->field->order
|| ouch 500,
'the two operands are not in the same field'
;
return
$order
;
}
sub
BUILD_multiplicative_inverse {
my
$self
=
shift
;
my
$v
=
$self
->v or ouch 500,
'no inverse for 0'
;
my
$pt
=
$self
->prod_table;
for
my
$i
(0 ..
$v
) {
return
$i
if
$pt
->[
$v
][
$i
] == 1;
}
for
my
$j
((
$v
+ 1) ..
$#$pt
) {
return
$j
if
$pt
->[
$j
][
$v
] == 1;
}
my
(
$p
,
$n
) = (
$self
->p,
$self
->n);
ouch 500,
"no inverse for $v in GF_${p}_$n"
;
}
sub
BUILD_additive_inverse {
my
$self
=
shift
;
my
$v
=
$self
->v or
return
0;
my
$pt
=
$self
->sum_table;
for
my
$i
(0 ..
$v
) {
return
$i
if
$pt
->[
$v
][
$i
] == 0;
}
for
my
$j
((
$v
+ 1) ..
$#$pt
) {
return
$j
if
$pt
->[
$j
][
$v
] == 0;
}
my
(
$p
,
$n
) = (
$self
->p,
$self
->n);
ouch 500,
"no opposite for $v in GF_${p}_$n"
;
}
sub
_prod {
my
(
$self
,
$x
,
$y
) =
@_
;
return
$x
>
$y
?
$self
->prod_table->[
$x
][
$y
]
:
$self
->prod_table->[
$y
][
$x
];
}
sub
_sum {
my
(
$self
,
$x
,
$y
) =
@_
;
return
$x
>
$y
?
$self
->sum_table->[
$x
][
$y
]
:
$self
->sum_table->[
$y
][
$x
];
}
sub
divided_by {
my
(
$self
,
$other
,
$swap
) =
@_
;
$self
->assert_compatibility(
$other
);
(
$self
,
$other
) = (
$other
,
$self
)
if
$swap
;
return
$self
->new(
field
=>
$self
->field,
v
=>
$self
->_prod(
$self
->v,
$other
->i),
);
}
sub
equal_to {
my
(
$self
,
$other
,
$swap
) =
@_
;
$self
->assert_compatibility(
$other
);
return
$self
->v ==
$other
->v;
}
sub
inv {
my
$self
=
shift
;
return
$self
->new(
field
=>
$self
->field,
v
=>
$self
->i,
i
=>
$self
->v,
);
}
sub
minus {
my
(
$self
,
$other
,
$swap
) =
@_
;
$self
->assert_compatibility(
$other
);
return
$self
->new(
field
=>
$self
->field,
v
=>
$self
->_sum(
$self
->v,
$other
->o),
);
}
sub
not_equal_to {
return
!
shift
->equal_to(
@_
);
}
sub
plus {
my
(
$self
,
$other
,
$swap
) =
@_
;
my
$n
=
$self
->assert_compatibility(
$other
);
return
$self
->new(
field
=>
$self
->field,
v
=>
$self
->_sum(
$self
->v,
$other
->v),
);
}
sub
stringify {
return
shift
->v;
}
sub
times
{
my
(
$self
,
$other
,
$swap
) =
@_
;
$self
->assert_compatibility(
$other
);
return
$self
->new(
field
=>
$self
->field,
v
=>
$self
->_prod(
$self
->v,
$other
->v),
);
}
sub
to_power {
my
(
$self
,
$exp
,
$swap
) =
@_
;
ouch 500,
'cannot elevate'
if
$swap
;
my
$x
=
$self
->field->multiplicative_neutral;
my
$zero
=
$self
->field->additive_neutral;
while
(
$exp
> 0) {
$x
=
$x
*
$self
;
last
if
$x
==
$zero
;
$exp
--;
}
return
$x
;
}
1;