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<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 };
68 if (value == int.MinValue)
69 data [0] = 0x80000000u;
71 data [0] = (uint)-value;
75 [CLSCompliantAttribute (false)]
76 public BigInteger (uint value)
83 data = new uint [1] { value };
87 public BigInteger (long value)
92 } else if (value > 0) {
94 uint low = (uint)value;
95 uint high = (uint)(value >> 32);
97 data = new uint [high != 0 ? 2 : 1];
104 if (value == long.MinValue) {
105 data = new uint [2] { 0, 0x80000000u };
108 uint low = (uint)value;
109 uint high = (uint)((ulong)value >> 32);
111 data = new uint [high != 0 ? 2 : 1];
119 [CLSCompliantAttribute (false)]
120 public BigInteger (ulong value)
127 uint low = (uint)value;
128 uint high = (uint)(value >> 32);
130 data = new uint [high != 0 ? 2 : 1];
137 [CLSCompliantAttribute (false)]
138 public BigInteger (byte[] value)
141 throw new ArgumentNullException ("value");
143 int len = value.Length;
145 if (len == 0 || (len == 1 && value [0] == 0)) {
151 if ((value [len - 1] & 0x80) != 0)
157 while (value [len - 1] == 0)
160 int full_words, size;
161 full_words = size = len / 4;
162 if ((len & 0x3) != 0)
165 data = new uint [size];
167 for (int i = 0; i < full_words; ++i) {
168 data [i] = (uint)value [j++] |
169 (uint)(value [j++] << 8) |
170 (uint)(value [j++] << 16) |
171 (uint)(value [j++] << 24);
175 int idx = data.Length - 1;
176 for (int i = 0; i < size; ++i)
177 data [idx] |= (uint)(value [j++] << (i * 8));
180 int full_words, size;
181 full_words = size = len / 4;
182 if ((len & 0x3) != 0)
185 data = new uint [size];
187 uint word, borrow = 1;
191 for (int i = 0; i < full_words; ++i) {
192 word = (uint)value [j++] |
193 (uint)(value [j++] << 8) |
194 (uint)(value [j++] << 16) |
195 (uint)(value [j++] << 24);
197 sub = (ulong)word - borrow;
199 borrow = (uint)(sub >> 32) & 0x1u;
207 for (int i = 0; i < size; ++i) {
208 word |= (uint)(value [j++] << (i * 8));
209 store_mask = (store_mask << 8) | 0xFF;
214 borrow = (uint)(sub >> 32) & 0x1u;
216 data [data.Length - 1] = ~word & store_mask;
218 if (borrow != 0) //FIXME I believe this can't happen, can someone write a test for it?
219 throw new Exception ("non zero final carry");
225 get { return (data [0] & 0x1) == 0; }
229 get { return sign == 1 && data.Length == 1 && data [0] == 1; }
233 //Gem from Hacker's Delight
234 //Returns the number of bits set in @x
235 static int PopulationCount (uint x)
237 x = x - ((x >> 1) & 0x55555555);
238 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
239 x = (x + (x >> 4)) & 0x0F0F0F0F;
242 return (int)(x & 0x0000003F);
245 public bool IsPowerOfTwo {
247 bool foundBit = false;
250 //This function is pop count == 1 for positive numbers
251 for (int i = 0; i < data.Length; ++i) {
252 int p = PopulationCount (data [i]);
254 if (p > 1 || foundBit)
264 get { return sign == 0; }
271 public static BigInteger MinusOne {
272 get { return new BigInteger (-1, ONE); }
275 public static BigInteger One {
276 get { return new BigInteger (1, ONE); }
279 public static BigInteger Zero {
280 get { return new BigInteger (0, ZERO); }
283 public static explicit operator int (BigInteger value)
285 if (value.data.Length > 1)
286 throw new OverflowException ();
287 uint data = value.data [0];
289 if (value.sign == 1) {
290 if (data > (uint)int.MaxValue)
291 throw new OverflowException ();
293 } else if (value.sign == -1) {
294 if (data > 0x80000000u)
295 throw new OverflowException ();
296 if (data == 0x80000000u)
304 [CLSCompliantAttribute (false)]
305 public static explicit operator uint (BigInteger value)
307 if (value.data.Length > 1 || value.sign == -1)
308 throw new OverflowException ();
309 return value.data [0];
312 public static explicit operator long (BigInteger value)
317 if (value.data.Length > 2)
318 throw new OverflowException ();
320 uint low = value.data [0];
322 if (value.data.Length == 1) {
325 long res = (long)low;
329 uint high = value.data [1];
331 if (value.sign == 1) {
332 if (high >= 0x80000000u)
333 throw new OverflowException ();
334 return (((long)high) << 32) | low;
337 if (high > 0x80000000u)
338 throw new OverflowException ();
340 if (high == 0x80000000u) {
342 throw new OverflowException ();
343 return long.MinValue;
346 return - ((((long)high) << 32) | (long)low);
349 [CLSCompliantAttribute (false)]
350 public static explicit operator ulong (BigInteger value)
352 if (value.data.Length > 2 || value.sign == -1)
353 throw new OverflowException ();
355 uint low = value.data [0];
356 if (value.data.Length == 1)
359 uint high = value.data [1];
360 return (((ulong)high) << 32) | low;
364 public static implicit operator BigInteger (int value)
366 return new BigInteger (value);
369 [CLSCompliantAttribute (false)]
370 public static implicit operator BigInteger (uint value)
372 return new BigInteger (value);
375 public static implicit operator BigInteger (long value)
377 return new BigInteger (value);
380 [CLSCompliantAttribute (false)]
381 public static implicit operator BigInteger (ulong value)
383 return new BigInteger (value);
386 public static BigInteger operator+ (BigInteger left, BigInteger right)
393 if (left.sign == right.sign)
394 return new BigInteger (left.sign, CoreAdd (left.data, right.data));
396 int r = CoreCompare (left.data, right.data);
399 return new BigInteger (0, ZERO);
401 if (r > 0) //left > right
402 return new BigInteger (left.sign, CoreSub (left.data, right.data));
404 return new BigInteger (right.sign, CoreSub (right.data, left.data));
407 public static bool operator< (BigInteger left, BigInteger right)
409 return Compare (left, right) < 0;
412 [CLSCompliantAttribute (false)]
413 public static bool operator< (BigInteger left, ulong right)
415 return left.CompareTo (right) < 0;
418 public static bool operator<= (BigInteger left, BigInteger right)
420 return Compare (left, right) <= 0;
423 [CLSCompliantAttribute (false)]
424 public static bool operator<= (BigInteger left, ulong right)
426 return left.CompareTo (right) <= 0;
429 public static bool operator> (BigInteger left, BigInteger right)
431 return Compare (left, right) > 0;
434 [CLSCompliantAttribute (false)]
435 public static bool operator> (BigInteger left, ulong right)
437 return left.CompareTo (right) > 0;
440 public static bool operator>= (BigInteger left, BigInteger right)
442 return Compare (left, right) >= 0;
445 [CLSCompliantAttribute (false)]
446 public static bool operator>= (BigInteger left, ulong right)
448 return left.CompareTo (right) >= 0;
451 public static bool operator== (BigInteger left, BigInteger right)
453 return Compare (left, right) == 0;
456 [CLSCompliantAttribute (false)]
457 public static bool operator== (BigInteger left, ulong right)
459 return left.CompareTo (right) == 0;
462 public static bool operator!= (BigInteger left, BigInteger right)
464 return Compare (left, right) != 0;
467 [CLSCompliantAttribute (false)]
468 public static bool operator!= (BigInteger left, ulong right)
470 return left.CompareTo (right) != 0;
473 public override bool Equals (object obj)
475 if (!(obj is BigInteger))
477 return Equals ((BigInteger)obj);
480 public bool Equals (BigInteger other)
482 if (sign != other.sign)
484 if (data.Length != other.data.Length)
486 for (int i = 0; i < data.Length; ++i) {
487 if (data [i] != other.data [i])
493 [CLSCompliantAttribute (false)]
494 public bool Equals (ulong other)
496 return CompareTo (other) == 0;
499 public override int GetHashCode ()
501 uint hash = (uint)(sign * 0x01010101u);
503 for (int i = 0; i < data.Length; ++i)
508 public static BigInteger Add (BigInteger left, BigInteger right)
513 public int CompareTo (BigInteger other)
515 return Compare (this, other);
518 [CLSCompliantAttribute (false)]
519 public int CompareTo (ulong other)
524 return other == 0 ? 0 : -1;
529 uint oh = (uint)(other >> 32);
539 uint ol = (uint)other;
550 public static int Compare (BigInteger left, BigInteger right)
556 return ls > rs ? 1 : -1;
558 int r = CoreCompare (left.data, right.data);
565 static int TopByte (uint x)
567 if ((x & 0xFFFF0000u) != 0) {
568 if ((x & 0xFF000000u) != 0)
572 if ((x & 0xFF00u) != 0)
577 static int FirstNonFFByte (uint word)
579 if ((word & 0xFF000000u) != 0xFF000000u)
581 else if ((word & 0xFF0000u) != 0xFF0000u)
583 else if ((word & 0xFF00u) != 0xFF00u)
588 public byte[] ToByteArray ()
593 //number of bytes not counting upper word
594 int bytes = (data.Length - 1) * 4;
595 bool needExtraZero = false;
597 uint topWord = data [data.Length - 1];
600 //if the topmost bit is set we need an extra
602 extra = TopByte (topWord);
603 uint mask = 0x80u << ((extra - 1) * 8);
604 if ((topWord & mask) != 0) {
605 needExtraZero = true;
608 extra = TopByte (topWord);
611 byte[] res = new byte [bytes + extra + (needExtraZero ? 1 : 0) ];
614 int end = data.Length - 1;
615 for (int i = 0; i < end; ++i) {
616 uint word = data [i];
618 res [j++] = (byte)word;
619 res [j++] = (byte)(word >> 8);
620 res [j++] = (byte)(word >> 16);
621 res [j++] = (byte)(word >> 24);
623 while (extra-- > 0) {
624 res [j++] = (byte)topWord;
629 int end = data.Length - 1;
631 uint carry = 1, word;
633 for (int i = 0; i < end; ++i) {
635 add = (ulong)~word + carry;
637 carry = (uint)(add >> 32);
639 res [j++] = (byte)word;
640 res [j++] = (byte)(word >> 8);
641 res [j++] = (byte)(word >> 16);
642 res [j++] = (byte)(word >> 24);
645 add = (ulong)~topWord + (carry);
647 carry = (uint)(add >> 32);
649 int ex = FirstNonFFByte (word);
650 bool needExtra = (word & (1 << (ex * 8 - 1))) == 0;
651 int to = ex + (needExtra ? 1 : 0);
654 res = Resize (res, bytes + to);
657 res [j++] = (byte)word;
663 res = Resize (res, bytes + 5);
664 res [j++] = (byte)word;
665 res [j++] = (byte)(word >> 8);
666 res [j++] = (byte)(word >> 16);
667 res [j++] = (byte)(word >> 24);
675 static byte[] Resize (byte[] v, int len)
677 byte[] res = new byte [len];
\r
678 Array.Copy (v, res, Math.Min (v.Length, len));
\r
682 static uint[] Resize (uint[] v, int len)
684 uint[] res = new uint [len];
\r
685 Array.Copy (v, res, Math.Min (v.Length, len));
\r
689 static uint[] CoreAdd (uint[] a, uint[] b)
691 if (a.Length < b.Length) {
700 uint[] res = new uint [bl];
705 for (; i < sl; i++) {
706 sum = sum + a [i] + b [i];
711 for (; i < bl; i++) {
718 res = Resize (res, bl + 1);
726 static uint[] CoreSub (uint[] a, uint[] b)
731 Console.WriteLine ("bl {0} sl {1}", bl, sl);
733 uint[] res = new uint [bl];
737 for (i = 0; i < sl; ++i) {
738 borrow = (ulong)a [i] - b [i] - borrow;
740 Console.WriteLine ("a {0} b {1}", a[i], b [i]);
742 res [i] = (uint)borrow;
743 borrow = (borrow >> 32) & 0x1;
746 for (; i < bl; i++) {
747 borrow = (ulong)a [i] - borrow;
748 res [i] = (uint)borrow;
749 borrow = (borrow >> 32) & 0x1;
752 //remove extra zeroes
753 for (i = bl - 1; i >= 0 && res [i] == 0; --i) ;
755 res = Resize (res, i + 1);
760 static int CoreCompare (uint[] a, uint[] b)
770 for (int i = al - 1; i >= 0; --i) {