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

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)

Related

Float to int error

Yesterday I was helping some one and got a weird error which I could not explain to him how it worked.
The code (tested on 3 machines (PHP 5.3 and PHP 5.4))
// (float)65.35
$percentage = round(65.351, 2);
// (float) 6535
$total = $percentage * 100;
// (int) 6534
$int = (int) $total;
What is suspected was that the int value would be 6535 but it ended up being 6534.
Could some one explain what is going on?
You don't actually have 65.35 after the first operation.
>>> '%.20f' % (65.351 - 0.001,)
'65.34999999999999431566'
Either start with an integral value scaled appropriately in the first place, don't attempt to convert the value to an integer, or add a small value before taking the integer value.
This has to do with how floating point (read the warning in this link!) values are stored in memory. Indeed after the first operation you don't have an exact decimal value, but a rounded value. Probably 65.34999999 or so. (The value is stored as a list of bits (0/1))
This is why when talking about money, developers don't store dollars/euros but rather the amount of cents. This way they avoid working with floats that are less precise for decimals, but rather work with integers, that are precise.
Use round instead of int
round($total)
$r=$explode('.',$total);
debug($r);

¨Showing significant figures

I have a question regarding number formating in PHP.
I have a variable called "average", which is simply an average of a few values. To make it clear I rounded the number to 2 decimal places. Now the problem is, that if the average is for example 2.90, it only shows 2.9. Is there any way of displaying 2 decimal places always? I though I could do it by multiplying the number by 100, rounding it to zero d.p. and then divide by 100 again, but that seems a bit overcomplicated if there is an easier way of doing it.
Maybe you can try the number_format(float $number [, int $decimals = 0 ])?
For more information, take a look at http://php.net/manual/en/function.number-format.php
Format the output with printf
printf("%.1f", $num); // prints 1 decimal place
printf("%.2f", $num); // prints 2 decimal places

Simple math with decimals in PHP

This is killing me! I've never had so much trouble and I can't figure out what I'm doing wrong here.
If I have a number, say 2.32, and I want to do math with it it won't work out. The very simplest example:
$income = $commission; //Commission is 2.32, retrieved from XML
echo "income: $income<br>";
$income100 = $income*100;
echo "income100: $income100<br>";
The result I get is:
income: 2.32
income100: 200
How can I use a decimal number accurately with math without it changing it?
Thanks so much!
You need to assign $income in the following manner to get rid of the underlying SimpleXMLElement:
$income = (float) $commission;
Example of what happens when you don't:
$x = simplexml_load_string("<a>2.4</a>");
echo $x * 100; // output: 200
Besides using floats as Tim said, also make sure to use the BC Math functions when performing arithmetic operation on floating point numbers. Specifically bcmul():
$income100 = bcmul($income, 100);
The problem with floating-point numbers is that you cannot represent decimal numbers with them (unless it can be written as a/b for integer a and b, and even then only if abs(a) < pow(2,52) and b is a power of 2).
You may be better off using string functions to get an integer value:
$tmp = explode(".",$commission);
$tmp = intval($tmp[0].str_pad(substr($tmp[1],0,2),2,"0"));
This will split up the integer part from the decimal part, ensure the decima part is two digits long, and shove it on the end of the integer part, thus effectively multiplying the original number by 100.
I think the easiest solution would be to cast it to a float with floatval()
$income = floatval($comission)
leave the rest of the code as is and it should work as intended.

PHP Subtraction Returning Infinite Number

I have an array that store data. If I subtract two arrays I get an infinately big number. Here is an example
$i[1] = 2.14;
$i[2] = 2.15;
$diff = $i[1] - $i[2];
echo $diff;
The output of this code should be -1 but instead I am getting -0.0099999999999998? With the code I am making I need the numbers to be exact. Does anyone know why this is happening and how I can fix it?
Thank you
This is because of inaccuracies introduced in floating point operations.
For arbitrary precision operations see BCMath in the manual.

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;

Categories