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

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

Couple of files that were missing.

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