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 [CLSCompliantAttribute (false)]
396 public static bool operator< (BigInteger left, ulong right)
398 return left.CompareTo (right) < 0;
401 [CLSCompliantAttribute (false)]
402 public static bool operator< (ulong left, BigInteger right)
404 return right.CompareTo (left) > 0;
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 [CLSCompliantAttribute (false)]
419 public static bool operator<= (ulong left, BigInteger right)
421 return right.CompareTo (left) >= 0;
424 public static bool operator> (BigInteger left, BigInteger right)
426 return Compare (left, right) > 0;
429 [CLSCompliantAttribute (false)]
430 public static bool operator> (BigInteger left, ulong right)
432 return left.CompareTo (right) > 0;
435 [CLSCompliantAttribute (false)]
436 public static bool operator> (ulong left, BigInteger right)
438 return right.CompareTo (left) < 0;
441 public static bool operator>= (BigInteger left, BigInteger right)
443 return Compare (left, right) >= 0;
446 [CLSCompliantAttribute (false)]
447 public static bool operator>= (BigInteger left, ulong right)
449 return left.CompareTo (right) >= 0;
452 [CLSCompliantAttribute (false)]
453 public static bool operator>= (ulong left, BigInteger right)
455 return right.CompareTo (left) <= 0;
458 public static bool operator== (BigInteger left, BigInteger right)
460 return Compare (left, right) == 0;
463 [CLSCompliantAttribute (false)]
464 public static bool operator== (BigInteger left, ulong right)
466 return left.CompareTo (right) == 0;
469 [CLSCompliantAttribute (false)]
470 public static bool operator== (ulong left, BigInteger right)
472 return right.CompareTo (left) == 0;
475 public static bool operator!= (BigInteger left, BigInteger right)
477 return Compare (left, right) != 0;
480 [CLSCompliantAttribute (false)]
481 public static bool operator!= (BigInteger left, ulong right)
483 return left.CompareTo (right) != 0;
486 [CLSCompliantAttribute (false)]
487 public static bool operator!= (ulong left, BigInteger right)
489 return right.CompareTo (left) != 0;
492 public override bool Equals (object obj)
494 if (!(obj is BigInteger))
496 return Equals ((BigInteger)obj);
499 public bool Equals (BigInteger other)
501 if (sign != other.sign)
503 if (data.Length != other.data.Length)
505 for (int i = 0; i < data.Length; ++i) {
506 if (data [i] != other.data [i])
512 [CLSCompliantAttribute (false)]
513 public bool Equals (ulong other)
515 return CompareTo (other) == 0;
518 public override int GetHashCode ()
520 uint hash = (uint)(sign * 0x01010101u);
522 for (int i = 0; i < data.Length; ++i)
527 public static BigInteger Add (BigInteger left, BigInteger right)
532 public int CompareTo (object obj)
537 if (!(obj is BigInteger))
540 return Compare (this, (BigInteger)obj);
543 public int CompareTo (BigInteger other)
545 return Compare (this, other);
548 [CLSCompliantAttribute (false)]
549 public int CompareTo (ulong other)
554 return other == 0 ? 0 : -1;
559 uint high = (uint)(other >> 32);
560 uint low = (uint)other;
562 return LongCompare (low, high);
565 int LongCompare (uint low, uint high)
586 public int CompareTo (long other)
589 int rs = Math.Sign (other);
592 return ls > rs ? 1 : -1;
602 uint low = (uint)other;
603 uint high = (uint)((ulong)other >> 32);
605 int r = LongCompare (low, high);
612 public static int Compare (BigInteger left, BigInteger right)
618 return ls > rs ? 1 : -1;
620 int r = CoreCompare (left.data, right.data);
627 static int TopByte (uint x)
629 if ((x & 0xFFFF0000u) != 0) {
630 if ((x & 0xFF000000u) != 0)
634 if ((x & 0xFF00u) != 0)
639 static int FirstNonFFByte (uint word)
641 if ((word & 0xFF000000u) != 0xFF000000u)
643 else if ((word & 0xFF0000u) != 0xFF0000u)
645 else if ((word & 0xFF00u) != 0xFF00u)
650 public byte[] ToByteArray ()
655 //number of bytes not counting upper word
656 int bytes = (data.Length - 1) * 4;
657 bool needExtraZero = false;
659 uint topWord = data [data.Length - 1];
662 //if the topmost bit is set we need an extra
664 extra = TopByte (topWord);
665 uint mask = 0x80u << ((extra - 1) * 8);
666 if ((topWord & mask) != 0) {
667 needExtraZero = true;
670 extra = TopByte (topWord);
673 byte[] res = new byte [bytes + extra + (needExtraZero ? 1 : 0) ];
676 int end = data.Length - 1;
677 for (int i = 0; i < end; ++i) {
678 uint word = data [i];
680 res [j++] = (byte)word;
681 res [j++] = (byte)(word >> 8);
682 res [j++] = (byte)(word >> 16);
683 res [j++] = (byte)(word >> 24);
685 while (extra-- > 0) {
686 res [j++] = (byte)topWord;
691 int end = data.Length - 1;
693 uint carry = 1, word;
695 for (int i = 0; i < end; ++i) {
697 add = (ulong)~word + carry;
699 carry = (uint)(add >> 32);
701 res [j++] = (byte)word;
702 res [j++] = (byte)(word >> 8);
703 res [j++] = (byte)(word >> 16);
704 res [j++] = (byte)(word >> 24);
707 add = (ulong)~topWord + (carry);
709 carry = (uint)(add >> 32);
711 int ex = FirstNonFFByte (word);
712 bool needExtra = (word & (1 << (ex * 8 - 1))) == 0;
713 int to = ex + (needExtra ? 1 : 0);
716 res = Resize (res, bytes + to);
719 res [j++] = (byte)word;
725 res = Resize (res, bytes + 5);
726 res [j++] = (byte)word;
727 res [j++] = (byte)(word >> 8);
728 res [j++] = (byte)(word >> 16);
729 res [j++] = (byte)(word >> 24);
737 static byte[] Resize (byte[] v, int len)
739 byte[] res = new byte [len];
\r
740 Array.Copy (v, res, Math.Min (v.Length, len));
\r
744 static uint[] Resize (uint[] v, int len)
746 uint[] res = new uint [len];
\r
747 Array.Copy (v, res, Math.Min (v.Length, len));
\r
751 static uint[] CoreAdd (uint[] a, uint[] b)
753 if (a.Length < b.Length) {
762 uint[] res = new uint [bl];
767 for (; i < sl; i++) {
768 sum = sum + a [i] + b [i];
773 for (; i < bl; i++) {
780 res = Resize (res, bl + 1);
788 static uint[] CoreSub (uint[] a, uint[] b)
793 Console.WriteLine ("bl {0} sl {1}", bl, sl);
795 uint[] res = new uint [bl];
799 for (i = 0; i < sl; ++i) {
800 borrow = (ulong)a [i] - b [i] - borrow;
802 Console.WriteLine ("a {0} b {1}", a[i], b [i]);
804 res [i] = (uint)borrow;
805 borrow = (borrow >> 32) & 0x1;
808 for (; i < bl; i++) {
809 borrow = (ulong)a [i] - borrow;
810 res [i] = (uint)borrow;
811 borrow = (borrow >> 32) & 0x1;
814 //remove extra zeroes
815 for (i = bl - 1; i >= 0 && res [i] == 0; --i) ;
817 res = Resize (res, i + 1);
822 static int CoreCompare (uint[] a, uint[] b)
832 for (int i = al - 1; i >= 0; --i) {