PHP: Does BCMath accept integers? - php

Is it safe to use INT-type variables in BCMath functions in PHP ?
Example:
<?php
$a = 1;
$b = "1";
echo bcadd($a,$b,0);
?>
This seems to work but is it safe to do this ? Or is there for example a risk that PHP can interpret an INT as something else than it's int value (I'm thinking about hexadecimal values etc) ?
Thanks !

Be careful with very large numbers. If you assign a literal integer > PHP_INT_MAX to a variable, PHP will automatically convert it to a float. I know you specifically asked about ints, and in that case you'd be passing a float, but if you don't know that about the automatic conversion it looks like you're using a large int, so I thought it worth mentioning.
$a = 9223372036854775808;
$b = '1';
var_dump($b); // float 9.2233720368548E+18
echo bcadd($a, $b, 0); // echoes 1
Basically, the function does take a string. If you give it something that isn't a string, PHP will automatically convert it to a string if it can, unless you have enabled strict mode.

Related

How to parse a String to a long with no loss

I'm having an issue when parsing a string to a long. I want the variable "695690829980893234" to be parsed to a long without any loss. I've looked around for a bit but nothing really seemed to have helped.
When using (double) $var it shows as a 4.2904753172133E+17 (which is not the way I need it)
Does anyone have any ideas? Much appreciated!
In standard PHP, the type long does not exist.
So, if you want to have a long integer, you may use the standard int type, or use an extension, such as BC or GMP.
Specifically, the value 695690829980893234 is in the integer range of 64bit PHP, but out of the integer range of 32bit PHP.
To convert to int:
First, please make sure the number is in the int range. Then just convert
$res = intval("695690829980893234");
if($res<PHP_INT_MAX){
// OK! inside the positive limitation
}
To convert to GMP
A GMP object represents an arbitrary length integer:
$res = gmp_init("695690829980893234");
Then, use GMP functions to operate the number, such as:
$res = gmp_add($res, gmp_init("100"));
$res = gmp_sub($res, gmp_init("200"));
and finally, convert it back to int or string:
$int = gmp_intval($res);
$str = gmp_strval($res);
Hope this answer helps.
Be sure you're running 64-bit version of PHP.
echo PHP_INT_SIZE;
8
Then it will cast string to int easily
$a = "695690829980893234";
$b = (int)$a;
var_dump($a, $b);
string(18) "695690829980893234"
int(695690829980893234)

How does php determine the needed internal type of a variable?

This is a question about PHP internals and how it works under the hood:
How does php decide that:
$a = 3;
needs to be an integer (internally)?
and how that
$a = "3";
needs to be a string?
I once heard that PHP uses to cast every variable around (to different types) to determine its needed internal data type, but when trying to verify this statement I was not able to find anything about in the Internet.
There are some weird examples on the official PHP doc which describe some of the language's strange behavior:
source: http://php.net/manual/en/language.types.type-juggling.php
<?php
$foo = "0"; // $foo is string (ASCII 48)
$foo += 2; // $foo is now an integer (2)
$foo = $foo + 1.3; // $foo is now a float (3.3)
$foo = 5 + "10 Little Piggies"; // $foo is integer (15)
$foo = 5 + "10 Small Pigs"; // $foo is integer (15)
?>
but that does not answer my question.
It just shows how dynamic PHP is on a very obscure way.
I don't think that has anything to do with evaluation (for example "":=false but "abc":=true), doesn't it?
One more question: how can php extract a "primitive" integer from a String like "10 Small Pigs"? Could this be done by typecasting (internally) or does this require some kind of string processing with included char converting or something?
PHP will automaticall convert values from one type to another as necessary. If the variable contains a string, but you use it in an arithmetic expression, it will convert it to a number. If it contains a number, but you use it as the argument to a function that needs a string, it will convert it to a string.
When you perform comparisons, if the types of the two values are different, one of them will be converted to the other type (unless you use the "strict" comparison operators, === and !==). The type comparison tables explain which will be converted depending on the two types.
When you do the initial assignments, like
$a = 3;
$b = "3";
$c = false;
it looks at the syntax. If the value is in quotes, then it's a string. If the value is a bare number, it's a number. So $a contains a number, $b contains a string. $c contains a boolean because it was assigned from a boolean literal.
If you assign the variable using a function call, it depends on what the function returns (e.g. substr returns a string); all the standard PHP functions have their return types specified in the documentation.
Most of the time, what it does in all these cases is what intuitively seems "right" from the syntax and likely semantics.
For your second question, you can use intval.
From php.net, http://php.net/manual/en/function.intval.php
(PHP 4, PHP 5)
intval — Get the integer value of a variable
int intval ( mixed $var [, int $base = 10 ] )
Returns the integer value of var, using the specified base for the
conversion (the default is base 10). intval() should not be used on
objects, as doing so will emit an E_NOTICE level error and return 1.

Why is bcdiv always returning 0?

I have a small issue with BIG numbers where BC Maths function bcdiv is always returning zero on non-zero results.
For example :
echo bcdiv(40075036, 86164.098903691, 40);
Versus the traditional method :
echo (40075036/86164.098903691);
I am not sure why the discrepency. Do BC Math functions only work on strings, and if so, how can i convert int values into strings before hand (inline notation preferred such as (int)$myvar; ) --- if that is the problem.
The solution to this problem was as follows:
bcmath operations only work with strings. You can not pass any other type of data as the parameters as it will not do any calculations unless the values are (string).
The set of functions will not automatically convert or cast the data into string, and NO ERROR WILL BE RETURNED if passing other data types.
To pass the data that is stored in an integer, float, etc, the following code will work for dynamic conversion of the variable data as needed:
bcdiv((string)40075036, (string)86164.098903691, (string)40);
OR
$num1 = 12345;
$num2 = 45678;
$digits = 40;
bcdiv((string)$num1, (string)$num2, (string)$digits);
If the numbers are fixed and known BEFORE you pass (aka, they aren't coming from a database, and aren't pre-calculated), then you should use the function as follows :
bcdiv('40075036', '86164.098903691', '40');
Use the "bcscale" function - Set default scale parameter for all bc math functions.
Ex.:
bcscale(40);
echo bcdiv(40075036, 86164.098903691);
It worked for me. (php 7.1)
bcscale manual

Converting two integers into a long in PHP

I've got two integers and I need to convert them into a long. I'm totally lost on how to do this. The two integers that I need to convert are:
INT 1: 60850985
INT 2: 59150141
I need a method that converts two integers into a long. If you can post one, that'd be great.
When I say converting to a long, I'm wondering how you would do the equivalent of (long) from java in PHP
Let me be completely clear here:
I'm receiving two ints from the client, then I need to convert them to a long, then the single long is to be used again as a single int.
In essence, I need to take two ints and convert them into a single int. An example of how this is done in java would be:
long $intA = (long) readInt();
long $intB = (long) readInt();
return ($intA << 32) + $intB;
PHP stores numbers as integers or floats, where the size of the integer is platform dependent (but usally 32 bit, signed). If you need to represent a larger number you should use the BC Math functions.
Using BCM adding two numbers is like:
$a = '60850985';
$b = '59150141';
echo bcadd($a, $b);
or multiplying:
$a = '60850985';
$b = '59150141';
echo bcmul($a, $b);
EDIT:
If you want to get, how it should look as a 64-bit signed integer in 1-complement (if there is an overflow), then you have to do some manual conversion to cast the value inside the -2^63 .. 2^63-1 range:
For nonnegative values you can for example first cast it to 0 .. 2^64-1:
$long = bcmod($value, bcpow('2','64'));
Then if it's larger than 2^63-1 then subtract 2^63 from it, and then subtract this value from -2^63.
For negative values, first add 2^64, until the value is positive, then do the above steps.
But the above steps are only needed if you want to check how the string number looks if there was an overflow. Usually you don't need this, and probably you don't even need to use BCM as your numbers will easily fit inside PHP's signed 32-bit integer datatype (for which no casting is needed, conversion is automatical):
$a = '123'; // $a is a string
echo $a + 1; // will write 124, $a gets converted into int
You can force conversion if you want though:
$a = $a+0;
or
$a = (int)$a;
EDIT 2:
You can still use BCM functions to do the math:
$long = bcadd($low, bcmul($high, bcpow('2','32')))
// this essentially means:
// $long = $low + $high * 2^32
// which is
// $long = $low + $high << 32
Then, if the result is larger than 2^63-1 you can do some additional BCM calculations, described above to convert the unsigned integer into a signed one.
I used regular addition:
$int1 = 60850985;
$int2 = 59150141;
$result = $int1 + $int2;//120001126
Here's a quote from the PHP manual:
The size of an integer is platform-dependent, although a maximum value
of about two billion is the usual value (that's 32 bits signed).
64-bit platforms usually have a maximum value of about 9E18. PHP does
not support unsigned integers. Integer size can be determined using
the constant PHP_INT_SIZE, and maximum value using the constant
PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.
If you want to deal with large numbers use GMP ( http://www.php.net/manual/en/book.gmp.php ) or BCMath ( http://www.php.net/manual/en/book.bc.php ).
To elaborate on what AgentConundrum said, there isn't a need to cast an integer to a long in PHP. PHP is a dynamic language which means that generally, for operations on fundamental types, there is no need for casting (unless it is for some explicit purpose - i.e. a float to an integer), as PHP handles it for you.

PHP var becoming negative

I have this code :
<?php
$integer = 33963677451;
$integer &= 0xFFFFFFFF;
echo $integer;
?>
But, when I execute it, the output is
-396060917
The same function in Python
if __name__ == '__main__':
integer = 33963677451
integer &= 0xFFFFFFFF
print integer
The output is
3898906379
It seems PHP can't store big variables. Do you guys have any idea how to get the same result in PHP I have in Python ?
Thanks !
That value is too big for an integer, python dynamically casts that into a long variable. INT_MAX defines how big your integer can be before it switches over into a double. If you want to manipulate large numbers without quirks use GMPLIB a multiple precision arithmetic library.
Your 33,963,677,451 is above what a signed 32bit integer supports (max 2,147,483,647). 64bit PHP versions do support higher values.
php only supports signed integers. You are seeing overflow
also, the answer for the python case should be 33963677451
I don't know if it's just a typo, but you are using different values when performing the AND operation in each language. :)
You have "0xFFFFFFFFFFF" (11 chars) in your PHP version, as opposed to only 8 in the Python version.
Either way, it should be integer overflow.
<?php
$integer = (float) 33963677451;
$integer &= 0xFFFFFFFFFFF;
echo $integer;
try making sure that $integer is of type float.
for more: http://www.php.net/manual/de/language.types.integer.php#language.types.integer.overflow
If you wish to see whats happening, here is a printf statement showing the different types.
$i1 = 33963677451;
$i2 = 0xFFFFFFFFFFF;
printf("%b (%d, %f) & \n%b (%d, %f)\n = \n%b (%d, %f)",
$i1, $i1, $i1, $i2, $i2, $i2, $i1&$i2, $i1&$i2, $i1&$i2);
PHP casts integers larger than 32 bits to floats. It seems that you can not perform this operation on floats.

Categories