1+ package com .thealgorithms .bitmanipulation ;
2+
3+ import java .math .BigInteger ;
4+
5+ /**
6+ * Bitwise GCD implementation with full-range support utilities.
7+ *
8+ * <p>This class provides a fast binary (Stein's) GCD implementation for {@code long}
9+ * inputs and a BigInteger-backed API for full 2's-complement range support (including
10+ * {@code Long.MIN_VALUE}). The {@code long} implementation is efficient and avoids
11+ * division/modulo operations. For edge-cases that overflow signed-64-bit ranges
12+ * (e.g., gcd(Long.MIN_VALUE, 0) = 2^63), use the BigInteger API {@code gcdBig}.
13+ *
14+ * <p>Behaviour:
15+ * <ul>
16+ * <li>{@code gcd(long,long)} : returns non-negative {@code long} gcd for inputs whose
17+ * absolute values fit in signed {@code long} (i.e., not causing an unsigned 2^63 result).
18+ * If the true gcd does not fit in a signed {@code long} (for example gcd(Long.MIN_VALUE,0) = 2^63)
19+ * this method will delegate to BigInteger and throw {@link ArithmeticException} if the
20+ * BigInteger result does not fit into a signed {@code long}.</li>
21+ * <li>{@code gcdBig(BigInteger, BigInteger)} : returns the exact gcd as a {@link BigInteger}
22+ * and works for the full signed-64-bit range and beyond.</li>
23+ * </ul>
24+ */
25+ public final class BitwiseGCD {
26+
27+ private BitwiseGCD () {}
28+
29+ /**
30+ * Computes GCD of two long values using Stein's algorithm (binary GCD).
31+ * <p>Handles negative inputs. If either input is {@code Long.MIN_VALUE} the
32+ * method delegates to the BigInteger implementation and will throw {@link ArithmeticException}
33+ * if the result cannot be represented as a signed {@code long}.
34+ *
35+ * @param a first value (may be negative)
36+ * @param b second value (may be negative)
37+ * @return non-negative gcd as a {@code long}
38+ * @throws ArithmeticException when the exact gcd does not fit into a signed {@code long}
39+ */
40+ public static long gcd (long a , long b ) {
41+ // Trivial cases
42+ if (a == 0L ) {
43+ return absOrThrowIfOverflow (b );
44+ }
45+ if (b == 0L ) {
46+ return absOrThrowIfOverflow (a );
47+ }
48+
49+ // If either is Long.MIN_VALUE, absolute value doesn't fit into signed long.
50+ if (a == Long .MIN_VALUE || b == Long .MIN_VALUE ) {
51+ // Delegate to BigInteger and try to return a long if it fits
52+ BigInteger g = gcdBig (BigInteger .valueOf (a ), BigInteger .valueOf (b ));
53+ try {
54+ return g .longValueExact ();
55+ } catch (ArithmeticException ex ) {
56+ throw new ArithmeticException ("GCD doesn't fit into signed long. Use gcdBig() for full-range result." );
57+ }
58+ }
59+
60+ // Work with non-negative long values now (safe because we excluded Long.MIN_VALUE)
61+ a = (a < 0 ) ? -a : a ;
62+ b = (b < 0 ) ? -b : b ;
63+
64+ // Count common factors of 2
65+ int commonTwos = Long .numberOfTrailingZeros (a | b );
66+
67+ // Remove all factors of 2 from a
68+ a >>= Long .numberOfTrailingZeros (a );
69+
70+ while (b != 0L ) {
71+ // Remove all factors of 2 from b
72+ b >>= Long .numberOfTrailingZeros (b );
73+
74+ // Now both a and b are odd. Ensure a <= b
75+ if (a > b ) {
76+ long tmp = a ;
77+ a = b ;
78+ b = tmp ;
79+ }
80+
81+ // b >= a; subtract a from b (result is even)
82+ b = b - a ;
83+ }
84+
85+ // Restore common powers of two
86+ return a << commonTwos ;
87+ }
88+
89+ /**
90+ * Helper to return absolute value of x unless x == Long.MIN_VALUE, in which
91+ * case we delegate to BigInteger and throw to indicate overflow.
92+ */
93+ private static long absOrThrowIfOverflow (long x ) {
94+ if (x == Long .MIN_VALUE ) {
95+ // |Long.MIN_VALUE| = 2^63 which does not fit into signed long
96+ throw new ArithmeticException ("Absolute value of Long.MIN_VALUE does not fit into signed long. Use gcdBig() for full-range support." );
97+ }
98+ return (x < 0 ) ? -x : x ;
99+ }
100+
101+ /**
102+ * Computes GCD for an array of {@code long} values. Returns 0 for empty/null arrays.
103+ * If any intermediate gcd cannot be represented in signed long (rare), an ArithmeticException
104+ * will be thrown.
105+ */
106+ public static long gcd (long ... values ) {
107+ if (values == null || values .length == 0 ) return 0L ;
108+ long result = values [0 ];
109+ for (int i = 1 ; i < values .length ; i ++) {
110+ result = gcd (result , values [i ]);
111+ if (result == 1L ) return 1L ; // early exit
112+ }
113+ return result ;
114+ }
115+
116+ /**
117+ * BigInteger-backed gcd that works for the full integer range (and beyond).
118+ * This is the recommended method when inputs may be Long.MIN_VALUE or when you
119+ * need an exact result even if it is greater than Long.MAX_VALUE.
120+ *
121+ * @param a first value (may be negative)
122+ * @param b second value (may be negative)
123+ * @return non-negative gcd as a {@link BigInteger}
124+ */
125+ public static BigInteger gcdBig (BigInteger a , BigInteger b ) {
126+ if (a == null || b == null ) throw new NullPointerException ("Arguments must not be null" );
127+ return a .abs ().gcd (b .abs ());
128+ }
129+
130+ /**
131+ * Convenience overload that accepts signed-64 inputs and returns BigInteger gcd.
132+ */
133+ public static BigInteger gcdBig (long a , long b ) {
134+ return gcdBig (BigInteger .valueOf (a ), BigInteger .valueOf (b ));
135+ }
136+
137+ /**
138+ * int overload for convenience.
139+ */
140+ public static int gcd (int a , int b ) {
141+ return (int ) gcd ((long ) a , (long ) b );
142+ }
143+
144+ /**
145+ * Demo main method. Remove in production; kept for ad-hoc running.
146+ */
147+ public static void main (String [] args ) {
148+ System .out .println ("gcd(48, 18) = " + gcd (48L , 18L ));
149+ System .out .println ("gcd(0, 5) = " + gcd (0L , 5L ));
150+ System .out .println ("gcd(270, 192) = " + gcd (270L , 192L ));
151+
152+ // BigInteger example with Long.MIN_VALUE
153+ BigInteger g = gcdBig (Long .MIN_VALUE , 0L );
154+ System .out .println ("gcdBig(Long.MIN_VALUE, 0) = " + g ); // prints 2^63
155+ }
156+ }
0 commit comments