2 // System.Numerics.BigInteger
4 // Rodrigo Kumpera (rkumpera@novell.com)
7 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections.Generic;
\r
30 using System.Diagnostics;
\r
31 using System.Diagnostics.CodeAnalysis;
\r
32 using System.Globalization;
\r
37 Have proper popcount function for IsPowerOfTwo
38 Use unsafe ops to avoid bounds check
39 CoreAdd could avoid some resizes by checking for equal sized array that top overflow
41 namespace System.Numerics {
\r
42 public struct BigInteger : IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
48 static readonly uint[] ZERO = new uint [1];
49 static readonly uint[] ONE = new uint [1] { 1 };
51 BigInteger (short sign, uint[] data)
57 public BigInteger (int value)
62 } else if (value > 0) {
64 data = new uint[] { (uint) value };
67 data = new uint[1] { (uint)-value };
71 [CLSCompliantAttribute (false)]
72 public BigInteger (uint value)
79 data = new uint [1] { value };
83 public BigInteger (long value)
88 } else if (value > 0) {
90 uint low = (uint)value;
91 uint high = (uint)(value >> 32);
93 data = new uint [high != 0 ? 2 : 1];
100 uint low = (uint)value;
101 uint high = (uint)((ulong)value >> 32);
103 data = new uint [high != 0 ? 2 : 1];
110 [CLSCompliantAttribute (false)]
111 public BigInteger (ulong value)
118 uint low = (uint)value;
119 uint high = (uint)(value >> 32);
121 data = new uint [high != 0 ? 2 : 1];
128 [CLSCompliantAttribute (false)]
129 public BigInteger (byte[] value)
132 throw new ArgumentNullException ("value");
134 int len = value.Length;
136 if (len == 0 || (len == 1 && value [0] == 0)) {
142 if ((value [len - 1] & 0x80) != 0)
148 while (value [len - 1] == 0)
151 int full_words, size;
152 full_words = size = len / 4;
153 if ((len & 0x3) != 0)
156 data = new uint [size];
158 for (int i = 0; i < full_words; ++i) {
159 data [i] = (uint)value [j++] |
160 (uint)(value [j++] << 8) |
161 (uint)(value [j++] << 16) |
162 (uint)(value [j++] << 24);
166 int idx = data.Length - 1;
167 for (int i = 0; i < size; ++i)
168 data [idx] |= (uint)(value [j++] << (i * 8));
171 int full_words, size;
172 full_words = size = len / 4;
173 if ((len & 0x3) != 0)
176 data = new uint [size];
178 uint word, borrow = 1;
182 for (int i = 0; i < full_words; ++i) {
183 word = (uint)value [j++] |
184 (uint)(value [j++] << 8) |
185 (uint)(value [j++] << 16) |
186 (uint)(value [j++] << 24);
188 sub = (ulong)word - borrow;
190 borrow = (uint)(sub >> 32) & 0x1u;
198 for (int i = 0; i < size; ++i) {
199 word |= (uint)(value [j++] << (i * 8));
200 store_mask = (store_mask << 8) | 0xFF;
205 borrow = (uint)(sub >> 32) & 0x1u;
207 data [data.Length - 1] = ~word & store_mask;
209 if (borrow != 0) //FIXME I believe this can't happen, can someone write a test for it?
210 throw new Exception ("non zero final carry");
216 get { return (data [0] & 0x1) == 0; }
220 get { return sign == 1 && data.Length == 1 && data [0] == 1; }
224 //Gem from Hacker's Delight
225 //Returns the number of bits set in @x
226 static int PopulationCount (uint x)
228 x = x - ((x >> 1) & 0x55555555);
229 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
230 x = (x + (x >> 4)) & 0x0F0F0F0F;
233 return (int)(x & 0x0000003F);
236 public bool IsPowerOfTwo {
238 bool foundBit = false;
241 //This function is pop count == 1 for positive numbers
242 for (int i = 0; i < data.Length; ++i) {
243 int p = PopulationCount (data [i]);
245 if (p > 1 || foundBit)
255 get { return sign == 0; }
262 public static BigInteger MinusOne {
263 get { return new BigInteger (-1, ONE); }
266 public static BigInteger One {
267 get { return new BigInteger (1, ONE); }
270 public static BigInteger Zero {
271 get { return new BigInteger (0, ZERO); }
274 public static explicit operator int (BigInteger value)
276 if (value.data.Length > 1)
277 throw new OverflowException ();
278 uint data = value.data [0];
280 if (value.sign == 1) {
281 if (data > (uint)int.MaxValue)
282 throw new OverflowException ();
284 } else if (value.sign == -1) {
285 if (data > 0x80000000u)
286 throw new OverflowException ();
293 [CLSCompliantAttribute (false)]
294 public static explicit operator uint (BigInteger value)
296 if (value.data.Length > 1 || value.sign == -1)
297 throw new OverflowException ();
298 return value.data [0];
301 public static explicit operator long (BigInteger value)
306 if (value.data.Length > 2)
307 throw new OverflowException ();
309 uint low = value.data [0];
311 if (value.data.Length == 1) {
314 long res = (long)low;
318 uint high = value.data [1];
320 if (value.sign == 1) {
321 if (high >= 0x80000000u)
322 throw new OverflowException ();
323 return (((long)high) << 32) | low;
326 if (high > 0x80000000u)
327 throw new OverflowException ();
329 return - ((((long)high) << 32) | (long)low);
332 [CLSCompliantAttribute (false)]
333 public static explicit operator ulong (BigInteger value)
335 if (value.data.Length > 2 || value.sign == -1)
336 throw new OverflowException ();
338 uint low = value.data [0];
339 if (value.data.Length == 1)
342 uint high = value.data [1];
343 return (((ulong)high) << 32) | low;
347 public static implicit operator BigInteger (int value)
349 return new BigInteger (value);
352 [CLSCompliantAttribute (false)]
353 public static implicit operator BigInteger (uint value)
355 return new BigInteger (value);
358 public static implicit operator BigInteger (long value)
360 return new BigInteger (value);
363 [CLSCompliantAttribute (false)]
364 public static implicit operator BigInteger (ulong value)
366 return new BigInteger (value);
369 public static BigInteger operator+ (BigInteger left, BigInteger right)
376 if (left.sign == right.sign)
377 return new BigInteger (left.sign, CoreAdd (left.data, right.data));
379 int r = CoreCompare (left.data, right.data);
382 return new BigInteger (0, ZERO);
384 if (r > 0) //left > right
385 return new BigInteger (left.sign, CoreSub (left.data, right.data));
387 return new BigInteger (right.sign, CoreSub (right.data, left.data));
390 public static bool operator< (BigInteger left, BigInteger right)
392 return Compare (left, right) < 0;
395 public static bool operator< (BigInteger left, long right)
397 return left.CompareTo (right) < 0;
401 public static bool operator< (long left, BigInteger right)
403 return right.CompareTo (left) > 0;
407 [CLSCompliantAttribute (false)]
408 public static bool operator< (BigInteger left, ulong right)
410 return left.CompareTo (right) < 0;
413 [CLSCompliantAttribute (false)]
414 public static bool operator< (ulong left, BigInteger right)
416 return right.CompareTo (left) > 0;
419 public static bool operator<= (BigInteger left, BigInteger right)
421 return Compare (left, right) <= 0;
424 public static bool operator<= (BigInteger left, long right)
426 return left.CompareTo (right) <= 0;
429 public static bool operator<= (long left, BigInteger right)
431 return right.CompareTo (left) >= 0;
434 [CLSCompliantAttribute (false)]
435 public static bool operator<= (BigInteger left, ulong right)
437 return left.CompareTo (right) <= 0;
440 [CLSCompliantAttribute (false)]
441 public static bool operator<= (ulong left, BigInteger right)
443 return right.CompareTo (left) >= 0;
446 public static bool operator> (BigInteger left, BigInteger right)
448 return Compare (left, right) > 0;
451 public static bool operator> (BigInteger left, long right)
453 return left.CompareTo (right) > 0;
456 public static bool operator> (long left, BigInteger right)
458 return right.CompareTo (left) < 0;
461 [CLSCompliantAttribute (false)]
462 public static bool operator> (BigInteger left, ulong right)
464 return left.CompareTo (right) > 0;
467 [CLSCompliantAttribute (false)]
468 public static bool operator> (ulong left, BigInteger right)
470 return right.CompareTo (left) < 0;
473 public static bool operator>= (BigInteger left, BigInteger right)
475 return Compare (left, right) >= 0;
478 public static bool operator>= (BigInteger left, long right)
480 return left.CompareTo (right) >= 0;
483 public static bool operator>= (long left, BigInteger right)
485 return right.CompareTo (left) <= 0;
488 [CLSCompliantAttribute (false)]
489 public static bool operator>= (BigInteger left, ulong right)
491 return left.CompareTo (right) >= 0;
494 [CLSCompliantAttribute (false)]
495 public static bool operator>= (ulong left, BigInteger right)
497 return right.CompareTo (left) <= 0;
500 public static bool operator== (BigInteger left, BigInteger right)
502 return Compare (left, right) == 0;
505 public static bool operator== (BigInteger left, long right)
507 return left.CompareTo (right) == 0;
510 public static bool operator== (long left, BigInteger right)
512 return right.CompareTo (left) == 0;
515 [CLSCompliantAttribute (false)]
516 public static bool operator== (BigInteger left, ulong right)
518 return left.CompareTo (right) == 0;
521 [CLSCompliantAttribute (false)]
522 public static bool operator== (ulong left, BigInteger right)
524 return right.CompareTo (left) == 0;
527 public static bool operator!= (BigInteger left, BigInteger right)
529 return Compare (left, right) != 0;
532 public static bool operator!= (BigInteger left, long right)
534 return left.CompareTo (right) != 0;
537 public static bool operator!= (long left, BigInteger right)
539 return right.CompareTo (left) != 0;
542 [CLSCompliantAttribute (false)]
543 public static bool operator!= (BigInteger left, ulong right)
545 return left.CompareTo (right) != 0;
548 [CLSCompliantAttribute (false)]
549 public static bool operator!= (ulong left, BigInteger right)
551 return right.CompareTo (left) != 0;
554 public override bool Equals (object obj)
556 if (!(obj is BigInteger))
558 return Equals ((BigInteger)obj);
561 public bool Equals (BigInteger other)
563 if (sign != other.sign)
565 if (data.Length != other.data.Length)
567 for (int i = 0; i < data.Length; ++i) {
568 if (data [i] != other.data [i])
574 public bool Equals (long other)
576 return CompareTo (other) == 0;
579 [CLSCompliantAttribute (false)]
580 public bool Equals (ulong other)
582 return CompareTo (other) == 0;
585 public override int GetHashCode ()
587 uint hash = (uint)(sign * 0x01010101u);
589 for (int i = 0; i < data.Length; ++i)
594 public static BigInteger Add (BigInteger left, BigInteger right)
599 public int CompareTo (object obj)
604 if (!(obj is BigInteger))
607 return Compare (this, (BigInteger)obj);
610 public int CompareTo (BigInteger other)
612 return Compare (this, other);
615 [CLSCompliantAttribute (false)]
616 public int CompareTo (ulong other)
621 return other == 0 ? 0 : -1;
626 uint high = (uint)(other >> 32);
627 uint low = (uint)other;
629 return LongCompare (low, high);
632 int LongCompare (uint low, uint high)
653 public int CompareTo (long other)
656 int rs = Math.Sign (other);
659 return ls > rs ? 1 : -1;
669 uint low = (uint)other;
670 uint high = (uint)((ulong)other >> 32);
672 int r = LongCompare (low, high);
679 public static int Compare (BigInteger left, BigInteger right)
685 return ls > rs ? 1 : -1;
687 int r = CoreCompare (left.data, right.data);
694 static int TopByte (uint x)
696 if ((x & 0xFFFF0000u) != 0) {
697 if ((x & 0xFF000000u) != 0)
701 if ((x & 0xFF00u) != 0)
706 static int FirstNonFFByte (uint word)
708 if ((word & 0xFF000000u) != 0xFF000000u)
710 else if ((word & 0xFF0000u) != 0xFF0000u)
712 else if ((word & 0xFF00u) != 0xFF00u)
717 public byte[] ToByteArray ()
722 //number of bytes not counting upper word
723 int bytes = (data.Length - 1) * 4;
724 bool needExtraZero = false;
726 uint topWord = data [data.Length - 1];
729 //if the topmost bit is set we need an extra
731 extra = TopByte (topWord);
732 uint mask = 0x80u << ((extra - 1) * 8);
733 if ((topWord & mask) != 0) {
734 needExtraZero = true;
737 extra = TopByte (topWord);
740 byte[] res = new byte [bytes + extra + (needExtraZero ? 1 : 0) ];
743 int end = data.Length - 1;
744 for (int i = 0; i < end; ++i) {
745 uint word = data [i];
747 res [j++] = (byte)word;
748 res [j++] = (byte)(word >> 8);
749 res [j++] = (byte)(word >> 16);
750 res [j++] = (byte)(word >> 24);
752 while (extra-- > 0) {
753 res [j++] = (byte)topWord;
758 int end = data.Length - 1;
760 uint carry = 1, word;
762 for (int i = 0; i < end; ++i) {
764 add = (ulong)~word + carry;
766 carry = (uint)(add >> 32);
768 res [j++] = (byte)word;
769 res [j++] = (byte)(word >> 8);
770 res [j++] = (byte)(word >> 16);
771 res [j++] = (byte)(word >> 24);
774 add = (ulong)~topWord + (carry);
776 carry = (uint)(add >> 32);
778 int ex = FirstNonFFByte (word);
779 bool needExtra = (word & (1 << (ex * 8 - 1))) == 0;
780 int to = ex + (needExtra ? 1 : 0);
783 res = Resize (res, bytes + to);
786 res [j++] = (byte)word;
792 res = Resize (res, bytes + 5);
793 res [j++] = (byte)word;
794 res [j++] = (byte)(word >> 8);
795 res [j++] = (byte)(word >> 16);
796 res [j++] = (byte)(word >> 24);
804 static byte[] Resize (byte[] v, int len)
806 byte[] res = new byte [len];
\r
807 Array.Copy (v, res, Math.Min (v.Length, len));
\r
811 static uint[] Resize (uint[] v, int len)
813 uint[] res = new uint [len];
\r
814 Array.Copy (v, res, Math.Min (v.Length, len));
\r
818 static uint[] CoreAdd (uint[] a, uint[] b)
820 if (a.Length < b.Length) {
829 uint[] res = new uint [bl];
834 for (; i < sl; i++) {
835 sum = sum + a [i] + b [i];
840 for (; i < bl; i++) {
847 res = Resize (res, bl + 1);
855 static uint[] CoreSub (uint[] a, uint[] b)
860 Console.WriteLine ("bl {0} sl {1}", bl, sl);
862 uint[] res = new uint [bl];
866 for (i = 0; i < sl; ++i) {
867 borrow = (ulong)a [i] - b [i] - borrow;
869 Console.WriteLine ("a {0} b {1}", a[i], b [i]);
871 res [i] = (uint)borrow;
872 borrow = (borrow >> 32) & 0x1;
875 for (; i < bl; i++) {
876 borrow = (ulong)a [i] - borrow;
877 res [i] = (uint)borrow;
878 borrow = (borrow >> 32) & 0x1;
881 //remove extra zeroes
882 for (i = bl - 1; i >= 0 && res [i] == 0; --i) ;
884 res = Resize (res, i + 1);
889 static int CoreCompare (uint[] a, uint[] b)
899 for (int i = al - 1; i >= 0; --i) {