PHP : The awk subtraction giving exponential values - php

I am getting awk result when I am subtracting two values, the error is I am getting exponent value 2.7755575615629E-17 instead of 0. Anything I am missing to apply, please suggest. These is happening with some cases only like 0.66, 0.67, 0.33,
The prototype of the code I am using is given below,
$_SESSION['x'] = 1;
$_SESSION['x'] = $_SESSION['x'] - 0.83;
echo ( $_SESSION['x']- 0.17) ;
echo '<br>';
But on reversing the values It all fine with 0
$_SESSION['x'] = 1;
$_SESSION['x'] = $_SESSION['x'] - 0.17;
echo ( $_SESSION['x']- 0.83) ;
echo '<br>';

This is because its the floating point numbers. And as per the manual
"The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format). "
http://php.net/manual/en/language.types.float.php
Now there are 2 things which could be done by using the type cast your result to (int) or round up the result.
The other option is to use the sprintf
Here is an example
$a = 0.00001234;
echo $a ;
The output will be as
1.234E-5
Now if we do
echo (int)$a ;
The output is 0
or
echo round($a) ;
output will be 0
And finally if we do
echo sprintf('%f', $a);
We will get 0.000012

It is a common problem in computer languages - float values aren't represented exactly. See also http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems. If you have a particular amount of decimal places you want to exactly calculate with, you can use the bcmath functions in PHP:
$_SESSION['x'] = 1;
$_SESSION['x'] = bcsub($_SESSION['x'], 0.83, 10);
echo bcsub($_SESSION['x'], 0.17, 10);
echo '<br>';
Otherwise you can simply use your calculation and add an round($result, $numberOfDecimalPlaces) to you calculated result.

Related

decimal point and zero are removed after adding two equal floating numbers in php

I am trying to solve a problem on HackerRank and its not making any sense.
<?php
$d = 4.0;
$f = 4.0;
$sum = $d + $f;
echo $sum;
?>
I need an output of 8.0 but its giving output of 8. Am I missing something?
Float values with decimal part equal to zero gets printed without the decimal part. If you need to force certain numbers of decimal places, use number_format().
In your case: echo number_format($sum, 1);

PHP modulo vs substract at PHP_INT_MAX

At some point i had this block of code:
while( $i> $l-1 )
{
$x= fmod($i,$l);
$i= floor($i/$l);
}
I decided to get rid of the modulo operation and wrote this block:
while( true )
{
$d= floor( $i/$l );
if( $d>= 1 )
{
$x= $i - ($d*$l);
$i= $d;
}
else
{
break;
}
}
The $x is used for indexing an array of length $l. The $i is in question here.
While for some relatively small initial $i, both blocks give the same $x over all iterations, when initialized with something close to PHP_INT_MAX the two blocks do not give the same $x.
Unfortunately $l cannot become a power of 2 in order to use bit operators so i am stuck with this.
I am guessing it has something to do with the inner roundings that take place. Could fmod be so optimized for this case? Is there something i am not seeing?
Additional Comment after accepting #trincot 's answer.
One thing i should have mentioned is that although one would expect the second method to produce better results, due to using simple subtraction, it did not. Possibly because of the division taking place at the beginning of the loop.(that is why i asked "Could fmod be so optimized).
According to the documentation, fmod works on floats:
fmod — Returns the floating point remainder (modulo) of the division of the arguments
Instead, the modulo operator (%) would be more suitable for what you need:
Operands of modulus are converted to integers (by stripping the decimal part) before processing.
fmod will become inaccurate for large integers as the floating point representation does not have the same precision.
Examples of some oddities that happen:
$l=3;
$i=9223372036854775295;
echo is_int($i) . "<br>"; // 1 (true)
echo (9223372036854775295==$i) . "<br>"; // 1 (true)
echo number_format($i, 0, ".", "") . "<br>"; // 9223372036854774784
echo fmod($i,$l) . "<br>"; // 1
echo fmod($i-1,$l) . "<br>"; // 1
echo fmod($i-2,$l) . "<br>"; // 1
echo ($i % $l) . "<br>"; // 2
echo (($i-1) % $l) . "<br>"; // 1
echo (($i-2) % $l) . "<br>"; // 0
Notice how a simple number_format already destroys the precision of the integer; it returns a different number because of floating point conversion.
Notice also that this lack of precision makes fmod return 1 for three consecutive numbers, while the modulo operator does what you would want.
So you seem much better of with %.
Alternative
Your function seems to break down a number into its "digits" in an L-basis. For instance, when $l=2, your $x-sequence produces the binary representation of the number, except for the last digit which you leave out.
In that respect, you might have a look at the function call base_convert($i,10,$l), which produces one digit corresponding to a value of $x in your code, with letters for digits above 9. The function can accept $l values up to 36.

Incorrect results obtained in simple arithmetic using php

Here is a simple PHP script:
<?php
$a = 100;
$b = 91.51;
$c = 8.49;
$d = $a - $b - $c;
echo $d;
?>
It outputs -5.3290705182008E-15 which is ugly
With minor change as follows:
$d = $a - ($b + $c);
echo $d;
?>
The output is 0 which is correct. Why is this happening?
Floating point maths is actually very inaccurate. It's a "best guess" value ;)
In floating point (single precision) 100 - 91.51 is not 8.49 as you would expect, but 8.4899978638 since the value 8.49 cannot be exactly expressed in floating point. With double precision it gets better, as it equates to 8.48999999999999488409 which is a little closer. Still not exact though.
Take the following code example:
echo (100 - 91.51) . "\n";
echo number_format(100 - 91.51, 20) . "\n";
The output of that you would expect to be
8.49
8.49000000000000000000
But in fact it is:
8.49
8.48999999999999488409
It defaults to rounding to 2 decimal places for printing floating point values.
Floating point is very much a trade-off. It is a numerical representation system that provides increased resolution and range at the cost of accuracy. For accuracy, but with limited resolution and range, fixed point arithmetic is often used. For instance, if you were storing voltage values between 0V and 5V and you wanted precise measurements at 1µV resolution (i.e., 0.000001V divisions) you may choose to instead represent your voltages in microvolts not volts, so a value of 100000 would actually be 0.1V, and 3827498 would be 3.827498 volts. The mathematics at your prescribed resolution become precise, however you lack the ability to then represent 287x1036V without having massive variables to store the value.
Try to use number_format like this:
$a = 100;
$b = number_format(91.51, 0, ".", "." );
$c = number_format(8.49, 0, ".", "." );
$d = $a - $b - $c;
echo $d;

Error With Using (int) and (double) together to Cut off Decimals

When I am using (int) with (double) some times it is not working correct.
Look At The PHP Code Example:
I Need To LEAVE 2 Decimals And REMOVE Other...
I Know number_format(); function But I Cannot Use It. Because It Is Rounding Number
number_format(24.299,2);
Output: 24.30
I Need: 24.29
<?php
$str="158.2";
echo (double)$str; // Output: 158.2
echo (double)$str*100; // Output: 15820
echo (int)((double)$str*100); // Output: 15819 <-WHY? It Must To Be 15820, Why 15819?
echo ((int)((double)$str*100)/100); // Output: 158.19
?>
I need To leave two decimals in the number and cut other WITHOUT rounding.
Because of floating point precision (see for example this question: PHP - Floating Number Precision), 158.2 * 100 is not exactly 15820 but something like 15819.99999999.
Now (int) is for type conversion, not for rounding, and any digits after the point are cut of.
I need To leave two decimals in the number and cut other WITHOUT rounding.
This is easy:
number_format($str, 2);
Update
number_format does round, so it is a bit more complicated:
bcmul($str,100,0)/100
bcmul multiplies with arbitrary precision, in this case 0. Results:
bcmul(158.2,100,0)/100 == 158.2
bcmul(24.299,100,0)/100 == 24.29
This doesn't answer the question of why that happens (it could be a precision bug), but to solve your problem, try using $foo = sprintf("%.2f", (float)$str);.
Example:
$str = "158.2";
$num = (double)$str;
print sprintf("%.2f", $num);
EDIT: Infact, yes, this is a precision issue. (in C++) by printing 158.2 to 20 decimal places, I get the output of "158.19999999999998863132". This is an inherent problem with floating point/double precision values. You can see the same effect by using echo sprintf("%.20f", $var); in PHP.
First off, PHP is a language that allows you to type juggle. Which means you do not need the (int) or the (double) to do what you're trying to do.
<?php
$str="158.2"; //could also do $str = 158.2
echo $str; // Ouput: 158.2
echo $str * 100; //Output: 15820
echo number_format($str, 2); //Output: 158.20
echo number_format(($str*100)/100, 2); //Output: 158.20
?>
Use the number_format command to format your numbers how you want.
More here
Never cast an unknown fraction to integers, see the manual on http://www.php.net/manual/en/language.types.integer.php.
(int) ( (0.1+0.7) * 10 ); will result in 7, not 8 as one might expect. Casting from float to integer will always round down - and you may also want to check the operator precedence http://php.net/manual/en/language.operators.precedence.php.
Solution: calculate your fraction before you cast it. $fStr = (float) $str; $iStr = (int) $fStr;
Fixed.
function cutDecimals($number,$decimal){
$_str=(string)$number;
if(strpos($_str,".")!==false){
$dotPosition=strpos($_str,".")+1;
$_numCount=strpos($_str,".");
$_decimal=strlen($_str)-$dotPosition;
if($_decimal<$decimal) return (double)$_str;
else return (double)substr($_str,0,$_numCount+$decimal+1);
}else return (double)$_str;
}
echo cutDecimals("158.099909865",2)."<br />";
echo cutDecimals("14.02",2)."<br />";
echo cutDecimals("41.12566",2)."<br />";
echo cutDecimals("1.981",2)."<br />";
echo cutDecimals("0.4111",2)."<br />";
echo cutDecimals("144.2",2)."<br />";
echo cutDecimals("55.000000",2)."<br />";
echo cutDecimals("1456115.499811445121",2)."<br />";
?>

How to get the division part of a number

Say I have 1.234 I want to get the .234
I tried echo 1.234%1 //I get 0
I am rusty, what is the correct way?
(The tags says PHP as this might be an issue only with PHP, but I really am looking for the general solution).
php's % modulo operator converts its arguments to integers. To get a floating-point modulus, use fmod:
echo fmod(1.234, 1);
You can remove the whole number from the number itself. in php its:
$num = 1.234;
echo $num - floor($num);
Subtract the integer portion of $x ((int)$x) from $x:
$x = 1.234;
$d = $x - (int)$x;
// $d now equals 0.234
echo $d;
Example
Just substract integer part 1.234 - (int)1.234
Try this:
echo 1.234 - intval(1.234);

Categories