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 public BigInteger (byte[] value)
140 throw new ArgumentNullException ("value");
142 int len = value.Length;
144 if (len == 0 || (len == 1 && value [0] == 0)) {
150 if ((value [len - 1] & 0x80) != 0)
156 while (value [len - 1] == 0)
159 int full_words, size;
160 full_words = size = len / 4;
161 if ((len & 0x3) != 0)
164 data = new uint [size];
166 for (int i = 0; i < full_words; ++i) {
167 data [i] = (uint)value [j++] |
168 (uint)(value [j++] << 8) |
169 (uint)(value [j++] << 16) |
170 (uint)(value [j++] << 24);
174 int idx = data.Length - 1;
175 for (int i = 0; i < size; ++i)
176 data [idx] |= (uint)(value [j++] << (i * 8));
179 int full_words, size;
180 full_words = size = len / 4;
181 if ((len & 0x3) != 0)
184 data = new uint [size];
186 uint word, borrow = 1;
190 for (int i = 0; i < full_words; ++i) {
191 word = (uint)value [j++] |
192 (uint)(value [j++] << 8) |
193 (uint)(value [j++] << 16) |
194 (uint)(value [j++] << 24);
196 sub = (ulong)word - borrow;
198 borrow = (uint)(sub >> 32) & 0x1u;
206 for (int i = 0; i < size; ++i) {
207 word |= (uint)(value [j++] << (i * 8));
208 store_mask = (store_mask << 8) | 0xFF;
213 borrow = (uint)(sub >> 32) & 0x1u;
215 data [data.Length - 1] = ~word & store_mask;
217 if (borrow != 0) //FIXME I believe this can't happen, can someone write a test for it?
218 throw new Exception ("non zero final carry");
224 get { return (data [0] & 0x1) == 0; }
228 get { return sign == 1 && data.Length == 1 && data [0] == 1; }
232 //Gem from Hacker's Delight
233 //Returns the number of bits set in @x
234 static int PopulationCount (uint x)
236 x = x - ((x >> 1) & 0x55555555);
237 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
238 x = (x + (x >> 4)) & 0x0F0F0F0F;
241 return (int)(x & 0x0000003F);
244 public bool IsPowerOfTwo {
246 bool foundBit = false;
249 //This function is pop count == 1 for positive numbers
250 for (int i = 0; i < data.Length; ++i) {
251 int p = PopulationCount (data [i]);
253 if (p > 1 || foundBit)
263 get { return sign == 0; }
270 public static BigInteger MinusOne {
271 get { return new BigInteger (-1, ONE); }
274 public static BigInteger One {
275 get { return new BigInteger (1, ONE); }
278 public static BigInteger Zero {
279 get { return new BigInteger (0, ZERO); }
282 public static explicit operator int (BigInteger value)
284 if (value.data.Length > 1)
285 throw new OverflowException ();
286 uint data = value.data [0];
288 if (value.sign == 1) {
289 if (data > (uint)int.MaxValue)
290 throw new OverflowException ();
292 } else if (value.sign == -1) {
293 if (data > 0x80000000u)
294 throw new OverflowException ();
295 if (data == 0x80000000u)
303 [CLSCompliantAttribute (false)]
304 public static explicit operator uint (BigInteger value)
306 if (value.data.Length > 1 || value.sign == -1)
307 throw new OverflowException ();
308 return value.data [0];
311 public static explicit operator long (BigInteger value)
316 if (value.data.Length > 2)
317 throw new OverflowException ();
319 uint low = value.data [0];
321 if (value.data.Length == 1) {
324 long res = (long)low;
328 uint high = value.data [1];
330 if (value.sign == 1) {
331 if (high >= 0x80000000u)
332 throw new OverflowException ();
333 return (((long)high) << 32) | low;
336 if (high > 0x80000000u)
337 throw new OverflowException ();
339 if (high == 0x80000000u) {
341 throw new OverflowException ();
342 return long.MinValue;
345 return - ((((long)high) << 32) | (long)low);
348 [CLSCompliantAttribute (false)]
349 public static explicit operator ulong (BigInteger value)
351 if (value.data.Length > 2 || value.sign == -1)
352 throw new OverflowException ();
354 uint low = value.data [0];
355 if (value.data.Length == 1)
358 uint high = value.data [1];
359 return (((ulong)high) << 32) | low;
363 public static implicit operator BigInteger (int value)
365 return new BigInteger (value);
368 [CLSCompliantAttribute (false)]
369 public static implicit operator BigInteger (uint value)
371 return new BigInteger (value);
374 public static implicit operator BigInteger (long value)
376 return new BigInteger (value);
379 [CLSCompliantAttribute (false)]
380 public static implicit operator BigInteger (ulong value)
382 return new BigInteger (value);
385 public static BigInteger operator+ (BigInteger left, BigInteger right)
392 if (left.sign == right.sign)
393 return new BigInteger (left.sign, CoreAdd (left.data, right.data));
395 int r = CoreCompare (left.data, right.data);
398 return new BigInteger (0, ZERO);
400 if (r > 0) //left > right
401 return new BigInteger (left.sign, CoreSub (left.data, right.data));
403 return new BigInteger (right.sign, CoreSub (right.data, left.data));
406 public static bool operator< (BigInteger left, BigInteger right)
408 return Compare (left, right) < 0;
411 [CLSCompliantAttribute (false)]
412 public static bool operator< (BigInteger left, ulong right)
414 return left.CompareTo (right) < 0;
417 public static bool operator<= (BigInteger left, BigInteger right)
419 return Compare (left, right) <= 0;
422 [CLSCompliantAttribute (false)]
423 public static bool operator<= (BigInteger left, ulong right)
425 return left.CompareTo (right) <= 0;
428 public static bool operator> (BigInteger left, BigInteger right)
430 return Compare (left, right) > 0;
433 [CLSCompliantAttribute (false)]
434 public static bool operator> (BigInteger left, ulong right)
436 return left.CompareTo (right) > 0;
439 public static bool operator>= (BigInteger left, BigInteger right)
441 return Compare (left, right) >= 0;
444 [CLSCompliantAttribute (false)]
445 public static bool operator>= (BigInteger left, ulong right)
447 return left.CompareTo (right) >= 0;
450 public static bool operator== (BigInteger left, BigInteger right)
452 return Compare (left, right) == 0;
455 [CLSCompliantAttribute (false)]
456 public static bool operator== (BigInteger left, ulong right)
458 return left.CompareTo (right) == 0;
461 public static bool operator!= (BigInteger left, BigInteger right)
463 return Compare (left, right) != 0;
466 [CLSCompliantAttribute (false)]
467 public static bool operator!= (BigInteger left, ulong right)
469 return left.CompareTo (right) != 0;
472 public override bool Equals (object obj)
474 if (!(obj is BigInteger))
476 return Equals ((BigInteger)obj);
479 public bool Equals (BigInteger other)
481 if (sign != other.sign)
483 if (data.Length != other.data.Length)
485 for (int i = 0; i < data.Length; ++i) {
486 if (data [i] != other.data [i])
492 public override int GetHashCode ()
494 uint hash = (uint)(sign * 0x01010101u);
496 for (int i = 0; i < data.Length; ++i)
501 public static BigInteger Add (BigInteger left, BigInteger right)
506 public int CompareTo (BigInteger other)
508 return Compare (this, other);
511 [CLSCompliantAttribute (false)]
512 public int CompareTo (ulong other)
517 return other == 0 ? 0 : -1;
522 uint oh = (uint)(other >> 32);
532 uint ol = (uint)other;
543 public static int Compare (BigInteger left, BigInteger right)
549 return ls > rs ? 1 : -1;
551 int r = CoreCompare (left.data, right.data);
558 static int TopByte (uint x)
560 if ((x & 0xFFFF0000u) != 0) {
561 if ((x & 0xFF000000u) != 0)
565 if ((x & 0xFF00u) != 0)
570 static int FirstNonFFByte (uint word)
572 if ((word & 0xFF000000u) != 0xFF000000u)
574 else if ((word & 0xFF0000u) != 0xFF0000u)
576 else if ((word & 0xFF00u) != 0xFF00u)
581 public byte[] ToByteArray ()
586 //number of bytes not counting upper word
587 int bytes = (data.Length - 1) * 4;
588 bool needExtraZero = false;
590 uint topWord = data [data.Length - 1];
593 //if the topmost bit is set we need an extra
595 extra = TopByte (topWord);
596 uint mask = 0x80u << ((extra - 1) * 8);
597 if ((topWord & mask) != 0) {
598 needExtraZero = true;
601 extra = TopByte (topWord);
604 byte[] res = new byte [bytes + extra + (needExtraZero ? 1 : 0) ];
607 int end = data.Length - 1;
608 for (int i = 0; i < end; ++i) {
609 uint word = data [i];
611 res [j++] = (byte)word;
612 res [j++] = (byte)(word >> 8);
613 res [j++] = (byte)(word >> 16);
614 res [j++] = (byte)(word >> 24);
616 while (extra-- > 0) {
617 res [j++] = (byte)topWord;
622 int end = data.Length - 1;
624 uint carry = 1, word;
626 for (int i = 0; i < end; ++i) {
628 add = (ulong)~word + carry;
630 carry = (uint)(add >> 32);
632 res [j++] = (byte)word;
633 res [j++] = (byte)(word >> 8);
634 res [j++] = (byte)(word >> 16);
635 res [j++] = (byte)(word >> 24);
638 add = (ulong)~topWord + (carry);
640 carry = (uint)(add >> 32);
642 int ex = FirstNonFFByte (word);
643 bool needExtra = (word & (1 << (ex * 8 - 1))) == 0;
644 int to = ex + (needExtra ? 1 : 0);
647 res = Resize (res, bytes + to);
650 res [j++] = (byte)word;
656 res = Resize (res, bytes + 5);
657 res [j++] = (byte)word;
658 res [j++] = (byte)(word >> 8);
659 res [j++] = (byte)(word >> 16);
660 res [j++] = (byte)(word >> 24);
668 static byte[] Resize (byte[] v, int len)
670 byte[] res = new byte [len];
\r
671 Array.Copy (v, res, Math.Min (v.Length, len));
\r
675 static uint[] Resize (uint[] v, int len)
677 uint[] res = new uint [len];
\r
678 Array.Copy (v, res, Math.Min (v.Length, len));
\r
682 static uint[] CoreAdd (uint[] a, uint[] b)
684 if (a.Length < b.Length) {
693 uint[] res = new uint [bl];
698 for (; i < sl; i++) {
699 sum = sum + a [i] + b [i];
704 for (; i < bl; i++) {
711 res = Resize (res, bl + 1);
719 static uint[] CoreSub (uint[] a, uint[] b)
724 Console.WriteLine ("bl {0} sl {1}", bl, sl);
726 uint[] res = new uint [bl];
730 for (i = 0; i < sl; ++i) {
731 borrow = (ulong)a [i] - b [i] - borrow;
733 Console.WriteLine ("a {0} b {1}", a[i], b [i]);
735 res [i] = (uint)borrow;
736 borrow = (borrow >> 32) & 0x1;
739 for (; i < bl; i++) {
740 borrow = (ulong)a [i] - borrow;
741 res [i] = (uint)borrow;
742 borrow = (borrow >> 32) & 0x1;
745 //remove extra zeroes
746 for (i = bl - 1; i >= 0 && res [i] == 0; --i) ;
748 res = Resize (res, i + 1);
753 static int CoreCompare (uint[] a, uint[] b)
763 for (int i = al - 1; i >= 0; --i) {