------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- This file is part of 'Finite Field Arithmetic', aka 'FFA'. -- -- -- -- (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) -- -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- -- -- -- You do not have, nor can you ever acquire the right to use, copy or -- -- distribute this software ; Should you use this software for any purpose, -- -- or copy and distribute it to anyone or in any manner, you are breaking -- -- the laws of whatever soi-disant jurisdiction, and you promise to -- -- continue doing so for the indefinite future. In any case, please -- -- always : read and understand any software ; verify any PGP signatures -- -- that you use - for any purpose. -- -- -- -- See also http://trilema.com/2015/a-new-software-licensing-paradigm . -- ------------------------------------------------------------------------------ with Words; use Words; with FZ_Basic; use FZ_Basic; with FZ_Shift; use FZ_Shift; with FZ_QShft; use FZ_QShft; with FZ_Arith; use FZ_Arith; with FZ_BitOp; use FZ_BitOp; with FZ_Pred; use FZ_Pred; package body FZ_GCD is -- Find Greatest Common Divisor (GCD) of X and Y. -- Note that by convention, GCD(0, 0) = 0. procedure FZ_Greatest_Common_Divisor(X : in FZ; Y : in FZ; Result : out FZ) is -- Widths of X, Y, and Result are equal subtype Width is Word_Index range X'Range; -- Working buffers for GCD computation, initially equal to the inputs A : FZ(Width) := X; B : FZ(Width) := Y; -- Evenness (negation of lowest bit) of A and B respectively Ae, Be : WBool; -- Common power-of-2 factor: incremented when Ae and Be are both 1 Twos : Word := 0; -- This flag is set when A and B are BOTH ODD OO : WBool; -- |A - B| D : FZ(Width); -- This flag is set iff A < B A_lt_B : WBool; begin -- To converge, requires number of shots equal to (2 * FZ_Bitness) - 1: for i in 1 .. (2 * FZ_Bitness(X)) - 1 loop -- Whether A and B are currently BOTH ODD : OO := FZ_OddP(A) and FZ_OddP(B); -- D := |A - B| FZ_Sub_Abs(X => A, Y => B, Difference => D, Underflow => A_lt_B); -- IFF A,B both ODD, and A < B : B' := A ; otherwise no change : FZ_Mux(X => B, Y => A, Result => B, Sel => OO and A_lt_B); -- IFF A,B both ODD: A' := |A - B| ; otherwise no change : FZ_Mux(X => A, Y => D, Result => A, Sel => OO); -- If A is now EVEN: A := A >> 1; otherwise no change Ae := 1 - FZ_OddP(A); FZ_ShiftRight(A, A, WBit_Index(Ae)); -- If B is now EVEN: B := B >> 1; otherwise no change Be := 1 - FZ_OddP(B); FZ_ShiftRight(B, B, WBit_Index(Be)); -- If both A and B were even, increment the common power-of-two Twos := Twos + (Ae and Be); end loop; -- Normally, B will contain the GCD, but in the (N,0) N > 0 case -- A. -- The other variable will always equal 0. Hence, take Bitwise-OR(A,B): FZ_Or(X => A, Y => B, Result => A); -- Reintroduce the common power-of-2 factor stored in 'Twos' FZ_Quiet_ShiftLeft(N => A, ShiftedN => A, Count => Indices(Twos)); -- Output final result -- the GCD. Result := A; end FZ_Greatest_Common_Divisor; end FZ_GCD;