C to QB64 translation of a Wikipedia code sample.

by (Login MCalkins)
C-Forum

Someone emailed me and asked me to translate the C code from:

http://en.wikipedia.org/wiki/Multiply-with-carry

into QB64. Below is a partial copy of my response. Please point out any mistakes.

Regards,
Michael

The types are defined in stdint.h.

Below, I'll explain the translation.

--------------------------------

#define PHI 0x9e3779b9

This is a symbolic constant implemented by the preprocessor. It becomes a CONST:

CONST PHI = &H9E3779B9~&

--------------------------------

static uint32_t Q[4096], c = 362436;

These are variables created outside of any function. Therefore, they
are statically allocated. The static, I think, means that they are not
visible to other modules. uint32_t is defined in stdint.h, and is
equivalent to _unsigned long. 4096 is the number of elements, not the
upper bound. c is initialized. QB64 doesn't have any way of
initializing variables as they are defined, so it is done with a
separate statement. In the C program, it should be initialized
directly in the executable image, but in the QB64 program, it will be
done at run time.

DIM SHARED Q(0 TO 4095) AS _UNSIGNED LONG
DIM SHARED c AS _UNSIGNED LONG
c = 362436

--------------------------------

void init_rand(uint32_t x)
{
       int i;

This becomes:

SUB init_rand (x AS _UNSIGNED LONG)
DIM i AS LONG

--------------------------------

       Q[0] = x;
       Q[1] = x + PHI;
       Q[2] = x + PHI + PHI;

Becomes:

Q(0) = x
Q(1) = x + PHI
Q(2) = x + PHI + PHI

For your information, in C, Q[0] is actually pointer arithmetic. 0 is
automatically scaled to the size of uint32_t, and added to the value
of Q, which is a constant pointer. Q[0] is the same as *(Q+0). Q[1] is
the same as *(Q+1). The pointer arithmetic automatically accounts for
the size of the data type.

--------------------------------

       for (i = 3; i < 4096; i++)
               Q[i] = Q[i - 3] ^ Q[i - 2] ^ PHI ^ i;
}

i = 3 is performed first. Before each iteration, i < 4096 is tested,
with nonzero being true. At the end of the loop, i++ is performed. i++
increments the value of i.

For your information, i++ would return the value of i, then increment
i. ++i would increment i, then return the value of i.

^ is the bitwise XOR operator.

Note that the for is followed by a single statement. It could be
followed by a block within braces, for a multi-statement block.

So, it is:

FOR i = 3 TO 4095
 Q(i) = Q(i - 3) XOR Q(i - 2) XOR PHI XOR i
NEXT
END SUB

Or, you could do:

i = 3
WHILE i < 4096
 Q(i) = Q(i - 3) XOR Q(i - 2) XOR PHI XOR i
 i = i + 1
WEND
END SUB

--------------------------------

uint32_t rand_cmwc(void)
{
       uint64_t t, a = 18782LL;
       static uint32_t i = 4095;
       uint32_t x, r = 0xfffffffe;

The void specifies explicitly that the function accepts no parameters.
uint64_t is defined in stdint.h, and is equivalent to _unsigned
_integer64. The LL says that the numeric literal constant 18782 is a
long long.

static within a function means that the variable is statically
allocated, instead of dynamically allocated on the stack. So, i keeps
its value across function calls, whereas the non-static variables are
destroyed when the function returns. Because it is static, and
initialized, I decided to move it outside of any function, and rename
it to avoid name conflicts.

0x means a hex number, so it becomes &h. For your information, 0
before a number would make it octal, and a .0 after a number would
make it floating point.

FUNCTION rand_cmwc~& ()
DIM t AS _UNSIGNED _INTEGER64
DIM a AS _UNSIGNED _INTEGER64
a = 18782&&
DIM x AS _UNSIGNED LONG
DIM r AS _UNSIGNED LONG
r = &HFFFFFFFE

and, outside of any function:

DIM SHARED rand_cmwc_i AS _UNSIGNED LONG
rand_cmwc_i = 4095

--------------------------------

       i = (i + 1) & 4095;
       t = a * Q[i] + c;
       c = (t >> 32);
       x = t + c;
       if (x < c) {
               x++;
               c++;
       }

& is the bitwise AND.

For your information, note that && would be logical AND, not bitwise.
In C there is a distinction. Likewise | would be bitwise OR, whereas
|| would be logical OR. ~ is bitwise NOT, whereas ! is logical NOT.
The logical operators return 1 for true, and don't evaluate the rest
of the expression if the outcome is already known. Operator precedence
and order of evaluation are important.

>> is a bitwise right shift. QB64 doesn't have bitwise shifts as far as I know, I substituted integer division by a power of 2.

For your information, if has a similar syntax to for, in that it could
have been followed by a single statement, but in this case was
followed by a block within braces. Like QBASIC, nonzero is true.
Unlike QBASIC, comparison operators return 1 instead of -1 for true,
as do the logical operators.

Remember that since I moved i outside of the function and made it
SHARED, I had to rename it.

So it becomes:

rand_cmwc_i = (rand_cmwc_i + 1) AND 4095
t = a * Q(rand_cmwc_i) + c
c = t \ (2~&& ^ 32)
x = t + c
IF x < c THEN
 x = x + 1
 c = c + 1
END IF

--------------------------------

       return (Q[i] = r - x);
}

Note that = is not an equality test, it is assignment. In QBASIC = is
either an equality test or assignment based on context. In C, == is an
equality test, whereas = is assignment. So the above is assigning r -
x to Q[i], and then returning the same value. It becomes:

Q(rand_cmwc_i) = r - x
rand_cmwc = Q(rand_cmwc_i)
END FUNCTION


----------------------------------------------------------------
C program with minimal test code:
----------------------------------------------------------------

#include <stdio.h>
#include <stdint.h>

#define PHI 0x9e3779b9
 
static uint32_t Q[4096], c = 362436;
 
void init_rand(uint32_t x)
{
        int i;
 
        Q[0] = x;
        Q[1] = x + PHI;
        Q[2] = x + PHI + PHI;
 
        for (i = 3; i < 4096; i++)
                Q[i] = Q[i - 3] ^ Q[i - 2] ^ PHI ^ i;
}
 
uint32_t rand_cmwc(void)
{
        uint64_t t, a = 18782LL;
        static uint32_t i = 4095;
        uint32_t x, r = 0xfffffffe;
        i = (i + 1) & 4095;
        t = a * Q[i] + c;
        c = (t >> 32);
        x = t + c;
        if (x < c) {
                x++;
                c++;
        }
        return (Q[i] = r - x);
}


int main(void)
{
int i;
init_rand(0);
/* for (i = 0; i<4096; ++i) printf("0x%x\n",Q[i]); */
for (i = 0; i<4096; ++i) printf("0x%x\n",rand_cmwc());
return 0;
}


----------------------------------------------------------------
QB64 program with minimal test code:
----------------------------------------------------------------

CONST PHI = &H9E3779B9~&
 
DIM SHARED Q(0 TO 4095) AS _UNSIGNED LONG
DIM SHARED c AS _UNSIGNED LONG
c = 362436
DIM SHARED rand_cmwc_i AS _UNSIGNED LONG
rand_cmwc_i = 4095

DIM i AS LONG
init_rand 0
'FOR i = 0 TO 4095
'PRINT LCASE$(HEX$(Q(i)))
'NEXT
FOR i = 0 TO 4095
 PRINT "0x" + LCASE$(HEX$(rand_cmwc))
NEXT
END
 
SUB init_rand (x AS _UNSIGNED LONG)
DIM i AS LONG
 
Q(0) = x
Q(1) = x + PHI
Q(2) = x + PHI + PHI
 
FOR i = 3 TO 4095
 Q(i) = Q(i - 3) XOR Q(i - 2) XOR PHI XOR i
NEXT
END SUB

FUNCTION rand_cmwc~& ()
DIM t AS _UNSIGNED _INTEGER64
DIM a AS _UNSIGNED _INTEGER64
a = 18782&&
DIM x AS _UNSIGNED LONG
DIM r AS _UNSIGNED LONG
r = &HFFFFFFFE
rand_cmwc_i = (rand_cmwc_i + 1) AND 4095
t = a * Q(rand_cmwc_i) + c
c = t \ (2~&& ^ 32)
x = t + c
IF x < c THEN
 x = x + 1
 c = c + 1
END IF
Q(rand_cmwc_i) = r - x
rand_cmwc = Q(rand_cmwc_i)
END FUNCTION



    
This message has been edited by MCalkins on Nov 27, 2011 5:01 AM

Posted on Nov 27, 2011, 4:59 AM

Respond to this message   

Return to Index