PHP Round() not working properly - php

I need help. I'm doing this:
round($myvar,2);
And this is the number I'm getting: 9.779999999999999€
With the other variables it works just fine, any idea how to fix this?

I did this:
<?php echo round(9.7752,2);?>
And I got: 9.779999999999999
I believe it's something in php.ini as #MarkBaker said..
But, I fixed it by doing:
<?php echo number_format($myvar,2);
And I got exactly what I wanted.
Thanks guys for the help!

what problem I encounter is that round(18.203,2) = 18.2 ,then json_encode(...) = 18.199999999 .
so I find the solution is json_encode(strval(round(18.203,2))) = 18.2
it works

Just join empty string before round function like
$val = "" . round(9.597466245, 2);

something (could be in some 3rd party code ?) set your ini setting precision to 16
$php -a
php > echo ini_get("precision");
14 // default
php > echo round(9.7752,2);
9.78
php > echo ini_set("precision", 16);
14
php > echo round(9.7752,2);
9.779999999999999

Although OP solved his issue, I saw this while searching for other (but similar) issue.
If you came here with a problem where PHP's round() function is misbehaving (i.e. round(1.4447, 2) will output 1.44 instead of 1.45) that's because round looks just 1 decimal position away from the needed precision, here's a small recursive helper function that solves the issue:
function roundFloat($float, $neededPrecision, $startAt = 7)
{
if ($neededPrecision < $startAt) {
$startAt--;
$newFloat = round($float, $startAt);
return roundFloat($newFloat, $neededPrecision, $startAt);
}
return $float;
}
Usage example:
roundFloat(1.4447, 2, 5); // Returns 1.45
Explanation:
In example above, it starts rounding from 5th decimal point (0) in this case since not stated otherwise.
You can call the function like roundFloat(1.4447, 2, 15) with same
outcome for given float 1.4447.
$startAt just defines the starting point for the "rounding process" or the required precision.
Note: all programming languages have issues with writing some floats precisely (has to do with binary, google that for more info).
Hope it helps someone.

Just encase the result in a floatval
floatval(round($myvar,2));
If you use number_format, you must add the next two parameters otherwise larger numbers will go wrong:
number_format($myvar,2, '.', '');
This tells PHP to use "." as the decimal separator and no thousands separator.

I had the same problem and my workaround (in order to not change the ini-file and possibly break something else):
$rounded = bcdiv($number, 1, 2);

Combining #PabloCamara's answer and the comment from #LorienBrune, this solution worked for me:
function roundFixed($number, $decimalPlaces)
{
return str_replace(',', '', number_format($number, $decimalPlaces));
}

Related

PHP round() function does not round the number

It looks like PHP round() does not behave as expected. Look at the following code:
log_rec("BEFORE ROUNDING","x", $x);
$x = round($x, 3);
log_rec("AFTER ROUNDING","x", $x);
where log_rec() is simply a function of mine to write a record in a log file,
and $x value is initially set to 3.339999999999999857891452847979962825775146484375.
I expect $x to be 3.34 after rounding.
Here is the result in log file:
▶"BEFORE ROUNDING"■"x"■3.339999999999999857891452847979962825775146484375■
▶"AFTER ROUNDING"■"x"■3.339999999999999857891452847979962825775146484375■
No change. What am I doing wrong? I am using PHP 7.4.26.
NOTE: I need to round the number, that is, to obtain another float number. So, number_format() is not a solution.
UPDATE
I decided to use a different approach, that is to use
log_rec("BEFORE ROUNDING","x", $x);
$x= intval(100 * $x)/100;
log_rec("AFTER ROUNDING","x", $x);
I expected now
▶"BEFORE ROUNDING"■"x"■3.339999999999999857891452847979962825775146484375■
▶"AFTER ROUNDING"■"x"■3.34■
but I still get
▶"BEFORE ROUNDING"■"x"■3.339999999999999857891452847979962825775146484375■
▶"AFTER ROUNDING"■"x"■3.339999999999999857891452847979962825775146484375■
Now I am totally confused. This is a sequence of three well defined instructions. No other code should create some collateral effect.
Any idea?
PS: WHERE THE NUMBER COMES FROM?
Someone asked where that big number comes from.
From a JSON file. What is strange is that that number in JSON is 3.334, but after json_decode() something strange happens: if I use var_dump() I get 3.334 but if I use print_r() I get that big number.

PHP very small decimals result in error

PHP is erroring out on me when working with small decimals / floats. Take the following code:
$spotPrices['entry'] = 1.6591;
$price['o'] = 1.65908;
$currentresult = $spotPrices['entry'] - $price['o'];
echo $currentresult;
I would expect this to output 0.00002 (the answer). But instead it outputs: -1.99999999999E-5
Why is it doing this and, more importantly, how can I get the correct result?
I've done some searching on the forums and seen that floating points give PHP fits but haven't seen a solution or workaround that seems to answer my question.
My calculator is saying that the result should be 0.00002
use number_format:
$currentresult = number_format($spotPrices['entry'] - $price['o'], 8);
Instead of 0.00002 you get 1.9999999999909E-5 which is 0.000019999999999909. This is due to floating point precision. Precision is platform-dependent. You can read up on it here: http://www.php.net/manual/en/language.types.float.php

PHP - number_format issues

number_format stupidly rounds numbers by default. Is there just a simple way to turn off the rounding? I'm working with randomly generated numbers, and I could get things like...
42533 * .003 = 127.599 or,
42533 * .03 = 1275.99 or,
42533 * .3 = 12759.9
I need number_format (or something else) to express the result in traditional U.S. format (with a comma separating the thousands) and not round the decimal.
Any ideas?
The second argument of number_format is the number of decimals in the number. The easiest way to find that out is probably to treat it as a string (as per this question). Traditional US format is default behaviour, so you don't need to specify remaining arguments.
$num_decimals = strlen(substr(strrchr($number, "."), 1));
$formatted_number = number_format($number, $num_decimals);
If anyone's interested in this, I've written a little function to get around this problem.
With credit to Joel Hinz above, I came up with...
function number_format_with_decimals($value, $round_to){
//$value is the decimal number you want to show with number_format.
//$round_to is the deicimal place value you want to round to.
$round_to_decimals = strlen(substr(strrchr($value, "."), $round_to));
$ans = number_format($value, $round_to);
return $ans;
}
I tried these solutions, but what ended up being my answer was this:
$output=money_format('%!i', $value);
This gives you something like 3,234.90 instead of 3,234 or 3,234.9

PHP ceil gives wrong results if input is a float with no decimal

I've been wrestling with PHP's ceil() function giving me slightly wrong results - consider the following:
$num = 2.7*3; //float(8.1)
$num*=10; //float(81)
$num = ceil($num); //82, but shouldn't this be 81??
$num/=10; //float(8.2)
I have a number which may have any number of decimal places, and I need it rounded up to one decimal place.
i.e 8.1 should be 8.1, 8.154 should be 8.2, and 8 should be left as 8.
How I've been getting there is to take the number, multiply by 10, ceil() it, then divide by ten but as you can see I'm getting an extra .1 added in some circumstances.
Can anyone tell my why this is happening, and how to fix it?
Any help greatly appreciated
EDIT: had +=10 instead of *=10 :S
EDIT 2:
I didn't explicitly mention this but I need the decimal to ALWAYS round UP, never down - this answer is closest so far:
rtrim(rtrim(sprintf('%.1f', $num), '0'), '.');
However rounds 3.84 down to 3.8 when I need 3.9.
Sorry this wasn't clearer :(
Final Edit:
What I ended up doing was this:
$num = 2.7*3; //float(8.1)
$num*=10; //float(81)
$num = ceil(round($num, 2)); //81 :)
$num/=10; //float(8.1)
Which works :)
This is more than likely due to floating point error.
http://support.microsoft.com/kb/42980
http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html
http://joshblog.net/2007/01/30/flash-floating-point-number-errors/
http://en.wikipedia.org/wiki/Floating_point
You may have luck trying this procedure instead.
<?php
$num = 2.7*3;
echo rtrim(rtrim(sprintf('%.1f', $num), '0'), '.');
Floats can be a fickle thing. Not all real numbers can be properly represented in a finite number of binary bits.
As it turns out, a decimal section of 0.7 is one of those numbers (comes out 0.10 with an infinity repeating "1100" after it). You end up with a number that's ever so slightly above 0.7, so when you multiply by 10, you have a one's digit slightly above 7.
What you can do is make a sanity check. Take you float digit and subtract it's integer form. If the resulting value is less than, say, 0.0001, consider it to be an internal rounding error and leave it as-is. If the result is greater than 0.0001, apply ceil() normally.
Edit: A fun example you can do if you're on windows to show this is to open up the built in calculator application. Put in "4" then apply a square root function (with x^y where y=0.5). You'll see it properly displays "2". Now, subtract 2 from it and you'll see that you don't have 0 as a result. This is caused by internal rounding errors when it attempted to compute the square root of 4. When displaying the number 2 earlier, it knew that those very distant trailing digits were probably a rounding error, but when those are all that's left, it gets a bit confused.
(Before anybody gets onto me about this, I understand that this is oversimplified, but nonetheless I consider it a decent example.)
Convert your number to a string and ceil the string.
function roundUp($number, $decimalPlaces){
$multi = pow(10, $decimalPlaces);
$nrAsStr = ($number * $multi) . "";
return ceil($nrAsStr) / $multi;
}
The problem is that floating point numbers are RARELY what you expect them to be. Your 2.7*3 is probably coming out to be something like 81.0000000000000000001, which ceil()'s up to 82. For this sort of thing, you'll have to wrap your ceil/round/floor calls with some precision checks, to handle those extra microscopic differences.
Use %f instead of %.1f.
echo rtrim(rtrim(sprintf('%f', $num), '0'), '.');
Why not try this:
$num = 2.7*3;
$num *= 100;
$num = floor($num);
$num /= 10;
$num = ceil($num);
$num /= 10;

Silly, can't figure out php round down :(

I have small problem and it might be silly somewhere, but still i have it :)
So the problem is:
By doing this
round(615.36*0.10, 2, PHP_ROUND_HALF_DOWN);
I expect outcome to be 61.53, but it's 61.54.
phpVersion = 5.3.2
Could anyone help me to solve this?
Thanks.
PHP_ROUND_HALF_DOWN will round the half -- i.e. the 0.005 part.
if you have 61.535, using PHP_ROUND_HALF_DOWN will get you 61.53 -- instead of the 61.54 you should have obtained with usual rounding.
Basicall, the .005 half has been rounded down.
But 61.536 is not a half : .006 is more than .005 ; so rounding that value gives 61.54.
In your case, you could multiply the value by 100, use the floor() function, and divide the result by 100 -- I suppose it would give you what you expect :
$value = 61.536;
$value_times_100 = $value * 100;
$value_times_100_floored = floor($value_times_100);
$value_floored = $value_times_100_floored / 100;
var_dump($value_floored);
Gives me :
float(61.53)
If you want to round down, you'll need to use floor(), which doesn't have a means to specify precision, so it has to be worked around, eg. with
function floor_prec($x, $prec) {
return floor($x*pow(10,$prec))/pow(10,$prec);
}
you obviously only wanting it to two decimal places why not just number_format(615.36*0.10, 2)

Categories