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
40 For bitwise operators, hoist the conditionals out of their main loop
42 namespace System.Numerics {
\r
43 public struct BigInteger : IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
49 static readonly uint[] ZERO = new uint [1];
50 static readonly uint[] ONE = new uint [1] { 1 };
52 BigInteger (short sign, uint[] data)
58 public BigInteger (int value)
63 } else if (value > 0) {
65 data = new uint[] { (uint) value };
68 data = new uint[1] { (uint)-value };
72 [CLSCompliantAttribute (false)]
73 public BigInteger (uint value)
80 data = new uint [1] { value };
84 public BigInteger (long value)
89 } else if (value > 0) {
91 uint low = (uint)value;
92 uint high = (uint)(value >> 32);
94 data = new uint [high != 0 ? 2 : 1];
101 uint low = (uint)value;
102 uint high = (uint)((ulong)value >> 32);
104 data = new uint [high != 0 ? 2 : 1];
111 [CLSCompliantAttribute (false)]
112 public BigInteger (ulong value)
119 uint low = (uint)value;
120 uint high = (uint)(value >> 32);
122 data = new uint [high != 0 ? 2 : 1];
129 [CLSCompliantAttribute (false)]
130 public BigInteger (byte[] value)
133 throw new ArgumentNullException ("value");
135 int len = value.Length;
137 if (len == 0 || (len == 1 && value [0] == 0)) {
143 if ((value [len - 1] & 0x80) != 0)
149 while (value [len - 1] == 0)
152 int full_words, size;
153 full_words = size = len / 4;
154 if ((len & 0x3) != 0)
157 data = new uint [size];
159 for (int i = 0; i < full_words; ++i) {
160 data [i] = (uint)value [j++] |
161 (uint)(value [j++] << 8) |
162 (uint)(value [j++] << 16) |
163 (uint)(value [j++] << 24);
167 int idx = data.Length - 1;
168 for (int i = 0; i < size; ++i)
169 data [idx] |= (uint)(value [j++] << (i * 8));
172 int full_words, size;
173 full_words = size = len / 4;
174 if ((len & 0x3) != 0)
177 data = new uint [size];
179 uint word, borrow = 1;
183 for (int i = 0; i < full_words; ++i) {
184 word = (uint)value [j++] |
185 (uint)(value [j++] << 8) |
186 (uint)(value [j++] << 16) |
187 (uint)(value [j++] << 24);
189 sub = (ulong)word - borrow;
191 borrow = (uint)(sub >> 32) & 0x1u;
199 for (int i = 0; i < size; ++i) {
200 word |= (uint)(value [j++] << (i * 8));
201 store_mask = (store_mask << 8) | 0xFF;
206 borrow = (uint)(sub >> 32) & 0x1u;
208 data [data.Length - 1] = ~word & store_mask;
210 if (borrow != 0) //FIXME I believe this can't happen, can someone write a test for it?
211 throw new Exception ("non zero final carry");
217 get { return (data [0] & 0x1) == 0; }
221 get { return sign == 1 && data.Length == 1 && data [0] == 1; }
225 //Gem from Hacker's Delight
226 //Returns the number of bits set in @x
227 static int PopulationCount (uint x)
229 x = x - ((x >> 1) & 0x55555555);
230 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
231 x = (x + (x >> 4)) & 0x0F0F0F0F;
234 return (int)(x & 0x0000003F);
237 public bool IsPowerOfTwo {
239 bool foundBit = false;
242 //This function is pop count == 1 for positive numbers
243 for (int i = 0; i < data.Length; ++i) {
244 int p = PopulationCount (data [i]);
246 if (p > 1 || foundBit)
256 get { return sign == 0; }
263 public static BigInteger MinusOne {
264 get { return new BigInteger (-1, ONE); }
267 public static BigInteger One {
268 get { return new BigInteger (1, ONE); }
271 public static BigInteger Zero {
272 get { return new BigInteger (0, ZERO); }
275 public static explicit operator int (BigInteger value)
277 if (value.data.Length > 1)
278 throw new OverflowException ();
279 uint data = value.data [0];
281 if (value.sign == 1) {
282 if (data > (uint)int.MaxValue)
283 throw new OverflowException ();
285 } else if (value.sign == -1) {
286 if (data > 0x80000000u)
287 throw new OverflowException ();
294 [CLSCompliantAttribute (false)]
295 public static explicit operator uint (BigInteger value)
297 if (value.data.Length > 1 || value.sign == -1)
298 throw new OverflowException ();
299 return value.data [0];
302 public static explicit operator long (BigInteger value)
307 if (value.data.Length > 2)
308 throw new OverflowException ();
310 uint low = value.data [0];
312 if (value.data.Length == 1) {
315 long res = (long)low;
319 uint high = value.data [1];
321 if (value.sign == 1) {
322 if (high >= 0x80000000u)
323 throw new OverflowException ();
324 return (((long)high) << 32) | low;
327 if (high > 0x80000000u)
328 throw new OverflowException ();
330 return - ((((long)high) << 32) | (long)low);
333 [CLSCompliantAttribute (false)]
334 public static explicit operator ulong (BigInteger value)
336 if (value.data.Length > 2 || value.sign == -1)
337 throw new OverflowException ();
339 uint low = value.data [0];
340 if (value.data.Length == 1)
343 uint high = value.data [1];
344 return (((ulong)high) << 32) | low;
348 public static implicit operator BigInteger (int value)
350 return new BigInteger (value);
353 [CLSCompliantAttribute (false)]
354 public static implicit operator BigInteger (uint value)
356 return new BigInteger (value);
359 public static implicit operator BigInteger (long value)
361 return new BigInteger (value);
364 [CLSCompliantAttribute (false)]
365 public static implicit operator BigInteger (ulong value)
367 return new BigInteger (value);
370 public static BigInteger operator+ (BigInteger left, BigInteger right)
377 if (left.sign == right.sign)
378 return new BigInteger (left.sign, CoreAdd (left.data, right.data));
380 int r = CoreCompare (left.data, right.data);
383 return new BigInteger (0, ZERO);
385 if (r > 0) //left > right
386 return new BigInteger (left.sign, CoreSub (left.data, right.data));
388 return new BigInteger (right.sign, CoreSub (right.data, left.data));
391 public static BigInteger operator- (BigInteger left, BigInteger right)
396 return new BigInteger ((short)-right.sign, right.data);
398 if (left.sign == right.sign) {
399 int r = CoreCompare (left.data, right.data);
402 return new BigInteger (0, ZERO);
404 if (r > 0) //left > right
405 return new BigInteger (left.sign, CoreSub (left.data, right.data));
407 return new BigInteger ((short)-right.sign, CoreSub (right.data, left.data));
410 return new BigInteger (left.sign, CoreAdd (left.data, right.data));
413 public static BigInteger operator- (BigInteger value)
417 return new BigInteger ((short)-value.sign, value.data);
420 public static BigInteger operator+ (BigInteger value)
425 public static BigInteger operator++ (BigInteger value)
427 short sign = value.sign;
428 uint[] data = value.data;
429 if (data.Length == 1) {
430 if (sign == -1 && data [0] == 1)
431 return new BigInteger (0, ZERO);
433 return new BigInteger (1, ONE);
437 data = CoreSub (data, 1);
439 data = CoreAdd (data, 1);
441 return new BigInteger (sign, data);
444 public static BigInteger operator-- (BigInteger value)
446 short sign = value.sign;
447 uint[] data = value.data;
448 if (data.Length == 1) {
449 if (sign == 1 && data [0] == 1)
450 return new BigInteger (0, ZERO);
452 return new BigInteger (-1, ONE);
456 data = CoreAdd (data, 1);
458 data = CoreSub (data, 1);
460 return new BigInteger (sign, data);
463 public static BigInteger operator& (BigInteger left, BigInteger right)
471 uint[] a = left.data;
472 uint[] b = right.data;
476 bool neg_res = (ls == rs) && (ls == -1);
478 uint[] result = new uint [Math.Max (a.Length, b.Length)];
480 ulong ac = 1, bc = 1, borrow = 1;
483 for (i = 0; i < result.Length; ++i) {
490 ac = (uint)(ac >> 32);
499 bc = (uint)(bc >> 32);
505 borrow = word - borrow;
506 word = ~(uint)borrow;
507 borrow = (uint)(borrow >> 32) & 0x1u;
513 for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
515 return new BigInteger (0, ZERO);
517 if (i < result.Length - 1)
518 result = Resize (result, i + 1);
520 return new BigInteger (neg_res ? (short)-1 : (short)1, result);
523 public static BigInteger operator| (BigInteger left, BigInteger right)
531 uint[] a = left.data;
532 uint[] b = right.data;
536 bool neg_res = (ls == -1) || (rs == -1);
538 uint[] result = new uint [Math.Max (a.Length, b.Length)];
540 ulong ac = 1, bc = 1, borrow = 1;
543 for (i = 0; i < result.Length; ++i) {
550 ac = (uint)(ac >> 32);
559 bc = (uint)(bc >> 32);
565 borrow = word - borrow;
566 word = ~(uint)borrow;
567 borrow = (uint)(borrow >> 32) & 0x1u;
573 for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
575 return new BigInteger (0, ZERO);
577 if (i < result.Length - 1)
578 result = Resize (result, i + 1);
580 return new BigInteger (neg_res ? (short)-1 : (short)1, result);
583 public static BigInteger operator^ (BigInteger left, BigInteger right)
591 uint[] a = left.data;
592 uint[] b = right.data;
596 bool neg_res = (ls == -1) ^ (rs == -1);
598 uint[] result = new uint [Math.Max (a.Length, b.Length)];
600 ulong ac = 1, bc = 1, borrow = 1;
603 for (i = 0; i < result.Length; ++i) {
610 ac = (uint)(ac >> 32);
619 bc = (uint)(bc >> 32);
625 borrow = word - borrow;
626 word = ~(uint)borrow;
627 borrow = (uint)(borrow >> 32) & 0x1u;
633 for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
635 return new BigInteger (0, ZERO);
637 if (i < result.Length - 1)
638 result = Resize (result, i + 1);
640 return new BigInteger (neg_res ? (short)-1 : (short)1, result);
643 public static BigInteger operator~ (BigInteger value)
646 return new BigInteger (-1, ONE);
648 uint[] data = value.data;
649 int sign = value.sign;
651 bool neg_res = sign == 1;
653 uint[] result = new uint [data.Length];
655 ulong carry = 1, borrow = 1;
658 for (i = 0; i < result.Length; ++i) {
659 uint word = data [i];
661 carry = ~word + carry;
663 carry = (uint)(carry >> 32);
669 borrow = word - borrow;
670 word = ~(uint)borrow;
671 borrow = (uint)(borrow >> 32) & 0x1u;
677 for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
679 return new BigInteger (0, ZERO);
681 if (i < result.Length - 1)
682 result = Resize (result, i + 1);
684 return new BigInteger (neg_res ? (short)-1 : (short)1, result);
687 public static bool operator< (BigInteger left, BigInteger right)
689 return Compare (left, right) < 0;
692 public static bool operator< (BigInteger left, long right)
694 return left.CompareTo (right) < 0;
698 public static bool operator< (long left, BigInteger right)
700 return right.CompareTo (left) > 0;
704 [CLSCompliantAttribute (false)]
705 public static bool operator< (BigInteger left, ulong right)
707 return left.CompareTo (right) < 0;
710 [CLSCompliantAttribute (false)]
711 public static bool operator< (ulong left, BigInteger right)
713 return right.CompareTo (left) > 0;
716 public static bool operator<= (BigInteger left, BigInteger right)
718 return Compare (left, right) <= 0;
721 public static bool operator<= (BigInteger left, long right)
723 return left.CompareTo (right) <= 0;
726 public static bool operator<= (long left, BigInteger right)
728 return right.CompareTo (left) >= 0;
731 [CLSCompliantAttribute (false)]
732 public static bool operator<= (BigInteger left, ulong right)
734 return left.CompareTo (right) <= 0;
737 [CLSCompliantAttribute (false)]
738 public static bool operator<= (ulong left, BigInteger right)
740 return right.CompareTo (left) >= 0;
743 public static bool operator> (BigInteger left, BigInteger right)
745 return Compare (left, right) > 0;
748 public static bool operator> (BigInteger left, long right)
750 return left.CompareTo (right) > 0;
753 public static bool operator> (long left, BigInteger right)
755 return right.CompareTo (left) < 0;
758 [CLSCompliantAttribute (false)]
759 public static bool operator> (BigInteger left, ulong right)
761 return left.CompareTo (right) > 0;
764 [CLSCompliantAttribute (false)]
765 public static bool operator> (ulong left, BigInteger right)
767 return right.CompareTo (left) < 0;
770 public static bool operator>= (BigInteger left, BigInteger right)
772 return Compare (left, right) >= 0;
775 public static bool operator>= (BigInteger left, long right)
777 return left.CompareTo (right) >= 0;
780 public static bool operator>= (long left, BigInteger right)
782 return right.CompareTo (left) <= 0;
785 [CLSCompliantAttribute (false)]
786 public static bool operator>= (BigInteger left, ulong right)
788 return left.CompareTo (right) >= 0;
791 [CLSCompliantAttribute (false)]
792 public static bool operator>= (ulong left, BigInteger right)
794 return right.CompareTo (left) <= 0;
797 public static bool operator== (BigInteger left, BigInteger right)
799 return Compare (left, right) == 0;
802 public static bool operator== (BigInteger left, long right)
804 return left.CompareTo (right) == 0;
807 public static bool operator== (long left, BigInteger right)
809 return right.CompareTo (left) == 0;
812 [CLSCompliantAttribute (false)]
813 public static bool operator== (BigInteger left, ulong right)
815 return left.CompareTo (right) == 0;
818 [CLSCompliantAttribute (false)]
819 public static bool operator== (ulong left, BigInteger right)
821 return right.CompareTo (left) == 0;
824 public static bool operator!= (BigInteger left, BigInteger right)
826 return Compare (left, right) != 0;
829 public static bool operator!= (BigInteger left, long right)
831 return left.CompareTo (right) != 0;
834 public static bool operator!= (long left, BigInteger right)
836 return right.CompareTo (left) != 0;
839 [CLSCompliantAttribute (false)]
840 public static bool operator!= (BigInteger left, ulong right)
842 return left.CompareTo (right) != 0;
845 [CLSCompliantAttribute (false)]
846 public static bool operator!= (ulong left, BigInteger right)
848 return right.CompareTo (left) != 0;
851 public override bool Equals (object obj)
853 if (!(obj is BigInteger))
855 return Equals ((BigInteger)obj);
858 public bool Equals (BigInteger other)
860 if (sign != other.sign)
862 if (data.Length != other.data.Length)
864 for (int i = 0; i < data.Length; ++i) {
865 if (data [i] != other.data [i])
871 public bool Equals (long other)
873 return CompareTo (other) == 0;
876 public static BigInteger Min (BigInteger left, BigInteger right)
886 int r = CoreCompare (left.data, right.data);
896 public static BigInteger Max (BigInteger left, BigInteger right)
906 int r = CoreCompare (left.data, right.data);
915 public static BigInteger Abs (BigInteger value)
917 return new BigInteger ((short)Math.Abs (value.sign), value.data);
920 [CLSCompliantAttribute (false)]
921 public bool Equals (ulong other)
923 return CompareTo (other) == 0;
926 public override int GetHashCode ()
928 uint hash = (uint)(sign * 0x01010101u);
930 for (int i = 0; i < data.Length; ++i)
935 public static BigInteger Add (BigInteger left, BigInteger right)
940 public static BigInteger Subtract (BigInteger left, BigInteger right)
945 public static BigInteger Negate (BigInteger value)
950 public int CompareTo (object obj)
955 if (!(obj is BigInteger))
958 return Compare (this, (BigInteger)obj);
961 public int CompareTo (BigInteger other)
963 return Compare (this, other);
966 [CLSCompliantAttribute (false)]
967 public int CompareTo (ulong other)
972 return other == 0 ? 0 : -1;
977 uint high = (uint)(other >> 32);
978 uint low = (uint)other;
980 return LongCompare (low, high);
983 int LongCompare (uint low, uint high)
1004 public int CompareTo (long other)
1007 int rs = Math.Sign (other);
1010 return ls > rs ? 1 : -1;
1015 if (data.Length > 2)
1020 uint low = (uint)other;
1021 uint high = (uint)((ulong)other >> 32);
1023 int r = LongCompare (low, high);
1030 public static int Compare (BigInteger left, BigInteger right)
1033 int rs = right.sign;
1036 return ls > rs ? 1 : -1;
1038 int r = CoreCompare (left.data, right.data);
1045 static int TopByte (uint x)
1047 if ((x & 0xFFFF0000u) != 0) {
1048 if ((x & 0xFF000000u) != 0)
1052 if ((x & 0xFF00u) != 0)
1057 static int FirstNonFFByte (uint word)
1059 if ((word & 0xFF000000u) != 0xFF000000u)
1061 else if ((word & 0xFF0000u) != 0xFF0000u)
1063 else if ((word & 0xFF00u) != 0xFF00u)
1068 public byte[] ToByteArray ()
1071 return new byte [1];
1073 //number of bytes not counting upper word
1074 int bytes = (data.Length - 1) * 4;
1075 bool needExtraZero = false;
1077 uint topWord = data [data.Length - 1];
1080 //if the topmost bit is set we need an extra
1082 extra = TopByte (topWord);
1083 uint mask = 0x80u << ((extra - 1) * 8);
1084 if ((topWord & mask) != 0) {
1085 needExtraZero = true;
1088 extra = TopByte (topWord);
1091 byte[] res = new byte [bytes + extra + (needExtraZero ? 1 : 0) ];
1094 int end = data.Length - 1;
1095 for (int i = 0; i < end; ++i) {
1096 uint word = data [i];
1098 res [j++] = (byte)word;
1099 res [j++] = (byte)(word >> 8);
1100 res [j++] = (byte)(word >> 16);
1101 res [j++] = (byte)(word >> 24);
1103 while (extra-- > 0) {
1104 res [j++] = (byte)topWord;
1109 int end = data.Length - 1;
1111 uint carry = 1, word;
1113 for (int i = 0; i < end; ++i) {
1115 add = (ulong)~word + carry;
1117 carry = (uint)(add >> 32);
1119 res [j++] = (byte)word;
1120 res [j++] = (byte)(word >> 8);
1121 res [j++] = (byte)(word >> 16);
1122 res [j++] = (byte)(word >> 24);
1125 add = (ulong)~topWord + (carry);
1127 carry = (uint)(add >> 32);
1129 int ex = FirstNonFFByte (word);
1130 bool needExtra = (word & (1 << (ex * 8 - 1))) == 0;
1131 int to = ex + (needExtra ? 1 : 0);
1134 res = Resize (res, bytes + to);
1137 res [j++] = (byte)word;
1143 res = Resize (res, bytes + 5);
1144 res [j++] = (byte)word;
1145 res [j++] = (byte)(word >> 8);
1146 res [j++] = (byte)(word >> 16);
1147 res [j++] = (byte)(word >> 24);
1155 static byte[] Resize (byte[] v, int len)
1157 byte[] res = new byte [len];
\r
1158 Array.Copy (v, res, Math.Min (v.Length, len));
\r
1162 static uint[] Resize (uint[] v, int len)
1164 uint[] res = new uint [len];
\r
1165 Array.Copy (v, res, Math.Min (v.Length, len));
\r
1169 static uint[] CoreAdd (uint[] a, uint[] b)
1171 if (a.Length < b.Length) {
1180 uint[] res = new uint [bl];
1185 for (; i < sl; i++) {
1186 sum = sum + a [i] + b [i];
1187 res [i] = (uint)sum;
1191 for (; i < bl; i++) {
1193 res [i] = (uint)sum;
1198 res = Resize (res, bl + 1);
1199 res [i] = (uint)sum;
1206 static uint[] CoreSub (uint[] a, uint[] b)
1211 uint[] res = new uint [bl];
1215 for (i = 0; i < sl; ++i) {
1216 borrow = (ulong)a [i] - b [i] - borrow;
1218 res [i] = (uint)borrow;
1219 borrow = (borrow >> 32) & 0x1;
1222 for (; i < bl; i++) {
1223 borrow = (ulong)a [i] - borrow;
1224 res [i] = (uint)borrow;
1225 borrow = (borrow >> 32) & 0x1;
1228 //remove extra zeroes
1229 for (i = bl - 1; i >= 0 && res [i] == 0; --i) ;
1231 res = Resize (res, i + 1);
1237 static uint[] CoreAdd (uint[] a, uint b)
1240 uint[] res = new uint [len];
1244 for (i = 0; i < len; i++) {
1246 res [i] = (uint)sum;
1251 res = Resize (res, len + 1);
1252 res [i] = (uint)sum;
1258 static uint[] CoreSub (uint[] a, uint b)
1261 uint[] res = new uint [len];
1265 for (i = 0; i < len; i++) {
1266 borrow = (ulong)a [i] - borrow;
1267 res [i] = (uint)borrow;
1268 borrow = (borrow >> 32) & 0x1;
1271 //remove extra zeroes
1272 for (i = len - 1; i >= 0 && res [i] == 0; --i) ;
1274 res = Resize (res, i + 1);
1279 static int CoreCompare (uint[] a, uint[] b)
1289 for (int i = al - 1; i >= 0; --i) {