clear
// ExtendedEuclidean
// 欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。
// 计算公式gcd(a,b) = gcd(b,a mod b)
a = hex( 1997 )
b = hex( 615 )
t = call gcd( $a, $b )
// 扩展欧几里得算法(Extended Euclidean algorithm)是欧几里得算法的扩展。
// 已知整数a、b,必存在整数x、y使得ax + by = gcd(a,b).
// 扩展欧几里得可以求出:
// a·x + m·y = gcd(a, m)
// 如果 gcd(a,m)=1,则变成:
// a·x + m·y = 1
// 把右边的 1 看成 mod m 的等式:
// a·x ≡ 1 (mod m)
// 所以 x 就是逆元
a = hex( 10 )
m = hex( 17 )
flag = ""
x = call modinv( $a, $m, &flag )
if $flag == 00
tmp = big_mul( $a, $x )
tmp = big_mod( $tmp, $m )
else
tmp = big_mul( $m, $x )
tmp = big_mod( $tmp, $a )
endif
if $tmp != 01
? "求逆失败"
pause
endif
m = hex( 10 )
a = hex( 17 )
flag = ""
x = call modinv( $a, $m, &flag )
if $flag == 00
tmp = big_mul( $a, $x )
tmp = big_mod( $tmp, $m )
else
tmp = big_mul( $m, $x )
tmp = big_mod( $tmp, $a )
endif
if $tmp != 01
? "求逆失败"
pause
endif
a = int2hex( 0987654321012345678909876543210123456789 )
m = int2hex( 1000000000000000000000000000000000000037 )
x = call modinv( $a, $m, &flag )
if $flag == 00
tmp = big_mul( $a, $x )
tmp = big_mod( $tmp, $m )
else
tmp = big_mul( $m, $x )
tmp = big_mod( $tmp, $a )
endif
if $tmp != 01
? "求逆失败"
pause
endif
a = int2hex( 0314159265358979323846264338327950288419 )
m = int2hex( 0271828182845904523536028747135266249775 )
x = call modinv( $a, $m, &flag )
if $flag == 00
tmp = big_mul( $a, $x )
tmp = big_mod( $tmp, $m )
else
tmp = big_mul( $m, $x )
tmp = big_mod( $tmp, $a )
endif
if $tmp != 01
? "求逆失败"
pause
endif
end
gcd:
prompt off
local a = getpara
local b = getpara
local tmp
local r
if $a < $b
tmp = $a
a = $b
b = $tmp
endif
r = big_mod( $a, $b )
if $r == 00
r = $b
else
r = call gcd( $b, $r )
endif
prompt on
return $r
ExtEuclid:
prompt off
local a = getpara
local b = getpara
local x_abs = getpara
local x_sign = getpara
local y_abs = getpara
local y_sign = getpara
local x
local g
local tmp
if $b == 00
x = set_value( $x_abs, 01 )
x = set_value( $x_sign, 01 )
x = set_value( $y_abs, 00 )
x = set_value( $y_sign, 01 )
g = $a
else
local x1_abs
local y1_abs
local x1_sign
local y1_sign
tmp = big_mod( $a, $b )
g = call exteuclid( $b, $tmp, &x1_abs, &x1_sign, &y1_abs, &y1_sign )
x = set_value( $x_abs, $y1_abs )
x = set_value( $x_sign, $y1_sign )
local k
local t_abs
local t_sign
local bigA
local bigAS
local bigB
local bigBS
k = big_div( $a, $b )
t_abs = big_mul( $y1_abs, $k )
t_sign = $y1_sign
bigA = $x1_abs
bigAS = $x1_sign
bigB = $t_abs
bigBS = $t_sign
if $bigbs == 01
bigbs = 00
else
bigbs = 01
endif
if $bigas == $bigbs
tmp = big_add( $biga, $bigb )
x = setvalue( $y_abs, $tmp )
x = setvalue( $y_sign, $bigas )
else
if $biga >= $bigb
tmp = big_sub( $biga, $bigb )
x = setvalue( $y_abs, $tmp )
x = setvalue( $y_sign, $bigas )
else
tmp = big_sub( $bigb, $biga )
x = setvalue( $y_abs, $tmp )
x = setvalue( $y_sign, $bigbs )
endif
endif
endif
prompt on
return $g
// long long ModInv(long long a, long long m)
// {
// long long x_abs, y_abs;
// int x_sign, y_sign;
// long long g = ExtEuclid(a, m,
// &x_abs, &x_sign,
// &y_abs, &y_sign);
// if (g != 1)
// return -1; /* 不存在逆元 */
// /* 还原 x,但这是最终一步,允许一次负数 */
// if (x_sign < 0)
// x_abs = m - (x_abs % m);
// return x_abs % m;
// }
ModInv:
prompt off
local a = getpara
local m = getpara
local swap_flag = getpara
local x_abs
local y_abs
local x_sign
local y_sign
local g
local res
local tmp
// 检查是否经过数据交易,要求a < m
if $a > $m
tmp = $a
a = $m
m = $tmp
g = setvalue( $swap_flag, 01 )
else
g = setvalue( $swap_flag, 00 )
endif
g = call exteuclid( $a, $m, &x_abs, &x_sign, &y_abs, &y_sign )
if $g != 01
res = 00
else
if $x_sign == 00 // 负数
tmp = big_mod( $x_abs, $m )
x_abs = big_sub( $m, $tmp )
endif
endif
res = big_mod( $x_abs, $m )
prompt on
return $res