Round to Highest Factor with Variable Scale? [duplicate] - php

This question already has answers here:
Round to max thousand, hundred etc in PHP
(5 answers)
Closed 5 years ago.
PHP's floor() and ceil() is useful for rounding floats to their nearest integers.
But what if we need to find the highest multiple of 10 (hundreds, thousands, etc.) for a given number? For example:
num_to_scale(538.9) // 500
num_to_scale(543123654.01234) // 5000000

Try this code, check the live demo. You also can refer to this post.
$floor = floor($v);
return str_pad(substr($floor, 0, 1), strlen($floor), '0');

function num_to_scale($number) {
$multiple=1; $test=1;
for ($i=1; $test>=1; $i++) {
$factor = $multiple/10;
$test = $number/$multiple;
$multiple = $multiple*10;
$scale = floor($number/$factor)*$factor;
} return $scale;
}
or more simply:
function num_to_scale($n) {
$m=1; $t=1;
for ($i=1; $t>=1; $i++) {
$f=$m/10; $t=$n/$m; $m=$m*10; $s=floor($n/$f)*$f;
} return $s;
}
Combined with a helper function to convert integers to text strings, we can easily do something like this:
echo 'Over '.num_to_scale(5395206).' units sold.';
// Over five million units sold.

try this:
function num_to_scale($number) {
$num = (int) floor($number);
$ln = strlen($num) - 1;
return (int) floor($num / pow(10, $ln)) * pow(10, $ln);
}

My answer uses logarithm :
function num_to_scale($var) {
$nbDigits = (int)log($var,10);
return (int)($var/10**$nbDigits)*10**$nbDigits;
}

Related

Round up decimal number for specific decimal places in PHP

I want to round up my variable if it's decimal larger than .3 and if it's lower or equal it will round down, for example if i have 1.34 it will round up to 2, if i have 1.29 it will round down to 1, and if i have 1.3 it will round down to 1. I don't know how to do this precisely, right now i'm using the round basic function like this:
$weight = $weight/1000;
if($weight < 1) $weight = 1;
else $weight = round($weight, 0, PHP_ROUND_HALF_DOWN);
If you manipulate the numbers a bit, you can figure out if the decimals are .3 or higher. You achieve this by flooring the value, and subtract that from the original value. Check if the result of that, multiplied by 10, is greater than 3. If it is, you've got something above x.3.
$number = 1.31;
$int = floor($number);
$float = $number-$int;
if ($float*10 > 3.1)
$result = ceil($number);
else
$result = $int;
echo $result; // 2
Live demo
I made you a little hack, here's the code
$weight = 5088;
$weight = $weight/1000;
if($weight < 1) {
$weight = 1;
} else {
// I get the last number (I treat the $weight as a string here)
$last_number = substr($weight, -1, 1);
// Then I get the precision (floating numbers)
$precision = strlen(substr(strrchr($weight, "."), 1));
// Then I convert it to a string so I can use some helpful string functions
$weight_str = (string) $weight;
// If the last number is less then 3
if ($last_number > 3)
// I change it to 9 I could just change it to 5 and it would work
// because round will round up if then number is 5 or greater
$weight_str[strlen($weight_str) -1] = 9;
}
}
// Then the round will round up if it's 9 or round down if it's 3 or less
$weight = round($weight_str, $precision);
echo $weight;
Maybe something like this function?
function roundImproved($value, $decimalBreakPart = 0.3) {
$whole = floor($value);
$decimal = $value - $whole;
$decimalPartLen = strlen($decimal) - 2;
return (number_format($decimal, $decimalPartLen) <= number_format($decimalBreakPart, $decimalPartLen) ? $whole : ceil($value));
}
Proof:
http://sandbox.onlinephpfunctions.com/code/d75858f175dd819de069a8a05611ac9e7053f07a
You can specify "break part" if you want.

Generate random numbers [duplicate]

This question already has answers here:
Generating UNIQUE Random Numbers within a range
(14 answers)
Closed 7 years ago.
I am trying to find a solution in PHP that can generate three random numbers.
At the moment I have this that generates a random number that is different from $randNum;
The numbers need to be different from each other and also different from the variable $randNum
Thank you
$wrong = $randNum;
while ($wrong == $randNum) {
$wrong = rand(0,$max - 1);
}
<?php
$numbers = [];
for($i = 0; $i < 10; $i++){
$number = rand (1,15);
while (in_array($number, $numbers)){
$number = rand (1,15);
}
$numbers[] = $number;
}
echo '<pre>';
print_r($numbers);
echo '</pre>';
This function generates unique 10 random numbers, range from 1-15 you can easy change this script to your needs.

perform round function without using round() in php [duplicate]

This question already has answers here:
Print numeric values to two decimal places
(6 answers)
Closed 11 months ago.
without use of round() function perfrom the round() in php
$a = "123.45785";
$v = round($a);
output: 123.46;
it had done by round function but i want to get output without use of round and number_format() function.
Here's a way of doing it with arithmetics:
function my_round($num, $places = 2) {
// Multiply to "move" decimals to the integer part
// (Save one extra digit for rounding)
$num *= pow(10, $places + 1);
// Truncate to remove decimal part
$num = (int) $num;
// Do rounding based on the last digit
$lastDigit = $num % 10;
if ($lastDigit >= 5)
$num += 10;
// Remove last digit
$num = (int) ($num/10);
// "Move" decimals in place, and you're done
$num /= pow(10, $places);
return $num;
}
You have sprintf.
$a = "123.45785";
echo sprintf("%01.2f", $a); // output: 123.46

php random x digit number

I need to create a random number with x amount of digits.
So lets say x is 5, I need a number to be eg. 35562
If x is 3, then it would throw back something like; 463
Could someone show me how this is done?
You can use rand() together with pow() to make this happen:
$digits = 3;
echo rand(pow(10, $digits-1), pow(10, $digits)-1);
This will output a number between 100 and 999. This because 10^2 = 100 and 10^3 = 1000 and then you need to subtract it with one to get it in the desired range.
If 005 also is a valid example you'd use the following code to pad it with leading zeros:
$digits = 3;
echo str_pad(rand(0, pow(10, $digits)-1), $digits, '0', STR_PAD_LEFT);
I usually just use RAND() http://php.net/manual/en/function.rand.php
e.g.
rand ( 10000 , 99999 );
for your 5 digit random number
Here is a simple solution without any loops or any hassle which will
allow you to create random string with characters, numbers or even with special symbols.
$randomNum = substr(str_shuffle("0123456789"), 0, $x);
where $x can be number of digits
Eg.
substr(str_shuffle("0123456789"), 0, 5);
Results after a couple of executions
98450
79324
23017
04317
26479
You can use the same code to generate random string also, like this
$randomNum=substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyzABCDEFGHIJKLMNOPQRSTVWXYZ"), 0, $x);
Results with $x = 11
FgHmqpTR3Ox
O9BsNgcPJDb
1v8Aw5b6H7f
haH40dmAxZf
0EpvHL5lTKr
You can use rand($min, $max) for that exact purpose.
In order to limit the values to values with x digits you can use the following:
$x = 3; // Amount of digits
$min = pow(10,$x);
$max = pow(10,$x+1)-1);
$value = rand($min, $max);
Treat your number as a list of digits and just append a random digit each time:
function n_digit_random($digits) {
$temp = "";
for ($i = 0; $i < $digits; $i++) {
$temp .= rand(0, 9);
}
return (int)$temp;
}
Or a purely numerical solution:
function n_digit_random($digits)
return rand(pow(10, $digits - 1) - 1, pow(10, $digits) - 1);
}
the simplest way i can think of is using rand function with str_pad
<?php
echo str_pad(rand(0,999), 5, "0", STR_PAD_LEFT);
?>
In above example , it will generate random number in range 0 to 999.
And having 5 digits.
function random_numbers($digits) {
$min = pow(10, $digits - 1);
$max = pow(10, $digits) - 1;
return mt_rand($min, $max);
}
Tested here.
rand(1000, 9999); works more faster than x4 times rand(0,9);
benchmark:
rand(1000, 9999) : 0.147 sec.
rand(0,9)x4 times : 0.547 sec.
both functions was running in 100000 iterations to make results more explicit
Well you can use as simple php function mt_rand(2000,9000) which can generate a 4 digit random number
mt_rand(2000,9000)
You can generate any x-digit random number with mt_rand() function.
mt_rand() is faster than rand().
Syntax : mt_rand() or mt_rand($min , $max).
Example : <?php echo mt_rand(); ?>
read more
do it with a loop:
function randomWithLength($length){
$number = '';
for ($i = 0; $i < $length; $i++){
$number .= rand(0,9);
}
return (int)$number;
}
rand or mt_rand will do...
usage:
rand(min, max);
mt_rand(min, max);
function random_number($size = 5)
{
$random_number='';
$count=0;
while ($count < $size )
{
$random_digit = mt_rand(0, 9);
$random_number .= $random_digit;
$count++;
}
return $random_number;
}
Following is simple method to generate specific length verification code. Length can be specified, by default, it generates 4 digit code.
function get_sms_token($length = 4) {
return rand(
((int) str_pad(1, $length, 0, STR_PAD_RIGHT)),
((int) str_pad(9, $length, 9, STR_PAD_RIGHT))
);
}
echo get_sms_token(6);
this simple script will do
$x = 4;//want number of digits for the random number
$sum = 0;
for($i=0;$i<$x;$i++)
{
$sum = $sum + rand(0,9)*pow(10,$i);
}
echo $sum;
This is another simple solution to generate random number of N digits:
$number_of_digits = 10;
echo substr(number_format(time() * mt_rand(),0,'',''),0,$number_of_digits);
Check it here: http://codepad.org/pyVvNiof
function rand_number_available($already_mem_array,$boundary_min,$boundary_max,$digits_num)
{
$already_mem_array_dim = count($already_mem_array); // dimension of array, that contain occupied elements
// --- creating Boundaries and possible Errors
if( empty($digits_num) ){
$boundary_dim = $boundary_max - $boundary_min;
if($boundary_dim <= 0){
$error = -1; // Error that might happen. Difference between $boundary_max and $boundary_min must be positive
}else{
$error = -2; // Error that might happen. All numbers between, $boundary_min and $boundary_max , are occupied, by $already_mem_array
}
}else{
if($digits_num < 0){ // Error. If exist, $digits_num must be, 1,2,3 or higher
$error = -3;
}elseif($digits_num == 1){ // if 'one-figure' number
$error = -4; // Error that might happen. All 'one-figure' numbers are occupied, by $already_mem_array
$boundary_min = 0;
$boundary_max = 9;
$boundary_dim = $boundary_max-$boundary_min;
}elseif($digits_num == 2){ // if 'two-figure' number
$error = -5; // Error that might happen. All 'two-figure' numbers are occupied, by $already_mem_array
$boundary_min = 10;
$boundary_max = 99;
$boundary_dim = $boundary_max-$boundary_min;
}elseif($digits_num>2){ // if 'X-figure' number. X>2
$error = -6; // Error that might happen. All 'X-figure' numbers are occupied, by $already_mem_array. Unlikely to happen
$boundary_min = pow(10, $digits_num-1); // stepenovanje - graduation
$boundary_max = pow(10, $digits_num)-1;
$boundary_dim = $boundary_max-$boundary_min;
}
}
// -------------------------------------------------------------------
// --- creating response ---------------------------------------------
if( ($already_mem_array_dim <= $boundary_dim) && $boundary_dim>0 ){ // go here only if, there are AVAILABLE numbers to extract, and [difference] $boundary_dim , is positive
do{
$num = rand($boundary_min,$boundary_max);
}while( in_array($num, $already_mem_array) );
$result = $num;
}else{
$result = $error; // Limit that happened
}
return $result;
// -------------------------------------------------------------------
}
This function works perfectly with no repeats and desired number of digits.
$digits = '';
function randomDigits($length){
$numbers = range(0,9);
shuffle($numbers);
for($i = 0; $i < $length; $i++){
global $digits;
$digits .= $numbers[$i];
}
return $digits;
}
You can call the function and pass the number of digits for example:
randomDigits(4);
sample results:
4957 8710 6730 6082 2987 2041 6721
Original script got from this gist
Please not that rand() does not generate a cryptographically secure value according to the docs:
http://php.net/manual/en/function.rand.php
This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using random_int(), random_bytes(), or openssl_random_pseudo_bytes() instead.
Instead it is better to use random_int(), available on PHP 7 (See: http://php.net/manual/en/function.random-int.php).
So to extend #Marcus's answer, you should use:
function generateSecureRandomNumber($digits): int {
return random_int(pow(10, $digits - 1), pow(10, $digits) - 1);
}
function generateSecureRandomNumberWithPadding($digits): string {
$randomNumber = random_int(0, pow(10, $digits) - 1);
return str_pad($randomNumber, $digits, '0', STR_PAD_LEFT);
}
Note that using rand() is fine if you don't need a secure random number.
The following code generates a 4 digits random number:
echo sprintf( "%04d", rand(0,9999));
you people really likes to complicate things :)
the real problem is that the OP wants to, probably, add that to the end of some really big number. if not, there is no need I can think of for that to be required. as left zeros in any number is just, well, left zeroes.
so, just append the larger portion of that number as a math sum, not string.
e.g.
$x = "102384129" . complex_3_digit_random_string();
simply becomes
$x = 102384129000 + rand(0, 999);
done.

How to round down to the nearest significant figure in php

Is there any slick way to round down to the nearest significant figure in php?
So:
0->0
9->9
10->10
17->10
77->70
114->100
745->700
1200->1000
?
$numbers = array(1, 9, 14, 53, 112, 725, 1001, 1200);
foreach($numbers as $number) {
printf('%d => %d'
, $number
, $number - $number % pow(10, floor(log10($number)))
);
echo "\n";
}
Unfortunately this fails horribly when $number is 0, but it does produce the expected result for positive integers. And it is a math-only solution.
Here's a pure math solution. This is also a more flexible solution if you ever wanted to round up or down, and not just down. And it works on 0 :)
if($num === 0) return 0;
$digits = (int)(log10($num));
$num = (pow(10, $digits)) * floor($num/(pow(10, $digits)));
You could replace floor with round or ceil. Actually, if you wanted to round to the nearest, you could simplify the third line even more.
$num = round($num, -$digits);
If you do want to have a mathy solution, try this:
function floorToFirst($int) {
if (0 === $int) return 0;
$nearest = pow(10, floor(log($int, 10)));
return floor($int / $nearest) * $nearest;
}
Something like this:
$str = (string)$value;
echo (int)($str[0] . str_repeat('0', strlen($str) - 1));
It's totally non-mathy, but I would just do this utilizing sting length... there's probably a smoother way to handle it but you could acomplish it with
function significant($number){
$digits = count($number);
if($digits >= 2){
$newNumber = substr($number,0,1);
$digits--;
for($i = 0; $i < $digits; $i++){
$newNumber = $newNumber . "0";
}
}
return $newNumber;
}
A math based alternative:
$mod = pow(10, intval(round(log10($value) - 0.5)));
$answer = ((int)($value / $mod)) * $mod;
I know this is an old thread but I read it when looking for inspiration on how to solve this problem. Here's what I came up with:
class Math
{
public static function round($number, $numberOfSigFigs = 1)
{
// If the number is 0 return 0
if ($number == 0) {
return 0;
}
// Deal with negative numbers
if ($number < 0) {
$number = -$number;
return -Math::sigFigRound($number, $numberOfSigFigs);
}
return Math::sigFigRound($number, $numberOfSigFigs);
}
private static function sigFigRound($number, $numberOfSigFigs)
{
// Log the number passed
$log = log10($number);
// Round $log down to determine the integer part of the log
$logIntegerPart = floor($log);
// Subtract the integer part from the log itself to determine the fractional part of the log
$logFractionalPart = $log - $logIntegerPart;
// Calculate the value of 10 raised to the power of $logFractionalPart
$value = pow(10, $logFractionalPart);
// Round $value to specified number of significant figures
$value = round($value, $numberOfSigFigs - 1);
// Return the correct value
return $value * pow(10, $logIntegerPart);
}
}
While the functions here worked, I needed significant digits for very small numbers (comparing low-value cryptocurrency to bitcoin).
The answer at Format number to N significant digits in PHP worked, somewhat, though very small numbers are displayed by PHP in scientific notation, which makes them hard for some people to read.
I tried using number_format, though that needs a specific number of digits after the decimal, which broke the 'significant' part of the number (if a set number is entered) and sometimes returned 0 (for numbers smaller than the set number).
The solution was to modify the function to identify really small numbers and then use number_format on them - taking the number of scientific notation digits as the number of digits for number_format:
function roundRate($rate, $digits)
{
$mod = pow(10, intval(round(log10($rate))));
$mod = $mod / pow(10, $digits);
$answer = ((int)($rate / $mod)) * $mod;
$small = strstr($answer,"-");
if($small)
{
$answer = number_format($answer,str_replace("-","",$small));
}
return $answer;
}
This function retains the significant digits as well as presents the numbers in easy-to-read format for everyone. (I know, it is not the best for scientific people nor even the most consistently length 'pretty' looking numbers, but it is overall the best solution for what we needed.)

Categories