Representation of small float numbers in json_encode - php

I'm executing the following code in a PHP script:
$obj = new \stdClass();
$obj->lat = 0.000011399388312455;
echo json_encode($obj) . "\n";
The output of the script is
{"lat":1.1399388312454999446e-5}
As you can see, the number is represented in exponential notation.
Is there some way to represent that particular number in extended notation, in the JSON-serialized object?
The desired output is
{"lat":0.000011399388312455}
The version of PHP is 5.6.30.
P.S.: This JSON-serialized object will be sent to an external web service that doesn't accept numbers in exponential form. Moreover, it needs to be a number and not a string ({"lat":"0.000011399388312455"} won't work).
The number should not be rounded (it's a geographical coordinate).
Here are other similar questions, but they don't fit my case unfortunately.
php- floating point number shown in exponential form
Remove the "E" in a number format for very small numbers
Thank you in advance.

It is implemented in PHP 7.1 https://wiki.php.net/rfc/precise_float_value
As a work around, use other JSON serializers not a default json_encode.
E notation is valid form of float representation. In php >7.1 with precision set to -1 results of your code would look like: {"lat":1.1399388312455e-5} which is absolutely the same as 0.000011399388312455 because you have 4 leading zeros.
If you still want to have leading zeroes in json i would go towards strings. They are perfectly fine for coordinates representations.

Related

Floating number upto two decimal PHP

I know the question is very basic but it seems nothing working for me.
I have a number (either or float or integer) which I want to be formatted upto two decimal point. For this purpose I'm using PHP function number_format but it converts my number to string.
To convert it back to float I am using (float) or floatval(). But these functions just truncates the number after converting it to float from string.
Here is my code
$revenue_sum = array_sum(array_column($val2, 'weighted_revenue')); //23722
$test = number_format($revenue_sum, 2); //"23,722.00"
$test = (float)number_format($revenue_sum, 2); //23.0
$test = floatval(number_format($revenue_sum, 2)); //23.0
I want the $test to be 23722.00 for the $revenue_sum = 23722
If $revenue_sum = 2372.2 the $test should be 2372.20
number_format() function can be used as follows:
echo number_format($revenue_sum, 2,'.',''); // will return 23722.00 for the $revenue_sum = 23722
You are trying to type cast with ',' value, it is truncating the string.
you can try this
<?php echo sprintf("%2.2f", 8900.258); ?>
which will output as
8900.26
If you assign a floating point value to a variable, then it is converted to an internal binary format (usually using IEEE 754). Not all possible values has an internal representation. So while scanning a text, the float is rounded to the nearest possible value. So for example 1.23 is rounded to 1.22999999999999998.
Because of the internal representation, there is no difference between 100 or 1e2 or 100.0 or 100.0000.
And when printing a floating point value without any formatting instruction, PHP guess a good format and rounding some digits. So 1.22999999999999 is displayed as 1.23(may varies on different systems).
In general: As long you are calculating, formatting doesn't matter. It is mostly the best, to ignore the decimal fragments on debugging. But when printing (=converting to text), use functions like format_number() or any of the printf() functions.
To be more pragmatic:

PHP Long string. Output it all

So I got a really long string, made by a calculator.
$string='483451102828322427131269442894636268716773727170';
$result=(8902543901+$string)*($string/93.189)/($string)+55643907015.57895461;
echo $result;
This outputs 5.1878558931668E+45
So now my question is. How can I output the whole string, without that nasty E+45?
PHP on a 64 bit machine can only accurately calculate number up until 9223372036854775807. As soon as you calculate with numbers higher than that, php will switch to floats which may loose some of it's precision, especially when you use divisions.
There's an extension for php that will allow you to make calculations based on string, called BCMath.
Example:
$string = '483451102828322427131269442894636268716773727170';
$result = bcadd($string, 8902543901);
echo $result;
bcadd() is for additions, bcdiv() for divisions and bcmul() for multiplying.
You can't print exact value because you are using calculation, so this $string becomes a number (float in this case) and all numbers have limited precision.
If you want to do operations on big numbers you should use BCMath
However if you want to display it without scientific notation you can do it using:
echo sprintf("%f",$result);
or
echo sprintf("%.0f",$result);
if you want to omit decimal part

php convert floating point to long (convert to string to pass to a xml function)

PHP converts a large number to floating point which I need in "long" format to pass to a soap xml api.
((round(time()/(60*15))*60*15)+(30*60))*1000
This gives the result:
1.28E+12
Whereas, what I need is:
"1280495700000"
in order to pass to the api
format it using number_format()
http://php.net/manual/en/function.number-format.php
This could work:
sprintf('%u',$number);
But if you're about to lose precision you need, look at the BCMath functions (bcadd, bcdiv and the like). They will keep precision, and give you back strings.

Cast a numeric string as float type data

What is the PHP command that does something similar to intval(), but for decimals?
Eg. I have string "33.66" and I want to convert it to decimal value before sending it to MSSQL.
How about floatval()?
$f = floatval("33.66");
You can shave a few nanoseconds off of type conversions by using casting instead of a function call. But this is in the realm of micro-optimization, so don't worry about it unless you do millions of these operations per second.
$f = (float) "33.66";
I also recommend learning how to use sscanf() because sometimes it's the most convenient solution.
list($f) = sscanf("33.66", "%f");
If you mean a float:
$var = floatval("33.66")
Or
$var = (float)"33.66";
If you need the exact precision of a decimal, there is no such type in PHP. There is the Arbitrary Precision Mathematics extension, but it will return strings, so it's only usefull for you when performing calculations.
You could try floatval, but floats are potentially lossy.
You could try running the number through sprintf to get it to a more correct format. The format string %.2f would produce a floating-point-formatted number with two decimal places. Excess places get rounded.
I'm not sure if sprintf will convert the value to a float internally for formatting, so the lossy problem might still exist. That being said, if you're only worrying about two decimal places, you shouldn't need to worry about precision loss.
php is a loosely typed language. It doesn't matter if you have
$x = 33.66;
or
$x = "33.66";
sending it to mssql will be the same regardless.
Are you just wanting to make sure it is formatted properly, or is an actual float?

PHP money string conversion to integer error

I have a small financial application with PHP as the front end and MySQL as the back end. I have ancient prejudices, and I store money values in MySQL as an integer of cents. My HTML forms allow input of dollar values, like "156.64" and I use PHP to convert that to cents and then I store the cents in the database.
I have a function that both cleans the dollar value from the form, and converts it to cents. I strip leading text, I strip trailing text, I multiply by 100 and convert to an integer. That final step is
$cents = (integer) ($dollars * 100);
This works fine for almost everything, except for a very few values like '156.64' which consistently converts to 15663 cents. Why does it do this?
If I do this:
$cents = (integer) ($dollars * 100 + 0.5);
then it consistently works. Why do I need to add that rounding value?
Also, my prejudices about storing money amounts as integers and not floating point values, is that no longer needed? Will modern float calculations produce nicely rounded and accurate money values adequate for keeping 100% accurate accounting?
If you want precision, you should store your money values using the DECIMAL data type in MySQL.
Your "prejudices" about floats will never be overcome - it's fundamental to the way they work. Without going into too much detail, they store a number based on powers of two and since not all decimal number can be presented this way, it doesn't always work. Your only reliable solution is to store the number as a sequence of digits and the location of the decimal point (as per DECIMAL type mentioned above).
I'm not 100% on the PHP, but is it possible the multiplication is converting the ints to floats and hence introducing exactly the problem you're trying to avoid?
Currency/money values should never be stored in a database (or used in a program) as floats.
Your integer method is fine, as is using a DECIMAL, NUMERIC or MONEY type where available.
Your problem is caused by $dollars being treated as a float and PHP doesn't have a better type to deal with money. Depending on when $dollars is being assigned, it could be being treated as a string or a float, but is certainly converted to a float if it's still a string for the * 100 operation if it looks like a float.
You might be better off parsing the string to an integer "money" value yourself (using a regex) instead of relying on the implicit conversions which PHP is doing.
The code you posted does the multiplication first, forcing a floating point calculation that introduces error, before converting the value to an integer. Instead, you should avoid floating point arithmetic entirely by reversing the order. Convert to integer values first, then perform the arithmetic.
Assuming previous code already validated and formatted the input, try this:
list($bills, $pennies) = explode('.', $dollars);
$cents = 100 * $bills + $pennies;
Your prejudice against floating point values to represent money is well founded because of truncation and because of values being converted from base-10 to base-2 and back again.
Casting does not round() as in round-to-nearest, it truncates at the decimal: (int)3.99 yields 3. (int)-3.99 yields -3.
Since float arithmetic often induces error (and possibly not in the direction you want), use round() if you want reliable rounding.
You should never ever store currency in floating point, because it always get results you don't expect.
Check out php BC Maths, it allow you to store your currency as string, then perform very high precision arithmetic on them.
Instead of using
$cents = (integer) ($dollars * 100);
you may want to try to use:
$cents = bcmul($dollars, 100, 2);
When converting from float to integer, the number will be rounded towards zero (src).
Read the Floating point precision warning.
There's no point in storing money as integer if you enter it through a floating point operation (no pun intended). If you want to convert from string to int and be consistent with your "prejudice" you can simply use string functions.
You can use an arbitrary precision library to divide by 10 (they handle numbers internally as strings), e.g. bcdiv() or gmp_div_q(), but of course, you could have also used it from the beginning for all the math.
Or you can use plain string functions:
<?php
// Quick ugly code not fully tested
$input = '156.64';
$output = NULL;
if( preg_match('/\d+(\.\d+)?/', $input) ){
$tmp = explode('.', $input);
switch( count($tmp) ){
case 1:
$output = $tmp[0];
break;
case 2:
$output = $tmp[0] . substr($tmp[1], 0, 2);
break;
default:
echo "Invalid decimal\n";
}
}else{
echo "Invalid number\n";
}
var_dump($output);
?>

Categories