RanRot/b PNRG: Translation from C to Lua : weirdo...

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

RanRot/b PNRG: Translation from C to Lua : weirdo...

Post by Roland_Yonaba »

Hi all,

Disclaimer: I am fairly inexperienced to C (and bitwise ops), apologies in advance if I am saying silly things.

Well, I was trying to translate to Lua the following C-code which is supposed to be a RANROT/B PRNG:

Code: Select all

/*
    RANROT-B/32 PRNG
    Call with 1 or higher to set seed; call with 0 to fetch values.
    Robin Leffmann 2005 / <robin at stolendata dot net>
*/

#include <stdint.h>
static uint32_t rrbRand( uint32_t rrbSeed )
{
    static uint32_t rrbLo, rrbHi;
    if( rrbSeed != 0 )
    {
        rrbLo = rrbSeed;
        rrbHi = ~rrbSeed;
    }
    else
    {
        rrbHi = ( rrbHi << 16 ) + ( rrbHi >> 16 );
        rrbHi += rrbLo;
        rrbLo += rrbHi;
    }
    return rrbHi;
}
Well, Lua 5.2 has bitwise ops, therefore I went with it. I added DavidManura's numberlua, in order to have compatible bitwise ops for Lua 5.1.4, or LuaJit:
(note, you can run it with the online cgi-bin Lua demo (5.2) :)

Code: Select all

local function checkBitImplementation(bit)
  local msg = 'Failed testing bitwise implementation'
  assert(bit.bnot ~= nil, msg)
  assert(bit.lshift ~= nil, msg)
  assert(bit.rshift ~= nil, msg)
  assert(bit.bnot(0) == 4294967295, msg)
  assert(bit.lshift(2, 16) == 131072, msg)
  assert(bit.rshift(2, 16) == 0, msg)
  return bit
end

local bit = checkBitImplementation(
   _VERSION:match('5.2') and bit32
	       or (jit ~= nil) and require ('numberlua').bit
	       or require 'numberlua'
)

-- Returns an iterator function
local function ranrotb(seed)
  seed = seed or os.time()
  local lo, hi = seed, bit.bnot(seed)
  return function()
    hi = bit.lshift(hi,16) + bit.rshift(hi, 16)
    hi = hi + lo
    lo = lo + hi
    return hi
  end
end
Then I tested it this way:

Code: Select all

-- Generates n random numbers betwen 1 and max
local function gen(n, max)
	local prng = ranrotb()
	local t = {}
	for i = 1, n do t[#t+1] = (prng() % max) end
	return t
end

-- Generates and print 100 random numbers between 1 and 10.
print(table.concat(gen(100, 10),'\n'))
The output is just ... strange. The first 20-30 values seems to be quite good, actually, then after that, I get a tons of 0's...
Can anyone explain and give pointers on how to fix that ?
Thanks in advance.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: RanRot/b PNRG: Translation from C to Lua : weirdo...

Post by Robin »

Hey, I know the problem and solution:

Lua doesn't have an integer type, so there was one important difference between the C code and your (otherwise excellent) translation:

Addition.

In C, int a = b + c is basically the same as a = (b + c) % 2^32 in Lua. It works if you change these three lines:

Code: Select all

    hi = (bit.lshift(hi,16) + bit.rshift(hi, 16)) % 2^32
    hi = (hi + lo) % 2^32
    lo = (lo + hi) % 2^32
(You might want to do local LIMIT = 2^32 somewhere and use % LIMIT instead.)
Help us help you: attach a .love.
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: RanRot/b PNRG: Translation from C to Lua : weirdo...

Post by Roland_Yonaba »

Gosh, this is outstanding :)
I learnt something today, much thanks.
How beautiful is that:

Code: Select all

local ranrotb_prng = require 'ranrotb_prng'

-- Taken from: https://github.com/Yonaba/Allen/blob/master/allen.lua#L279
function string_split(str,n)
  n = n or 1
  if not (#str > 0) then return nil end
  local _chopped = {}
  for w in str:gmatch(('.'):rep(n)) do table.insert(_chopped,w) end
  local s,e
  if _chopped and (#_chopped > 0) then
    s,e = str:find(_chopped[#_chopped])
    if e then
    local _end = str:sub(e+1)
      if _end~='' then table.insert(_chopped,_end) end
    end
  elseif #str<=n then _chopped = {str}
  end
  return _chopped
end

local function gen(n, max)
  local prng = ranrotb_prng()
  local t = {}
  for i = 1, n do t[#t+1] = (prng() % max) end
  return t
end

local cat = table.concat
local linemax = 80
local n, max, sep = 1000, 10, ' '
print(cat(string_split(cat(gen(n, max),sep), linemax), '\n'))
9 9 9 6 9 1 8 7 8 1 0 4 2 1 5 8 9 2 7 9 9 3 4 8 1 9 5 2 9 6 7 4 6 9 5 0 4 7 5 9
6 3 7 4 3 5 2 1 6 6 1 7 4 5 6 3 2 7 4 9 8 9 8 0 6 7 0 2 6 5 8 3 2 6 7 8 8 0 2 1
0 4 8 8 1 9 6 8 8 1 9 6 4 0 5 5 5 8 5 1 3 2 2 4 5 5 4 6 9 0 6 8 2 7 8 7 3 1 4 1
3 2 3 6 0 9 8 8 1 4 6 9 5 1 7 0 2 0 2 6 6 6 2 8 7 9 9 2 6 0 3 9 8 5 7 4 6 7 0 3
8 5 7 0 7 9 1 8 2 8 1 0 8 3 1 9 1 3 7 2 9 9 2 7 4 9 2 2 9 4 8 3 7 6 2 8 7 7 5 2
6 6 6 7 8 7 2 4 4 8 5 6 9 9 3 9 9 6 4 1 3 8 1 4 6 8 7 4 4 8 8 1 4 5 4 3 8 7 1 6
2 5 2 1 0 9 2 2 8 7 7 4 4 3 5 7 0 2 0 3 4 8 9 3 9 3 6 9 0 1 2 9 0 1 6 8 8 9 9 8
5 5 6 7 4 9 3 9 4 7 1 0 9 1 3 9 3 9 4 8 0 1 6 2 5 8 4 8 4 9 2 2 8 6 1 1 2 4 5 0
4 2 2 8 6 4 1 9 4 8 6 9 5 0 4 7 7 8 1 0 8 3 6 0 9 1 4 5 0 6 7 5 7 5 9 0 6 3 2 2
8 8 9 4 3 3 5 2 1 5 9 5 2 6 9 6 4 5 0 5 4 1 9 5 5 0 9 2 1 7 8 2 7 4 5 0 5 9 7 1
5 8 0 6 6 2 9 5 1 3 3 1 3 8 6 9 5 5 4 7 6 6 6 2 9 0 6 6 7 9 9 3 0 1 8 4 3 9 8 0
1 8 7 8 2 1 6 6 3 1 6 1 1 6 3 6 9 1 4 5 6 8 8 5 0 0 6 2 9 0 6 6 7 4 5 0 1 7 4 9
3 9 9 3 0 6 2 0 8 8 5 1 7 6 0 3 9 9 2 7 3 8 0 1 8 8 0 1 3 2 2 9 3 0 1 7 9 4 3 4
5 0 0 4 2 2 8 1 0 7 1 0 3 9 4 3 5 0 5 5 9 2 0 4 5 6 2 5 2 5 8 3 7 2 7 0 2 5 3 8
0 7 4 6 3 8 5 7 0 3 8 5 2 4 5 0 1 7 0 7 5 3 3 1 4 6 5 7 6 1 1 7 0 1 8 8 0 2 6 5
8 9 3 5 1 8 2 7 4 4 3 9 9 7 7 3 6 4 2 1 0 3 8 2 7 3 2 8 1 6 6 6 7 3 1 1 1 7 0 7
1 5 4 5 1 3 4 7 7 3 3 9 0 0 0 8 0 1 8 7 2 9 0 1 2 4 5 1 2 9 0 1 8 3 4 3 6 5 3 3
0 8 3 5 1 2 9 1 8 7 2 9 5 5 5 9 1 9 6 9 0 1 7 4 9 2 2 8 7 2 4 4 2 6 0 3 9 4 2 6
5 5 4 0 1 8 2 3 7 7 3 7 7 8 7 3 7 3 2 2 3 7 6 6 7 5 8 3 6 9 5 7 0 9 5 7 5 7 5 8
4 9 7 7 9 3 1 0 2 0 3 3 6 1 6 7 1 4 6 9 5 1 3 8 9 8 6 8 4 4 6 9 1 8 8 5 2 1 0 8
3 5 8 2 8 2 8 7 7 4 9 2 7 3 7 8 6 4 0 6 3 2 7 0 7 0 7 6 5 9 6 3 8 1 0 9 2 2 8 2
7 4 5 5 0 5 4 7 7 8 8 0 6 7 4 5 1 3 2 8 7 3 1 4 1 8 3 4 9 2 6 5 4 1 8 8 0 7 0 8
9 4 7 6 5 9 5 6 8 7 7 9 0 6 3 2 2 4 0 0 6 6 3 2 3 1 0 8 3 1 0 3 0 5 0 0 0 0 4 2
2 3 6 0 3 4 3 4 9 7 2 4 4 2 6 6 1 1 2 5 3 4 8 4 8 0 1 3 4 3 4 3 9 9 1 0 3 8 5 7
6 6 6 2 6 5 9 1 9 6 4 6 3 9 7 2 3 7 3 7 2 8 8 0 2 0 3 9 4 7 2 4 4 8 3 6 5 8 3 6
Subarashiiii... :awesome:
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 1 guest