mt_rand() gives me always the same number - php

I have a problem with this function always my mt_rand() give me the same number:
$hex = 'f12a218a7dd76fb5924f5deb1ef75a889eba4724e55e6568cf30be634706bd4c'; // i edit this string for each request
$hex = hexdec($hex);
mt_srand($hex);
$hex = sprintf("%04d", mt_rand('0','9999'));
$hex is always changed, but the result is always the same 4488.
Edit
$hex = str_split($hex);
$hex = implode("", array_slice($hex, 0, 7));
mt_srand($hex);
$number = sprintf("%04d", mt_rand('0','9999'));
http://php.net/manual/en/function.mt-srand.php

Your problem is, that you always end up with a float value in your variable $hex. And the function mt_srand() as you can also see in the manual:
void mt_srand ([ int $seed ] )
Expects an integer. So what it does is, it simply tries to convert your float value to an integer. But since this fails it will always return 0.
So at the end you always end up with the seed 0 and then also with the same "random" number.
You can see this if you do:
var_dump($hex);
output:
float(1.0908183557664E+77)
And if you then want to see in which integer it will end up if it gets converted you can use this:
var_dump((int)$hex);
And you will see it will always be 0.
Also if you are interested in, why your number ends up as float, it's simply because of the integer overflow, since your number is way too big and accoding to the manual:
If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.
And if you do:
echo PHP_INT_MAX;
You will get the max value of int, which will be:
28192147483647 //32 bit
9223372036854775807 //64 bit
EDIT:
So now how to fix this problem and still make sure to get a random number?
Well the first thought could be just to check if the value is bigger than PHP_INT_MAX and if yes set it to some other number. But I assume and it seems like you will always have such a large hex number.
So I would recommend you something like this:
$arr = str_split($hex);
shuffle($arr);
$hex = implode("", array_slice($arr, 0, 7));
Here I just split your number into an array with str_split(), to then shuffle() the array and after this I implode() the first 7 array elements which I get with array_slice().
After you have done this you can use it with hexdec() and then use it in mt_srand().
Also why do I only get the first 7 elements? Simply because then I can make sure I don't hit the PHP_INT_MAX value.

Related

Why PHP round my number when I use json_encode?

I need execute json_encode() and convert my original number from:
50610101800060384093800100001010000000056199999999
to
"50610101800060384093800100001010000000056199999999"
But it return
5.061010180006E+49
I tried this:
ini_set('precision', 30); //With 1, 30, 50, 100, 1000
ini_set('serialize_precision', -1);
'content' => json_encode($params, JSON_NUMERIC_CHECK)
but doesn't work. Can you help me?
50610101800060384093800100001010000000056199999999 exceeds the value of the maximum integer in PHP and so it is promoted to a float and expressed in scientific notation. The float result may be problematic for various reasons as the Manual explains in warning about floating point precision.
If you wish to express the value as if it were an integer you must encapsulate it in a string. That string you may add zero to it but when you do so the result in scientific notation will refer to a float, as follows:
<?php
$s = "50610101800060384093800100001010000000056199999999";
echo $s,"\n";
$x = $s + 0;
echo $x, "\n",is_float($x);
See here.
For more info in re PHP and floats, see here.
On the other hand, if there were an array of numbers whose digits corresponded to the numerical display in the OP's post, you could write code as follows:
<?php
$a = [5,0,6,1,0,1,0,1,8,0,0,0,6,0,3,8,4,0,9,3,8,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,5,6,1,9,9,9,9,9,9,9,9];
foreach($a as $e) {
$e = (string) $e;
}
$foo = join($a);
var_dump($foo);
$foo = bcadd($foo, 1);
var_dump($foo);
See live code.
The reason this example works is because each array value is converted to a numerical string and then the individual elements are joined to form one very long numerical string. BC Math is an extension in PHP which supports arbitrary precision. In this case, the bcadd() function adds one to the numerical string which results in the display of an incremented numerical string value.
Try This [https://3v4l.org/biNJG][1]
If you want this output "50610101800060384093800100001010000000056199999999"
you may want to pass this Value as string after encoding the value to JSON using json_encode
An integer data type is a non-decimal number between -2,147,483,648 and 2,147,483,647.
Rules for integers:
An integer must have at least one digit
An integer must not have a decimal point
An integer can be either positive or negative
Integers can be specified in three formats: decimal (10-based), hexadecimal (16-based - prefixed with 0x) or octal (8-based - prefixed with 0)

Always round up on first decimal

I want my variable's first decimal to always be rounded up. For example:
9.66 goes to 9.7
9.55 goes to 9.6
9.51 goes to 9.6
9.00000001 goes to 9.1
How do I do this?
Use round() with an optional precision and round type arguments, e.g.:
round($value, 1, PHP_ROUND_HALF_UP)
The optional second argument to round() is the precision argument and it specifies the number of decimal digits to round to. The third optional argument specifies the rounding mode. See the PHP manual for round for details.
Using round() does not always round up, even when using PHP_ROUND_HALF_UP (e.g. 9.00001 is not rounded to 9.1). You could instead try to use multiplication, ceil() and division:
ceil($value * 10.0) / 10.0
Since these are floating-point values, you might not get exact results.
I made couple tests and suggest the following answer with test cases
<?php
echo '9.66 (expected 9.7) => '.myRound(9.66).PHP_EOL;
echo '9.55 (expected 9.6) => '.myRound(9.55).PHP_EOL;
echo '9.51 (expected 9.6) => '.myRound(9.51).PHP_EOL;
echo '9.00000001 (expected 9.1) => '.myRound(9.00000001).PHP_EOL;
echo '9.9 (expected ??) => '.myRound(9.9).PHP_EOL;
echo '9.91 (expected ??) => '.myRound(9.91).PHP_EOL;
function myRound($value)
{
return ceil($value*10)/10;
}
I'm not a php programmer so will have to answer in "steps". The problem you have is the edge case where you have a number with exactly one decimal. (e.g. 9.5)
Here's how you could do it:
Multiply your number by 10.
If that's an integer, then return the original number (that's the edge case), else continue as follows:
Add 0.5
Round that in the normal way to an integer (i.e. "a.5" rounds up).
Divide the result by 10.
For step (2), sniffing around the php documentation reveals a function bool is_int ( mixed $var ) to test for an integer.
You will need a custom ceil() function, your requirements cannot be satisfied by the default function or by the round.
Use this: online test
You can use this technique. Just explode the given number / string, get the number which is next value / digit of the .. after getting this you need to increment that value and check if the value is greater than 9 or nor, if then divide that and add the carry to the first portion of the main number.
$var = '9.96';
$ar = explode(".", $var);
$nxt = substr($ar[1], 0, 1) + 1;
if($nxt > 9){
$tmp = (string) $nxt;
$num = floatval(($ar[0] + $tmp[0]).".".$tmp[1]);
}
else
$num = floatval($ar[0].".".$nxt);
var_dump($num); // float(10)

rand(0,$var) returns zero when $var is really big

When I run the code below:
<?
echo rand(0, 0xfffffffffffffbff);
echo rand(0, 0xfffffffffffffc00);
echo rand(0, $something_bigger_than_0xfffffffffffffbff);
I got something like:
-828
0
0
(the 2nd and 3rd number will always be zero)
mt_rand() has the same behavior.
so, why zero?
rand() function takes two integers as its arguments. Integers usually have the maximum range of 2^32. The supplied argument, when converted to integers, will be larger than this, hence causing an integer overflow.
This is actually documented behavior. From the PHP manual documentation:
When converting from float to integer, the number will be rounded
towards zero.
If the float is beyond the boundaries of integer (usually +/- 2.15e+9
= 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have
enough precision to give an exact integer result. No warning, not even
a notice will be issued when this happens!
You need to pass integer value to the rand() as the above $a = 0xfffffffffffffbff; is a double but not an integer value, the double value 0xfffffffffffffbff will be cast to an integer and eventually you will be getting a zero.
An illustration for your understanding.
<?php
$a = 0xfffffffffffffbff;
echo gettype($a); //"prints" double
if(is_int($a))
{
echo "Yes";
}
else
{
echo "Nope.. casting that to int results in..".intval($a)."<br>";
}
echo rand(0, $a);
OUTPUT :
double
Nope.. casting that to int results in..0
0

How do I truncate a decimal in PHP?

I know of the PHP function floor() but that doesn't work how I want it to in negative numbers.
This is how floor works
floor( 1234.567); // 1234
floor(-1234.567); // -1235
This is what I WANT
truncate( 1234.567); // 1234
truncate(-1234.567); // -1234
Is there a PHP function that will return -1234?
I know I could do this but I'm hoping for a single built-in function
$num = -1234.567;
echo $num >= 0 ? floor($num) : ceil($num);
Yes intval
intval(1234.567);
intval(-1234.567);
Truncate floats with specific precision:
echo bcdiv(2.56789, 1, 1); // 2.5
echo bcdiv(2.56789, 1, 3); // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 3); // -2.567
This method solve the problem with round() function.
Also you can use typecasting (no need to use functions),
(int) 1234.567; // 1234
(int) -1234.567; // -1234
http://php.net/manual/en/language.types.type-juggling.php
You can see the difference between intval and (int) typecasting from here.
another hack is using prefix ~~ :
echo ~~1234.567; // 1234
echo ~~-1234.567; // 1234
it's simpler and faster
Tilde ~ is bitwise NOT operator in PHP and Javascript
Double tilde(~) is a quick way to cast variable as integer, where it is called 'two tildes' to indicate a form of double negation.
It removes everything after the decimal point because the bitwise operators implicitly convert their operands to signed 32-bit integers. This works whether the operands are (floating-point) numbers or strings, and the result is a number
reference:
https://en.wikipedia.org/wiki/Double_tilde
What does ~~ ("double tilde") do in Javascript?
you can use intval(number); but if your number bigger than 2147483648 (and your machine/os is x64) all bigs will be truncated to 2147483648. So you can use
if($number < 0 )
$res = round($number);
else
$res = floor($number);
echo $res;
You can shift the decimal to the desired place, intval, and shift back:
function truncate($number, $precision = 0) {
// warning: precision is limited by the size of the int type
$shift = pow(10, $precision);
return intval($number * $shift)/$shift;
}
Note the warning about size of int -- this is because $number is potentially being multiplied by a large number ($shift) which could make the resulting number too large to be stored as an integer type. Possibly converting to floating point might be better.
You could get fancy with a $base parameter, and sending that to intval(...).
Could (should) also get fancy with error/bounds checking.
An alternative approach would be to treat number as a string, find the decimal point and do a substring at the appropriate place after the decimal based on the desired precision. Relatively speaking, that won't be fast.

In PHP, how do I add to a zero-padded numeric string and preserve the zero padding?

If I have a variable in PHP containing 0001 and I add 1 to it, the result is 2 instead of 0002.
How do I solve this problem?
$foo = sprintf('%04d', $foo + 1);
It would probably help you to understand the PHP data types and how they're affected when you do operations to variables of various types. You say you have "a variable in PHP say 0001", but what type is that variable? Probably a string, "0001", since an integer can't have that value (it's just 1). So when you do this:
echo ("0001" + 1);
...the + operator says, "Hm, that's a string and an integer. I don't know how to add a string and an int. But I DO know how to convert a string INTO an int, and then add two ints together, so let me do that," and then it converts "0001" to 1. Why? Because the PHP rules for converting a string to an integer say that any number of leading zeroes in the string are discarded. Which means that the string "0001" becomes 1.
Then the + says, "Hey, I know how to add 1 and 1. It's 2!" and the output of that statement is 2.
Another option is the str_pad() function.
$text = str_pad($text, 4, '0', STR_PAD_LEFT);
<?php
#how many chars will be in the string
$fill = 6;
#the number
$number = 56;
#with str_pad function the zeros will be added
echo str_pad($number, $fill, '0', STR_PAD_LEFT);
// The result: 000056
?>

Categories