How much precision for a bcmath PHP library? - php

I'm writing a PHP library that has a Number class that uses the bcmath extension for arbitrary precision.
I have two questions:
How much slower is bcmath compared to using the built-in int and float types?
bcmath has an optional scale argument (that defaults to 3 digits). For an general purpose Number class that anyone could use, what would be a good level of precision? How do languages like Perl (that have arbitrary precision numbers) deal with scale?

I would decide what range of numbers you need to support. The built in values will be faster than any value that requires calculation and conversion to/from some other format.
Built in integers are good until 32 bits on any system, some systems support 64 bit values. You can check what your system supports by checking the value of the constant PHP_INT_MAX and determine if you want to carry the overhead of the math library after that. For systems with 32 bit integers, anything above 32 bits will be converted to a float automatically. This isn't an issue unless you are using built in functions for things like round, printf, modulus etc.
I was bit by this using modulus to divide traffic coming to my site as well as with formatting integers using %d in sprintf: http://af-design.com/blog/2009/10/28/php-64-bit-integer-modulus-almost/

Related

How to find out the size of a float in PHP?

I'm using PHP 7.2.5(installed using the latest version of XAMPP) on my machine that runs on Windows 10 Home Single Language 64-bit operating system.
As per my knowledge, in PHP, the sizes of an integer and a float are platform-dependent.
PHP has provided a predefined constant PHP_INT_SIZE to find out the size of an integer but it has not provided any such constant to find out the size of a float.
So, my question is how should I find out the size of a float in PHP?
P.S. : I've referred the Previously Asked Question but couldn't get the reliable, efficient and satisfactory solution for my problem. At the end of an answer of this question the author of the answer is making the below assumption
I suppose "platform-dependent" means it uses 4 bytes on 32-bit platforms (the traditional size for float) and 8 bytes on 64-bit and larger platforms (the traditional double).
which is vague I think as it has no more related evidence or proof.
The size of a float is platform dependent, but since PHP 7.2, there actually is a constant PHP_FLOAT_MAX.
Because it's platform dependent, there isn't a definite answer. But you can at least see what the max size is on your platform with this constant in PHP 7.2: https://3v4l.org/QpHOI
To count the bytes, we have to convert that very large float into binary and then we can manually count the bytes, see here: https://3v4l.org/ASZbs
Apparently 3v4l.org can handle some pretty large floats, up to 128 bytes!
Credits to an anonymous user in the PHP docs who created a function to convert 32+ bit floats into binary which I blatantly copy pasted.
It's almost certainly going to use the IEEE 64-bit format, since this is basically what every platform uses these days. You could add an assertion to that effect, e.g.
assert((1.0+pow(2.0,-52))-1 != 0)
assert((1.0+pow(2.0,-53))-1 == 0)
will check that the format has exactly 53 significant bits.

PHP long integers for thrift

My Thrift service expects to receive a Long integer representing a timestamp in milliseconds, but coming from PHP, I know PHP thrift is supposed to automagically turn my PHP types into thrift types, but which PHP type does it expect for Long integers? I think my computer is 64-bit, but since I think that PHP integers' length is platform dependent, I don't really want to depend upon a platform-dependent length for my integers.
I am currently grabbing microtime() and multiplying by 1000, then converting to integer. Is this the "correct" way to work with PHP & thrift long ints?
You are right,
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.
http://www.php.net/manual/en/language.types.integer.php
If you use microtime() you need not to divide it by 1000. Its float, you may want to multiply it by 1000.
You may use BC Math for calclulate it as numbers, using string types. I guess string are OK to communicate with any other thing.
In case of multiplying by 1000, you even not need BCMath. Just delete comma from string representation of microtime(true) (or space from microtime)
Maybe you should use id of string type as like twitter: https://dev.twitter.com/docs/twitter-ids-json-and-snowflake

How to parse long value in php?

Need something like intVal() but for bigger numbers, for example: 100001416147426.
Is there a function like this in php? Can't find it.
You should use BC Math, it is designed to numbers of any size with PHP.
The BC Math extensions offers several mathematic functions like:
bcadd Add two arbitrary precision numbers
bccomp — Compare two arbitrary precision numbers
bcsqrt Get the square root of an arbitrary precision number
...
On the PHP documentation site there is a small code example by Charles to round a long number!
consider
$x = (double) "100001416147426";
var_dump($x);
output:
float(1.0000141614743E+14)
coding standard in the past (since C) has been to follow the number with an L/l
$x = 100001416147426L;
This cue's the parser to allocate 64 bits in order to read the number out of the script to compile.
But unless you are running the php x64 this will be useless. Other wise you will have to build it out of a big_number component. Once in a x64 environment intval will automatically expand to a long when exceeding a 32-bit int.

What is the difference between bcpow and pow?

Can someone explain to me if I should use bcpow() instead of pow() and why?
I understand that not all installations of php have bcmath enabled. So if I write an open source project, and want to have as few dependencies/requirements as possible, I would rather use pow() in my code.
But what are the downsides to using pow() over bcpow()?
bcpow() is a function of the BCMath Arbitrary Precision Mathematics library.
Quoting the introduction of it's manual :
For arbitrary precision mathematics
PHP offers the Binary Calculator which
supports numbers of any size and
precision, represented as strings.
On the other hand, pow() is limited to floats, which have a limited size (quoting) :
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)
Generally, you'll work with pow() and other float-based functions (which are probably faster, and are always enabled) ; but, if you need to handle very big number, you'll have to work with bcpow().
According to the manual the bc* functions are
[...] arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings.
pow() is limited to the maximum supported numeric representation on the system it runs on.
bcpow is used for arbitrary precision values. As a third parameter you can specify a number of digits after coma.

Doing exact real number arithmetic with PHP

What is fastest and most easy way of making basic arithmetic operations on strings representing real numbers in PHP? I have a string representing MySQL's DECIMAL value on which I want to operate and return the result to a database after that. I would like to avoid errors introduced by floating-point real number representation.
Is there some standard library like Python's decimal? Are there any FOSS libraries you can recommend?
Regards
You could use the BC math functions:
http://www.php.net/manual/en/ref.bc.php
Or the GMP functions, although they seem to be integer only.
http://www.php.net/manual/en/ref.gmp.php
You can use the bc_math extension, which works exactly how you ask (it's used for arbitrary precision numbers):
$num = '123.456';
$twoNum = bcadd($num, $num);

Categories