2
0

Number.BigInteger.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using System.Numerics;
  6. using System.Runtime.InteropServices;
  7. using Internal.Runtime.CompilerServices;
  8. namespace System
  9. {
  10. internal static partial class Number
  11. {
  12. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  13. internal unsafe ref struct BigInteger
  14. {
  15. // The longest binary mantissa requires: explicit mantissa bits + abs(min exponent)
  16. // * Half: 10 + 14 = 24
  17. // * Single: 23 + 126 = 149
  18. // * Double: 52 + 1022 = 1074
  19. // * Quad: 112 + 16382 = 16494
  20. private const int BitsForLongestBinaryMantissa = 1074;
  21. // The longest digit sequence requires: ceil(log2(pow(10, max significant digits + 1 rounding digit)))
  22. // * Half: ceil(log2(pow(10, 21 + 1))) = 74
  23. // * Single: ceil(log2(pow(10, 112 + 1))) = 376
  24. // * Double: ceil(log2(pow(10, 767 + 1))) = 2552
  25. // * Quad: ceil(log2(pow(10, 11563 + 1))) = 38415
  26. private const int BitsForLongestDigitSequence = 2552;
  27. // We require BitsPerBlock additional bits for shift space used during the pre-division preparation
  28. private const int MaxBits = BitsForLongestBinaryMantissa + BitsForLongestDigitSequence + BitsPerBlock;
  29. private const int BitsPerBlock = sizeof(int) * 8;
  30. private const int MaxBlockCount = (MaxBits + (BitsPerBlock - 1)) / BitsPerBlock;
  31. private static readonly uint[] s_Pow10UInt32Table = new uint[]
  32. {
  33. 1, // 10^0
  34. 10, // 10^1
  35. 100, // 10^2
  36. 1000, // 10^3
  37. 10000, // 10^4
  38. 100000, // 10^5
  39. 1000000, // 10^6
  40. 10000000, // 10^7
  41. };
  42. private static readonly int[] s_Pow10BigNumTableIndices = new int[]
  43. {
  44. 0, // 10^8
  45. 2, // 10^16
  46. 5, // 10^32
  47. 10, // 10^64
  48. 18, // 10^128
  49. 33, // 10^256
  50. 61, // 10^512
  51. 116, // 10^1024
  52. };
  53. private static readonly uint[] s_Pow10BigNumTable = new uint[]
  54. {
  55. // 10^8
  56. 1, // _length
  57. 100000000, // _blocks
  58. // 10^16
  59. 2, // _length
  60. 0x6FC10000, // _blocks
  61. 0x002386F2,
  62. // 10^32
  63. 4, // _length
  64. 0x00000000, // _blocks
  65. 0x85ACEF81,
  66. 0x2D6D415B,
  67. 0x000004EE,
  68. // 10^64
  69. 7, // _length
  70. 0x00000000, // _blocks
  71. 0x00000000,
  72. 0xBF6A1F01,
  73. 0x6E38ED64,
  74. 0xDAA797ED,
  75. 0xE93FF9F4,
  76. 0x00184F03,
  77. // 10^128
  78. 14, // _length
  79. 0x00000000, // _blocks
  80. 0x00000000,
  81. 0x00000000,
  82. 0x00000000,
  83. 0x2E953E01,
  84. 0x03DF9909,
  85. 0x0F1538FD,
  86. 0x2374E42F,
  87. 0xD3CFF5EC,
  88. 0xC404DC08,
  89. 0xBCCDB0DA,
  90. 0xA6337F19,
  91. 0xE91F2603,
  92. 0x0000024E,
  93. // 10^256
  94. 27, // _length
  95. 0x00000000, // _blocks
  96. 0x00000000,
  97. 0x00000000,
  98. 0x00000000,
  99. 0x00000000,
  100. 0x00000000,
  101. 0x00000000,
  102. 0x00000000,
  103. 0x982E7C01,
  104. 0xBED3875B,
  105. 0xD8D99F72,
  106. 0x12152F87,
  107. 0x6BDE50C6,
  108. 0xCF4A6E70,
  109. 0xD595D80F,
  110. 0x26B2716E,
  111. 0xADC666B0,
  112. 0x1D153624,
  113. 0x3C42D35A,
  114. 0x63FF540E,
  115. 0xCC5573C0,
  116. 0x65F9EF17,
  117. 0x55BC28F2,
  118. 0x80DCC7F7,
  119. 0xF46EEDDC,
  120. 0x5FDCEFCE,
  121. 0x000553F7,
  122. // 10^512
  123. 54, // _length
  124. 0x00000000, // _blocks
  125. 0x00000000,
  126. 0x00000000,
  127. 0x00000000,
  128. 0x00000000,
  129. 0x00000000,
  130. 0x00000000,
  131. 0x00000000,
  132. 0x00000000,
  133. 0x00000000,
  134. 0x00000000,
  135. 0x00000000,
  136. 0x00000000,
  137. 0x00000000,
  138. 0x00000000,
  139. 0x00000000,
  140. 0xFC6CF801,
  141. 0x77F27267,
  142. 0x8F9546DC,
  143. 0x5D96976F,
  144. 0xB83A8A97,
  145. 0xC31E1AD9,
  146. 0x46C40513,
  147. 0x94E65747,
  148. 0xC88976C1,
  149. 0x4475B579,
  150. 0x28F8733B,
  151. 0xAA1DA1BF,
  152. 0x703ED321,
  153. 0x1E25CFEA,
  154. 0xB21A2F22,
  155. 0xBC51FB2E,
  156. 0x96E14F5D,
  157. 0xBFA3EDAC,
  158. 0x329C57AE,
  159. 0xE7FC7153,
  160. 0xC3FC0695,
  161. 0x85A91924,
  162. 0xF95F635E,
  163. 0xB2908EE0,
  164. 0x93ABADE4,
  165. 0x1366732A,
  166. 0x9449775C,
  167. 0x69BE5B0E,
  168. 0x7343AFAC,
  169. 0xB099BC81,
  170. 0x45A71D46,
  171. 0xA2699748,
  172. 0x8CB07303,
  173. 0x8A0B1F13,
  174. 0x8CAB8A97,
  175. 0xC1D238D9,
  176. 0x633415D4,
  177. 0x0000001C,
  178. // 10^1024
  179. 107, // _length
  180. 0x00000000, // _blocks
  181. 0x00000000,
  182. 0x00000000,
  183. 0x00000000,
  184. 0x00000000,
  185. 0x00000000,
  186. 0x00000000,
  187. 0x00000000,
  188. 0x00000000,
  189. 0x00000000,
  190. 0x00000000,
  191. 0x00000000,
  192. 0x00000000,
  193. 0x00000000,
  194. 0x00000000,
  195. 0x00000000,
  196. 0x00000000,
  197. 0x00000000,
  198. 0x00000000,
  199. 0x00000000,
  200. 0x00000000,
  201. 0x00000000,
  202. 0x00000000,
  203. 0x00000000,
  204. 0x00000000,
  205. 0x00000000,
  206. 0x00000000,
  207. 0x00000000,
  208. 0x00000000,
  209. 0x00000000,
  210. 0x00000000,
  211. 0x00000000,
  212. 0x2919F001,
  213. 0xF55B2B72,
  214. 0x6E7C215B,
  215. 0x1EC29F86,
  216. 0x991C4E87,
  217. 0x15C51A88,
  218. 0x140AC535,
  219. 0x4C7D1E1A,
  220. 0xCC2CD819,
  221. 0x0ED1440E,
  222. 0x896634EE,
  223. 0x7DE16CFB,
  224. 0x1E43F61F,
  225. 0x9FCE837D,
  226. 0x231D2B9C,
  227. 0x233E55C7,
  228. 0x65DC60D7,
  229. 0xF451218B,
  230. 0x1C5CD134,
  231. 0xC9635986,
  232. 0x922BBB9F,
  233. 0xA7E89431,
  234. 0x9F9F2A07,
  235. 0x62BE695A,
  236. 0x8E1042C4,
  237. 0x045B7A74,
  238. 0x1ABE1DE3,
  239. 0x8AD822A5,
  240. 0xBA34C411,
  241. 0xD814B505,
  242. 0xBF3FDEB3,
  243. 0x8FC51A16,
  244. 0xB1B896BC,
  245. 0xF56DEEEC,
  246. 0x31FB6BFD,
  247. 0xB6F4654B,
  248. 0x101A3616,
  249. 0x6B7595FB,
  250. 0xDC1A47FE,
  251. 0x80D98089,
  252. 0x80BDA5A5,
  253. 0x9A202882,
  254. 0x31EB0F66,
  255. 0xFC8F1F90,
  256. 0x976A3310,
  257. 0xE26A7B7E,
  258. 0xDF68368A,
  259. 0x3CE3A0B8,
  260. 0x8E4262CE,
  261. 0x75A351A2,
  262. 0x6CB0B6C9,
  263. 0x44597583,
  264. 0x31B5653F,
  265. 0xC356E38A,
  266. 0x35FAABA6,
  267. 0x0190FBA0,
  268. 0x9FC4ED52,
  269. 0x88BC491B,
  270. 0x1640114A,
  271. 0x005B8041,
  272. 0xF4F3235E,
  273. 0x1E8D4649,
  274. 0x36A8DE06,
  275. 0x73C55349,
  276. 0xA7E6BD2A,
  277. 0xC1A6970C,
  278. 0x47187094,
  279. 0xD2DB49EF,
  280. 0x926C3F5B,
  281. 0xAE6209D4,
  282. 0x2D433949,
  283. 0x34F4A3C6,
  284. 0xD4305D94,
  285. 0xD9D61A05,
  286. 0x00000325,
  287. // 9 Trailing blocks to ensure MaxBlockCount
  288. 0x00000000,
  289. 0x00000000,
  290. 0x00000000,
  291. 0x00000000,
  292. 0x00000000,
  293. 0x00000000,
  294. 0x00000000,
  295. 0x00000000,
  296. 0x00000000,
  297. };
  298. private int _length;
  299. private fixed uint _blocks[MaxBlockCount];
  300. public BigInteger(uint value)
  301. {
  302. _blocks[0] = value;
  303. _length = (value == 0) ? 0 : 1;
  304. }
  305. public BigInteger(ulong value)
  306. {
  307. uint lower = (uint)(value);
  308. uint upper = (uint)(value >> 32);
  309. _blocks[0] = lower;
  310. _blocks[1] = upper;
  311. _length = (upper == 0) ? 1 : 2;
  312. }
  313. public static void Add(ref BigInteger lhs, ref BigInteger rhs, out BigInteger result)
  314. {
  315. // determine which operand has the smaller length
  316. ref BigInteger large = ref (lhs._length < rhs._length) ? ref rhs : ref lhs;
  317. ref BigInteger small = ref (lhs._length < rhs._length) ? ref lhs : ref rhs;
  318. int largeLength = large._length;
  319. int smallLength = small._length;
  320. // The output will be at least as long as the largest input
  321. result = new BigInteger(0);
  322. result._length = largeLength;
  323. // Add each block and add carry the overflow to the next block
  324. ulong carry = 0;
  325. int largeIndex = 0;
  326. int smallIndex = 0;
  327. int resultIndex = 0;
  328. while (smallIndex < smallLength)
  329. {
  330. ulong sum = carry + large._blocks[largeIndex] + small._blocks[smallIndex];
  331. carry = sum >> 32;
  332. result._blocks[resultIndex] = (uint)(sum);
  333. largeIndex++;
  334. smallIndex++;
  335. resultIndex++;
  336. }
  337. // Add the carry to any blocks that only exist in the large operand
  338. while (largeIndex < largeLength)
  339. {
  340. ulong sum = carry + large._blocks[largeIndex];
  341. carry = sum >> 32;
  342. result._blocks[resultIndex] = (uint)(sum);
  343. largeIndex++;
  344. resultIndex++;
  345. }
  346. // If there's still a carry, append a new block
  347. if (carry != 0)
  348. {
  349. Debug.Assert(carry == 1);
  350. Debug.Assert((resultIndex == largeLength) && (largeLength < MaxBlockCount));
  351. result._blocks[resultIndex] = 1;
  352. result._length++;
  353. }
  354. }
  355. public static int Compare(ref BigInteger lhs, ref BigInteger rhs)
  356. {
  357. Debug.Assert(unchecked((uint)(lhs._length)) <= MaxBlockCount);
  358. Debug.Assert(unchecked((uint)(rhs._length)) <= MaxBlockCount);
  359. int lhsLength = lhs._length;
  360. int rhsLength = rhs._length;
  361. int lengthDelta = (lhsLength - rhsLength);
  362. if (lengthDelta != 0)
  363. {
  364. return lengthDelta;
  365. }
  366. if (lhsLength == 0)
  367. {
  368. Debug.Assert(rhsLength == 0);
  369. return 0;
  370. }
  371. for (int index = (lhsLength - 1); index >= 0; index--)
  372. {
  373. long delta = (long)(lhs._blocks[index]) - rhs._blocks[index];
  374. if (delta != 0)
  375. {
  376. return delta > 0 ? 1 : -1;
  377. }
  378. }
  379. return 0;
  380. }
  381. public static uint CountSignificantBits(uint value)
  382. {
  383. return 32 - (uint)BitOperations.LeadingZeroCount(value);
  384. }
  385. public static uint CountSignificantBits(ulong value)
  386. {
  387. return 64 - (uint)BitOperations.LeadingZeroCount(value);
  388. }
  389. public static uint CountSignificantBits(ref BigInteger value)
  390. {
  391. if (value.IsZero())
  392. {
  393. return 0;
  394. }
  395. // We don't track any unused blocks, so we only need to do a BSR on the
  396. // last index and add that to the number of bits we skipped.
  397. uint lastIndex = (uint)(value._length - 1);
  398. return (lastIndex * BitsPerBlock) + CountSignificantBits(value._blocks[lastIndex]);
  399. }
  400. public static void DivRem(ref BigInteger lhs, ref BigInteger rhs, out BigInteger quo, out BigInteger rem)
  401. {
  402. // This is modified from the CoreFX BigIntegerCalculator.DivRem.cs implementation:
  403. // https://github.com/dotnet/corefx/blob/0bb106232745aedfc0d0c5a84ff2b244bf190317/src/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.DivRem.cs
  404. Debug.Assert(!rhs.IsZero());
  405. quo = new BigInteger(0);
  406. rem = new BigInteger(0);
  407. if (lhs.IsZero())
  408. {
  409. return;
  410. }
  411. int lhsLength = lhs._length;
  412. int rhsLength = rhs._length;
  413. if ((lhsLength == 1) && (rhsLength == 1))
  414. {
  415. uint quotient = Math.DivRem(lhs._blocks[0], rhs._blocks[0], out uint remainder);
  416. quo = new BigInteger(quotient);
  417. rem = new BigInteger(remainder);
  418. return;
  419. }
  420. if (rhsLength == 1)
  421. {
  422. // We can make the computation much simpler if the rhs is only one block
  423. int quoLength = lhsLength;
  424. ulong rhsValue = rhs._blocks[0];
  425. ulong carry = 0;
  426. for (int i = quoLength - 1; i >= 0; i--)
  427. {
  428. ulong value = (carry << 32) | lhs._blocks[i];
  429. ulong digit = Math.DivRem(value, rhsValue, out carry);
  430. if ((digit == 0) && (i == (quoLength - 1)))
  431. {
  432. quoLength--;
  433. }
  434. else
  435. {
  436. quo._blocks[i] = (uint)(digit);
  437. }
  438. }
  439. quo._length = quoLength;
  440. rem.SetUInt32((uint)(carry));
  441. return;
  442. }
  443. else if (rhsLength > lhsLength)
  444. {
  445. // Handle the case where we have no quotient
  446. rem.SetValue(ref lhs);
  447. return;
  448. }
  449. else
  450. {
  451. int quoLength = lhsLength - rhsLength + 1;
  452. rem.SetValue(ref lhs);
  453. int remLength = lhsLength;
  454. // Executes the "grammar-school" algorithm for computing q = a / b.
  455. // Before calculating q_i, we get more bits into the highest bit
  456. // block of the divisor. Thus, guessing digits of the quotient
  457. // will be more precise. Additionally we'll get r = a % b.
  458. uint divHi = rhs._blocks[rhsLength - 1];
  459. uint divLo = rhs._blocks[rhsLength - 2];
  460. // We measure the leading zeros of the divisor
  461. int shiftLeft = BitOperations.LeadingZeroCount(divHi);
  462. int shiftRight = 32 - shiftLeft;
  463. // And, we make sure the most significant bit is set
  464. if (shiftLeft > 0)
  465. {
  466. divHi = (divHi << shiftLeft) | (divLo >> shiftRight);
  467. divLo <<= shiftLeft;
  468. if (rhsLength > 2)
  469. {
  470. divLo |= (rhs._blocks[rhsLength - 3] >> shiftRight);
  471. }
  472. }
  473. // Then, we divide all of the bits as we would do it using
  474. // pen and paper: guessing the next digit, subtracting, ...
  475. for (int i = lhsLength; i >= rhsLength; i--)
  476. {
  477. int n = i - rhsLength;
  478. uint t = i < lhsLength ? rem._blocks[i] : 0;
  479. ulong valHi = ((ulong)(t) << 32) | rem._blocks[i - 1];
  480. uint valLo = i > 1 ? rem._blocks[i - 2] : 0;
  481. // We shifted the divisor, we shift the dividend too
  482. if (shiftLeft > 0)
  483. {
  484. valHi = (valHi << shiftLeft) | (valLo >> shiftRight);
  485. valLo <<= shiftLeft;
  486. if (i > 2)
  487. {
  488. valLo |= (rem._blocks[i - 3] >> shiftRight);
  489. }
  490. }
  491. // First guess for the current digit of the quotient,
  492. // which naturally must have only 32 bits...
  493. ulong digit = valHi / divHi;
  494. if (digit > uint.MaxValue)
  495. {
  496. digit = uint.MaxValue;
  497. }
  498. // Our first guess may be a little bit to big
  499. while (DivideGuessTooBig(digit, valHi, valLo, divHi, divLo))
  500. {
  501. digit--;
  502. }
  503. if (digit > 0)
  504. {
  505. // Now it's time to subtract our current quotient
  506. uint carry = SubtractDivisor(ref rem, n, ref rhs, digit);
  507. if (carry != t)
  508. {
  509. Debug.Assert(carry == t + 1);
  510. // Our guess was still exactly one too high
  511. carry = AddDivisor(ref rem, n, ref rhs);
  512. digit--;
  513. Debug.Assert(carry == 1);
  514. }
  515. }
  516. // We have the digit!
  517. if (quoLength != 0)
  518. {
  519. if ((digit == 0) && (n == (quoLength - 1)))
  520. {
  521. quoLength--;
  522. }
  523. else
  524. {
  525. quo._blocks[n] = (uint)(digit);
  526. }
  527. }
  528. if (i < remLength)
  529. {
  530. remLength--;
  531. }
  532. }
  533. quo._length = quoLength;
  534. // We need to check for the case where remainder is zero
  535. for (int i = remLength - 1; i >= 0; i--)
  536. {
  537. if (rem._blocks[i] == 0)
  538. {
  539. remLength--;
  540. }
  541. }
  542. rem._length = remLength;
  543. }
  544. }
  545. public static uint HeuristicDivide(ref BigInteger dividend, ref BigInteger divisor)
  546. {
  547. int divisorLength = divisor._length;
  548. if (dividend._length < divisorLength)
  549. {
  550. return 0;
  551. }
  552. // This is an estimated quotient. Its error should be less than 2.
  553. // Reference inequality:
  554. // a/b - floor(floor(a)/(floor(b) + 1)) < 2
  555. int lastIndex = (divisorLength - 1);
  556. uint quotient = dividend._blocks[lastIndex] / (divisor._blocks[lastIndex] + 1);
  557. if (quotient != 0)
  558. {
  559. // Now we use our estimated quotient to update each block of dividend.
  560. // dividend = dividend - divisor * quotient
  561. int index = 0;
  562. ulong borrow = 0;
  563. ulong carry = 0;
  564. do
  565. {
  566. ulong product = ((ulong)(divisor._blocks[index]) * quotient) + carry;
  567. carry = product >> 32;
  568. ulong difference = (ulong)(dividend._blocks[index]) - (uint)(product) - borrow;
  569. borrow = (difference >> 32) & 1;
  570. dividend._blocks[index] = (uint)(difference);
  571. index++;
  572. }
  573. while (index < divisorLength);
  574. // Remove all leading zero blocks from dividend
  575. while ((divisorLength > 0) && (dividend._blocks[divisorLength - 1] == 0))
  576. {
  577. divisorLength--;
  578. }
  579. dividend._length = divisorLength;
  580. }
  581. // If the dividend is still larger than the divisor, we overshot our estimate quotient. To correct,
  582. // we increment the quotient and subtract one more divisor from the dividend (Because we guaranteed the error range).
  583. if (Compare(ref dividend, ref divisor) >= 0)
  584. {
  585. quotient++;
  586. // dividend = dividend - divisor
  587. int index = 0;
  588. ulong borrow = 0;
  589. do
  590. {
  591. ulong difference = (ulong)(dividend._blocks[index]) - divisor._blocks[index] - borrow;
  592. borrow = (difference >> 32) & 1;
  593. dividend._blocks[index] = (uint)(difference);
  594. index++;
  595. }
  596. while (index < divisorLength);
  597. // Remove all leading zero blocks from dividend
  598. while ((divisorLength > 0) && (dividend._blocks[divisorLength - 1] == 0))
  599. {
  600. divisorLength--;
  601. }
  602. dividend._length = divisorLength;
  603. }
  604. return quotient;
  605. }
  606. public static void Multiply(ref BigInteger lhs, uint value, ref BigInteger result)
  607. {
  608. if (lhs.IsZero() || (value == 1))
  609. {
  610. result.SetValue(ref lhs);
  611. return;
  612. }
  613. if (value == 0)
  614. {
  615. result.SetZero();
  616. return;
  617. }
  618. int lhsLength = lhs._length;
  619. int index = 0;
  620. uint carry = 0;
  621. while (index < lhsLength)
  622. {
  623. ulong product = ((ulong)(lhs._blocks[index]) * value) + carry;
  624. result._blocks[index] = (uint)(product);
  625. carry = (uint)(product >> 32);
  626. index++;
  627. }
  628. if (carry != 0)
  629. {
  630. Debug.Assert(unchecked((uint)(lhsLength)) + 1 <= MaxBlockCount);
  631. result._blocks[index] = carry;
  632. result._length = (lhsLength + 1);
  633. }
  634. else
  635. {
  636. result._length = lhsLength;
  637. }
  638. }
  639. public static void Multiply(ref BigInteger lhs, ref BigInteger rhs, ref BigInteger result)
  640. {
  641. if (lhs.IsZero() || rhs.IsOne())
  642. {
  643. result.SetValue(ref lhs);
  644. return;
  645. }
  646. if (rhs.IsZero())
  647. {
  648. result.SetZero();
  649. return;
  650. }
  651. ref readonly BigInteger large = ref lhs;
  652. int largeLength = lhs._length;
  653. ref readonly BigInteger small = ref rhs;
  654. int smallLength = rhs._length;
  655. if (largeLength < smallLength)
  656. {
  657. large = ref rhs;
  658. largeLength = rhs._length;
  659. small = ref lhs;
  660. smallLength = lhs._length;
  661. }
  662. int maxResultLength = smallLength + largeLength;
  663. Debug.Assert(unchecked((uint)(maxResultLength)) <= MaxBlockCount);
  664. // Zero out result internal blocks.
  665. Buffer.ZeroMemory((byte*)result.GetBlocksPointer(), (uint)maxResultLength * sizeof(uint));
  666. int smallIndex = 0;
  667. int resultStartIndex = 0;
  668. while (smallIndex < smallLength)
  669. {
  670. // Multiply each block of large BigNum.
  671. if (small._blocks[smallIndex] != 0)
  672. {
  673. int largeIndex = 0;
  674. int resultIndex = resultStartIndex;
  675. ulong carry = 0;
  676. do
  677. {
  678. ulong product = result._blocks[resultIndex] + ((ulong)(small._blocks[smallIndex]) * large._blocks[largeIndex]) + carry;
  679. carry = product >> 32;
  680. result._blocks[resultIndex] = (uint)(product);
  681. resultIndex++;
  682. largeIndex++;
  683. }
  684. while (largeIndex < largeLength);
  685. result._blocks[resultIndex] = (uint)(carry);
  686. }
  687. smallIndex++;
  688. resultStartIndex++;
  689. }
  690. if ((maxResultLength > 0) && (result._blocks[maxResultLength - 1] == 0))
  691. {
  692. result._length = (maxResultLength - 1);
  693. }
  694. else
  695. {
  696. result._length = maxResultLength;
  697. }
  698. }
  699. public static void Pow2(uint exponent, out BigInteger result)
  700. {
  701. uint blocksToShift = DivRem32(exponent, out uint remainingBitsToShift);
  702. result._length = (int)blocksToShift + 1;
  703. Debug.Assert(unchecked((uint)result._length) <= MaxBlockCount);
  704. if (blocksToShift > 0)
  705. {
  706. Buffer.ZeroMemory((byte*)result.GetBlocksPointer(), blocksToShift * sizeof(uint));
  707. }
  708. result._blocks[blocksToShift] = 1U << (int)(remainingBitsToShift);
  709. }
  710. public static void Pow10(uint exponent, out BigInteger result)
  711. {
  712. // We leverage two arrays - s_Pow10UInt32Table and s_Pow10BigNumTable to speed up the Pow10 calculation.
  713. //
  714. // s_Pow10UInt32Table stores the results of 10^0 to 10^7.
  715. // s_Pow10BigNumTable stores the results of 10^8, 10^16, 10^32, 10^64, 10^128, 10^256, and 10^512
  716. //
  717. // For example, let's say exp = 0b111111. We can split the exp to two parts, one is small exp,
  718. // which 10^smallExp can be represented as uint, another part is 10^bigExp, which must be represented as BigNum.
  719. // So the result should be 10^smallExp * 10^bigExp.
  720. //
  721. // Calculating 10^smallExp is simple, we just lookup the 10^smallExp from s_Pow10UInt32Table.
  722. // But here's a bad news: although uint can represent 10^9, exp 9's binary representation is 1001.
  723. // That means 10^(1011), 10^(1101), 10^(1111) all cannot be stored as uint, we cannot easily say something like:
  724. // "Any bits <= 3 is small exp, any bits > 3 is big exp". So instead of involving 10^8, 10^9 to s_Pow10UInt32Table,
  725. // consider 10^8 and 10^9 as a bigNum, so they fall into s_Pow10BigNumTable. Now we can have a simple rule:
  726. // "Any bits <= 3 is small exp, any bits > 3 is big exp".
  727. //
  728. // For 0b111111, we first calculate 10^(smallExp), which is 10^(7), now we can shift right 3 bits, prepare to calculate the bigExp part,
  729. // the exp now becomes 0b000111.
  730. //
  731. // Apparently the lowest bit of bigExp should represent 10^8 because we have already shifted 3 bits for smallExp, so s_Pow10BigNumTable[0] = 10^8.
  732. // Now let's shift exp right 1 bit, the lowest bit should represent 10^(8 * 2) = 10^16, and so on...
  733. //
  734. // That's why we just need the values of s_Pow10BigNumTable be power of 2.
  735. //
  736. // More details of this implementation can be found at: https://github.com/dotnet/coreclr/pull/12894#discussion_r128890596
  737. // Validate that `s_Pow10BigNumTable` has exactly enough trailing elements to fill a BigInteger (which contains MaxBlockCount + 1 elements)
  738. // We validate here, since this is the only current consumer of the array
  739. Debug.Assert((s_Pow10BigNumTableIndices[^1] + MaxBlockCount + 2) == s_Pow10BigNumTable.Length);
  740. BigInteger temp1 = new BigInteger(s_Pow10UInt32Table[exponent & 0x7]);
  741. ref BigInteger lhs = ref temp1;
  742. BigInteger temp2 = new BigInteger(0);
  743. ref BigInteger product = ref temp2;
  744. exponent >>= 3;
  745. uint index = 0;
  746. while (exponent != 0)
  747. {
  748. // If the current bit is set, multiply it with the corresponding power of 10
  749. if ((exponent & 1) != 0)
  750. {
  751. // Multiply into the next temporary
  752. fixed (uint* pBigNumEntry = &s_Pow10BigNumTable[s_Pow10BigNumTableIndices[index]])
  753. {
  754. ref BigInteger rhs = ref *(BigInteger*)(pBigNumEntry);
  755. Multiply(ref lhs, ref rhs, ref product);
  756. }
  757. // Swap to the next temporary
  758. ref BigInteger temp = ref product;
  759. product = ref lhs;
  760. lhs = ref temp;
  761. }
  762. // Advance to the next bit
  763. ++index;
  764. exponent >>= 1;
  765. }
  766. result = new BigInteger(0);
  767. result.SetValue(ref lhs);
  768. }
  769. private static uint AddDivisor(ref BigInteger lhs, int lhsStartIndex, ref BigInteger rhs)
  770. {
  771. int lhsLength = lhs._length;
  772. int rhsLength = rhs._length;
  773. Debug.Assert(lhsLength >= 0);
  774. Debug.Assert(rhsLength >= 0);
  775. Debug.Assert(lhsLength >= rhsLength);
  776. // Repairs the dividend, if the last subtract was too much
  777. ulong carry = 0UL;
  778. for (int i = 0; i < rhsLength; i++)
  779. {
  780. ref uint lhsValue = ref lhs._blocks[lhsStartIndex + i];
  781. ulong digit = lhsValue + carry + rhs._blocks[i];
  782. lhsValue = unchecked((uint)digit);
  783. carry = digit >> 32;
  784. }
  785. return (uint)(carry);
  786. }
  787. private static bool DivideGuessTooBig(ulong q, ulong valHi, uint valLo, uint divHi, uint divLo)
  788. {
  789. Debug.Assert(q <= 0xFFFFFFFF);
  790. // We multiply the two most significant limbs of the divisor
  791. // with the current guess for the quotient. If those are bigger
  792. // than the three most significant limbs of the current dividend
  793. // we return true, which means the current guess is still too big.
  794. ulong chkHi = divHi * q;
  795. ulong chkLo = divLo * q;
  796. chkHi += (chkLo >> 32);
  797. chkLo &= uint.MaxValue;
  798. if (chkHi < valHi)
  799. return false;
  800. if (chkHi > valHi)
  801. return true;
  802. if (chkLo < valLo)
  803. return false;
  804. if (chkLo > valLo)
  805. return true;
  806. return false;
  807. }
  808. private static uint SubtractDivisor(ref BigInteger lhs, int lhsStartIndex, ref BigInteger rhs, ulong q)
  809. {
  810. int lhsLength = lhs._length - lhsStartIndex;
  811. int rhsLength = rhs._length;
  812. Debug.Assert(lhsLength >= 0);
  813. Debug.Assert(rhsLength >= 0);
  814. Debug.Assert(lhsLength >= rhsLength);
  815. Debug.Assert(q <= uint.MaxValue);
  816. // Combines a subtract and a multiply operation, which is naturally
  817. // more efficient than multiplying and then subtracting...
  818. ulong carry = 0;
  819. for (int i = 0; i < rhsLength; i++)
  820. {
  821. carry += rhs._blocks[i] * q;
  822. uint digit = unchecked((uint)carry);
  823. carry >>= 32;
  824. ref uint lhsValue = ref lhs._blocks[lhsStartIndex + i];
  825. if (lhsValue < digit)
  826. {
  827. carry++;
  828. }
  829. lhsValue = unchecked(lhsValue - digit);
  830. }
  831. return (uint)(carry);
  832. }
  833. public void Add(uint value)
  834. {
  835. int length = _length;
  836. if (length == 0)
  837. {
  838. SetUInt32(value);
  839. return;
  840. }
  841. _blocks[0] += value;
  842. if (_blocks[0] >= value)
  843. {
  844. // No carry
  845. return;
  846. }
  847. for (int index = 1; index < length; index++)
  848. {
  849. _blocks[index]++;
  850. if (_blocks[index] > 0)
  851. {
  852. // No carry
  853. return;
  854. }
  855. }
  856. Debug.Assert(unchecked((uint)(length)) + 1 <= MaxBlockCount);
  857. _blocks[length] = 1;
  858. _length = length + 1;
  859. }
  860. public uint GetBlock(uint index)
  861. {
  862. Debug.Assert(index < _length);
  863. return _blocks[index];
  864. }
  865. public int GetLength()
  866. {
  867. return _length;
  868. }
  869. public bool IsOne()
  870. {
  871. return (_length == 1)
  872. && (_blocks[0] == 1);
  873. }
  874. public bool IsZero()
  875. {
  876. return _length == 0;
  877. }
  878. public void Multiply(uint value)
  879. {
  880. Multiply(ref this, value, ref this);
  881. }
  882. public void Multiply(ref BigInteger value)
  883. {
  884. BigInteger temp = new BigInteger(0);
  885. temp.SetValue(ref this);
  886. Multiply(ref temp, ref value, ref this);
  887. }
  888. public void Multiply10()
  889. {
  890. if (IsZero())
  891. {
  892. return;
  893. }
  894. int index = 0;
  895. int length = _length;
  896. ulong carry = 0;
  897. while (index < length)
  898. {
  899. ulong block = (ulong)(_blocks[index]);
  900. ulong product = (block << 3) + (block << 1) + carry;
  901. carry = product >> 32;
  902. _blocks[index] = (uint)(product);
  903. index++;
  904. }
  905. if (carry != 0)
  906. {
  907. Debug.Assert(unchecked((uint)(_length)) + 1 <= MaxBlockCount);
  908. _blocks[index] = (uint)carry;
  909. _length++;
  910. }
  911. }
  912. public void MultiplyPow10(uint exponent)
  913. {
  914. if (IsZero())
  915. {
  916. return;
  917. }
  918. Pow10(exponent, out BigInteger poweredValue);
  919. if (poweredValue._length == 1)
  920. {
  921. Multiply(poweredValue._blocks[0]);
  922. }
  923. else
  924. {
  925. Multiply(ref poweredValue);
  926. }
  927. }
  928. public void SetUInt32(uint value)
  929. {
  930. if (value == 0)
  931. {
  932. SetZero();
  933. }
  934. else
  935. {
  936. _blocks[0] = value;
  937. _length = 1;
  938. }
  939. }
  940. public void SetUInt64(ulong value)
  941. {
  942. if (value <= uint.MaxValue)
  943. {
  944. SetUInt32((uint)(value));
  945. }
  946. else
  947. {
  948. _blocks[0] = (uint)(value);
  949. _blocks[1] = (uint)(value >> 32);
  950. _length = 2;
  951. }
  952. }
  953. public void SetValue(ref BigInteger rhs)
  954. {
  955. int rhsLength = rhs._length;
  956. Buffer.Memcpy((byte*)GetBlocksPointer(), (byte*)rhs.GetBlocksPointer(), rhsLength * sizeof(uint));
  957. _length = rhsLength;
  958. }
  959. public void SetZero()
  960. {
  961. _length = 0;
  962. }
  963. public void ShiftLeft(uint shift)
  964. {
  965. // Process blocks high to low so that we can safely process in place
  966. int length = _length;
  967. if ((length == 0) || (shift == 0))
  968. {
  969. return;
  970. }
  971. uint blocksToShift = DivRem32(shift, out uint remainingBitsToShift);
  972. // Copy blocks from high to low
  973. int readIndex = (length - 1);
  974. int writeIndex = readIndex + (int)(blocksToShift);
  975. // Check if the shift is block aligned
  976. if (remainingBitsToShift == 0)
  977. {
  978. Debug.Assert(writeIndex < MaxBlockCount);
  979. while (readIndex >= 0)
  980. {
  981. _blocks[writeIndex] = _blocks[readIndex];
  982. readIndex--;
  983. writeIndex--;
  984. }
  985. _length += (int)(blocksToShift);
  986. // Zero the remaining low blocks
  987. Buffer.ZeroMemory((byte*)GetBlocksPointer(), blocksToShift * sizeof(uint));
  988. }
  989. else
  990. {
  991. // We need an extra block for the partial shift
  992. writeIndex++;
  993. Debug.Assert(writeIndex < MaxBlockCount);
  994. // Set the length to hold the shifted blocks
  995. _length = writeIndex + 1;
  996. // Output the initial blocks
  997. uint lowBitsShift = (32 - remainingBitsToShift);
  998. uint highBits = 0;
  999. uint block = _blocks[readIndex];
  1000. uint lowBits = block >> (int)(lowBitsShift);
  1001. while (readIndex > 0)
  1002. {
  1003. _blocks[writeIndex] = highBits | lowBits;
  1004. highBits = block << (int)(remainingBitsToShift);
  1005. --readIndex;
  1006. --writeIndex;
  1007. block = _blocks[readIndex];
  1008. lowBits = block >> (int)lowBitsShift;
  1009. }
  1010. // Output the final blocks
  1011. _blocks[writeIndex] = highBits | lowBits;
  1012. _blocks[writeIndex - 1] = block << (int)(remainingBitsToShift);
  1013. // Zero the remaining low blocks
  1014. Buffer.ZeroMemory((byte*)GetBlocksPointer(), blocksToShift * sizeof(uint));
  1015. // Check if the terminating block has no set bits
  1016. if (_blocks[_length - 1] == 0)
  1017. {
  1018. _length--;
  1019. }
  1020. }
  1021. }
  1022. public ulong ToUInt64()
  1023. {
  1024. if (_length > 1)
  1025. {
  1026. return ((ulong)(_blocks[1]) << 32) + _blocks[0];
  1027. }
  1028. if (_length > 0)
  1029. {
  1030. return _blocks[0];
  1031. }
  1032. return 0;
  1033. }
  1034. private uint* GetBlocksPointer()
  1035. {
  1036. // This is safe to do since we are a ref struct
  1037. return (uint*)(Unsafe.AsPointer(ref _blocks[0]));
  1038. }
  1039. private static uint DivRem32(uint value, out uint remainder)
  1040. {
  1041. remainder = value & 31;
  1042. return value >> 5;
  1043. }
  1044. }
  1045. }
  1046. }