coder-spirit / php-bignumbers Goto Github PK
View Code? Open in Web Editor NEWA robust library to handle immutable big numbers inside PHP applications
License: MIT License
A robust library to handle immutable big numbers inside PHP applications
License: MIT License
php BasicUsage.php prompts Class Decimal not found.
Hello!
The Decimal class throws an exception on numbers like these:
1.048576E+06 // leading zero
3.14E+00 // just zero
But it's a valid form. So I think they should be handled well.
The default string representation that the Decimal class gives is like this:
(string)Litipk\BigNumbers\Decimal::fromString('11111111111111111.55555555555555')
"11111111111111111.55555555555555"
It would be nice if there is a method to format strings like these to 11,111,111,111,111,111.55555555555555
In order to allow a more straightforward and efficient interaction with Decimal objects, it would be a great step if we add specific methods to avoid the need of creating new Decimal objects on the fly every time we have to operate with PHP's native numbers.
The current methods (add, mul, div, and so on) have hinting, in order to allow interpreter/compiler optimizations. I propose to create equivalents with the prefix n, for example: mul
's native equivalent will be nMul
.
It would be very useful to determine if we are working with real number approximations or if we explicitly know that we're working with rational numbers when we apply the pow
method to a negative number, because the outcome can vary from undefined to a defined value depending on this.
I think fixing #27 before trying to fix the issue will help in this task.
I am trying to extend Decimal class to add some methods like greaterThan, ...
It would be easier for me if you use self in constructor.
Constructor from integer:
/**
* @param integer $intValue
* @return Decimal
*/
public static function fromInteger($intValue)
{
....
return new Decimal((string)$intValue, 0);
}
Extended class example:
class ExtrendedDecimal
{
/**
* @param Decimal $b
* @param integer $scale
* @return bool
*/
public function greaterThan(Decimal $b, $scale = null)
{
if ($this->comp($b, $scale) == 1)
return true;
else
return false;
}
}
New using Self:
return new Self((string)$intValue, 0);
I know that is not a great new feature but I want to use my own class in case I need some extensions in the future.
When creating from a string value leading decimals cause a NaNInputError
.
// Works
\Litipk\BigNumbers\Decimal::fromString('0.110');
// PHP Fatal error: Uncaught Litipk\BigNumbers\Errors\NaNInputError: strValue must be a number
\Litipk\BigNumbers\Decimal::fromString('.110');
A simple fix would be adding the following to fromString()
if (substr($strValue, 0, 1) === '.') {
$strValue = '0' . $strValue;
}
There have been numerous improvements since the 0.7.2 release - is it possible to get a new release version tagged and added to packagist?
Currently, the unit tests of the library aren't properly marked with the @uses
and @covers
annotations to indicate what's the test intending to cover. This fact leads us to an optimistic and erroneous code coverage ratio, potentially hiding important bugs.
Mutation testing it's very useful to discover new bugs and discover test coverage "holes". Recently has appeared a new PHP mutation testing called Humbug, which could be used to improve the library's tests.
I've been experimenting without success (I didn't spent enough time, and the project is currently in alpha or beta state), but if anyone wants to experiment, I think the task is worth.
got this value -2.689785E + 23
and i need convert it to absolute before work with him.
When abs
method is used, it returns 0
. I was checking why and it's about that abs
checks if number is zero before call additiveInverse
, that method also check if value is zero.
The scale with that number is -1
automaticaly, then the check of isZero always returns true.
It would be nice to have the following trigonometric functions:
When using number_format() like here, you are relying on php's float precision.
Trying to use a number like Decimal::fromFloat(90.05)
will cause a precision error as number_format(90.05, 16, ".", "") === "90.0499999999999972"
.
There needs to be another method used to load in the numbers initially, as all following operation are going to be wrong.
I was testing negative values for tangent and cotangente when i found several rounding errors.
I followed the process and I think there is a mistake with the rounding of negative numbers.
Exemple : I use the division of 0.984376 by -0.176077. the result is -5.59059956723478932512..
but with the Decimal::div(), it gives
for the scale of 3 : -5.589
for the scale of 4 : -5.5904
for the scale of 5 : -5.59058
for the scale of 6 : -5.590598
I think i have pinpointed the probleme in Decimal::innerRound().
When a number is negative and if the next digit after the scale is greater than 5, the one should be substracted and not added.
Hi,
I'm thinking about creating an organization to hold scientific and mathematical libraries projects in PHP, and sharing the ownership of this organization with more people to improve the reliability of projects like this one.
I have three other projects which I would transfer to this hypothetical organization:
@codisart , I'm mentioning you because maybe you're interested. I hope you don't get this mention as SPAM ^_^U .
Currently there are methods not properly implemented for working with infinite values, this should be fixed.
When I run the DecimalModTest::testFiniteFiniteMod()
test using the following data sets, I get failures:
# Extant passing tests.
['10', '3', '1'],
['34', '3.4', '0'],
['15.1615', '3.156156', '2.536876'],
['15.1615', '3.156156', '2.5369', 4],
['-3.4', '-2', '-1.4'],
['3.4', '-2', '-0.6'],
['-3.4', '2', '0.6'],
# New tests.
['0.949', '1', '0.949'],
['0.95', '1', '0.95'],
['0.99', '1', '0.99'],
['1', '1', '0'],
PHPUnit 6.5.14 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.10-1+ubuntu18.04.1+deb.sury.org+1
Configuration: /home/vagrant/www/php-bignumbers/phpunit.xml
Error: No code coverage driver is available
........FF. 11 / 11 (100%)
Time: 338 ms, Memory: 6.00MB
There were 2 failures:
1) DecimalModTest::testFiniteFiniteMod with data set #8 ('0.95', '1', '0.95')
-0.05 % 1 must be equal to 0.95, but was -0.05
Failed asserting that false is true.
/home/vagrant/www/php-bignumbers/tests/Decimal/DecimalModTest.php:37
2) DecimalModTest::testFiniteFiniteMod with data set #9 ('0.99', '1', '0.99')
-0.01 % 1 must be equal to 0.99, but was -0.01
Failed asserting that false is true.
/home/vagrant/www/php-bignumbers/tests/Decimal/DecimalModTest.php:37
However, when I run the 2 failing tests through PHP's native fmod()
, I get expected results:
php > echo fmod(.95, 1);
0.95
php > echo fmod(.99, 1);
0.99
php >
Decimal
isn't enough to handle integer properties because the following reasons:
BigInteger
type to implement the BigRational
type (#27).Related to bug #8 . In order to allow really big numbers (with very large exponents), Decimal isn't enough, so we need to introduce a float point type.
PHP's float/double type also allows very large numbers, but exponents limits vary from 256 values to 16536 values depending on the CPU, with a BigFloat type we can work with very large exponents. This type will be slower than native the native float type, but the tradeoff is worth. The explanation about exponents it's also applicable to mantissas.
It's important to implement conversion methods 'from & to' Decimal objects in the numeric range where it's possible.
It would be nice if we implement in the Decimal type a system to detect when it's preferable to switch to BigFloat. Maybe capturing memory exhaustion exceptions and handling it?
It would be nice to have the same round modes than round() PHP function:
Two previous tickets have resolved other division by zero issues in the innerLog10 method, however we've encountered another when dealing with Decimals created from floats when the precision is being calculated to a higher value than the 'length'. This results in a negative $value_log10_approx
which triggers a division by zero warning in \bcdiv
:
To replicate:
$x = Decimal::fromFloat(1.001);
// PHP Warning: bcdiv(): Division by zero in /vendor/litipk/php-bignumbers/src/Decimal.php on line 1159
$x->div(Decimal::fromFloat(1.0));
Complex numbers are very interesting because they have a lot of uses in scientific and engineering computations. They are a MUST in a good numeric computation library.
This new feature must be carefully designed because ideally it have to use the other numeric types internally to reuse code and obtain a clean class. The problem is that we have Decimal
, but also we're planning to add BigRational
and BigInteger
.
Maybe we can't discard using BigInteger
, but the first two options should be an option to represent the complex number components, so we need a very flexible class.
There are PSR-1 violations in the code (mainly in the DecimalConstants
class) reported by Sensiolabs Insight ( https://insight.sensiolabs.com/projects/9a279fbe-2b37-4612-abc0-027a3ad5d69c/analyses/2 ), it would be nice to change the methods names to follow the standard.
If the object inherits object Decimal
, methods from*
return the wrong object.
example: https://gist.github.com/Gemorroj/f1a5ccc98d90615a3bf754b839b04300
I think #32 this is resolve problem
What is going on here? I couldn't understand what this line (and the concept of "natural scale") is for:
https://github.com/Litipk/php-bignumbers/blob/master/src/Decimal.php#L102
When you have a scale set, it wrongly adds zeroes for some reason:
define('PRECISION', 8);
print Decimal::create(4, PRECISION)->asFloat(); // prints "4";
print Decimal::create(4.0, PRECISION)->asFloat(); // prints "400000000";
print Decimal::create((float)4, PRECISION)->asFloat(); // prints "400000000";
Was your goal to arrive at "4.00000000" instead?
The documentation is outdated, it refers to NaN objects, but those objects where removed from php-bignumbers in favour of throwing exceptions in order to make easier to ensure code correctness.
In addition, it's preferable to move the documentation to another file or to the project's wiki, the README.md file should be for more general information.
It's very useful to check if a number is an integer number in order to properly handle cases where we apply pow
on negative numbers.
Please bring back php-exceptions repository. We're still using php5, so that means we use 0.7.3 version which has a dependancy on php-exceptions.
It affects Decimals with auto-calculated scales.
For example:
print Decimal::create(10.13777777)->div(Decimal::create(1));
When running the following code, I get a PHP division by zero warning: PHP Warning: bcdiv(): Division by zero in vendor/litipk/php-bignumbers/src/Decimal.php on line 1140
<?php
declare(strict_types=1);
require("vendor/autoload.php");
use Litipk\BigNumbers\Decimal;
$d1 = Decimal::create(192078120.5, 28);
$d2 = Decimal::create(31449600, 28);
echo $d1->div($d2);
If I remove the .5
from the first value, the division by zero warning does not occur. Similarly, if I pass 28
as the second parameter to div()
, the warning does not occur.
I'm using v0.8.2 of this package, running on PHP 7.1.2 (cli) with opcache enabled. Xdebug is not installed. Please don't hesitate to request more information.
When using the library for divisions at a higher scale, you can run into division by zero errors:
<?php
declare(strict_types=1);
use Litipk\BigNumbers\Decimal;
require_once __DIR__ . '/vendor/autoload.php';
$value = Decimal::create('12.99', 4);
$divisor = Decimal::create(2, 4);
var_dump($value->div($divisor));
Warning: bcdiv(): Division by zero in src/Decimal.php on line 1155
The affected part is the innerLog10
method used while calculating the division.
A list of important numerical constants.
$scale
parameter)Zero
constant instead of creating new zero objects inside Decimal methods.One
constant instead of creating new one objects inside Decimal methods.The non-phisical numerical constants must be associated to a method with the following signature:
public static function ConstantName($scale);
This methods will allow to specify how many digits we want for every one of the supported numerical constants.
EDIT : This idea is no longer proposed, a new issue will be posted if we arrive to a consensus in this thread.
Because we want to introduce new classes for big numbers (See #15, #27, #28 and #29), it would be necessary to create a BigReal
interface or abstract class (more probably the second one) in order to allow interoperability between those classes.
Currently, the class Decimal have many defined methods, but almost all the methods use the
$scale`parameter, which is very specific for this type. Because it's desirable to use type hinting in the methods signatures, and because PHP doesn't allow classical method overliading (as in Java or C#), I propose to do a big refactor with the following steps:
Decimal
class (de ''d'' is for Decimal), where method
refers to the previous method name, for example mul
or add
.$scale
parameter, and hinting the BigNumber
type instead of Decimal
. Those methods should have a switch-like control structure to map the calls to the specific-type methods :
dMethod
for Decimal
rMethod
for BigRational
iMethod
for BigInteger
cMethod
for BigComplex
nMethod
for PHP's native types (see #16).BigReal
abstract class, and make Decimal
to inherit from BigReal
.Important Note: I'm talking about BigReal
and not about BigNumber
because this way we have more flexibility . Number is a very general concept, and may be in the future we want to implement other number types (not only real or complex numbers, but... say finite fields, quaternions or whatever you can imagine).
public function arccos(int $scale = null): Decimal
$scale is null here by default, but used like (int) 0. This is working in the additions $scale + 2
etc., but crashes on calling round(int)
method, which does not accept null
.
But later it is checked for explicit null
value
$scale = ($scale === null) ? 32 : $scale;
The round
method does not yield expected results. To reproduce:
$oneHundred = Decimal::fromInteger(100);
$grossAmount = Decimal::create(6.45);
$netAmount = $grossAmount->mul($oneHundred->div($oneHundred->add(Decimal::fromInteger(19))));
$vat = $grossAmount->sub($netAmount);
var_dump($vat->innerValue());
var_dump($vat->round(3)->innerValue());
(so basically, grossAmount - grossAmount / 1.19
)
The second dump should display 1.03
but displays 1.032
. Other inputs for $grossAmount
which lead to rounding error are:
29.95
results in 4.792
while 4.782
is expected.12.26
results in 1.962
while 1.958
is expected.For comparison, I have performed the same calculations using a desktop calculator, GNOME calculator and https://www.geogebra.org/calculator, all of which yield the expected results.
(I have used float as input for $grossAmount
because an external interface gives me a float, over which I have no control. Even with string as input, the rounding is unexpected.)
Using PHP 7.3.6 I get the following results using PHP "straight math":
php > echo 156 + (44 / 60) + (31 / 3600);
156.74194444444
Using this library (same system and PHP version), I get:
156.7386
On my iPhone and Mac, I get the same value as this library. However, on a Microsoft Surface Go tablet, Google's online calculator and an Android phone, I get:
156.741944444
Google's Calculator
https://www.google.com/search?q=online+calculator
Right now, rounding a decimal will only round half up, I need a round up (ceiling). Looking through the code it seems that just changing the >= 5 to > 0 will make this happen.
I noticed that there is no size check of exponential part. If I pass something like this:
1.33E+3333333333333333333333
It will cause "Allowed memory size exhausted" error.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.