Get only positive integers above 10 digits from mt_rand

I have a function like this

function positiveRand() {
	$rand = intval(str_pad(abs(mt_rand()), 10, '0'));
	
	return $rand;
}

And a benchmark like so

for ($i=0; $i++ < 1000;) { 
	$log[] = positiveRand();
}

But for some weird reason, this echoes no numbers

foreach ($log as $index => $num) {
	if ($num != abs($num)) var_dump($num);
}```
When I explicitly inspect the arrays, I find some of them have negative values (which I intend to exclude) and that some of them have integers less than 10 characters long (even though the `strval` function always returns a 10 char long positive integer string). So what is going on? How do I get to sift positives from negatives and why does the `intval` go out of its way to shed some characters off after the type conversion?

Won’t intval() drop the leading pad characters if they’re zero, leading to some smaller than ten digits? I’m guessing the negative numbers come from the situation where mt_rand() generates a number larger than your systems maximum positive integer, but as mt_rand() never generates a negative number in the way you call it, surely the abs() would be better outside the invtval() if you don’t actually want negative numbers?

according to the Manual, the default minimal value is 0 …

That’s why I wondered if it’s wrapping round negative when it goes through intval().

Sorry for my late response. I think sitepoint has a problem with its mail response feature. I got your mail some minutes after you made it and sent the following to the same email I got it from, as instructed. I’m just regaining access to my machine and much to my dismay, I find my reply refused to appear here even though the message had long been sent. So I’ll go over it again. You said,

Well, no. It won’t. Str_pad takes a 4th argument which specifies in what direction the string should be padded. But the default value is STR_PAD_RIGHT which in essence means I’m trying to complete the string at times when mt_rand returns less than 10 digits. There are only trailing zeros but no preceding ones.[quote=“droopsnoot, post:2, topic:261096”]
but as mt_rand() never generates a negative number in the way you call it
[/quote]

You’d think it doesn’t wouldn’t you? See this. The problem isn’t peculiar to me alone. For some reason, that function returns negative values at times. I use PHP 7 so if that what you use too, log its value a few dozen times and view the result. You’ll find the poignant and unsightly image of a number of negative integers in there.

Ah yes, sorry, mixed up my left and right there.

Oh, I’ve never tried that, I hadn’t realised you could just reply with a comment. I only get email notifications for a some responses, on this and many other forums.

I’ve tried my hands on a new initiative but sadly, every once in a while, an uncooperative number rears its ugly head. It goes like this,

private function positiveRand($limit) {
		$num = '';
		for ($i=0; $i++ < $limit;) { 
			$num .= abs(mt_rand(0, 9));
		}
		$rand = intval($num);
		if (strlen($rand) < $limit) $this->positiveRand($limit);
		return $rand;
}

Sometimes, it returns an integer shy.

I don’t know if type juggling (string ↔ numeric) is the best thing to be doing.
Are the “shy” values being seen as octal? i.e. No 8s or 9s

Do you use PHP7?

Why not set the following and it may highlight the problem?

<?php
declare( strict_types=1);
error_reporting(-1);
ini_set( 'display_errors', 'true' );

// your script

It usually takes a number of iterations before you find an occurrence. Like, i just tried one now with the $limit as 5 and it returned 9952. But it usually includes all digits from 0-9.[quote=“John_Betong, post:10, topic:261096”]
Why not set the following and it may highlight the problem?
[/quote]

lol. My error reporting is on. Is it an error or a bug in my code? By 'rearing its ugly head’what I meant is that sometimes the number generated or returned is a digit less than the $limit I passed onto the method. But this usually happens once in a while and I find it odd that these digit-shy numbers escape the vigilance of the recursion I put there.

I was procrastinating and wrote the following - which highlights the errors:

<?php
# echo __FILE__;die;

# DEBUG STUFF
	declare( strict_types=1); # file wide, PHP7 SPECIFIC
	error_reporting(-1); // maximum errors
	ini_set( 'display_errors', 'true' );
	ini_set( 'display_startup_errors', 'On' );

# CONSTANTS
	define('iDOZEN', 12);

# DEBUG fnction
	# =================================================================================
	function fred( $val='Nothing set???', string $title='Yes we have NO $title')
	{
		$result = NULL;

		echo '<pre>' .$title .' => ';
			print_r($val);
			# var_dump($val);
		echo '</pre>';

		# return;// $result;
	}


# TEST function
	# =====================
	function positiveRand()
	:int // RETURN VALUE MUST BE AN INTEGER
	{
		# SET DEFAULT RETURN VALUE
			$result = NULL;  

		# TEST SCRIPT	TO FIND ERROR
			if(0):	
				$ok = mt_rand();
				$ok = abs($ok);
				$ok = (string) $ok; // PROBLEM SOLVED BY ADDING (string)
				$ok = str_pad($ok, 10, '0');
				$ok = intval($ok);

				$result = $ok;
			endif;
			
		# OLD vs NEW		
			if(0):
				# PROBLEM SCRIPT GIVES ERROR
					$result = intval(str_pad(abs(mt_rand()), 10, '0'));
			else:
				$result = intval(str_pad( (string) abs(mt_rand()), 10, '0'));
			endif;

		# VALIDATE
			if( $result <= 0 ):
				echo '<br> PROBLEM: ';
				echo '<br> $result => ' .number_format( (float) $result, 0);
				die;
			endif;	
		
		return $result; // integer
	}


# CREATE RESULTS
	$log = [];
	# for ($i=0; $i++ < 10000;) - DOES NOT START AT 0 ???
	for ($i=0; $i <= 10000; $i++)
	{ 
		$log[$i] = positiveRand();
	}


# SHOW RESULTS
	fred( array_slice($log, 0, iDOZEN, true), 'FIRST DOZEN' );
	fred( array_slice($log, count($log)-iDOZEN, iDOZEN, true), 'LAST DOZEN' );


// ============================================== [quote="nmeri17, post:11, topic:261096"] lol. My error reporting is on. Is it an error or a bug in my code? [/quote]

What is wrong with your error reporting if it did not highlight the same errors?

2 Likes


1st of all, I take the L for not explicitly switching my errors on. In my defense, php.ini convinced me I had no need to set it in each script I intended to see errors on.

; display_errors
;   Default Value: On
;   Development Value: On

; display_startup_errors
;   Default Value: Off
;   Development Value: On

; error_reporting
;   Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED

That’s what informed my earlier comment. I also tried reverting to my earlier settings with

	declare( strict_types=0);
	error_reporting(0);
	ini_set( 'display_startup_errors', 'Off' );

just to be sure could replicate the negative or incomplete digits I was getting previously but it still “highlights” the “problem”. Anyway, isn’t it counter-intuitive that string functions don’t implicitly convert to string? In JS for instance the toString() method is called or at least they could either cast it as a string as you have done. Matter of fact, this

$ok = mt_rand();
$okInt = abs($ok);
$okImplicitConvert = str_pad($ok, 10, '0');
var_dump($okInt, $okImplicitConvert);

returns the same integer, but as a string. Casting it as a string like you did returns the exact same value as $okImplicitConvert except with the trailing 0. So doesn’t this mean it underwent strval() internally?

This comment may sound like the wails of a crybaby. I admit being wrong in not going the extra mile of turning on my error reporting. I just tried explaining my stubbornness. But your TDD is painstakingly thorough; for a problem that isn’t even yours, thank you very much.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.