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
|