Generating random values with restricted digits - php

What is the best way to generate a random integer with a restricted set of digits?
I want to generate a 4 digit random number, where each digit is in the range [1..6]. I was thinking generate a number in the range [0..1295], then converting to base 6 and incrementing the digits, but that goes through a string.

Without string conversion, and with only one call to a random number generator, you could do this:
function myRandom() {
$num = mt_rand(0, 1295);
$result = 0;
for ($i = 0; $i < 4; $i++) {
$result = $result*10 + $num % 6;
$num = floor($num / 6);
}
return $result + 1111;
}

You could generate each digit separately like this:
$result = '';
for ($i=0; $i < 4; $i++) {
$result .= mt_rand(1, 6);
}
$result = (int) $result;
Or if using a string is not preferred, you could do it with math:
$result = 0;
for ($i=0; $i < 4; $i++) {
$result += mt_rand(1, 6) * 10 ** $i;
// or for PHP versions < 5.6 (no ** exponentiation operator)
// $result += mt_rand(1, 6) * pow(10, $i);
}

<?php
// 216_10 = 1000_6
// 1295_10 = 5555_6
base_convert(mt_rand(216,1295),10,6);

Related

PHP - get random integer using random_int() without repeating and looping

I need to get 50 random numbers out of range 1-100 without repeating. The current way i do is :
$array = array();
while (count($array) <= 50) {
$temp = random_int(1,100);
if (!in_array($temp, $array))
$array[] = $temp;
}
However, the looping is too many because I need to generate for more than 100,000 times.
Is there other ways that I can get a 50 random non-repeating numbers without looping ?
For example:
$number= range(1,100);
$array = array_slice(shuffle($number),0,50);
I can't use shuffle because it uses pseudo random number.
Is there other ways to achieve what I need, or ways that could shorten time.
pre fill a array of numbers and pick from them, and then remove it.
it prevents the unnecessary random generations you have
$numbers = [];
for ($i = 1; $i <= 100; $i++) {
$numbers[] = $i;
}
$randomNumbers = [];
for ($i = 1; $i <= 50; $i++) {
$r = rand(0, count($numbers) - 1);
$randomNumbers[] = $numbers[$r];
array_splice($numbers, $r, 1);
}
This would be my approach:
This gives you 50 numbers in any case, and they are defenitely different from each other. PLUS: you dont have to prefill some other array:
$start = microtime(true);
for($i = 0; $i <= 100000; $i++){
$arr = [];
while(sizeof($arr) < 50){
$num = rand(1, 100);
$arr[$num] = $num;
}
if(array_unique($arr) !== $arr || sizeof($arr) !== 50 ){
print("FAIL");
}
//print(array_unique($arr) == $arr ? "true" : "false");print("<br>");
//print(sizeof($arr));print("<br>");
//print_r(array_count_values ($arr));print("<br>");
//print_r($arr);print("<br>");
}
$time_elapsed_secs = microtime(true) - $start;
print($time_elapsed_secs);print("<br>");
Running this 100000 times takes about 0.4sec for me.
The actual generation is done in this part:
$arr = [];
while(sizeof($arr) < 50){
$num = rand(1, 100);
$arr[$num] = $num;
}
We can do in 2 steps:
$x = 0;
$arr = [];
while($x < 50){
$tmp = rand(1, 100);
if(!in_array($tmp, $arr)){
$arr[] = $tmp;
$x++;
}
}

How to generate several random numbers included in a range and whose evolution is in a range in percent in PHP?

How to generate several random numbers included in a range and whose evolution is in a range in percent?
The goal is to generate random numbers while avoiding significant discrepancies.
i tried this code but with php 7.4, the random number only increases until I get a fatal error
$min=400; // starting value
$max = 600; // starting value
for ($i = 1; $i <= 1000; $i++)
{
$nb = random_int($min, $max);
echo $nb . "\n";
$percentage_min = random_int(0, 10);
$percentage_max = random_int(10, 20);
$min = floor($nb-($nb * $percentage_min)/100);
$max = floor($nb+($nb * $percentage_max)/100);
}
Here is the solution
$min=0; // starting value
$max = 600; // starting value
$min_absolute = 100;
$max_absolute = 1000;
for ($i = 1; $i <= 2000; $i++)
{
if($max > $max_absolute)
{
$min = $min_absolute;
$max = random_int($min_absolute, $max_absolute);
}
$nb = random_int($min, $max);
echo $nb . "\n";
$percentage_min = random_int(0, 10);
$percentage_max = random_int(10, 20);
$min = floor($nb-($nb * $percentage_min)/100);
$max = floor($nb+($nb * $percentage_max)/100);
}
EDIT: It's funny to see anonymous hypocrites voting negatively about a problem and its solution which they don't understand 😂

PHP, reading 8 byte integers from a MySQL database?

I have a BINARY(40) column in a MySQL and there I store 5 8 byte integers. I am trying to read those numbers in PHP one by one:
$result = mysqli_query($con,"SELECT data FROM list WHERE id=".$id);
$mysql_array = mysqli_fetch_array($result);
$list = str_split($mysql_array["data"], 8);
for($i = 0; $i < 5; $i++)
echo $list[$i]."<br/>";
Instead of the numbers I expect, weird symbols are printed. How can I convert those numbers from binary strings to integers?
Change your query as follows:
$result = mysqli_query($con,"SELECT cast(data as char(40)) FROM list WHERE id=".$id);
OK, because of the way you're storing the numbers, this code will only work if you've got 64 bit support, otherwise you'll have to look at a bc replacement, shouldn't be too difficult:
for($i = 0; $i < 5; $i++) {
$bin_str = $list[$i];
$int_val = 0;
for ($j = 0; $j < 8; ++$j) {
$byte_val = ord(substr($bin_str, $j, 1));
// push the next byte onto our integer:
$int_val = ($int_val << 8) + $byte_val;
}
echo $int_val;
}
EDIT: In all likelyhood this is a BC equiv, I'm unable to test it at the moment though, however the logic remains unchanged.
for($i = 0; $i < 5; $i++) {
$bin_str = $list[$i];
$bc_val = '0';
for ($j = 0; $j < 8; ++$j) {
$byte_val = ord(substr($bin_str, $j, 1));
// push the next byte onto our integer:
$bc_val = bcadd(bcmul($bc_val, 256, 0), "$byte_val", 0);
}
echo $bc_val;
}

prevent Random PHP generator from including zeros

I have a php script that creates a random 10 digit order number:
// Assign order number length
$digits = 10;
// Create random order number to be stored with this order
$order_number = rand(pow(10, $digits-1), pow(10, $digits)-1);
How do I prevent this from ever including the digit zero 0 in the random 10 digit number? Thanks in advance!
You can do fancy base conversions, but in the end, the most straightforward way is to just get a string:
function random_string($count, $available) {
$result = '';
$max = strlen($available) - 1;
for($i = 0; $i < $count; $i++) {
$result .= $available[rand(0, $max)];
}
return $result;
}
…
$order_number = random_string($digits, '123456789');
You can treat it as a number of base 9
base_convert(rand(0, pow(9, $digits) - 1), 10, 9)
This will give you numbers with digits from 0 to 8.
Now just add 1 to every digit to make it 1 to 9
(pow(10, $digits) - 1) / 9
will give you a number filled with ones. Now just add it to your previous number and there you go:
$digits = 10;
$order_number = (pow(10, $digits) - 1) / 9 + base_convert(rand(0, pow(9, $digits) - 1), 10, 9);
Try this :D
function getRandom($from, $to){
$num = rand($from, $to);
$have_zero = true;
$strNum = strval($num);
while ($have_zero){
$have_zero = false;
for ($i = 0; $i < sizeof($strNum); $i++){
if ($strNum[$i] == '0'){
$have_zero = true;
$num = rand($from, $to);
$strNum = strval($num);
break;
}
}
}
return $num;
}
getRandom(1111111111, 9999999999);
You could use a simple function like this:
function getRandom($length) {
$numbers = '';
for($i = 0; $i < $length; $i++) {
$numbers .= rand(1, 9);
}
return $numbers;
}
echo getRandom(10);
I would make a function.
<?php
function myRandomNumberWithoutZeros($digits)
{
$result = str_replace("0", "",rand(pow(10,$digits-1), pow(10, $digits)-1)."");
$resultLength = strlen($result);
if($resultLength < $digits)
{
return intval($result.myRandomNumberWithoutZeros($digits-$resultLength));
}
return intval($result);
}
echo myRandomNumberWithoutZeros(10);
?>

Auto incrementing unique url

I am looking to create an auto incrementing unique string using PHP, containing [a-Z 0-9] starting at 2 chars long and growing when needed.
This is for a url shrinker so each string (or alias) will be saved in the database attached to a url.
Any insight would be greatly appreciated!
Note this solution won't produce uppercase letters.
Use base_convert() to convert to base 36, which will use [a-z0-9].
<?php
// outputs a, b, c, ..., 2o, 2p, 2q
for ($i = 10; $i < 99; ++$i)
echo base_convert($i, 10, 36), "\n";
Given the last used number, you can convert it back to an integer with intval() increment it and convert the result back to base 36 with base_convert().
<?php
$value = 'bc9z';
$value = intval($value, 36);
++$value;
$value = base_convert($value, 10, 36);
echo $value; // bca0
// or
echo $value = base_convert(intval($value, 36) + 1, 10, 36);
Here's an implementation of an incr function which takes a string containing characters [0-9a-zA-Z] and increments it, pushing a 0 onto the front if required using the 'carry-the-one' method.
<?php
function incr($num) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$parts = str_split((string)$num);
$carry = 1;
for ($i = count($parts) - 1; $i >= 0 && $carry; --$i) {
$value = strpos($chars, $parts[$i]) + 1;
if ($value >= strlen($chars)) {
$value = 0;
$carry = 1;
} else {
$carry = 0;
}
$parts[$i] = $chars[$value];
}
if ($carry)
array_unshift($parts, $chars[0]);
return implode($parts);
}
$num = '0';
for ($i = 0; $i < 1000; ++$i) {
echo $num = incr($num), "\n";
}
If your string was single case rather than mixed, and didn't contain numerics, then you could literally just increment it:
$testString="AA";
for($x = 0; $x < 65536; $x++) {
echo $testString++.'<br />';
}
$testString="aa";
for($x = 0; $x < 65536; $x++) {
echo $testString++.'<br />';
}
But you could possibly make some use of this feature even with a mixed alphanumeric string
To expand on meagar's answer, here is how you can do it with uppercase letters as well and for number arbitrarily big (requires the bcmath extension, but you could as well use gmp or the bigintegers pear package):
function base10ToBase62($number) {
static $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$result = "";
$n = $number;
do {
$remainder = bcmod($n, 62);
$n = bcdiv($n, 62);
$result = $chars[$remainder] . $result;
} while ($n > 0);
return $result;
}
for ($i = 10; $i < 99; ++$i) {
echo base10ToBase62((string) $i), "\n";
}

Categories