Skip to content

srand(0) set random seed to 0 instead random #10292

Closed

Description

@adic3x

Description

The following code:

<?php
function foo(): int
{
	srand(0);
	$bar = rand(0, 1023);
	var_dump($bar);
	return $bar;
}

var_dump(foo() === foo());

Resulted in this output:

int(684)
int(684)
bool(true)

But I expected this output instead:

int(23)
int(756)
bool(false)

But this code:

<?php
function foo(): int
{
	srand();
	$bar = rand(0, 1023);
	var_dump($bar);
	return $bar;
}

var_dump(foo() === foo());

Works fine:

int(722)
int(132)
bool(false)

https://www.php.net/manual/en/function.srand.php

Seeds the random number generator with seed or with a random value if seed is 0.

It's seems like srand(0) process 0 as new seed value instead 0 must reset seed to new random value.

PHP Version

PHP 8.2.0

Operating System

Win 11 build 25272 (insider)

Activity

  1. hormus commented on Jan 11, 2023

    @hormus
    <?php
    
    function foo()
    {
    	srand(0);
    	$bar = rand(0, 1023);
    	return $bar;
    }
    
    var_dump(foo() === foo());
    ?>

    From php >= 4.3.0 expected result bool true
    mt_srand(0) From php >= 7.1.0 expected result bool true
    https://3v4l.org/JNHF8

  2. damianwadley commented on Jan 11, 2023

    @damianwadley
    Member

    The srand page is a bit weird because it seems to try to document a function that doesn't exist anymore: it's mt_srand now, and that does not do the "with a random value if seed is 0" behavior. And given that 3v4l, it seems the original rand didn't actually do this?

    Either way this seems like a documentation issue.

  3. transferred this issue fromphp/php-srcon Jan 11, 2023
  4. cmb69 commented on Jan 11, 2023

    @cmb69
    Member

    The srand page is a bit weird because it seems to try to document a function that doesn't exist anymore: it's mt_srand now

    The docs mention that srand() is an alias of mt_srand() as of PHP 7.1.0, and since the docs are currently supposed to document PHP 7.0 - 8.2, that looks okay.

    Anyhow, the problem is that the stubs are not matching the implementation; the stubs claim the default of $seed would be zero:

    function mt_srand(int $seed = 0, int $mode = MT_RAND_MT19937): void {}

    However, actually the implementation just checks whether an argument has been passed, or not:

    if (ZEND_NUM_ARGS() == 0) {

    So there is no default value.

    So back to php-src. Documentation should be fixed afterwards.

  5. transferred this issue fromphp/doc-enon Jan 11, 2023
  6. cmb69 commented on Jan 11, 2023

    @cmb69
    Member

    The big question is how to solve this: fix the stubs (resulting in a painful signature), or fix the implementation (resulting in a BC break). @kocsismate, thoughts?

  7. cmb69 commented on Jan 11, 2023

    @cmb69
    Member

    Ah, and since this is now part of ext/random, maybe @zeriyoshi and @TimWolla have thoughts on this as well.

  8. TimWolla commented on Jan 11, 2023

    @TimWolla
    Member

    I do have thoughts on this: The only good reason to use mt_rand() and mt_srand() in the first place since PHP 7.0 is getting a reproducible sequence, thus changing the long-standing behavior of 0 is a no-go in my book, especially since this would either also affect the OOP Mt19937 engine or result in differences between Mt19937 and mt_rand, which directly goes against the intended behavior.

    I suggest to change the actual default value to null, like Mt19937's default is null as well and make null equivalent to a random uint32_t.

  9. adic3x commented on Jan 11, 2023

    @adic3x
    Author

    https://www.php.net/manual/en/function.mt-srand.php

    Seeds the random number generator with seed or with a random value if no seed is given.

    Ok, but it factually contradicts to signature of this function:

    mt_srand(int $seed = 0, int $mode = MT_RAND_MT19937): void
    

    Where default value of $seed is 0. And I expect mt_srand(); and mt_srand(0); must works identically. For example, if I declare some function foo(int $ i = 0) then foo(); and foo(0); works identically.

    As for me

    srand(?int $seed = null, int $mode = MT_RAND_MT19937): void
    

    looks more intuitive. For example substr takes int or null:

    substr(string $string, int $offset, ?int $length = null): string
    
  10. 6 remaining items

  11. Girgias commented on Jan 12, 2023

    @Girgias
    Member

    Everything should work as written in the documentation.

    No the documentation should reflect the actual implementation in this case. So the issue is more related to the docs lying currently.

  12. kocsismate commented on Jan 19, 2023

    @kocsismate
    Member

    I think this is indeed be the best way forward, although I'm slightly concerned regarding coercive typing; prior to PHP 8.1.0, one could pass null as $seed which would be coerced to zero. However, the alternative of changing the default to UNKNOWN would prevent any automatic seeding when the $mode parameter would be used.

    I agree with making the default value null, but I think we should only fix this in master due to the BC break, shouldn't we? The BC break is very unfortunate, but we changed quite many similar signatures in the past, so this shouldn't be too big of an issue, especially because the documentation clearly states that the parameter is an int right now, and the description is correct about when the automatic seed is applied (when no parameter is given).

  13. added 5 commits that reference this issue on Jan 20, 2023
    1f05d6e
    92d7cbe
    3197104
    7517cf3
    ec23f28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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