I have a floating point number in exponential format i.e. 4.1595246940817E-17 and I want to convert it into decimal number like 2.99 etc.
Any help will be appreciated.
format_number() sprintf() don't seem to be working for me.
You need a better math extension like BC Math, GMP... to handle the more precise precision.
Limitation of floating number & integer
Using the BC Math library you can bcscale() the numbers to a predetermined decimal, which sets the parameter for future calculations that require arithmetic precision.
bcscale(3);
echo bcdiv('105', '6.55957'); // 16.007
You could remove the decimal point ($x is your number):
$strfloat = strtolower((string)($x));
$nodec = str_replace(".", "", $x);
Then extract the exponential part.
list($num, $exp) = explode("e", $nodec);
$exp = intval($exp);
Then you have the decimal, and the number, so you can format it:
if($exp < 0) return "0." . ("0" * -($exp + 1)) . $num;
if($exp == 0) return (string)$x;
if($exp > 0) return $num . ("0" * $exp);
This doesn't add precision though, just extra zeroes.
Here's a solution using BC Math, as suggested by ajreal and Russell Dias:
$au = 65536;
$auk = bcdiv($au, 1024);
$totalSize = bcdiv(bcmul(49107, $auk), bcpow(1024, 2), 2);
echo $totalSize . "\n";
// echos 2.99
Related
For example...
$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
// result is:-1198.9699999988 not the -1198,97
But in this exampe:
$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
//Result is: 0.03
Why the difference in to examples? Lacks precision?
None of the numbers in your code can be expressed exactly in binary floating point. They have all been rounded somehow. The question is why one of the results has been (seemingly) rounded to two decimal digits and not the other. The answer lies in the difference between the precision and accuracy of floating point numbers and the precision PHP uses to print them.
Floating point numbers are represented by a significand (or mantissa) in the range [1, 2), which is scaled by multiplying it by a power of two. (This is what the "floating" in floating point means). The precision of the number is determined by the number of digits in the significand. The accuracy is determined by how many of those digits are actually correct. See: How are floating point numbers stored in memory? for more details.
When you echo floating point numbers in PHP, they are first converted to string using the precision configuration setting, which defaults to 14. (In Zend/zend_operators.c)
To see what is really going on, you have to print the numbers using a larger precision:
$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
printf ("\$aa: %.20G\n", $aa);
printf ("\$bb: %.20G\n", $bb);
printf ("\$ab: %.20G\n\n", $ab);
$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
printf ("\$cc: %.20G\n", $cc);
printf ("\$dd: %.20G\n", $dd);
printf ("\$cd: %.20G\n", $cd);
Output:
$aa: 10694994.890000000596
$bb: 10696193.859999999404
$ab: -1198.9699999988079071
$cc: 0.89000000000000001332
$dd: 0.85999999999999998668
$cd: 0.030000000000000026645
The initial numbers have a precision of about 16 to 17 digits. When you subtract $aa-$bb, the first 4 digits cancel each other out. The result, (while still having a precision of about 16 to 17 digits), is now only accurate to about 12 digits. This lower accuracy shows up when the results is printed using a 14-digit precision.
The other subtraction ($cc-$dd) loses only a single digit of accuracy, which isn't noticable when printed with a 14-digit precision.
This should work for you:
(You have to round your result!)
$aa = 10694994.89;
$bb = 10696193.86;
echo $ab = round($aa - $bb, 2);
I get a number from database and this number might be either float or int.
I need to set the decimal precision of the number to 3, which makes the number not longer than (regarding decimals) 5.020 or 1518845.756.
Using PHP
round($number, $precision)
I see a problem:
It rounds the number. I need a function to only cut the decimals short, without changing their values which round( ) seems not to follow.
You can use number_format() to achieve this:
echo number_format((float) $number, $precision, '.', '');
This would convert 1518845.756789 to 1518845.757.
But if you just want to cut off the number of decimal places short to 3, and not round, then you can do the following:
$number = intval($number * ($p = pow(10, $precision))) / $p;
It may look intimidating at first, but the concept is really simple. You have a number, you multiply it by 103 (it becomes 1518845756.789), cast it to an integer so everything after the 3 decimal places is removed (becomes 1518845756), and then divide the result by 103 (becomes 1518845.756).
Demo
Its sound like floor with decimals. So you can try something like
floor($number*1000)/1000
If I understand correctly, you would not want rounding to occur and you would want the precision to be 3.
So the idea is to use number_format() for a precision of 4 and then remove the last digit:
$number = '1518845.756789';
$precision = 3;
echo substr(number_format($number, $precision+1, '.', ''), 0, -1);
Will display:
1518845.756
rather than:
1518845.757
Links : number_format() , substr()
See this answer for more details.
function numberPrecision($number, $decimals = 0)
{
$negation = ($number < 0) ? (-1) : 1;
$coefficient = pow(10, $decimals);
return $negation * floor((string)(abs($number) * $coefficient)) / $coefficient;
}
$num=5.1239;
$testnum=intval($num*1000)/1000;
echo $testnum; //return 5.123
I know of the PHP function floor() but that doesn't work how I want it to in negative numbers.
This is how floor works
floor( 1234.567); // 1234
floor(-1234.567); // -1235
This is what I WANT
truncate( 1234.567); // 1234
truncate(-1234.567); // -1234
Is there a PHP function that will return -1234?
I know I could do this but I'm hoping for a single built-in function
$num = -1234.567;
echo $num >= 0 ? floor($num) : ceil($num);
Yes intval
intval(1234.567);
intval(-1234.567);
Truncate floats with specific precision:
echo bcdiv(2.56789, 1, 1); // 2.5
echo bcdiv(2.56789, 1, 3); // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 3); // -2.567
This method solve the problem with round() function.
Also you can use typecasting (no need to use functions),
(int) 1234.567; // 1234
(int) -1234.567; // -1234
http://php.net/manual/en/language.types.type-juggling.php
You can see the difference between intval and (int) typecasting from here.
another hack is using prefix ~~ :
echo ~~1234.567; // 1234
echo ~~-1234.567; // 1234
it's simpler and faster
Tilde ~ is bitwise NOT operator in PHP and Javascript
Double tilde(~) is a quick way to cast variable as integer, where it is called 'two tildes' to indicate a form of double negation.
It removes everything after the decimal point because the bitwise operators implicitly convert their operands to signed 32-bit integers. This works whether the operands are (floating-point) numbers or strings, and the result is a number
reference:
https://en.wikipedia.org/wiki/Double_tilde
What does ~~ ("double tilde") do in Javascript?
you can use intval(number); but if your number bigger than 2147483648 (and your machine/os is x64) all bigs will be truncated to 2147483648. So you can use
if($number < 0 )
$res = round($number);
else
$res = floor($number);
echo $res;
You can shift the decimal to the desired place, intval, and shift back:
function truncate($number, $precision = 0) {
// warning: precision is limited by the size of the int type
$shift = pow(10, $precision);
return intval($number * $shift)/$shift;
}
Note the warning about size of int -- this is because $number is potentially being multiplied by a large number ($shift) which could make the resulting number too large to be stored as an integer type. Possibly converting to floating point might be better.
You could get fancy with a $base parameter, and sending that to intval(...).
Could (should) also get fancy with error/bounds checking.
An alternative approach would be to treat number as a string, find the decimal point and do a substring at the appropriate place after the decimal based on the desired precision. Relatively speaking, that won't be fast.
Thanks to stack, I learned about floating point imprecision, so I went over to the bc functions.
That works great on "normal" floats, but with extremely small floats, say 10^-10 types, bcadd always gives 0.
Can someone show me what I'm doing wrong to make these small floats add with precision?
Many thanks in advance!
PHP
$numerator = 1;
$denominator = 1000000000;
$quotientOne = $numerator / $denominator;
$numerator = 1;
$denominator = 1000000000000000;
$quotientTwo = $numerator / $denominator;
$smallSum = bcadd($quotientOne, $quotientTwo, 100);
echo $quotientOne . "<br>";
echo $quotientTwo . "<br>";
echo $smallSum . "<br>";
gives
1.0E-9
1.0E-15
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The / operator returns either a float or an integer. It's interfering with your attempts to use bcadd() correctly. The limitations of floating-point arithmetic will take hold before bcadd() gets a chance to show its stuff.
echo gettype($numerator / $denominator);
double
Use bcdiv() instead. Note that the bc*() functions take strings as their arguments, and they also return a string.
$ cat code/php/test.php
<?php
$num_1 = 1;
$denom_1 = 1000000000;
# Cast values to string type to be crystal clear about what you're doing.
$q_1 = bcdiv((string)$num_1, (string)$denom_1, strlen($denom_1));
printf("q_1: %s\n", $q_1);
$num_2 = 1;
$denom_2 = 1000000000000000;
# php will do an implicit conversion to string anyway, though.
$q_2 = bcdiv($num_2, $denom_2, strlen($denom_2));
printf("q_2: %s\n", $q_2);
printf("sum: %s\n", bcadd($q_1, $q_2, strlen($denom_2)));
?>
$ php code/php/test.php
q_1: 0.0000000010
q_2: 0.0000000000000010
sum: 0.0000000010000010
Arbitrary-precision arithmetic is inherently slower than floating-point arithmetic. That's the price you pay for dozens, hundreds, or thousands of digits of accuracy.
can help me to see this calculation? It suppose echo "equal"... but it give me "not equal"
<?php
$tl_pax = 1;
$ct_pax = 2;
$at_pax = 2;
$a = 0.5;
$b = 0.2;
$c = 0.2;
$d = 0.2;
$e = 0.2;
$f = 0.2;
$g = 0.2;
$h = 0.9;
$sum = $a + $b + $c + $d + ($e * $tl_pax) + ($f * $ct_pax) + ($g * $at_pax) + $h;
$total = 3;
if($total == $sum){
echo 'equal: ' . $sum . ' - ' . $total;
}
else{
echo 'not equal: ' . $sum . ' - ' . $total;
}
?>
This is the usual case of the rounding error associated with binary floating point numbers. There are numbers that can't be represented exactly in binary, and thus the result will be of by some margin. To read up on it, the wikipedia article about floating point numbers is great.
The usual pattern found in this case is to pick a delta and compare against it:
if(abs($total - $sum) < 0.01)
echo "equal";
You'll have to pick your delta appropiately according to the usecase.
Check if they have difference less than 0.00001
if(abs($total - $sum) < 0.00001){
http://sandbox.phpcode.eu/g/56905/6
This article shows you why is this happening
It's because your sum is really something like 2.9999999999999999999, due to floating pont arithmetic. PHP just hides that from you when you print it. See the example on floor((0.1+0.7)*10) here: http://php.net/manual/en/language.types.float.php
You should never compare a floating point number for equality. The proper way to compare floats is using a range like:
if($total-0.0000001 <= $sum && $sum <= $total+0.0000001){
You can see it in action here: http://codepad.org/kaVXM5g0
That line just means that $total must be within 0.0000001 of $sum to be considered equal. You can pick the number yourself, depending on the amount of precision you need.
Alternatively you can just round $sum in this case, but then you're basically doing the same thing just with a range from 2.5 - 3.499... instead of 2.9999999 - 3.0000001
The difference is due to the limits of floating point precision.
Values like 0.9 (9/10) can't be written exactly as binary floating point numbers, just like 0.3333... (1/3) can't be written exactly as a decimal fraction. This means that e.g. $h holds an inexact, rounded representation of 0.9. As a result, your calculation yields something very close to 3, but not exactly 3.
Floats are evil.
Quote from http://php.net/float
"So never trust floating number results to the last digit, and never compare floating point numbers for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available."