Modular inverse: Difference between revisions
Content added Content deleted
(Modular inverse in BASIC256) |
|||
Line 216: | Line 216: | ||
<pre>1969</pre> |
<pre>1969</pre> |
||
=={{header|ATS}}== |
|||
In addition to solving the task, I demonstrate some aspects of call-by-reference in ATS. In particular, ATS can distinguish ''at compile time'' between uninitialized and initialized variables. |
|||
<syntaxhighlight lang="ats"> |
|||
(* |
|||
Using the algorithm described at |
|||
https://en.wikipedia.org/w/index.php?title=Extended_Euclidean_algorithm&oldid=1135569411#Modular_integers |
|||
*) |
|||
#include "share/atspre_staload.hats" |
|||
fn {tk : tkind} |
|||
division_with_nonnegative_remainder |
|||
(n : g0int tk, d : g0int tk, |
|||
(* q and r are called by reference, and start out |
|||
uninitialized. *) |
|||
q : &g0int tk? >> g0int tk, |
|||
r : &g0int tk? >> g0int tk) |
|||
: void = |
|||
let |
|||
(* The C optimizer most likely will reduce these these two |
|||
divisions to just one. They are simply synonyms for C '/' and |
|||
'%', and perform division that rounds the quotient towards |
|||
zero. *) |
|||
val q0 = g0int_div (n, d) |
|||
val r0 = g0int_mod (n, d) |
|||
in |
|||
(* The following calculation results in 'floor division', if the |
|||
divisor is positive, or 'ceiling division', if the divisor is |
|||
negative. This choice of method results in the remainder never |
|||
being negative. *) |
|||
if isgtez n || iseqz r0 then |
|||
(q := q0; r := r0) |
|||
else if isltz d then |
|||
(q := succ q0; r := r0 - d) |
|||
else |
|||
(q := pred q0; r := r0 + d) |
|||
end |
|||
fn {tk : tkind} |
|||
inverse (a : g0int tk, n : g0int tk) : Option_vt (g0int tk) = |
|||
let |
|||
typedef integer = g0int tk |
|||
fun |
|||
loop (t : integer, newt : integer, |
|||
r : integer, newr : integer) : Option_vt integer = |
|||
if iseqz newr then |
|||
begin |
|||
if r > g0i2i 1 then |
|||
None_vt () |
|||
else if t < g0i2i 0 then |
|||
Some_vt (t + n) |
|||
else |
|||
Some_vt t |
|||
end |
|||
else |
|||
let |
|||
(* These become C variables. *) |
|||
var quotient : g0int tk? |
|||
var remainder : g0int tk? |
|||
(* Show the type AT COMPILE TIME. *) |
|||
prval _ = $showtype quotient |
|||
prval _ = $showtype remainder |
|||
val () = |
|||
division_with_nonnegative_remainder |
|||
(r, newr, quotient, remainder) |
|||
(* THE TYPES WILL HAVE CHANGED, because the storage is |
|||
initialized by the call to |
|||
division_with_nonnegative_remainder. *) |
|||
prval _ = $showtype quotient |
|||
prval _ = $showtype remainder |
|||
val t = newt |
|||
and newt = t - (quotient * newt) |
|||
and r = newr |
|||
and newr = remainder |
|||
in |
|||
loop (t, newt, r, newr) |
|||
end |
|||
in |
|||
loop (g0i2i 0, g0i2i 1, n, a) |
|||
end |
|||
implement |
|||
main0 () = |
|||
case+ inverse (42LL, 2017LL) of |
|||
| ~ None_vt () => println! "There is no inverse." |
|||
| ~ Some_vt value => println! value |
|||
</syntaxhighlight> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |