Is it possible to round a number where if it's .5, just leave it, anything below .5 round down, anything above .5 round up?
For example:
5.0 * 1.35 = 6.75 // leave it
5.2 * 1.35 = 7.02 // round down to 7.00
5.5 * 1.35 = 7.56 // round up to 8.00
I've formatted with round($n,0, PHP_ROUND_HALF_UP) where $n is the product from the above calc , which leaves 6.75 but returns 7.02 for the next one. I also tried round($n,-1, PHP_ROUND_HALF_UP) which gives me the 7.00 on the second calc but then of course won't return a 6.75 for the first, instead it returns 680.
This is a ticket markup calculation where the user enters the first number and is multiplied by the second. I actually remove the decimal because they don't want to see it, and they want this sort of customized rounding on the result.
function myround($num, $prec) {
$rhu = round($num, $prec, PHP_ROUND_HALF_UP);
$rhd = round($num, $prec, PHP_ROUND_HALF_DOWN);
return ($rhu + $rhd) / 2;
}
Works for any precision you like. For hundreth's place, as in the example, $prec would need to be 2.
The only way to determine the value of the last non-zero digit of a given floating point number in PHP is to convert it to a string.
$str = (string) $float;
$result = ($str[strlen($str) - 1] == 5) ? $float : round($float);
Example
Of course, no matter what you do it will be subject to a small margin of error because of the floating point precision issue.
$n = round($n, 2);
if($n % .05 != 0 || $n % .1 == 0)
{
$n = round($n);
}
Does this work for you? I'm assuming the 5 you speak of is the hundredth digit, and if it's not 5 then you want a whole number.
Related
How does one generate a random float between 0 and 1 in PHP?
I'm looking for the PHP's equivalent to Java's Math.random().
You may use the standard function: lcg_value().
Here's another function given on the rand() docs:
// auxiliary function
// returns random number with flat distribution from 0 to 1
function random_0_1()
{
return (float)rand() / (float)getrandmax();
}
Example from documentation :
function random_float ($min,$max) {
return ($min+lcg_value()*(abs($max-$min)));
}
rand(0,1000)/1000 returns:
0.348 0.716 0.251 0.459 0.893 0.867 0.058 0.955 0.644 0.246 0.292
or use a bigger number if you want more digits after decimal point
class SomeHelper
{
/**
* Generate random float number.
*
* #param float|int $min
* #param float|int $max
* #return float
*/
public static function rand($min = 0, $max = 1)
{
return ($min + ($max - $min) * (mt_rand() / mt_getrandmax()));
}
}
update:
forget this answer it doesnt work wit php -v > 5.3
What about
floatVal('0.'.rand(1, 9));
?
this works perfect for me, and it´s not only for 0 - 1 for example between 1.0 - 15.0
floatVal(rand(1, 15).'.'.rand(1, 9));
function mt_rand_float($min, $max, $countZero = '0') {
$countZero = +('1'.$countZero);
$min = floor($min*$countZero);
$max = floor($max*$countZero);
$rand = mt_rand($min, $max) / $countZero;
return $rand;
}
example:
echo mt_rand_float(0, 1);
result: 0.2
echo mt_rand_float(3.2, 3.23, '000');
result: 3.219
echo mt_rand_float(1, 5, '00');
result: 4.52
echo mt_rand_float(0.56789, 1, '00');
result: 0.69
$random_number = rand(1,10).".".rand(1,9);
function frand($min, $max, $decimals = 0) {
$scale = pow(10, $decimals);
return mt_rand($min * $scale, $max * $scale) / $scale;
}
echo "frand(0, 10, 2) = " . frand(0, 10, 2) . "\n";
This question asks for a value from 0 to 1. For most mathematical purposes this is usually invalid albeit to the smallest possible degree. The standard distribution by convention is 0 >= N < 1. You should consider if you really want something inclusive of 1.
Many things that do this absent minded have a one in a couple billion result of an anomalous result. This becomes obvious if you think about performing the operation backwards.
(int)(random_float() * 10) would return a value from 0 to 9 with an equal chance of each value. If in one in a billion times it can return 1 then very rarely it will return 10 instead.
Some people would fix this after the fact (to decide that 10 should be 9). Multiplying it by 2 should give around a ~50% chance of 0 or 1 but will also have a ~0.000000000465% chance of returning a 2 like in Bender's dream.
Saying 0 to 1 as a float might be a bit like mistakenly saying 0 to 10 instead of 0 to 9 as ints when you want ten values starting at zero. In this case because of the broad range of possible float values then it's more like accidentally saying 0 to 1000000000 instead of 0 to 999999999.
With 64bit it's exceedingly rare to overflow but in this case some random functions are 32bit internally so it's not no implausible for that one in two and a half billion chance to occur.
The standard solutions would instead want to be like this:
mt_rand() / (getrandmax() + 1)
There can also be small usually insignificant differences in distribution, for example between 0 to 9 then you might find 0 is slightly more likely than 9 due to precision but this will typically be in the billionth or so and is not as severe as the above issue because the above issue can produce an invalid unexpected out of bounds figure for a calculation that would otherwise be flawless.
Java's Math.random will also never produce a value of 1. Some of this comes from that it is a mouthful to explain specifically what it does. It returns a value from 0 to less than one. It's Zeno's arrow, it never reaches 1. This isn't something someone would conventionally say. Instead people tend to say between 0 and 1 or from 0 to 1 but those are false.
This is somewhat a source of amusement in bug reports. For example, any PHP code using lcg_value without consideration for this may glitch approximately one in a couple billion times if it holds true to its documentation but that makes it painfully difficult to faithfully reproduce.
This kind of off by one error is one of the common sources of "Just turn it off and on again." issues typically encountered in embedded devices.
Solution for PHP 7. Generates random number in [0,1). i.e. includes 0 and excludes 1.
function random_float() {
return random_int(0, 2**53-1) / (2**53);
}
Thanks to Nommyde in the comments for pointing out my bug.
>>> number_format((2**53-1)/2**53,100)
=> "0.9999999999999998889776975374843459576368331909179687500000000000000000000000000000000000000000000000"
>>> number_format((2**53)/(2**53+1),100)
=> "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Most answers are using mt_rand. However, mt_getrandmax() usually returns only 2147483647. That means you only have 31 bits of information, while a double has a mantissa with 52 bits, which means there is a density of at least 2^53 for the numbers between 0 and 1.
This more complicated approach will get you a finer distribution:
function rand_754_01() {
// Generate 64 random bits (8 bytes)
$entropy = openssl_random_pseudo_bytes(8);
// Create a string of 12 '0' bits and 52 '1' bits.
$x = 0x000FFFFFFFFFFFFF;
$first12 = pack("Q", $x);
// Set the first 12 bits to 0 in the random string.
$y = $entropy & $first12;
// Now set the first 12 bits to be 0[exponent], where exponent is randomly chosen between 1 and 1022.
// Here $e has a probability of 0.5 to be 1022, 0.25 to be 1021, etc.
$e = 1022;
while($e > 1) {
if(mt_rand(0,1) == 0) {
break;
} else {
--$e;
}
}
// Pack the exponent properly (add four '0' bits behind it and 49 more in front)
$z = "\0\0\0\0\0\0" . pack("S", $e << 4);
// Now convert to a double.
return unpack("d", $y | $z)[1];
}
Please note that the above code only works on 64-bit machines with a Litte-Endian byte order and Intel-style IEEE754 representation. (x64-compatible computers will have this). Unfortunately PHP does not allow bit-shifting past int32-sized boundaries, so you have to write a separate function for Big-Endian.
You should replace this line:
$z = "\0\0\0\0\0\0" . pack("S", $e << 4);
with its big-endian counterpart:
$z = pack("S", $e << 4) . "\0\0\0\0\0\0";
The difference is only notable when the function is called a large amount of times: 10^9 or more.
Testing if this works
It should be obvious that the mantissa follows a nice uniform distribution approximation, but it's less obvious that a sum of a large amount of such distributions (each with cumulatively halved chance and amplitude) is uniform.
Running:
function randomNumbers() {
$f = 0.0;
for($i = 0; $i < 1000000; ++$i) {
$f += \math::rand_754_01();
}
echo $f / 1000000;
}
Produces an output of 0.49999928273099 (or a similar number close to 0.5).
I found the answer on PHP.net
<?php
function randomFloat($min = 0, $max = 1) {
return $min + mt_rand() / mt_getrandmax() * ($max - $min);
}
var_dump(randomFloat());
var_dump(randomFloat(2, 20));
?>
float(0.91601131712832)
float(16.511210331931)
So you could do
randomFloat(0,1);
or simple
mt_rand() / mt_getrandmax() * 1;
what about:
echo (float)('0.' . rand(0,99999));
would probably work fine... hope it helps you.
So, I need to create the following functions but my head can't think of any possibility in PHP without complicated math.
Round always up to the nearest decimal (1.81 = 1.90, 1.89 = 1.90, 1.85 = 1.90)
Round always down to the nearest decimal (1.81 = 1.80, 1.89 = 1.80, 1.85 = 1.80)
Round always up to the nearest x.25 / x.50 / x.75 / x.00 (1.81 = 2, 1.32 = 1.50)
Round always down to the nearest x.25 / x.50 / x.75 / x.00 (1.81 = 1.75, 1.32 = 1.25)
Round always up to the nearest x.50 / 1 (1.23 = 1.50, 1.83 = 2)
Round always down to the nearest x.50 / 1 (1.23 = 1, 1.83 = 1.50)
I have searched on Google for 2 hours now and the only things that came up were Excel forums. Is it possible with some simple lines of PHP?
Since you're looking for fourths (.00, .25, .50, .75), multiply your number by 4, round to nearest whole number as desired (floor if down, ceil if up), then divide by 4.
1.32, down to nearest fourth:
1.32 * 4 = 5.28
floor(5.28) = 5.00
5.00 / 4 = 1.25
Same principle applies for any other fractions, such as thirds or eighths (.0, .125, .25, .375, .5, .625, .75, .875). For example:
1.77, up to nearest eighth:
1.77 * 8 = 14.16
ceil(14.16) = 15.00
15.00 / 8 = 1.875
Just for fun, you could write a function like this:
function floorToFraction($number, $denominator = 1)
{
$x = $number * $denominator;
$x = floor($x);
$x = $x / $denominator;
return $x;
}
echo floorToFraction(1.82); // 1
echo floorToFraction(1.82, 2); // 1.5
echo floorToFraction(1.82, 3); // 1.6666666666667
echo floorToFraction(1.82, 4); // 1.75
echo floorToFraction(1.82, 9); // 1.7777777777778
echo floorToFraction(1.82, 25); // 1.8
Please note that the answer isn't really water tight. Since we're dealing with floats here it's not guaranteed that when you divide the rounded number by the denominator it returns a neatly round number. It may return 1.499999999999 instead of 1.5. It's the nature of floating point numbers.
Another round is needed before returning the number from the function.
Just in case someone lands here from google like I did :)
According to the mround() function in Excel:
function MRound($num,$parts) {
$res = $num * $parts;
$res = round($res);
return $res /$parts;
}
echo MRound(-1.38,4);//gives -1.5
echo MRound(-1.37,4);//gives -1.25
echo MRound(1.38,4);//gives 1.5
echo MRound(1.37,4);//gives 1.25
Look at example #3 on here and it is half of your solution - http://php.net/manual/en/function.round.php
How does one generate a random float between 0 and 1 in PHP?
I'm looking for the PHP's equivalent to Java's Math.random().
You may use the standard function: lcg_value().
Here's another function given on the rand() docs:
// auxiliary function
// returns random number with flat distribution from 0 to 1
function random_0_1()
{
return (float)rand() / (float)getrandmax();
}
Example from documentation :
function random_float ($min,$max) {
return ($min+lcg_value()*(abs($max-$min)));
}
rand(0,1000)/1000 returns:
0.348 0.716 0.251 0.459 0.893 0.867 0.058 0.955 0.644 0.246 0.292
or use a bigger number if you want more digits after decimal point
class SomeHelper
{
/**
* Generate random float number.
*
* #param float|int $min
* #param float|int $max
* #return float
*/
public static function rand($min = 0, $max = 1)
{
return ($min + ($max - $min) * (mt_rand() / mt_getrandmax()));
}
}
update:
forget this answer it doesnt work wit php -v > 5.3
What about
floatVal('0.'.rand(1, 9));
?
this works perfect for me, and it´s not only for 0 - 1 for example between 1.0 - 15.0
floatVal(rand(1, 15).'.'.rand(1, 9));
function mt_rand_float($min, $max, $countZero = '0') {
$countZero = +('1'.$countZero);
$min = floor($min*$countZero);
$max = floor($max*$countZero);
$rand = mt_rand($min, $max) / $countZero;
return $rand;
}
example:
echo mt_rand_float(0, 1);
result: 0.2
echo mt_rand_float(3.2, 3.23, '000');
result: 3.219
echo mt_rand_float(1, 5, '00');
result: 4.52
echo mt_rand_float(0.56789, 1, '00');
result: 0.69
$random_number = rand(1,10).".".rand(1,9);
function frand($min, $max, $decimals = 0) {
$scale = pow(10, $decimals);
return mt_rand($min * $scale, $max * $scale) / $scale;
}
echo "frand(0, 10, 2) = " . frand(0, 10, 2) . "\n";
This question asks for a value from 0 to 1. For most mathematical purposes this is usually invalid albeit to the smallest possible degree. The standard distribution by convention is 0 >= N < 1. You should consider if you really want something inclusive of 1.
Many things that do this absent minded have a one in a couple billion result of an anomalous result. This becomes obvious if you think about performing the operation backwards.
(int)(random_float() * 10) would return a value from 0 to 9 with an equal chance of each value. If in one in a billion times it can return 1 then very rarely it will return 10 instead.
Some people would fix this after the fact (to decide that 10 should be 9). Multiplying it by 2 should give around a ~50% chance of 0 or 1 but will also have a ~0.000000000465% chance of returning a 2 like in Bender's dream.
Saying 0 to 1 as a float might be a bit like mistakenly saying 0 to 10 instead of 0 to 9 as ints when you want ten values starting at zero. In this case because of the broad range of possible float values then it's more like accidentally saying 0 to 1000000000 instead of 0 to 999999999.
With 64bit it's exceedingly rare to overflow but in this case some random functions are 32bit internally so it's not no implausible for that one in two and a half billion chance to occur.
The standard solutions would instead want to be like this:
mt_rand() / (getrandmax() + 1)
There can also be small usually insignificant differences in distribution, for example between 0 to 9 then you might find 0 is slightly more likely than 9 due to precision but this will typically be in the billionth or so and is not as severe as the above issue because the above issue can produce an invalid unexpected out of bounds figure for a calculation that would otherwise be flawless.
Java's Math.random will also never produce a value of 1. Some of this comes from that it is a mouthful to explain specifically what it does. It returns a value from 0 to less than one. It's Zeno's arrow, it never reaches 1. This isn't something someone would conventionally say. Instead people tend to say between 0 and 1 or from 0 to 1 but those are false.
This is somewhat a source of amusement in bug reports. For example, any PHP code using lcg_value without consideration for this may glitch approximately one in a couple billion times if it holds true to its documentation but that makes it painfully difficult to faithfully reproduce.
This kind of off by one error is one of the common sources of "Just turn it off and on again." issues typically encountered in embedded devices.
Solution for PHP 7. Generates random number in [0,1). i.e. includes 0 and excludes 1.
function random_float() {
return random_int(0, 2**53-1) / (2**53);
}
Thanks to Nommyde in the comments for pointing out my bug.
>>> number_format((2**53-1)/2**53,100)
=> "0.9999999999999998889776975374843459576368331909179687500000000000000000000000000000000000000000000000"
>>> number_format((2**53)/(2**53+1),100)
=> "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Most answers are using mt_rand. However, mt_getrandmax() usually returns only 2147483647. That means you only have 31 bits of information, while a double has a mantissa with 52 bits, which means there is a density of at least 2^53 for the numbers between 0 and 1.
This more complicated approach will get you a finer distribution:
function rand_754_01() {
// Generate 64 random bits (8 bytes)
$entropy = openssl_random_pseudo_bytes(8);
// Create a string of 12 '0' bits and 52 '1' bits.
$x = 0x000FFFFFFFFFFFFF;
$first12 = pack("Q", $x);
// Set the first 12 bits to 0 in the random string.
$y = $entropy & $first12;
// Now set the first 12 bits to be 0[exponent], where exponent is randomly chosen between 1 and 1022.
// Here $e has a probability of 0.5 to be 1022, 0.25 to be 1021, etc.
$e = 1022;
while($e > 1) {
if(mt_rand(0,1) == 0) {
break;
} else {
--$e;
}
}
// Pack the exponent properly (add four '0' bits behind it and 49 more in front)
$z = "\0\0\0\0\0\0" . pack("S", $e << 4);
// Now convert to a double.
return unpack("d", $y | $z)[1];
}
Please note that the above code only works on 64-bit machines with a Litte-Endian byte order and Intel-style IEEE754 representation. (x64-compatible computers will have this). Unfortunately PHP does not allow bit-shifting past int32-sized boundaries, so you have to write a separate function for Big-Endian.
You should replace this line:
$z = "\0\0\0\0\0\0" . pack("S", $e << 4);
with its big-endian counterpart:
$z = pack("S", $e << 4) . "\0\0\0\0\0\0";
The difference is only notable when the function is called a large amount of times: 10^9 or more.
Testing if this works
It should be obvious that the mantissa follows a nice uniform distribution approximation, but it's less obvious that a sum of a large amount of such distributions (each with cumulatively halved chance and amplitude) is uniform.
Running:
function randomNumbers() {
$f = 0.0;
for($i = 0; $i < 1000000; ++$i) {
$f += \math::rand_754_01();
}
echo $f / 1000000;
}
Produces an output of 0.49999928273099 (or a similar number close to 0.5).
I found the answer on PHP.net
<?php
function randomFloat($min = 0, $max = 1) {
return $min + mt_rand() / mt_getrandmax() * ($max - $min);
}
var_dump(randomFloat());
var_dump(randomFloat(2, 20));
?>
float(0.91601131712832)
float(16.511210331931)
So you could do
randomFloat(0,1);
or simple
mt_rand() / mt_getrandmax() * 1;
what about:
echo (float)('0.' . rand(0,99999));
would probably work fine... hope it helps you.
Searching for a function ro round numbers to the nearest multiple of 5
22 -> 20
23 -> 25
40 -> 40
46 -> 45
48 -> 50
and so on.
Tried this which always returns the higher value:
5 * ceil($n / 5);
Use round() instead of ceil().
5 * round($n / 5);
ceil() rounds a floating point number up to its next integer in sequence. round() will round to the nearest integer using standard rounding rules.
Back to maths, since round works with decimals, multiply by 5 and divide by 10 and then round, it. Multiply by 5 again to get what u want. (Other answer works as well, just a different way of looking at it)
function round_5($in)
{
return round(($in*2)/10)*5;
}
echo round_5(48);
See if this helps
Well, facing this issue while helping make an POS for a Canadian company, came up with this solution, hope it helps someone. (Canada removed the penny in 2012). Also includes for doing tax included pricing, just pass '1' as second argh.
//calculate price and tax
function calctax($amt,$tax_included = NULL){
$taxa = 'tax rate 1 here';
$taxb = 'tax rate 2 here';
$taxc = ($taxa + $taxb) + 1;
if(is_null($tax_included)){
$p = $amt;
}else{
$p = number_format(round($amt / $taxc,2),2);
}
$ta = round($p * $taxa,2);
$tb = round($p * $taxb,2);
$sp = number_format(round($p+($ta + $tb),2),2);
$tp = number_format(round(($sp*2)/10,2)*5,2);
$ret = array($ta,$tb,$tp);
return $ret;
}
I need to convert pounds to kilograms and vice versa -- and round the number to the nearest quarter (and possibly half). I need to be able to make a conversion, take that conversion and convert it back, and have all the values still be the same.
Sample code:
for ($i = 1; $i <= 100; $i = $i + .25)
{
$kilograms = convert_pounds_to_kilograms($i);
$pounds = convert_kilograms_to_pounds($kilograms);
$new_kilograms = convert_pounds_to_kilograms($pounds);
echo ("$i => $pounds => $kilograms => $new_kilograms<br/>");
}
function convert_pounds_to_kilograms($pounds)
{
assert(is_numeric($pounds) === TRUE);
$kilograms = $pounds * 0.45359237;
// Round to the nearest quarter
$kilograms = round($kilograms * 4, 0) / 4;
return $kilograms;
}
function convert_kilograms_to_pounds($kilograms)
{
assert(is_numeric($kilograms) === TRUE);
$pounds = $kilograms * 2.20462262185;
// Round to the nearest quarter
$pounds = round($pounds * 4, 0) / 4;
return $pounds;
}
The first line of output is correct:
1 => 1 => 0.5 => 0.5
The second is not correct:
1.25 => 1 => 0.5 => 0.5
(the value 1 should have been 1.25)
How do I do this? I'm not looking for precision in the conversion, obviously. I just need to be able to convert these imprecise values back and forth to the same number.
EDIT 1:
The reason for this is that I will be allowing users to enter their height in centimeters, meters, or feet/inches -- then saving whatever their entered value to centimeters (thus, the first conversion). Users can then view their height in either centimeters, meters, or feet/inches (thus, a possible conversion again).
So, say a user enters their height in ft/inches, I need to store that in centimeters. Then the user may want to see that height again in ft/inches -- meaning I need to convert the centimeters back to the original ft/inches value.
Users will probably be limited to entering and viewing values to quarter increments. Meaning, 5'8.25" is valid, but not 5'8.39".
Do not round in the function itself. Go as precise as you can. Only round right before you display it.
If you round it off in the functions, then the ROUNDED value is put into the next function. If you keep doing this, you're going to lose a lot of precision, and you'll get less precise results the more you loop it.
You are rounding to 0 decimal places, hence the 1.25 is rounded to 1.
Try removimg the round() function and see what happens.
http://php.net/manual/en/function.round.php
Edit
To address your comment change:-
$kilograms = convert_pounds_to_kilograms($i);
To:-
$kilograms = round(convert_pounds_to_kilograms($i), 0);
And remove round() from inside your functions.
You're rounding out the precision. Your $pounds that you're printing out are converted from original value ($i) to kilograms with a round function, and then back to pounds with a round function; the round() is causing your values to converge.