-
-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add sqrt feature #19
Add sqrt feature #19
Conversation
{ | ||
$x = $a; | ||
if ($a[0] === '-') { | ||
return NAN; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NAN is a float
, not a string; you cannot return NAN. We should throw an exception here. Actually we can even do nothing: Calculator
is not part of the public API, and assumes that all input is already validated.
As such, we can perform the test only in the BigNumber
classes, you can safely remove this check.
This looks like a good start! 👍 A few guidelines:
(1) I don't mind if the (2) I don't mind if, for now, a single rounding is performed (most likely, rounding down), but it needs to be documented, consistent across calculators, and well tested. |
@BenMorel, thank you for your reply. I think we can do the following works at this time:
Can you explain more details about how to add the Thanks. |
So adding Check how other methods are implemented (
|
Hi @BenMorel, thank you for your reply. I've added the Please check that. I also do the input validation, perform operation with If having any problem, please write the comment on that line of code. Thanks. |
Hi @peter279k, I've actually fixed the issues above myself, and also added a good number of tests for It seems to work fine, however the current implementation of This makes tests fail as they take too long to complete. Of course NativeCalculator will always be slower than GMP or BCMath, but to give you an idea, the same Can you please investigate? Thanks! |
Hi @BenMorel, thank you for your reply. Actually I use the I don't think other methods can be faster than this method. And other methods will be slower than |
Actually the issue with the tests is not the slowness of the algorithm, it's that there's an infinite loop. Try: BigInteger::of('3')->sqrt(); Could you please fix this? |
@BenMorel, thank you for your reply. I will fix that later. |
Why the last 2 commits? You explicitly created another infinite loop. |
@BenMorel, I misunderstand your request. I will revert them. Forgive me I'm tired recently.... |
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function sqrt(string $a) : string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @BenMorel, after tracing source code, It looks strange.
Firstly, consider following approach:
$ans = 3;
$x = 3;
$del = 0;
$pre = 0;
while (abs($ans - $pre) > 0) {
$pre = $ans;
$ans = ($ans + $x / $ans) / 2;
}
echo $ans;
It worked fine when we let $ans=3
calculate sqrt
result.
If we use this sqrt
method, the result will happen infinite loop.
I guess the operator calculations have some problems and this will cause the infinite loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we have to let the division
operator calculation allow float string result?
I think it can solve this infinite loop problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the other operators are bugged, they're well tested, the problem most likely lies in the sqrt algorithm. And no, you can't allow float, this would defeat the whole purpose of an arbitrary precision library, that must deal with exact calculations of any size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I think it's still about the numbers problem. Consider following code snippet:
$ans = 3;
$x = 3;
$del = 0;
$pre = 0;
while (abs($ans - $pre) > 0) {
$pre = $ans;
$ans = (int) ((int) ($ans + (int) $x / $ans) / 2);
var_dump($ans);
}
echo $ans;
It lets all division
operator calculation result will be the integer
. And this will cause the infinite loop problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You most likely adapted some code that is supposed to deal with floats, and trying to make it work with integer arithmetic. You need to fix this algo, or find another one.
Note that it works fine for other sqrt() tests, so it can probably work with a few tweaks, if you really take the time to understand it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICS in this Newton pseudocode, it looks like you're using a zero Epsilon
(error tolerance), which returns the exact result but may end up with an infinite loop with some numbers in our case.
When I change cmp($checkedSqrtNumber, '0')
to cmp($checkedSqrtNumber, '1')
, the infinite loop is gone, but some tests fail, for example:
--- Expected
+++ Actual
-'7'
+'8'
-'66291728919896041699308382947726934'
+'66291728919896041699308382947726935'
Always wrong by 1 on the last digit. I guess this is where the issue lies, we need to use a zero epsilon indeed, but find a way to detect and prevent the infinite loop.
OK I changed the algorithm to the one described here: https://cp-algorithms.com/num_methods/roots_newton.html Which describes the problem well:
And now all tests pass. I'll merge this now, and will polish it later: we can speed up the algorithm by starting with a closer approximation (they use I'll probably release it later today. 👍 |
@peter279k This little change on the initial approximation made There is always room for improvement :) |
@BenMorel, thank you for your reply. I appreciate your help and review. I also find another way to calculate the square root number. The latest Travis CI build log is available here and here is the code. I will keep this finding the better way to optimize this |
Released in 0.8.3 👍 |
@peter279k If you find a faster way, don't hesitate to open a pull request! If you are interested, I would be happy if you could investigate:
|
Note: added support for |
As title, it's related to issue #18.