Rewriting RNG algorithm gives different results than in C


#1

I’m starting to get the hang of Rust after being with C/C++ since about 2003 and am feeling comfortable porting some of my code over. However, a legacy random number generation algorithm I need seems to generate different results than its C counterpart when given the seed ‘666666’. I’ve followed the algorithm to the letter, so I don’t know if Rust is policing it to the extent it has different output or what…

In C/C++:

int seed = 0xa2c2a;
int quo, rem, k;
    int lut[512];

for (short i = 0; i < 512; i++)
{
	quo = seed / 0x1f31d;
	rem = seed % 0x1f31d;
	k = 16807 * rem - 2836 * quo;
	seed = k > 0 ? k : k + 0x7fffffff;
	lut[i] = (int)(((double)seed / (double)2147483647) * (double)256);
}
seed = 1;

Approximately the same code in Rust:

const R_A: i32 = 16807;
const R_Q: i32 = 127773;
const R_R: i32 = 2836;
const TABLE_SIZE: usize = 512;

static mut LUT: [u16; TABLE_SIZE] = [0; TABLE_SIZE];

fn gen_table() -> [u16; TABLE_SIZE] {
  use std::i32;
  
  let mut seed = 66666;
  let mut table: [u16; TABLE_SIZE] = [0; TABLE_SIZE];
  for i in 0..TABLE_SIZE {
    let hi = seed / R_Q;
    let lo = seed % R_Q;
    let test = R_A * lo - R_R * hi;
    seed = if test > 0 { test } else { test + i32::MAX };
    table[i] = (((seed as f64) / (i32::MAX as f64)) * 256.0) as u16;
  }
  table
}

#2

Because in C you use the seed 0xa2c2a = 666666, where as you use 66666 = 0x1046a in the Rust code.


#3

C99 has the stdint types, so start using them everywhere in your C code if you want Rust-reproducible code:
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/stdint.h.html

Rust too has hex values, so use them in both C and Rust, or don’t use them in both. The same with the 2147483647 magic value. In C you have the same constants available. Even if this is not the cause of your problem, the point is that it could be. You should minimize arbitrary sources of differences and bugs.

Then, in your code you have lut that’s global, while in Rust you use a local. Use a local in both programs, or a global in both. And so on. Keep removing differences and probably eventually your two programs will give the same outputs.


#4

Oh darn, I missed a digit on the seed. Whoops. Thanks for pointing it out. I’m going to use a hex literal to avoid that problem again.