Pweebs

BigInteger.c (as of 9:27 PM, 11/13)

Nov 13th, 2019
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.57 KB | None | 0 0
  1. // Jevin Olano
  2. // jolano
  3. // CSE 101
  4. // November 9, 2019
  5. // BigInteger.c
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <assert.h>
  10. #include <string.h>
  11. #include "BigInteger.h"
  12. #include "List.h"
  13.  
  14. const int POWER = 9;
  15. const int BASE = 1000000000;
  16.  
  17. // Constructors & Destructors ---------------------------
  18.  
  19. // newBigInteger()
  20. // Returns a reference to a new BigInteger object in the zero state.
  21. BigInteger newBigInteger() {
  22. BigInteger bi = malloc(sizeof(BigIntegerObj));
  23. bi->number = newList();
  24. bi->sign = 0;
  25. return bi;
  26. }
  27.  
  28. // freeBigInteger()
  29. // Frees heap memory associated with *pN, sets *pN to NULL.
  30. void freeBigInteger(BigInteger *pN) {
  31. BigInteger N = *pN;
  32. makeZero(N);
  33. free(N);
  34. N = NULL;
  35. }
  36.  
  37. // Access Functions -------------------------------------
  38.  
  39. // sign()
  40. // Returns -1 if N is negative, 1 if N is positive, and 0 if N is in the zero state.
  41. int sign(BigInteger N) {
  42. return N->sign;
  43. }
  44.  
  45. // compare()
  46. // Returns -1 if A<B, 1 if A>B, and 0 if A=B.
  47. int compare(BigInteger A, BigInteger B) {
  48. if (A->sign == 0 && B->sign == 0) {
  49. return 0; // if both A & B are in the zero state
  50. }
  51. if (A->sign > B->sign) {
  52. return 1; // if A is positive and B is negative
  53. }
  54. if (A->sign < B->sign) {
  55. return -1; // if A is negative and B is positive
  56. }
  57.  
  58. int lengthA = length(A->number);
  59. int lengthB = length(B->number);
  60. if (lengthA > lengthB && A->sign == 1) {
  61. return 1; // if both A & B are positive and A is longer than B
  62. }
  63. if (lengthA > lengthB && A->sign == -1) {
  64. return -1; // if both A & B are negative and A is longer than B
  65. }
  66. if (lengthB > lengthA && B->sign == 1) {
  67. return -1; // if both A & B are positive and B is longer than A
  68. }
  69. if (lengthB > lengthA && B->sign == -1) {
  70. return 1; // if both A & B are negative and B is longer than A
  71. }
  72.  
  73. BigInteger clonedB = copy(B);
  74.  
  75. // at this point, A & B must be the same sign
  76. moveFront(A->number);
  77. moveFront(clonedB->number);
  78. while (get(A->number) != -1) {
  79. int digitA = get(A->number);
  80. int digitB = get(clonedB->number);
  81. if (digitA > digitB && A->sign == 1) {
  82. return 1;
  83. }
  84. if (digitA < digitB && A->sign == 1) {
  85. return -1;
  86. }
  87. if (digitA > digitB && A->sign == -1) {
  88. return -1;
  89. }
  90. if (digitA < digitB && A->sign == -1) {
  91. return 1;
  92. }
  93. moveNext(A->number);
  94. moveNext(clonedB->number);
  95. }
  96. freeBigInteger(&clonedB);
  97. return 0;
  98. }
  99.  
  100. // equals()
  101. // Return true (1) if A and B are equal, false (0) otherwise.
  102. int equals(BigInteger A, BigInteger B) {
  103. return compare(A, B) == 0 ? 1 : 0;
  104. }
  105.  
  106. // Manipulation Procedures ------------------------------
  107.  
  108. // makeZero()
  109. // Re-sets N to the zero state.
  110. void makeZero(BigInteger N) {
  111. clear(N->number);
  112. N->sign = 0;
  113. }
  114.  
  115. // negate()
  116. // Reverses the sign of N: positive <--> negative. Does nothing if N is in the zero state.
  117. void negate(BigInteger N) {
  118. N->sign *= -1;
  119. }
  120.  
  121. // BigInteger Arithmetic Operations ---------------------
  122.  
  123. // private helper
  124. long strToLong(char *s, long numChars) {
  125. char buffer[10];
  126. for (int i = 0; i < numChars; i++) {
  127. buffer[i] = s[i];
  128. }
  129. buffer[numChars] = '\0';
  130. return strtol(buffer, NULL, 10);
  131. }
  132.  
  133. // stringToBigInteger()
  134. // Returns a reference to a new BigInteger represented in base 10 by the string s.
  135. // Pre: s is a non-empty string containing only base ten digits {0,1,2,3,4,5,6,7,8,9}
  136. // and an optional sign {+, -} prefix.
  137. BigInteger stringToBigInteger(char* s) {
  138. BigInteger bi = newBigInteger();
  139.  
  140. // handles input = '0'
  141. if (strlen(s) == 1 && s[0] == '0') {
  142. return bi;
  143. }
  144.  
  145. // p is basically a cursor
  146. char *p = s;
  147.  
  148. // checks optional sign prefixes
  149. if (s[0] == '+') {
  150. bi->sign = 1;
  151. p++;
  152. } else if (s[0] == '-') {
  153. bi->sign = -1;
  154. p++;
  155. } else {
  156. bi->sign = 1;
  157. }
  158.  
  159. // check for incomplete digit (incomplete chunk)
  160. int remainder = strlen(p) % POWER;
  161. if (remainder > 0) {
  162. append(bi->number, strToLong(p, remainder));
  163. p += remainder;
  164. }
  165.  
  166. // add "full" digits
  167. int numDigitsLeft = strlen(p) / POWER;
  168. for (int i = 0; i < numDigitsLeft; i++) {
  169. append(bi->number, strToLong(p, POWER));
  170. p += POWER;
  171. }
  172.  
  173. return bi;
  174. }
  175.  
  176. // copy()
  177. // Returns a reference to a new BigInteger object in the same state as N.
  178. BigInteger copy(BigInteger N) {
  179. BigInteger copyInt = newBigInteger();
  180. copyInt->sign = N->sign;
  181. copyInt->number = copyList(N->number);
  182. return copyInt;
  183. }
  184.  
  185. // longerNumLength
  186. // helper method
  187. int longerNumLength(BigInteger A, BigInteger B) {
  188. int lengthA = length(A->number);
  189. int lengthB = length(B->number);
  190. return (lengthA > lengthB) ? lengthA : lengthB;
  191. }
  192.  
  193. // getDigit
  194. // helper method
  195. long getDigit(List L) {
  196. long digit = get(L);
  197. return (digit != -1) ? digit : 0;
  198. }
  199.  
  200. // add()
  201. // Places the sum of A and B in the existing BigInteger S, overwriting its current state: S = A + B
  202. void add(BigInteger S, BigInteger A, BigInteger B) {
  203. BigInteger sumInt = sum(A, B);
  204. makeZero(S);
  205. S->sign = sumInt->sign;
  206. S->number = copyList(sumInt->number);
  207. freeBigInteger(&sumInt);
  208. }
  209.  
  210. void removeLeadingZeroes(BigInteger bi) {
  211. if (isEmpty(bi->number)) {
  212. return;
  213. }
  214. moveFront(bi->number);
  215. while(get(bi->number) != -1) {
  216. if (get(bi->number) != 0) {
  217. return;
  218. }
  219. delete(bi->number);
  220. if (isEmpty(bi->number)) {
  221. return;
  222. }
  223. moveFront(bi->number);
  224. }
  225. }
  226.  
  227. // sum()
  228. // Returns a reference to a new BigInteger object representing A + B.
  229. BigInteger sum(BigInteger A, BigInteger B) {
  230. if (A->sign == 0 && B->sign == 0) {
  231. return newBigInteger();
  232. }
  233. if (A->sign == 0) {
  234. return copy(B);
  235. }
  236. if (B->sign == 0) {
  237. return copy(A);
  238. }
  239.  
  240. if (A->sign == 1 && B->sign == -1) {
  241. negate(B);
  242. BigInteger temp = diff(A, B);
  243. negate(B);
  244. return temp;
  245. }
  246.  
  247. if (A->sign == -1 && B->sign == 1) {
  248. negate(A);
  249. BigInteger temp = diff(B, A);
  250. negate(A);
  251. return temp;
  252. }
  253.  
  254. BigInteger sumInt = newBigInteger();
  255.  
  256. BigInteger clonedB = copy(B);
  257.  
  258. moveBack(A->number);
  259. moveBack(clonedB->number);
  260.  
  261. int longerNumLen = longerNumLength(A, clonedB);
  262.  
  263. int carry = 0;
  264.  
  265. for (int i = 0; i < longerNumLen; i++) {
  266. long digitA = getDigit(A->number);
  267. long digitB = getDigit(clonedB->number);
  268. long sum = digitA + digitB + carry;
  269. carry = 0;
  270. if (sum >= BASE) {
  271. sum -= BASE;
  272. carry = 1;
  273. }
  274. prepend(sumInt->number, sum);
  275. movePrev(A->number);
  276. movePrev(clonedB->number);
  277. }
  278.  
  279. if (carry == 1) {
  280. prepend(sumInt->number, 1);
  281. }
  282.  
  283. sumInt->sign = A->sign; // or B->sign since they're the same
  284. freeBigInteger(&clonedB);
  285. removeLeadingZeroes(sumInt);
  286. return sumInt;
  287. }
  288.  
  289. // copyNegate()
  290. // helper method
  291. BigInteger copyNegate(BigInteger A) {
  292. BigInteger negativeA = copy(A);
  293. negate(negativeA);
  294. return negativeA;
  295. }
  296.  
  297. // subtract()
  298. // Places the difference of A and B in the existing BigInteger D, overwriting its current state: D = A - B
  299. void subtract(BigInteger D, BigInteger A, BigInteger B) {
  300. BigInteger diffInt = diff(A, B);
  301. makeZero(D);
  302. D->sign = diffInt->sign;
  303. D->number = copyList(diffInt->number);
  304. freeBigInteger(&diffInt);
  305. }
  306.  
  307. // diff()
  308. // Returns a reference to a new BigInteger object representing A - B.
  309. BigInteger diff(BigInteger A, BigInteger B) {
  310. if (A->sign == 0 && B->sign == 0) {
  311. return newBigInteger();
  312. }
  313. if (A->sign == 0) {
  314. return copyNegate(B);
  315. }
  316. if (B->sign == 0) {
  317. return copy(A);
  318. }
  319. if (A->sign != B->sign) {
  320. return sum(A, copyNegate(B));
  321. }
  322.  
  323. BigInteger diffInt = newBigInteger();
  324. diffInt->sign = equals(A, B) == 1 ? 0 : A->sign;
  325. BigInteger clonedB = copy(B);
  326.  
  327. moveBack(A->number);
  328. moveBack(clonedB->number);
  329.  
  330. int longerNumLen = longerNumLength(A, clonedB);
  331.  
  332. int borrow = 0;
  333.  
  334. for (int i = 0; i < longerNumLen; i++) {
  335. long digitA = getDigit(A->number);
  336. long digitB = getDigit(clonedB->number);
  337. long diff = digitA - digitB - borrow;
  338. borrow = 0;
  339. if (diff < 0) {
  340. diff += BASE;
  341. borrow = 1;
  342. }
  343. prepend(diffInt->number, diff);
  344. movePrev(A->number);
  345. movePrev(clonedB->number);
  346. }
  347.  
  348. if (borrow == 1) {
  349. moveFront(diffInt->number);
  350. set(diffInt->number, get(diffInt->number) - BASE);
  351. negate(diffInt);
  352. }
  353.  
  354. freeBigInteger(&clonedB);
  355. removeLeadingZeroes(diffInt);
  356. return diffInt;
  357. }
  358.  
  359. // multiply()
  360. // Places the product of A and B in the existing BigInteger P, overwriting its current state: P = A * B
  361. void multiply(BigInteger P, BigInteger A, BigInteger B) {
  362. BigInteger prodInt = prod(A, B);
  363. makeZero(P);
  364. P->sign = prodInt->sign;
  365. P->number = copyList(prodInt->number);
  366. freeBigInteger(&prodInt);
  367. }
  368.  
  369. // prod()
  370. // Returns a reference to a new BigInteger object representing A * B.
  371. BigInteger prod(BigInteger A, BigInteger B) {
  372. if (A->sign == 0 || B->sign == 0) {
  373. return newBigInteger(); // zero state
  374. }
  375.  
  376. BigInteger prodInt = newBigInteger();
  377.  
  378. int carry = 0;
  379. int zeroes = 0;
  380. BigInteger prodTemp = newBigInteger();
  381.  
  382. BigInteger clonedB = copy(B);
  383.  
  384. moveBack(A->number);
  385.  
  386. // A = "bottom" number in traditional multiplication
  387. // B = "top" number in traditional multiplication
  388.  
  389. while (A->number->cursor != NULL) {
  390. moveBack(clonedB->number);
  391. makeZero(prodTemp);
  392. int isNonZero = 0;
  393. while (clonedB->number->cursor != NULL) {
  394. long digitA = getDigit(A->number);
  395. printf("digitA is = %ld\n", digitA);
  396. long digitB = getDigit(clonedB->number);
  397. printf("digitB is = %ld\n", digitB);
  398. long prod = digitA * digitB + carry;
  399. printf("prod is = %ld\n", prod);
  400. carry = 0;
  401. if (prod > 0) {
  402. isNonZero = 1;
  403. }
  404. if (prod >= BASE) {
  405. carry = prod/BASE; // integer division drops fractional part
  406. printf("carry is = %d\n", carry);
  407. prod -= BASE * carry;
  408. }
  409. prepend(prodTemp->number, prod);
  410. movePrev(clonedB->number);
  411. }
  412.  
  413. if (carry > 0) {
  414. prepend(prodTemp->number, carry);
  415. isNonZero = 1;
  416. }
  417.  
  418. for (int i = 0; i < zeroes; i++) {
  419. append(prodTemp->number, 0);
  420. }
  421.  
  422. if (isNonZero == 1) {
  423. prodTemp->sign = 1;
  424. }
  425.  
  426. add(prodInt, prodInt, prodTemp);
  427. zeroes++;
  428. movePrev(A->number);
  429. }
  430.  
  431. freeBigInteger(&prodTemp);
  432. freeBigInteger(&clonedB);
  433.  
  434. prodInt->sign = (A->sign == B->sign) ? 1 : -1;
  435. removeLeadingZeroes(prodInt);
  436. return prodInt;
  437. }
  438.  
  439. // Other Operations -------------------------------------
  440.  
  441. // printBigInteger()
  442. // Prints a base 10 string representation of N to filestream out.
  443. void printBigInteger(FILE* out, BigInteger N) {
  444. if (N->sign == 0) {
  445. fprintf(out, "0\n");
  446. return;
  447. }
  448. if (N->sign == -1) {
  449. fprintf(out, "-");
  450. }
  451. moveFront(N->number);
  452. // skip leading zeroes
  453. while (get(N->number) == 0) {
  454. moveNext(N->number);
  455. }
  456. while (get(N->number) != -1) {
  457. fprintf(out, "%ld", get(N->number));
  458. moveNext(N->number);
  459. }
  460. fprintf(out, "\n");
  461. }
Add Comment
Please, Sign In to add comment