source: trunk/src/helpers/math.c@ 108

Last change on this file since 108 was 88, checked in by umoeller, 24 years ago

Misc changes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1
2/*
3 *@@sourcefile math.c:
4 * some math helpers.
5 *
6 * This file is new with V0.9.14 (2001-07-07) [umoeller]
7 * Unless marked otherwise, these things are based
8 * on public domain code found at
9 * "ftp://ftp.cdrom.com/pub/algorithms/c/".
10 *
11 * Usage: All C programs.
12 *
13 * Function prefix:
14 *
15 * -- math*: semaphore helpers.
16 *
17 *@@added V0.9.14 (2001-07-07) [umoeller]
18 *@@header "helpers\math.h"
19 */
20
21#define OS2EMX_PLAIN_CHAR
22 // this is needed for "os2emx.h"; if this is defined,
23 // emx will define PSZ as _signed_ char, otherwise
24 // as unsigned char
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <math.h>
29
30#include "setup.h" // code generation and debugging options
31
32#include "helpers\math.h"
33#include "helpers\linklist.h"
34#include "helpers\standards.h"
35
36#pragma hdrstop
37
38/*
39 *@@category: Helpers\Math helpers
40 * see math.c.
41 */
42
43
44/*
45 *@@ mathGCD:
46 * returns the greatest common denominator that
47 * evenly divides m and n.
48 *
49 * For example, mathGCD(10, 12) would return 2.
50 *
51 * Modern Euclidian algorithm (The Art of Computer
52 * Programming, 4.5.2).
53 */
54
55int mathGCD(int a, int b)
56{
57 int r;
58
59 while (b)
60 {
61 r = a % b;
62 a = b;
63 b = r;
64 }
65
66 return (a);
67
68}
69
70/* binary GCD alg. Based on following facts.
71 If N and M are even, then gcd(N,M) = 2 * gcd (N/2, M/2)
72 If N even and M odd, then gcd(N,M) = gcd(N/2, M)
73 If N,M odd, then |N-M|<max(N,M) thus guaranteeing that
74 we can use gcd(N,M) = gcd(N-M,M) to reduce.
75 fact: a&1 is 1 iff a is odd. Mult. and Div. by 2 more efficiently
76 implemented as shift-left 1 and shift-right 1 resp.
77
78 Found at http://remus.rutgers.edu/~rhoads/Code/int_gcd.c
79*/
80
81/* long gcd( long a, long b)
82{
83 int t;
84
85 if (a < 0) a = -a;
86 if (!b) return a;
87 if (b < 0) b = -b;
88 if (!a) return b;
89 t = 0;
90 while (! ((a|b) & 1)) {a >>= 1; b >>= 1; ++t;}
91 while (! (a&1)) a >>= 1;
92 while (! (b&1)) b >>= 1;
93 while (a != b)
94 {
95 if (a > b)
96 {
97 a -= b;
98 do {a >>= 1;} while (! (a&1));
99 }
100 else {
101 b -= a;
102 do {b >>= 1;} while (! (b&1));
103 }
104 }
105 return(a<<t); */
106
107/*
108 *@@ mathIsSquare:
109 * returns 1 if x is a perfect square, that is, if
110 *
111 + sqrt(x) ^ 2 ==x
112 */
113
114int mathIsSquare(int x)
115{
116 int t;
117 int z = x % 4849845; // 4849845 = 3*5*7*11*13*17*19
118 double r;
119 // do some quick tests on x to see if we can quickly
120 // eliminate it as a square using quadratic-residues.
121 if (z % 3 == 2)
122 return 0;
123
124 t = z % 5;
125 if((t==2) || (t==3))
126 return 0;
127 t = z % 7;
128 if((t==3) || (t==5) || (t==6))
129 return 0;
130 t = z % 11;
131 if((t==2) || (t==6) || (t==7) || (t==8) || (t==10))
132 return 0;
133 t = z % 13;
134 if((t==2) || (t==5) || (t==6) || (t==7) || (t==8) || (t==11))
135 return 0;
136 t = z % 17;
137 if((t==3) || (t==5) || (t==6) || (t==7) || (t==10) || (t==11) || (t==12) || (t==14))
138 return 0;
139 t = z % 19;
140 if((t==2) || (t==3) || (t==8) || (t==10) || (t==12) || (t==13) || (t==14) || (t==15) || (t==18))
141 return 0;
142
143 // If we get here, we'll have to just try taking
144 // square-root & compare its square...
145 r = sqrt(abs(x));
146 if (r*r == abs(x))
147 return 1;
148
149 return 0;
150}
151
152/*
153 *@@ mathFindFactor:
154 * returns the smallest factor > 1 of n or 1 if n is prime.
155 *
156 * From "http://tph.tuwien.ac.at/~oemer/doc/quprog/node28.html".
157 */
158
159int mathFindFactor(int n)
160{
161 int i,
162 max;
163 if (n <= 0)
164 return 0;
165
166 max = floor(sqrt(n));
167
168 for (i=2;
169 i <= max;
170 i++)
171 {
172 if (n % i == 0)
173 return i;
174 }
175 return 1;
176}
177
178/*
179 *@@ testprime:
180 * returns 1 if n is a prime number.
181 *
182 * From "http://tph.tuwien.ac.at/~oemer/doc/quprog/node28.html".
183 */
184
185int mathIsPrime(unsigned n)
186{
187 int i,
188 max = floor(sqrt(n));
189
190 if (n <= 1)
191 return 0;
192
193 for (i=2;
194 i <= max;
195 i++)
196 {
197 if (n % i == 0)
198 return 0;
199 }
200
201 return 1;
202}
203
204/*
205 *@@ mathFactorBrute:
206 * calls pfnCallback with every integer that
207 * evenly divides n ("factor").
208 *
209 * pfnCallback must be declared as:
210 *
211 + int pfnCallback(int iFactor,
212 + int iPower,
213 + void *pUser);
214 *
215 * pfnCallback will receive the factor as its
216 * first parameter and pUser as its third.
217 * The second parameter will always be 1.
218 *
219 * The factor will not necessarily be prime,
220 * and it will never be 1 nor n.
221 *
222 * If the callback returns something != 0,
223 * computation is stopped.
224 *
225 * Returns the no. of factors found or 0 if
226 * n is prime.
227 *
228 * Example: mathFactor(42) will call the
229 * callback with
230 *
231 + 2 3 6 7 14 21
232 *
233 + This func is terribly slow.
234 */
235
236int mathFactorBrute(int n, // in: integer to factor
237 PFNFACTORCALLBACK pfnCallback, // in: callback func
238 void *pUser) // in: user param for callback
239{
240 int rc = 0;
241
242 if (n > 2)
243 {
244 int i;
245 int max = n / 2;
246
247 for (i = 2;
248 i <= max;
249 i++)
250 {
251 if ((n % i) == 0)
252 {
253 rc++;
254 // call callback with i as the factor
255 if (pfnCallback(i,
256 1,
257 pUser))
258 // stop then
259 break;
260 }
261 }
262 }
263
264 return (rc);
265}
266
267/*
268 *@@ mathFactorPrime:
269 * calls pfnCallback for every prime factor that
270 * evenly divides n.
271 *
272 * pfnCallback must be declared as:
273 *
274 + int pfnCallback(int iFactor,
275 + int iPower,
276 + void *pUser);
277 *
278 * pfnCallback will receive the prime as its
279 * first parameter, its power as its second,
280 * and pUser as its third.
281 *
282 * For example, with n = 200, pfnCallback will
283 * be called twice:
284 *
285 * 1) iFactor = 2, iPower = 3
286 *
287 * 2) iFactor = 5, iPower = 2
288 *
289 * because 2^3 * 5^2 is 200.
290 *
291 * Returns the no. of times that the callback
292 * was called. This will be the number of
293 * prime factors found or 0 if n is prime
294 * itself.
295 */
296
297int mathFactorPrime(double n,
298 PFNFACTORCALLBACK pfnCallback, // in: callback func
299 void *pUser) // in: user param for callback
300{
301 int rc = 0;
302
303 double d;
304 double k;
305
306 if (n <= 3)
307 // this is a prime for sure
308 return 0;
309
310 d = 2;
311 for (k = 0;
312 fmod(n, d) == 0;
313 k++)
314 {
315 n /= d;
316 }
317
318 if (k)
319 {
320 rc++;
321 pfnCallback(d,
322 k,
323 pUser);
324 }
325
326 for (d = 3;
327 d * d <= n;
328 d += 2)
329 {
330 for (k = 0;
331 fmod(n,d) == 0.0;
332 k++ )
333 {
334 n /= d;
335 }
336
337 if (k)
338 {
339 rc++;
340 pfnCallback(d,
341 k,
342 pUser);
343 }
344 }
345
346 if (n > 1)
347 {
348 if (!rc)
349 return (0);
350
351 rc++;
352 pfnCallback(n,
353 1,
354 pUser);
355 }
356
357 return (rc);
358}
359
360/*
361 *@@ mathGCDMulti:
362 * finds the greatest common divisor for a
363 * whole array of integers.
364 *
365 * For example, if you pass in three integers
366 * 1000, 1500, and 1800, this would return 100.
367 * If you only pass in 1000 and 1500, you'd
368 * get 500.
369 *
370 * Use the fact that:
371 *
372 * gcd(u1, u2, ..., un) = gcd(u1, gcd(u2, ..., un))
373 *
374 * Greatest common divisor of n integers (The
375 * Art of Computer Programming, 4.5.2).
376 */
377
378int mathGCDMulti(int *paNs, // in: array of integers
379 int cNs) // in: array item count (NOT array size)
380{
381 int d = paNs[cNs-1];
382 int k = cNs-1;
383
384 while ( (d != 1)
385 && (k > 0)
386 )
387 {
388 d = mathGCD(paNs[k-1], d);
389 k--;
390 }
391
392 return (d);
393}
394
395/* typedef struct _PRIMEDATA
396{
397 LINKLIST llPrimes;
398 int iCurrentInt;
399} PRIMEDATA, *PPRIMEDATA;
400
401
402typedef struct _PRIMEENTRY
403{
404 int iPrime;
405 int iLowestPowerFound;
406 // lowest power that was found for this prime number;
407 // if 0, a prime was previously present and then not
408 // for a later prime
409 int iLastInt;
410} PRIMEENTRY, *PPRIMEENTRY; */
411
412/*
413 *@@ GCDMultiCallbackCreate:
414 * first callback for mathGCDMulti.
415 */
416
417/* int XWPENTRY GCDMultiCallbackCreate(int n, // in: prime
418 int p, // in: power
419 void *pUser) // in: user param, here root of tree
420{
421 // see if we had this
422 PPRIMEDATA pData = (PPRIMEDATA)pUser;
423 PLISTNODE pNode;
424 PPRIMEENTRY pEntry;
425 for (pNode = lstQueryFirstNode(&pData->llPrimes);
426 pNode;
427 pNode = pNode->pNext)
428 {
429 pEntry = (PPRIMEENTRY)pNode->pItemData;
430 if (pEntry->iPrime == n)
431 {
432 // mark this as processed so we can later see
433 // if the current integer had this prime factor
434 // at all
435 pEntry->iLastInt = pData->iCurrentInt;
436
437 // printf(" %d^%d", n, p);
438
439 // and stop
440 return 0;
441 }
442 }
443
444 // no entry for this yet:
445 // printf(" %d^%d", n, p);
446 pEntry = NEW(PRIMEENTRY);
447 pEntry->iPrime = n;
448 pEntry->iLowestPowerFound = p;
449 pEntry->iLastInt = pData->iCurrentInt;
450 lstAppendItem(&pData->llPrimes, pEntry);
451
452 return (0);
453} */
454
455/*
456 *@@ GCDMultiCallbackLowest:
457 * second callback for mathGCDMulti.
458 */
459
460/* int XWPENTRY GCDMultiCallbackLowest(int n, // in: prime
461 int p, // in: power
462 void *pUser) // in: user param, here root of tree
463{
464 // see if we had this
465 PPRIMEDATA pData = (PPRIMEDATA)pUser;
466 PLISTNODE pNode;
467 PPRIMEENTRY pEntry;
468 for (pNode = lstQueryFirstNode(&pData->llPrimes);
469 pNode;
470 pNode = pNode->pNext)
471 {
472 pEntry = (PPRIMEENTRY)pNode->pItemData;
473 if (pEntry->iPrime == n)
474 {
475 if (p < pEntry->iLowestPowerFound)
476 {
477 pEntry->iLowestPowerFound = p;
478 // printf(" %d^%d", n, p);
479 }
480 pEntry->iLastInt = pData->iCurrentInt;
481
482 // and stop
483 return 0;
484 }
485 }
486
487 exit(1);
488
489 return (0);
490} */
491
492/* int mathGCDMulti(int *paNs, // in: array of integers
493 int cNs) // in: array item count (NOT array size)
494{
495 int i;
496 double dGCD;
497
498 PLISTNODE pNode;
499 PPRIMEENTRY pEntry;
500
501 PRIMEDATA Data;
502 lstInit(&Data.llPrimes, TRUE);
503
504 // this is done by prime-factoring each frequency
505 // and then multiplying all primes with the lowest
506 // common power that we found:
507
508 // Example 1: If we have two timers with freq.
509 // 1000 and 1500, obviously, the master timer
510 // should run at 500 ms.
511
512 // With prime factorization, we end up like this:
513
514 // 1000 = 2^3 * 5^3
515 // 1500 = 2^2 * 3^1 * 5^3
516
517 // so the highest power for factor 2 is 2;
518 // the highest power for factor 3 is 0;
519 // the highest power for factor 5 is 3;
520
521 // freq = 2^2 * 5^3 = 500
522
523 // Example 2: If we have three timers with freq.
524 // 1000 and 1500 and 1800:
525
526 // 1000 = 2^3 * 5^3
527 // 1500 = 2^2 * 3^1 * 5^3
528 // 1800 = 2^3 * 3^2 * 5^2
529
530 // so the highest power for factor 2 is 2;
531 // the highest power for factor 3 is 0;
532 // the highest power for factor 5 is 2;
533
534 // freq = 2^2 * * 5^2 = 100
535
536 // Example 3: If we have four timers with freq.
537 // 1200 and 1500 and 1800 and 60:
538
539 // 1200 = 2^4 * 3^1 * 5^2
540 // 1500 = 2^2 * 3^1 * 5^3
541 // 1800 = 2^3 * 3^2 * 5^2
542 // 60 = 2^2 * 3^1 * 5^1
543
544 // so the highest power for factor 2 is 2;
545 // the highest power for factor 3 is 1;
546 // the highest power for factor 5 is 1;
547
548 // freq = 2^2 * 3^1 * 5^1 = 60
549
550 // go thru the ints array to create
551 // an entry for each prime there is
552 for (i = 0;
553 i < cNs;
554 i++)
555 {
556 // printf("\nFactoring %d\n", paNs[i]);
557 Data.iCurrentInt = paNs[i];
558 mathFactorPrime(paNs[i],
559 GCDMultiCallbackCreate,
560 &Data);
561 }
562
563 // now run this a second time to find the
564 // lowest prime for each
565 for (i = 0;
566 i < cNs;
567 i++)
568 {
569 // printf("\nTouching %d\n", paNs[i]);
570 Data.iCurrentInt = paNs[i];
571 mathFactorPrime(paNs[i],
572 GCDMultiCallbackLowest,
573 &Data);
574
575 // all list items that were just touched
576 // now have iLastInt set to the current
577 // integer; so go thru the list and set
578 // all items which do NOT have that set
579 // to power 0 because we must not use them
580 // in factoring
581 for (pNode = lstQueryFirstNode(&Data.llPrimes);
582 pNode;
583 pNode = pNode->pNext)
584 {
585 pEntry = (PPRIMEENTRY)pNode->pItemData;
586 if (pEntry->iLastInt != paNs[i])
587 {
588 pEntry->iLowestPowerFound = 0;
589 // printf(" ###%d^%d", pEntry->iPrime, 0);
590 }
591 }
592 }
593
594 // printf("\nNew:\n");
595
596 // now compose the GCD
597 dGCD = 1;
598 for (pNode = lstQueryFirstNode(&Data.llPrimes);
599 pNode;
600 pNode = pNode->pNext)
601 {
602 pEntry = (PPRIMEENTRY)pNode->pItemData;
603
604 // printf(" %d^%d", pEntry->iPrime, pEntry->iLowestPowerFound);
605
606 if (pEntry->iLowestPowerFound)
607 dGCD *= pow(pEntry->iPrime, pEntry->iLowestPowerFound);
608 }
609
610 lstClear(&Data.llPrimes);
611
612 return dGCD;
613} */
614
615// testcase
616
617#ifdef BUILD_MAIN
618
619#define INCL_DOSMISC
620#include <os2.h>
621
622int callback(int n,
623 int p,
624 void *pUser)
625{
626 if (p > 1)
627 printf("%d^%d ", n, p);
628 else
629 printf("%d ", n);
630 fflush(stdout);
631
632 return (0);
633}
634
635int main (int argc, char *argv[])
636{
637 if (argc > 1)
638 {
639 int i,
640 c,
641 cInts = argc - 1;
642 ULONG ulms, ulms2;
643 int *aInts = malloc(sizeof(int) * cInts);
644
645 for (c = 0;
646 c < cInts;
647 c++)
648 {
649 aInts[c] = atoi(argv[c + 1]);
650 }
651
652 DosQuerySysInfo(QSV_MS_COUNT,
653 QSV_MS_COUNT,
654 &ulms,
655 sizeof(ulms));
656
657 c = mathGCDMulti(aInts,
658 cInts);
659
660 DosQuerySysInfo(QSV_MS_COUNT,
661 QSV_MS_COUNT,
662 &ulms2,
663 sizeof(ulms2));
664
665 printf("\nGCD is %d, %d ms time.\n",
666 c,
667 ulms2 - ulms);
668
669 for (i = 0;
670 i < cInts;
671 i++)
672 {
673 printf(" %d / %d = %d rem. %d\n",
674 aInts[i], c, aInts[i] / c, aInts[i] % c);
675 }
676
677 /* c = mathFactorBrute(atoi(argv[1]),
678 callback,
679 0);
680 printf("\n%d factors found.\n", c); */
681 }
682
683 return (0);
684}
685
686#endif
Note: See TracBrowser for help on using the repository browser.