polynomial_adt.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /* Polynomial ADT
  2. ** A polynomial module with
  3. ** ability to add,sub,mul derivate/integrate, compose ... polynomials
  4. ** ..expansion in progress ...
  5. * Copyright (c) 2009 I. Soule
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. ** iasoule32@gmail.com
  30. */
  31. #ifndef __POLYNOMIAL_ADT
  32. #define __POLYNOMIAL_ADT
  33. #include <assert.h>
  34. #include <stdlib.h>
  35. #include <stdbool.h> //C99 compliance
  36. #include <math.h>
  37. #define max(a, b) (a) > (b) ? (a) : (b)
  38. #define sgn(a) (a) < 0 ? '+' : '-' //for quadratic factored form
  39. typedef struct node {
  40. int exp;
  41. float coeff;
  42. struct node *next;
  43. }Node;
  44. typedef struct polynomial_adt {
  45. Node *head;
  46. int terms, hp; //hp highest power
  47. }PolyAdt;
  48. void display_poly(const PolyAdt *a);
  49. /**
  50. * create_adt - create a polynomial on the heap
  51. * @hp: the highest power in the polynomial
  52. */
  53. PolyAdt *create_adt(int hp)
  54. {
  55. PolyAdt *pAdt = malloc(sizeof(PolyAdt));
  56. assert(pAdt != NULL);
  57. pAdt->head = NULL;
  58. pAdt->terms = 0;
  59. pAdt->hp = hp;
  60. return pAdt;
  61. }
  62. /**
  63. * create_node - creates a Node (exponent, constant and next pointer) on the heap
  64. * @constant: the contant in the term
  65. * @exp: the exponent on the term
  66. * @next: the next pointer to another term in the polynomial
  67. *
  68. * This should not be called by client code (hence marked static)
  69. * used to assist insert_term()
  70. */
  71. static Node *create_node(float constant, int exp, Node *next)
  72. {
  73. Node *nNode = malloc(sizeof(Node));
  74. assert(nNode != NULL);
  75. nNode->exp = exp;
  76. nNode->coeff = constant;
  77. nNode->next = next;
  78. return nNode;
  79. }
  80. /**
  81. * insert_term - inserts a term into the polynomial
  82. * @pAdt: the polynomial
  83. * @c: constant value on the term
  84. * @e: the exponent on the term
  85. */
  86. void insert_term(PolyAdt *pAdt, float c, int e)
  87. {
  88. assert(pAdt != NULL); //assume client code didnt call create_adt()
  89. Node *n = malloc(sizeof(Node));
  90. if(pAdt->head == NULL)
  91. pAdt->head = create_node(c, e, pAdt->head);
  92. else
  93. for(n = pAdt->head; n->next != NULL; n = n->next); //go to the end of list
  94. n->next = create_node(c, e, NULL);
  95. pAdt->terms++;
  96. }
  97. /**
  98. * polyImage - returns an image (direct) copy of the polynomial
  99. * @orig: the polynomial to be duplicated
  100. */
  101. PolyAdt *polyImage(const PolyAdt *orig)
  102. {
  103. PolyAdt *img = create_adt(orig->hp);
  104. Node *origHead = orig->head;
  105. for(; origHead; origHead = origHead->next)
  106. insert_term(img, origHead->coeff, origHead->exp);
  107. return img;
  108. }
  109. /**
  110. * add - adds two polynomials together, and returns their sum (as a polynomial)
  111. * @a: the 1st polynomial
  112. * @b: the 2nd polynomial
  113. */
  114. PolyAdt *add(const PolyAdt *a, const PolyAdt *b)
  115. {
  116. PolyAdt *sum;
  117. Node *n, *np;
  118. _Bool state = true;
  119. assert(a != NULL && b != NULL);
  120. int hpow = max(a->hp, b->hp);
  121. sum = create_adt(hpow); //create space for it
  122. /* using state machine to compare the poly with the most terms to
  123. ** the poly with fewer, round robin type of effect comparison of
  124. ** exponents => 3 Cases: Equal, Less, Greater
  125. */
  126. n = a->head; np = b->head;
  127. while(state) {
  128. /* compare the exponents */
  129. if(n->exp == np->exp){
  130. insert_term(sum, n->coeff + np->coeff, n->exp);
  131. n = n->next;
  132. np = np->next;
  133. }
  134. else if(n->exp < np->exp){
  135. insert_term(sum, np->coeff, np->exp);
  136. np = np->next; //move to next term of b
  137. }
  138. else { //greater than
  139. insert_term(sum, n->coeff, n->exp);
  140. n = n->next;
  141. }
  142. /* check whether at the end of one list or the other */
  143. if(np == NULL && state == true){ //copy rest of a to sum
  144. for(; n != NULL; n = n->next)
  145. insert_term(sum, n->coeff, n->exp);
  146. state = false;
  147. }
  148. if(n == NULL && state == true){
  149. for(; np != NULL; np = np->next)
  150. insert_term(sum, np->coeff, np->exp);
  151. state = false;
  152. }
  153. }
  154. return sum;
  155. }
  156. /**
  157. * sub - subtracts two polynomials, and returns their difference (as a polynomial)
  158. * @a: the 1st polynomial
  159. * @b: the 2nd polynomial
  160. * Aids in code reuse by negating the terms (b) and then calls the add() function
  161. */
  162. PolyAdt *subtract(const PolyAdt *a, const PolyAdt *b)
  163. {
  164. assert(a != NULL && b != NULL);
  165. PolyAdt *tmp = create_adt(b->hp);
  166. Node *bptr;
  167. for(bptr = b->head; bptr != NULL; bptr = bptr->next)
  168. insert_term(tmp,-bptr->coeff,bptr->exp); //negating b's coeffs
  169. return add(a,tmp);
  170. }
  171. /**
  172. * multiply - multiply two polynomials, and returns their product (as a polynomial)
  173. * @a: the 1st polynomial
  174. * @b: the 2nd polynomial
  175. */
  176. PolyAdt *multiply(const PolyAdt *a, const PolyAdt *b)
  177. {
  178. assert(a != NULL && b != NULL);
  179. //the polys are inserted in order for now
  180. PolyAdt *prod = create_adt(a->head->exp + b->head->exp);
  181. Node *n = a->head, *np = b->head;
  182. Node *t = b->head;
  183. if(a->terms < b->terms){
  184. n = b->head;
  185. np = t = a->head;
  186. }
  187. for(; n != NULL; n = n->next){
  188. np = t; //reset to the beginning
  189. for(; np != NULL; np = np->next){ //always the least term in this loop
  190. insert_term(prod, n->coeff * np->coeff, n->exp + np->exp);
  191. }
  192. }
  193. return prod;
  194. }
  195. /**
  196. * derivative - computes the derivative of a polynomial and returns the result
  197. * @a: the polynomial to take the derivative upon
  198. */
  199. PolyAdt *derivative(const PolyAdt *a)
  200. {
  201. assert(a != NULL);
  202. PolyAdt *deriv = create_adt(a->head->exp - 1);
  203. Node *n = a->head;
  204. for(; n != NULL; n = n->next){
  205. if(n->exp == 0) break;
  206. insert_term(deriv, n->coeff * n->exp, n->exp-1);
  207. }
  208. return deriv;
  209. }
  210. /**
  211. * integrate - computes the integral of a polynomial and returns the result
  212. * @a: the polynomial to take the integral of
  213. *
  214. * Will compute an indefinite integral over a
  215. */
  216. PolyAdt *integrate(const PolyAdt *a)
  217. {
  218. assert(a != NULL);
  219. PolyAdt *integrand = create_adt(a->head->exp + 1);
  220. Node *n;
  221. for(n = a->head; n != NULL; n = n->next) //very simple term by term
  222. insert_term(integrand, (float)n->coeff/(n->exp+1.0F), n->exp + 1);
  223. return integrand;
  224. }
  225. /**
  226. * quadratic_roots - finds the roots of the polynomial ax^2+bx+c, a != 0 && b != 0
  227. * @a: the polynomial
  228. * @real: a pointer to float of the real(R) part of a
  229. * @cplx: a pointer to float of the imaginary(I) part of a
  230. *
  231. * Usage:
  232. * Two options can be done by the client
  233. * 1. Either pass NULL to real and cplx
  234. * this will display the roots by printf
  235. * quadratic_roots(myPolynomial, NULL, NULL);
  236. *
  237. * 2. Pass in pointers** to type float of the real and complex
  238. * if the discriminant is >0 cplx = -ve root of X
  239. * quadratic_roots(myPolynomial, &realPart, &complexPart);
  240. */
  241. void quadratic_roots(const PolyAdt *a, float *real, float *cplx)
  242. {
  243. assert(a != NULL);
  244. float dscrmnt, _a, b, c;
  245. float u, v;
  246. Node *n = a->head;
  247. _a = n->coeff; b = n->next->coeff; c = n->next->next->coeff;
  248. dscrmnt = (b*b) - 4*_a*c;
  249. u = -b/(2*_a); v = sqrt((double)fabs(dscrmnt))/(2*_a);
  250. if(real && !cplx || !real && cplx)
  251. assert(true);
  252. if(real == NULL && cplx == NULL){
  253. if(a->hp != 2 && a->terms < 3){
  254. printf("Invalid Quadratic*, A and B must be non-zero");
  255. return;
  256. }
  257. if(dscrmnt != 0)
  258. printf("X = %.2f +/- %.2f%c\n",u,v,dscrmnt < 0 ? 'I':' ');
  259. else{
  260. printf("(X %c %.2f)(X %c %.2f)\n",sgn(u),fabs(u),sgn(u),fabs(u));
  261. printf("X1,2 = %.2f\n",u);
  262. }
  263. }
  264. //save values in pointers
  265. else {
  266. if(dscrmnt < 0){ //x = u +/- vI Re(x) = u, Im(x) = +v
  267. *real = u;
  268. *cplx = v; //understand +/- is not representable
  269. }
  270. else if(dscrmnt == 0){
  271. *real = u;
  272. *cplx = 0.00F;
  273. }
  274. else{
  275. *real = u + v;
  276. *cplx = u - v;
  277. }
  278. }
  279. }
  280. /**
  281. * exponentiate - computes polynomial exponentiation (P(x))^n, n E Z*
  282. * @a: the polynomial
  283. * @n: the exponent
  284. * Works fast for small n (n < 8) currently runs ~ O(n^2 lg n)
  285. */
  286. PolyAdt *exponentiate(const PolyAdt *a, int n)
  287. {
  288. assert(a != NULL);
  289. PolyAdt *expn = create_adt(a->hp * n);
  290. PolyAdt *aptr = polyImage(a);
  291. int hl = n / 2;
  292. //check default cases before calculation
  293. if(n == 0){
  294. insert_term(expn, 1, 0);
  295. return expn;
  296. }
  297. else if(n == 1){
  298. return aptr;
  299. }
  300. for(; hl ; hl--)
  301. aptr = multiply(aptr, aptr);
  302. if(n % 2) //odd exponent do a^(n-1) * a = a^n
  303. expn = multiply(aptr, a);
  304. else
  305. expn = aptr;
  306. return expn;
  307. }
  308. /**
  309. * compose - computes the composition of two polynomials P(Q(x)) and returns the composition
  310. * @p: polynomial P(x) which will x will be equal to Q(x)
  311. * @q: polynomial Q(x) which is the argument to P(x)
  312. */
  313. PolyAdt *compose(const PolyAdt *p, const PolyAdt *q)
  314. {
  315. assert(p && q);
  316. PolyAdt *comp = create_adt(p->head->exp * q->head->exp);
  317. PolyAdt *exp;
  318. Node *pp = p->head;
  319. Node *qq = q->head;
  320. int swap = 0;
  321. if(p->terms < q->terms){
  322. pp = q->head;
  323. qq = p->head;
  324. swap = 1;
  325. }
  326. /* going through, exponentiate each term with the exponent of p */
  327. for(; pp != NULL; pp = pp->next){
  328. exp = exponentiate(swap ? p: q, pp->exp);
  329. insert_term(comp, pp->coeff * exp->head->coeff, exp->head->exp);
  330. }
  331. return comp;
  332. }
  333. /**
  334. * destroy_poly - completely frees the polynomial from the heap and resets all values
  335. * @poly: the polynomial to release memory back to the heap
  336. * Usage:
  337. * destroy_poly(myPoly); //puts polynomial on free list
  338. */
  339. void destroy_poly(PolyAdt *poly)
  340. {
  341. Node *ps = poly->head;
  342. Node *tmp = NULL;
  343. while(ps != NULL){
  344. tmp = ps;
  345. free(tmp);
  346. ps = ps->next;
  347. }
  348. poly->hp = poly->terms = 0;
  349. poly->head = NULL;
  350. }
  351. /**
  352. * display_poly - displays the polynomial to the console in nice format
  353. * @a: the polynomial to display
  354. */
  355. void display_poly(const PolyAdt *a)
  356. {
  357. assert(a != NULL);
  358. Node *n;
  359. for(n = a->head; n != NULL; n = n->next){
  360. n->coeff < 0 ? putchar('-') : putchar('+');
  361. if(n->exp == 0)
  362. printf(" %.2f ",fabs(n->coeff));
  363. else if(n->coeff == 1)
  364. printf(" X^%d ",n->exp);
  365. else if(n->exp == 1)
  366. printf(" %.2fX ",fabs(n->coeff));
  367. else if(n->coeff == 0)
  368. continue;
  369. else
  370. printf(" %.2fX^%d ",fabs(n->coeff),n->exp);
  371. }
  372. printf("\n\n");
  373. }
  374. #endif