Skip to content

random and rand are inconsistent #759

@ZERICO2005

Description

@ZERICO2005

We provide two random number generation functions:

uint32_t random(void); // [0, 2^32)
int rand(void); // [0, 2^23)

Currently rand() wraps random(). To do this, it just needs to clear bit 23 to make sure the result is [0, RAND_MAX] or [0, 2^23). I believe the intended implementation is return (random() & 0x7FFFFF), however, since the sbc instruction is used in a place where carry is unknown, the result may or may not be off by one (Although it will still be [0, RAND_MAX]).

_rand:
    ; the last operation performed by _random is add hl, de \ adc a, c \ ld e, a \ ret
    ; therefore the state of carry is indeterminate
    call    _random
    ld    de, 8388608
    sbc    hl, de ; carry is unknown here
    ret    p
    add    hl, de
    ret

We can fix it so rand() always does return (random() & 0x7FFFFF) by doing this:

_rand:
    call    _random
    ld    de, 8388608
    add hl, de
    ret    c
    add    hl, de
    ret

Pros:

  • rand() and random() produce consistent results
  • 1 byte smaller

Cons:

  • rand() will output different results when recompiling a program. More specifically, 50% of the results from rand() will be one higher than they were before.

Here is how the test cases (#760) differ for rand with this change. rand_X calls srand every iteration, and since the initial state is 1,2,3,4,5,... carry will almost never be set. But rand_0 does call rand several times, allowing the state to become more randomized and start emitting carrys

Image

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions