~icefox/garnet#58: 
Pondering current state

I just wrote a smol PRNG in Garnet and it looks like this:

--- A test implementation of the PCG PRNG from https://sr.ht/~icefox/oorandom
--- Fails to give perfect results after the first 3 numbers due to signed/unsigned 
--- arithmetic nonsense, but it's a start.
type Rand32 = struct
    state: I64,
    inc: I64,
end

const RAND32_DEFAULT_INC I64 = 1442695040888963407
const RAND32_MULTIPLIER I64 = 6364136223846793005

fn rand32_new_inc(seed I64, inc I64) Rand32 =
    let rng = Rand32({
        .state = 0,
        .inc = __bor_i64(__lshift_i64(inc, 1), 1),
    })
    let mut rng2 = rand32_u32(rng).0
    rng2$.state = rng2$.state + seed
    let rng3 = rand32_u32(rng2).0
    rng3
end

fn rand32_new(seed I64) Rand32 =
    rand32_new_inc(seed, RAND32_DEFAULT_INC)
end

fn rand32_u32(rand Rand32) {Rand32, I32} =
    let oldstate = rand$.state
    let mut newrng = rand
    newrng$.state = oldstate * RAND32_MULTIPLIER + rand$.inc
    -- ok maybe binary op operators are an ok idea
    let xorshifted = __i64_to_i32( __rshift_i64( __bxor_i64( __rshift_i64(oldstate, 18),  oldstate),  27))
    let rot = __i64_to_i32(__rshift_i64(oldstate, 59))
    {newrng, __ror_i32(xorshifted, rot)} 
end




fn main() {} =
    let mut rng = rand32_new(54321);
    let mut i I32 = 0
    loop
        if i == 3 then break end
        i = i + 1
        
        let res = rand32_u32(rng)
        rng = res.0
        let out I32 = res.1
        __println(out)
    end
end

Now let me take a moment to ponder what I want it to look like.

Status
REPORTED
Submitter
~icefox
Assigned to
No-one
Submitted
1 year, 12 days ago
Updated
1 year, 10 days ago
Labels
T-THOUGHTS

~icefox 1 year, 12 days ago*

  • Unsigned integers
  • Bit operators
  • borrows/unique borrows for function calls
  • += -= *= etc assignment operators
  • Imports of some kind of stdlib
  • While loops

Things I'm not so sure about yet:

  • Type unwrap operator
  • Wrapping vs checked operators
  • Associated consts?
  • Some kind of method decl shortcut syntax?

So I guess it becomes something like this:

type Rand32 = struct
    state: U64,
    inc: U64,
end

const RAND32_DEFAULT_INC U64 = 1442695040888963407
const RAND32_MULTIPLIER U64 = 6364136223846793005
 
const RAND32 = {
    .new = fn(seed U64) Rand32 =
        RAND32.new_inc(seed, RAND32_DEFAULT_INC)
    end

    .new_inc = fn(seed U64, inc U64) Rand32 =
        let mut rng = Rand32 {
            .state = 0,
            .inc = inc << 1 | 1,
        }
        RAND32.next(rng &uniq)
        rng$.state = rng$.state + seed
        RAND32.next(rng &uniq)
        rng
    end

    .next = fn(rand &uniq Rand32) U32 =
        let oldstate = rand^$.state
        rand^$.state = oldstate * RAND32_MULTIPLIER + rand^$.inc
        let xorshifted = cast(|U32| ((oldstate >> 18) ^ oldstate) >> 27)
        let rot = cast(|U32| oldstate >> 59)
        U32.ror(xorshifted, rot)
    end
}

fn main() =
    let mut rng = RAND32.new(54321)
    let mut i U32 = 0
    while i != 0 do
        let res = RAND32.next(rng)
        println(res)
        i += 1
    end
end

Not so sure if the code atually needs to be in a module yet, but it feels a little odd to have methods flapping around in the breeze. A UFCS would help but again that's kinda tricksy rn. Maybe .foo = fn(...) can be sugar'd into fn foo(...) in a struct decl? Still, overall it isn't the worst thing ever.

Simon Heath 1 year, 10 days ago ยท edit

Oh right, still need to get rid of @ for generic types, sigh.

Register here or Log in to comment, or comment via email.