]> git.sur5r.net Git - cc65/commitdiff
Added functions to factorize a value and to create the lcm of two factorized
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 27 Dec 2011 12:58:15 +0000 (12:58 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 27 Dec 2011 12:58:15 +0000 (12:58 +0000)
numbers.

git-svn-id: svn://svn.cc65.org/cc65/trunk@5322 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/common/alignment.c [new file with mode: 0644]
src/common/alignment.h
src/common/make/gcc.mak
src/common/make/watcom.mak

diff --git a/src/common/alignment.c b/src/common/alignment.c
new file mode 100644 (file)
index 0000000..f61dc08
--- /dev/null
@@ -0,0 +1,180 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                alignment.c                                */
+/*                                                                           */
+/*                             Address aligment                              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2011,      Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                70794 Filderstadt                                          */
+/* EMail:         uz@cc65.org                                                */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "alignment.h"
+#include "check.h"
+
+
+
+/*****************************************************************************/
+/*                                   Data                                    */
+/*****************************************************************************/
+
+
+
+/* To factorize an alignment, we will use the following prime table. It lists
+ * all primes up to 256, which means we're able to factorize alignments up to
+ * 0x10000. This is checked in the code.
+ */
+static const unsigned char Primes[PRIME_COUNT] = {
+      2,   3,   5,   7,  11,  13,  17,  19,  23,  29,
+     31,  37,  41,  43,  47,  53,  59,  61,  67,  71,
+     73,  79,  83,  89,  97, 101, 103, 107, 109, 113,
+    127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+    179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
+    233, 239, 241, 251
+};
+#define LAST_PRIME      ((unsigned long)Primes[PRIME_COUNT-1])
+
+#define FAC_MAX         (LAST_PRIME * LAST_PRIME - 1)
+
+
+
+/*****************************************************************************/
+/*                                   Code                                    */
+/*****************************************************************************/
+
+
+
+static void Initialize (FactorizedNumber* F, unsigned long Value)
+/* Initialize a FactorizedNumber structure */
+{
+    unsigned I;
+
+    F->Value = Value;
+    for (I = 0; I < PRIME_COUNT; ++I) {
+        F->Powers[I] = 0;
+    }
+}
+
+
+
+static unsigned char MaxPower (unsigned char A, unsigned char B)
+/* Return the larger of A and B. This will get hopefully inlined by the
+ * compiler.
+ */
+{
+    return (A > B)? A : B;
+}
+
+
+
+static FactorizedNumber* Produce (FactorizedNumber* F)
+/* Generate a value from a list of powers of primes and return F */
+{
+    unsigned I;
+
+    F->Value = 1;
+    for (I = 0; I < PRIME_COUNT; ++I) {
+        unsigned Count = F->Powers[I];
+        while (Count--) {
+            F->Value *= Primes[I];
+        }
+    }
+    return F;
+}
+
+
+
+void Factorize (unsigned long Value, FactorizedNumber* F)
+/* Factorize a value between 1 and 0x10000. */
+{
+    unsigned I;
+
+    /* Initialize F */
+    Initialize (F, Value);
+
+    /* If the value is 1 we're already done */
+    if (Value == 1) {
+        return;
+    }
+
+    /* Be sure we can factorize */
+    CHECK (Value <= FAC_MAX && Value != 0);
+
+    /* Handle factor 2 separately for speed */
+    while ((Value & 0x01UL) == 0UL) {
+        ++F->Powers[0];
+        Value >>= 1;
+    }
+
+    /* Factorize. We don't need to check for array bounds since we checked the
+     * maximum value above.
+     */
+    I = 1;      /* Skip 2 because it was handled above */
+    while (Value > 1) {
+        unsigned long Tmp = Value / Primes[I];
+        if (Tmp * Primes[I] == Value) {
+            /* This is a factor */
+            ++F->Powers[I];
+            Value = Tmp;
+        } else {
+            /* This is not a factor, try next one */
+            ++I;
+        }
+    }
+}
+
+
+
+FactorizedNumber* LCM (const FactorizedNumber* Left,
+                       const FactorizedNumber* Right,
+                       FactorizedNumber* Res)
+/* Calculate the least common multiple of two factorized numbers and return
+ * the result.
+ */
+{
+    unsigned I;
+
+    /* Generate the powers for the lcm */
+    for (I = 0; I < PRIME_COUNT; ++I) {
+        Res->Powers[I] = MaxPower (Left->Powers[I], Right->Powers[I]);
+    }
+
+    /* Generate the actual lcm value from the powers and return the result */
+    return Produce (Res);
+}
+
+
+
+unsigned long AlignAddr (unsigned long Addr, unsigned long Alignment)
+/* Align an address to the given alignment */
+{
+    return ((Addr + Alignment - 1) / Alignment) * Alignment;
+}
+
+
+
index 795797ae8b43d80b1db9bc3a401e831412ea1dd7..b55cd6f2b0c9bab3650a14d24c8cd352e82ba3a7 100644 (file)
 
 
 
+/*****************************************************************************/
+/*                                   Data                                    */
+/*****************************************************************************/
+
+
+
+/* The C file contains a list of primes up to 256, so we can factorize numbers
+ * up to 0x10000 or somewhat more. The FactorizedNumber structure below
+ * contains the powers of the primes from the prime table. The size of the
+ * table (= the number of primes contained therein) is the constant below.
+ */
+#define PRIME_COUNT     54
+
+
+
+
+/* A number together with its prime factors */
+typedef struct FactorizedNumber FactorizedNumber;
+struct FactorizedNumber {
+    unsigned long       Value;                  /* The actual number */
+    unsigned char       Powers[PRIME_COUNT];    /* Powers of the factors */
+};
+
+
+
 /*****************************************************************************/
 /*                                   Code                                    */
 /*****************************************************************************/
 
 
 
-#if defined(HAVE_INLINE)
-INLINE unsigned long AlignAddr (unsigned long Addr, unsigned long Alignment)
+void Factorize (unsigned long Value, FactorizedNumber* F);
+/* Factorize a value between 1 and 0x10000. */
+
+FactorizedNumber* LCM (const FactorizedNumber* Left,
+                       const FactorizedNumber* Right,
+                       FactorizedNumber* Res);
+/* Calculate the least common multiple of two factorized numbers and return
+ * the result.
+ */
+
+unsigned long AlignAddr (unsigned long Addr, unsigned long Alignment);
 /* Align an address to the given alignment */
-{
-    return ((Addr + Alignment - 1) / Alignment) * Alignment;
-}
-#else
-/* Beware: Evaluates the argument more than once! */
-#  define AlignAddr(Addr, Alignment)    \
-        ((((Addr) + (Alignment) - 1) / (Alignment)) * (Alignment))
-#endif
 
 
 
index d0fc1904b1ebeccd405e2e003b9e05ced63bdd3e..049f44eedf04092667a5aa8d815d74fd3971cd81 100644 (file)
@@ -15,6 +15,7 @@ LIB   = common.a
 
 OBJS = abend.o         \
        addrsize.o      \
+        alignment.o     \
         assertion.o     \
        bitops.o        \
        chartype.o      \
index e814115e503e77ebde427d6866de67f16649a288..99a9924fc9573d589c3a35c4e07f048348c2c28a 100644 (file)
@@ -57,6 +57,7 @@ endif
 
 OBJS = abend.obj       \
         addrsize.obj    \
+        alignment.obj   \
         assertion.obj   \
        bitops.obj      \
        chartype.obj    \