Basically, I need a function to help me achieve this:
I have a raw integer, say 5000, which is an amount of money. It's not formatted in any way. I want to be able to convert 5000 into a string like "$5k".
If the amount was 1000000 (one million), the string would be "$1m".
If the amount was 1000000000 (one billion), the string would be "$1b";
I also need to round the number, so say the amount was 5555555, the string would be "$5.5m"
A simple way to do that id to create a format function like this :
function format($amount) {
if ($amount < 1000) {
return '$' . $amount;
} else if($amount < 1000000) {
$amount /= 1000;
return '$' . round($amount, 1) . 'k';
} else if($amount < 1000000000) {
$amount /= 1000000;
return '$' . round($amount, 1) . 'm';
} else {
$amount /= 1000000000;
return '$' . round($amount, 1) . 'b';
}
}
If you're running PHP on a system with strfmon capabilities, you can use the money_format method (windows don't support it).
Related
I need to create a player with 3 properties:
Life (must be a random integer from 1 to 100);
Attack (must be a random integer from 1 to 100);
Defense (must be a random integer from 1 to 100);
But the total sum of all properties must be 200 (Life + Attack + Defense = 200). No more or less.
I’ve tried to make something like this:
public function initPlayer(){
$life = random_int(1, 100);
$attack = random_int(1, 100);
$lifeAttack = $life + $attack;
if($lifeAttack >= 100) {
$defense = 200 - $lifeAttack;
} else {
$defense = random_int(1, 100);
}
echo $life . '-' . $attack . '-' . $defense;
}
But it works correctly only if the sum of two params is equal or more than 100.
If the three values of life + attack + defense are to be real random numbers in the range 1..100, then the total is only 200 with a very low probability.
When the third value is calculated, it is no longer random.
The correct solution is: The 3 values have to be determined again and again until the total is equal 200.
for($sum = 0;$sum !== 200;){
$life = random_int(1, 100);
$attack = random_int(1, 100);
$defense = random_int(1, 100);
$sum = $life + $attack + $defense;
}
var_dump($life,$attack,$defense,$life + $attack + $defense);
Output example:
int(65) int(77) int(58) int(200)
That's basically because $lifeAttack must be greater than 100 to meet all your conditions. You could recurse when it isn't, like this:
public function initPlayer()
{
$life = random_int(1, 100);
$attack = random_int(1, 100);
$lifeAttack = $life + $attack;
if($lifeAttack >= 100) {
$defense = 200 - $lifeAttack;
} else {
$this->initPlayer();
return;
}
echo $life . '-' . $attack . '-' . $defense;
}
Of course you can do the same without recursion. Perhaps it would be nice to return these values from the function?
check this algorithm, that produce an array of values in a defined range with a defined sum :
function generate_values($total, $range_min, $range_max, $nb_values) {
// impossible conditions
if($total < $range_min*$nb_values || $total > $range_max*$nb_values) {
return null;
}
$values = [];
for($i=0; $i<$nb_values; $i++) {
$current_total = $total - array_sum($values);
// the last value is the remaining total
$value = $current_total;
if( $i < ($nb_values-1) ) {
$current_range_min = max($range_min, $current_total - ($nb_values-$i-1)*$range_max);
$current_range_max = min($range_max, $current_total - ($nb_values-$i-1)*$range_min);
$value = rand($current_range_min, $current_range_max);
}
array_push($values, $value);
}
shuffle($values);
return $values;
}
// test with your needs
for($i=0; $i<10; $i++) {
$values = generate_values(200, 1, 100, 3);
var_dump($values, array_sum($values));
}
This would be a case where only 2 numbers would be I inherently random. I would recommend first randomizing life from 1 to 100, and set the upper bound for attack as 100 -$life (I.e. 1 to 100 - $life) . Finally, defense would be pre-determined as 100 - lifeAttack.
I am creating a social site. And I want to show people things like their total amount of likes, followers and people they are following. The way it is now, it shows the total amount of likes, followers and following as a whole number and if it's too long it will go over other words on the page.
So how do I use abbreviations like: K(for thousands), m(millions) etc ? This is what I have now.
$stmt = $con->prepare('SELECT name, username, num_likes, profile_pic FROM users WHERE user_closed = "0"
ORDER BY num_likes DESC LIMIT 100');
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($name, $username, $num_likes, $profile_pic);
function convert($num_likes)
{
$num_likes = $number / 1000;
return $num_likes . 'k';
}
This is how I show the result: <p> Total Likes: " . $num_likes ."</p>
I tried the following:
PHP Count round thousand to a K style count like facebook Share . . . Twitter Button ect
Shorten long numbers to K/M/B?
PHP Count round thousand to a K style count Facebook Share
First of all, your function:
function convert($num_likes)
{
$num_likes = $number / 1000;
return $num_likes . 'k';
}
will not work as expected, because it converts to the opposite way :) Here is updated version:
function convert($num_likes)
{
$number = $num_likes / 1000;
return $number . 'k';
}
Second point. You should use the function somewhere... for example your line (actually only a part of it):
<p> Total Likes: " . $num_likes ."</p>
must be:
<p> Total Likes: " . convert($num_likes) ."</p>
And finally, using this answer we can modify convert function to this:
function convert($n) {
if ($n < 1000) {
$n_format = number_format($n);
} else if ($n < 1000000) {
// Anything less than a million
$n_format = number_format($n / 1000, 3) . 'k';
} else if ($n < 1000000000) {
// Anything less than a billion
$n_format = number_format($n / 1000000, 3) . 'M';
} else {
// At least a billion
$n_format = number_format($n / 1000000000, 3) . 'B';
}
return $n_format;
}
Now we can convert all numbers up to billions.
Playground: click.
Perhaps like this,
Use round() if you don't want large fractions.
<?php
function convert(int $number)
{
if ($number >= 1E9) {
return round($number / 1E9, 2).'b';
} else if ($number >= 1E6) {
return round($number / 1E6, 2).'m';
} else if ($number >= 1E3) {
return round($number / 1E3, 2).'k';
}
return $number;
}
echo convert(1000000000).PHP_EOL; // 1b
echo convert(1000000).PHP_EOL; // 1m
echo convert(1200).PHP_EOL; // 1.2k
echo convert(1234).PHP_EOL; // 1.23k
echo convert(100).PHP_EOL; // 100
https://3v4l.org/cc54H
This is a similar question to Fastest way to determine if an integer is between two integers (inclusive) with known sets of values, but the accepted answer will not work (as far as I know) in php due to php not being strictly typed and not having controllable integer overflow.
The use case here is to determine if an integer is between 65 and 90 (ASCII values for 'A' and 'Z'). These bounds might help optimize the solution due to 64 being a power of two and acting as boundary condition for this problem.
The only pseudo optimization I have come up with so far is:
//$intVal will be between 0 and 255 (inclusive)
function isCapital($intVal)
{
//255-64=191 (bit mask of 1011 1111)
return (($intVal & 191) <= 26) && (($intVal & 191) > 0);
}
This function is not much of an improvement (possibly slower) over a normal double comparison of $intVal >= 65 && $intVal <= 90, but it is just where I started heading while trying to optimize.
function isCapitalBitwise($intVal) {
return (($intVal & 191) <= 26) && (($intVal & 191) > 0);
}
function isCapitalNormal($intVal) {
return $intVal >= 65 && $intVal <= 90;
}
function doTest($repetitions) {
$i = 0;
$startFirst = microtime();
while ($i++ < $repetitions) {
isCapitalBitwise(76);
}
$first = microtime() - $startFirst;
$i = 0;
$startSecond = microtime();
while ($i++ < $repetitions) {
isCapitalNormal(76);
}
$second = microtime() - $startSecond;
$i = 0;
$startThird = microtime();
while ($i++ < $repetitions) {
ctype_upper('A');
}
$third = $startThird - microtime();
echo $first . ' ' . $second . ' ' . $third . PHP_EOL;
}
doTest(1000000);
On my system this returns:
0.217393 0.188426 0.856837
PHP is not as good at bitwise operations as compiled languages... but more importantly, I had to do a million comparisons to get less than 3 hundredths of a second of difference.
Even ctype_upper() is well in the range of "you might save a few seconds of CPU time per year" with these other ways of comparison, with the added bonus that you don't have to call ord() first.
Go for readability. Go for maintainability. Write your application, then profile it to see where your real bottlenecks are.
Instead of recreating the wheel, why not use the pre-built php method ctype_upper
$char = 'A';
echo ctype_upper($char) ? "It's uppercase" : "It's lowercase";
You can even pass in the integer value of a character:
echo ctype_upper($intVal) ? "It's uppercase" : "It's lowercase";
http://php.net/manual/en/function.ctype-upper.php
Even if you do find a method other than comparing via && or what I pasted above, it will be microseconds difference. You will waste hours coming up with a way to save a few seconds in the course of a year.
From How to check if an integer is within a range?:
t1_test1: ($val >= $min && $val <= $max): 0.3823 ms
t2_test2: (in_array($val, range($min, $max)): 9.3301 ms
t3_test3: (max(min($var, $max), $min) == $val): 0.7272 ms
You can also use range with characters (A, B, C...) but as you see it is not a good approach.
I think you will get best results by going native, but its only a fraction faster. Use ctype_upper directly. Here are my tests.
<?php
$numTrials = 500000;
$test = array();
for ($ii = 0; $ii < $numTrials; $ii++) {
$test[] = mt_rand(0, 255);
}
function compare2($intVal) {
return $intVal >= 65 && $intVal <= 90;
}
$tic = microtime(true);
for ($ii = 0; $ii < $numTrials; $ii++) {
$result = compare2($test[$ii]);
}
$toc = microtime(true);
echo "compare2...: " . ($toc - $tic) . "\n";
$tic = microtime(true);
for ($ii = 0; $ii < $numTrials; $ii++) {
$result = ctype_upper($test[$ii]);
}
$toc = microtime(true);
echo "ctype_upper: " . ($toc - $tic) . "\n";
echo "\n";
Which gives something pretty consistently like:
compare2...: 0.39210104942322
ctype_upper: 0.32374000549316
I'm trying to round a number to 1 decimal place.
I've written this code to shorten numbers over 1000:
$numbers = array($count);
function format_number($number) {
if($number >= 1000) {
return $number/1000 . "k";
}
}
foreach($numbers as $number) {
echo "Posts: ";
echo format_number($number);
}
For example this makes 15900 15.900k. Now I made a rounding part so it only reads as 15.9k:
$rounded = round($number, 1); // e.g. 66.7346 becomes 66.7
and echoed it:
echo "".$rounded."";
but nothing shows.
Any ideas?
You aren't returning anything if the number is less than 1000.
function format_number($number) {
if($number >= 1000) {
return $number/1000 . "k";
}
//What happens here if the number is not 1000?
}
I'd rewrite it as this:
function format_number($number) {
$append = '';
if($number >= 1000) {
$number /= 1000;
$append = 'k';
}
return round($number, 1) . $append;
}
I need to round up any integer between 1 and infinity in php to the next significant figure (though in practice I'm unlikely to need to round up infinity, so will be happy to settle on reasonable internal limits) eg:
$x <= 10 ? $x = 10
10 < $x <= 100 ? $x = 100
100 < $x <= 1000 ? $x = 1000
etc.
Round / ceil etc don't seem to do the job quite as planned. A pointer towards the correct algorhythm (or function?) would be much appreciated
i think this method will fix your problem:
function n($nr, $p = 10) {
if($nr <= $p) {
return $p;
}
return n($nr, $p*10);
}
heres the result:
echo n(1);
//output 10
echo n(232);
//output 1000
echo n(89289382);
//output 100000000
$x = pow(10,floor(log10($x)) + (floor(log10($x)) == log10($x) && $x!=1 ? 0:1) );
function my_ceil($in) {
if($in == 1) return $in;
if($in == pow(10, strlen($in)-1)) return $in;
return pow(10, strlen($in));
}
echo my_ceil(11); //100
echo my_ceil(10); //10
I think this is what you're looking for:
echo ceil($x / pow(10, strlen($x))) * pow(10, strlen($x));
Only works when $x is an integer, but you say in your question that that is indeed the case, so there's no issue (unless you try to later use it with numbers containing decimals).
This should do the trick:
<?php
function nextSignificantFeature($number){
$upper = pow(10, strlen($number));
return $number == $upper/10 ? $number : $upper;
}
?>
Actually there is the infinity number in PHP, so the implementation should deal with it as you wrote any number from 1 up to infinity Demo:
<?php
function n($number) {
if ($number < 1) {
throw new InvalidArgumentException('Number must be greater or equal 1.');
}
if ($number === INF) {
return INF;
}
$p = 10;
while($number > ($p*=10));
return $p;
}
echo n(1), "\n";
//output 10
echo n(232), "\n";
//output 1000
echo n(89289382), "\n";
//output 100000000
echo n(INF), "\n";
// output INF
echo n(-INF), "\n";
// throws exception 'InvalidArgumentException' with message 'Number must be greater or equal 1.'
This example does the iterative calculation in PHP userland code. There are some math functions in PHP that can do it inline like pow.