[87] | 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 |
|
---|
[88] | 43 |
|
---|
[87] | 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.
|
---|
[88] | 50 | *
|
---|
| 51 | * Modern Euclidian algorithm (The Art of Computer
|
---|
| 52 | * Programming, 4.5.2).
|
---|
[87] | 53 | */
|
---|
| 54 |
|
---|
[88] | 55 | int mathGCD(int a, int b)
|
---|
[87] | 56 | {
|
---|
[88] | 57 | int r;
|
---|
[87] | 58 |
|
---|
[88] | 59 | while (b)
|
---|
[87] | 60 | {
|
---|
[88] | 61 | r = a % b;
|
---|
| 62 | a = b;
|
---|
| 63 | b = r;
|
---|
[87] | 64 | }
|
---|
| 65 |
|
---|
[238] | 66 | return a;
|
---|
[88] | 67 |
|
---|
[87] | 68 | }
|
---|
| 69 |
|
---|
| 70 | /*
|
---|
| 71 | *@@ mathIsSquare:
|
---|
| 72 | * returns 1 if x is a perfect square, that is, if
|
---|
| 73 | *
|
---|
| 74 | + sqrt(x) ^ 2 ==x
|
---|
| 75 | */
|
---|
| 76 |
|
---|
| 77 | int mathIsSquare(int x)
|
---|
| 78 | {
|
---|
| 79 | int t;
|
---|
| 80 | int z = x % 4849845; // 4849845 = 3*5*7*11*13*17*19
|
---|
| 81 | double r;
|
---|
| 82 | // do some quick tests on x to see if we can quickly
|
---|
| 83 | // eliminate it as a square using quadratic-residues.
|
---|
| 84 | if (z % 3 == 2)
|
---|
| 85 | return 0;
|
---|
| 86 |
|
---|
| 87 | t = z % 5;
|
---|
| 88 | if((t==2) || (t==3))
|
---|
| 89 | return 0;
|
---|
| 90 | t = z % 7;
|
---|
| 91 | if((t==3) || (t==5) || (t==6))
|
---|
| 92 | return 0;
|
---|
| 93 | t = z % 11;
|
---|
| 94 | if((t==2) || (t==6) || (t==7) || (t==8) || (t==10))
|
---|
| 95 | return 0;
|
---|
| 96 | t = z % 13;
|
---|
| 97 | if((t==2) || (t==5) || (t==6) || (t==7) || (t==8) || (t==11))
|
---|
| 98 | return 0;
|
---|
| 99 | t = z % 17;
|
---|
| 100 | if((t==3) || (t==5) || (t==6) || (t==7) || (t==10) || (t==11) || (t==12) || (t==14))
|
---|
| 101 | return 0;
|
---|
| 102 | t = z % 19;
|
---|
| 103 | if((t==2) || (t==3) || (t==8) || (t==10) || (t==12) || (t==13) || (t==14) || (t==15) || (t==18))
|
---|
| 104 | return 0;
|
---|
| 105 |
|
---|
| 106 | // If we get here, we'll have to just try taking
|
---|
| 107 | // square-root & compare its square...
|
---|
| 108 | r = sqrt(abs(x));
|
---|
| 109 | if (r*r == abs(x))
|
---|
| 110 | return 1;
|
---|
| 111 |
|
---|
| 112 | return 0;
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 | /*
|
---|
| 116 | *@@ mathFindFactor:
|
---|
| 117 | * returns the smallest factor > 1 of n or 1 if n is prime.
|
---|
| 118 | *
|
---|
| 119 | * From "http://tph.tuwien.ac.at/~oemer/doc/quprog/node28.html".
|
---|
| 120 | */
|
---|
| 121 |
|
---|
| 122 | int mathFindFactor(int n)
|
---|
| 123 | {
|
---|
| 124 | int i,
|
---|
| 125 | max;
|
---|
| 126 | if (n <= 0)
|
---|
| 127 | return 0;
|
---|
| 128 |
|
---|
| 129 | max = floor(sqrt(n));
|
---|
| 130 |
|
---|
| 131 | for (i=2;
|
---|
| 132 | i <= max;
|
---|
| 133 | i++)
|
---|
| 134 | {
|
---|
| 135 | if (n % i == 0)
|
---|
| 136 | return i;
|
---|
| 137 | }
|
---|
| 138 | return 1;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | /*
|
---|
| 142 | *@@ testprime:
|
---|
| 143 | * returns 1 if n is a prime number.
|
---|
| 144 | *
|
---|
| 145 | * From "http://tph.tuwien.ac.at/~oemer/doc/quprog/node28.html".
|
---|
| 146 | */
|
---|
| 147 |
|
---|
| 148 | int mathIsPrime(unsigned n)
|
---|
| 149 | {
|
---|
| 150 | int i,
|
---|
| 151 | max = floor(sqrt(n));
|
---|
| 152 |
|
---|
| 153 | if (n <= 1)
|
---|
| 154 | return 0;
|
---|
| 155 |
|
---|
| 156 | for (i=2;
|
---|
| 157 | i <= max;
|
---|
| 158 | i++)
|
---|
| 159 | {
|
---|
| 160 | if (n % i == 0)
|
---|
| 161 | return 0;
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 | return 1;
|
---|
| 165 | }
|
---|
| 166 |
|
---|
| 167 | /*
|
---|
| 168 | *@@ mathFactorBrute:
|
---|
| 169 | * calls pfnCallback with every integer that
|
---|
| 170 | * evenly divides n ("factor").
|
---|
| 171 | *
|
---|
| 172 | * pfnCallback must be declared as:
|
---|
| 173 | *
|
---|
| 174 | + int pfnCallback(int iFactor,
|
---|
| 175 | + int iPower,
|
---|
| 176 | + void *pUser);
|
---|
| 177 | *
|
---|
| 178 | * pfnCallback will receive the factor as its
|
---|
| 179 | * first parameter and pUser as its third.
|
---|
| 180 | * The second parameter will always be 1.
|
---|
| 181 | *
|
---|
| 182 | * The factor will not necessarily be prime,
|
---|
| 183 | * and it will never be 1 nor n.
|
---|
| 184 | *
|
---|
| 185 | * If the callback returns something != 0,
|
---|
| 186 | * computation is stopped.
|
---|
| 187 | *
|
---|
| 188 | * Returns the no. of factors found or 0 if
|
---|
| 189 | * n is prime.
|
---|
| 190 | *
|
---|
| 191 | * Example: mathFactor(42) will call the
|
---|
| 192 | * callback with
|
---|
| 193 | *
|
---|
| 194 | + 2 3 6 7 14 21
|
---|
| 195 | *
|
---|
| 196 | + This func is terribly slow.
|
---|
| 197 | */
|
---|
| 198 |
|
---|
| 199 | int mathFactorBrute(int n, // in: integer to factor
|
---|
| 200 | PFNFACTORCALLBACK pfnCallback, // in: callback func
|
---|
| 201 | void *pUser) // in: user param for callback
|
---|
| 202 | {
|
---|
| 203 | int rc = 0;
|
---|
| 204 |
|
---|
| 205 | if (n > 2)
|
---|
| 206 | {
|
---|
| 207 | int i;
|
---|
| 208 | int max = n / 2;
|
---|
| 209 |
|
---|
| 210 | for (i = 2;
|
---|
| 211 | i <= max;
|
---|
| 212 | i++)
|
---|
| 213 | {
|
---|
| 214 | if ((n % i) == 0)
|
---|
| 215 | {
|
---|
| 216 | rc++;
|
---|
| 217 | // call callback with i as the factor
|
---|
| 218 | if (pfnCallback(i,
|
---|
| 219 | 1,
|
---|
| 220 | pUser))
|
---|
| 221 | // stop then
|
---|
| 222 | break;
|
---|
| 223 | }
|
---|
| 224 | }
|
---|
| 225 | }
|
---|
| 226 |
|
---|
[238] | 227 | return rc;
|
---|
[87] | 228 | }
|
---|
| 229 |
|
---|
| 230 | /*
|
---|
| 231 | *@@ mathFactorPrime:
|
---|
| 232 | * calls pfnCallback for every prime factor that
|
---|
| 233 | * evenly divides n.
|
---|
| 234 | *
|
---|
| 235 | * pfnCallback must be declared as:
|
---|
| 236 | *
|
---|
| 237 | + int pfnCallback(int iFactor,
|
---|
| 238 | + int iPower,
|
---|
| 239 | + void *pUser);
|
---|
| 240 | *
|
---|
| 241 | * pfnCallback will receive the prime as its
|
---|
| 242 | * first parameter, its power as its second,
|
---|
| 243 | * and pUser as its third.
|
---|
| 244 | *
|
---|
| 245 | * For example, with n = 200, pfnCallback will
|
---|
| 246 | * be called twice:
|
---|
| 247 | *
|
---|
| 248 | * 1) iFactor = 2, iPower = 3
|
---|
| 249 | *
|
---|
| 250 | * 2) iFactor = 5, iPower = 2
|
---|
| 251 | *
|
---|
| 252 | * because 2^3 * 5^2 is 200.
|
---|
| 253 | *
|
---|
| 254 | * Returns the no. of times that the callback
|
---|
| 255 | * was called. This will be the number of
|
---|
| 256 | * prime factors found or 0 if n is prime
|
---|
| 257 | * itself.
|
---|
| 258 | */
|
---|
| 259 |
|
---|
| 260 | int mathFactorPrime(double n,
|
---|
| 261 | PFNFACTORCALLBACK pfnCallback, // in: callback func
|
---|
| 262 | void *pUser) // in: user param for callback
|
---|
| 263 | {
|
---|
| 264 | int rc = 0;
|
---|
| 265 |
|
---|
| 266 | double d;
|
---|
| 267 | double k;
|
---|
| 268 |
|
---|
| 269 | if (n <= 3)
|
---|
| 270 | // this is a prime for sure
|
---|
| 271 | return 0;
|
---|
| 272 |
|
---|
| 273 | d = 2;
|
---|
| 274 | for (k = 0;
|
---|
| 275 | fmod(n, d) == 0;
|
---|
| 276 | k++)
|
---|
| 277 | {
|
---|
| 278 | n /= d;
|
---|
| 279 | }
|
---|
| 280 |
|
---|
| 281 | if (k)
|
---|
| 282 | {
|
---|
| 283 | rc++;
|
---|
| 284 | pfnCallback(d,
|
---|
| 285 | k,
|
---|
| 286 | pUser);
|
---|
| 287 | }
|
---|
| 288 |
|
---|
| 289 | for (d = 3;
|
---|
| 290 | d * d <= n;
|
---|
| 291 | d += 2)
|
---|
| 292 | {
|
---|
| 293 | for (k = 0;
|
---|
| 294 | fmod(n,d) == 0.0;
|
---|
| 295 | k++ )
|
---|
| 296 | {
|
---|
| 297 | n /= d;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | if (k)
|
---|
| 301 | {
|
---|
| 302 | rc++;
|
---|
| 303 | pfnCallback(d,
|
---|
| 304 | k,
|
---|
| 305 | pUser);
|
---|
| 306 | }
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | if (n > 1)
|
---|
| 310 | {
|
---|
| 311 | if (!rc)
|
---|
[238] | 312 | return 0;
|
---|
[87] | 313 |
|
---|
| 314 | rc++;
|
---|
| 315 | pfnCallback(n,
|
---|
| 316 | 1,
|
---|
| 317 | pUser);
|
---|
| 318 | }
|
---|
| 319 |
|
---|
[238] | 320 | return rc;
|
---|
[87] | 321 | }
|
---|
| 322 |
|
---|
[88] | 323 | /*
|
---|
| 324 | *@@ mathGCDMulti:
|
---|
| 325 | * finds the greatest common divisor for a
|
---|
| 326 | * whole array of integers.
|
---|
| 327 | *
|
---|
| 328 | * For example, if you pass in three integers
|
---|
| 329 | * 1000, 1500, and 1800, this would return 100.
|
---|
| 330 | * If you only pass in 1000 and 1500, you'd
|
---|
| 331 | * get 500.
|
---|
| 332 | *
|
---|
| 333 | * Use the fact that:
|
---|
| 334 | *
|
---|
| 335 | * gcd(u1, u2, ..., un) = gcd(u1, gcd(u2, ..., un))
|
---|
| 336 | *
|
---|
| 337 | * Greatest common divisor of n integers (The
|
---|
| 338 | * Art of Computer Programming, 4.5.2).
|
---|
| 339 | */
|
---|
| 340 |
|
---|
| 341 | int mathGCDMulti(int *paNs, // in: array of integers
|
---|
| 342 | int cNs) // in: array item count (NOT array size)
|
---|
[87] | 343 | {
|
---|
[88] | 344 | int d = paNs[cNs-1];
|
---|
| 345 | int k = cNs-1;
|
---|
| 346 |
|
---|
| 347 | while ( (d != 1)
|
---|
| 348 | && (k > 0)
|
---|
| 349 | )
|
---|
| 350 | {
|
---|
| 351 | d = mathGCD(paNs[k-1], d);
|
---|
| 352 | k--;
|
---|
| 353 | }
|
---|
| 354 |
|
---|
[238] | 355 | return d;
|
---|
[88] | 356 | }
|
---|
| 357 |
|
---|
[87] | 358 |
|
---|