I'm looking to find an algorithm that I can implement in PHP to get the natural log() of an integer number using arbitrary precision maths. I'm limited by the PHP overlay library of the GMP library (see http://php.net/manual/en/ref.gmp.php for available GMP functions in PHP.)
If you know of a generic algorithm that can be translated into PHP, that would also be a useful starting point.
PHP supports a native log() function, I know, but I want to be able to work this out using arbitrary precision.
Closely related is getting an exp() function. If my schoolboy Maths serves me right, getting one can lead to the other.
Well you would have the Taylor series, that can be rewritten for better convergence
To transform this nice equality into an algorithm, you have to understand how a converging series work : each term is smaller and smaller. This decrease happens fast enough so that the total sum is a finite value : ln(y).
Because of nice properties of the real numbers, you may consider the sequence converging to ln(y) :
L(1) = 2/1 * (y-1)/(y+1)
L(2) = 2/1 * (y-1)/(y+1) + 2/3 * ( (y-1)/(y+1) )^3
L(3) = 2/1 * (y-1)/(y+1) + 2/3 * ( (y-1)/(y+1) )^3 + 2/5 * ( (y-1)/(y+1) )^5
.. and so on.
Obviously, the algorithm to compute this sequence is easy :
x = (y-1)/(y+1);
z = x * x;
L = 0;
k = 0;
for(k=1; x > epsilon; k+=2)
{
L += 2 * x / k;
x *= z;
}
At some point, your x will become so small that it will not contribute to the interesting digits of L anymore, instead only modifying the much smaller digits. When these modifications start to be too insignificant for your purposes, you may stop.
Thus if you want to achieve a precision 1e^-20, set epsilon to be reasonably smaller than that, and you're good to go.
Don't forget to factorize within the log if you can. If it's a perfect square for example, ln(a²) = 2 ln(a)
Indeed, the series will converge faster when (y-1)/(y+1) is smaller, thus when y is smaller (or rather, closer to 1, but that should be equivalent if you're planning on using integers).
Related
I am working with some logical problems in my localhost. At a case I need to calculate power of 2 and sum them in integer type to proceed next case. I am using 32 bit system, so I can calculate up to 2^31, as well as sum up to 2147483648 in integer type.
How can I increase the number of power up to 10000? Is there any math library or class available to calculate big integer effectively?
Probably I dont need the power over thousand but I am curious if it is possible in PHP or not. Can anyone answer my with proper reference ?
There are two libraries available in PHP to work with BIG Numbers.
They are,
BC Math
GMP
In both of them GMP has more library function then BC Math.
GMP - It considers leading zeros in a number string as meaning the
number is in octal, whereas 'BC' doesn't. Reference:
http://www.php.net/manual/en/book.gmp.php
In JavaScript this math operation returns:
1913397 / 13.054 = 146575.53240386088
but same operation in php returns:
1913397 / 13.054 = 146575.53240386
I guess this is due to rounding.
How can I extend php's precision?
From an article I wrote for Authorize.Net:
One plus one equals two, right? How about .2 plus 1.4 times 10? That equals 16, right? Not if you're doing the math with PHP (or most other programming languages):
echo floor((0.2 + 1.4) * 10); // Should be 16. But it's 15!
This is due to how floating point numbers are handled internally. They are represented with a fixed number of decimal places and can result in numbers that do not add up quite like you expect. Internally our .2 plus 1.4 times 10 example computes to roughly 15.9999999998 or so. This kind of math is fine when working with numbers that do not have to be precise like percentages. But when working with money precision matters as a penny or a dollar missing here or there adds up quickly and no one likes being on the short end of any missing money.
The BC Math Solution
Fortunately PHP offers the BC Math extension which is "for arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings." In other words, you can do precise math with monetary values using this extension. The BC Math extension contains functions that allow you to perform the most common operations with precision including addition, subtraction, multiplication, and division.
A Better Example
Here's the same example as above but using the bcadd() function to do the math for us. It takes three parameters. The first two are the values we wish to add and the third is the number of decimal places we wish to be precise to. Since we're working with money we'll set the precision to be two decimal palces.
echo floor(bcadd('0.2', '1.4', 2) * 10); // It's 16 like we would expect it to be.
24151.40 - 31891.10 = -7739.699999999997
I grab these two numbers from a MySQL table with the type as decimal(14,2)
24151.40
31891.10
It is saved exactly as stated above and it echos exactly like that in PHP. But the minute I subtract the second value from the first value, I get a number -7739.699999999997 instead of -7,739.7. Why the extra precision? And where is it coming from?
From an article I wrote for Authorize.Net:
One plus one equals two, right? How about .2 plus 1.4 times 10? That equals 16, right? Not if you're doing the math with PHP (or most other programming languages):
echo floor((0.2 + 1.4) * 10); // Should be 16. But it's 15!
This is due to how floating point numbers are handled internally. They are represented with a fixed number of decimal places and can result in numbers that do not add up quite like you expect. Internally our .2 plus 1.4 times 10 example computes to roughly 15.9999999998 or so. This kind of math is fine when working with numbers that do not have to be precise like percentages. But when working with money precision matters as a penny or a dollar missing here or there adds up quickly and no one likes being on the short end of any missing money.
The BC Math Solution
Fortunately PHP offers the BC Math extension which is "for arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings." In other words, you can do precise math with monetary values using this extension. The BC Math extension contains functions that allow you to perform the most common operations with precision including addition, subtraction, multiplication, and division.
A Better Example
Here's the same example as above but using the bcadd() function to do the math for us. It takes three parameters. The first two are the values we wish to add and the third is the number of decimal places we wish to be precise to. Since we're working with money we'll set the precision to be two decimal palces.
echo floor(bcadd('0.2', '1.4', 2) * 10); // It's 16 like we would expect it to be.
PHP doesn't have a decimal type like MySQL does, it uses floats; and floats are notorious for being inaccurate.
To cure this, look into number_format, e.g.:
echo number_format(24151.40 - 31891.10, 2, '.', '');
For more accurate number manipulation, you could also look at the math extensions of PHP:
http://www.php.net/manual/en/refs.math.php
This has to do with general float / double precision rates, which scientifically relates to 1.FRACTAL * 2^exponential power. Being that there's a prefix of 1, there's technically no such thing as zero, and the closest value you can obtain to 0 is 1.0 * 2 ^ -127 which is .000000[127 0s]00001
By rounding off your answer to a certain precision, the round factor will give you a more precise answer
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_round
Is it possible to generate this kind of random curves?
I've tried IMagick bezier curves (see http://www.php.net/manual/en/function.imagickdraw-bezier.php), but even with 20-30 points they do not look like this. Here is my sample http://mechanicalzilla.com/sandbox/imagick/curve.php
Thank you.
I bet you could write an algorithm which would basically take x number of random twists before going straight to the exit coordinates. This also assumes that algorithm is smart enough to check the angle of the turn. (assuming you don't want to endup in knot-web)
However, assuming that this isn't your graduation task or that you are paid on per-hour basis to work on this, this would be a waste of time and success is highly doubtful.
Even if you'd manage to generate single line algorithm, doing it so that the lines wouldn't come too close to each other is close to impossible. You will end up with something like this:
Looks like:
x = 0; y = 0; angel = 0;
while (true) {
angel = angel + 0.5 - random(1);
x1 = x + 0.1 * cos(angel);
y1 = y + 0.1 * sin(angel);
if (abs(x1 - x) + abs(y1 - y) < 10)
drawline(x,y,x1,y1);
x = x1; y = y1;
if (x < 0) x = width;
if (y < 0) y = height;
if (x > width) x = 0;
if (y > height) y = 0;
}
This is far from a complete answer, but in my mind's eye seems like it could help you:
Instead of drawing curves from the start to the end point of the entire line, consider subdividing your board into a evenly spaced grid. Each square of one column of the grid is entitled to have one point of one curve in it, and you'd steadily advance from left to right (at first? for simplicity's sake.).
The randomness would come into play by picking a square for a curve - to prevent it from getting too chaotic, you could give this randomness bounds, say, "you're not allowed to pick a square that (if a distance from square to square is considered 1) violates abs(current vertical position - new vertical position) <= 5 unless none such is free anymore at this point" or some other arbitrary restraint. ("unless none such is free anymore at this point" is important, otherwise it's possible to lock yourself into an unsolvable state.)
(Sorry, drawing curves with my mouse -> worst/no interpolation ever. Catmull-Rom interpolation will probably be your friend here, though, I imagine.)
The display should be loose enough given that your curve points cannot arbitrarily scatter together given a grid, but it's probably very difficult to get the curve to connect to the end point 'fluidly' - might be a good solution if you don't mind arbitrary end points, though, read as, the algorithm can decide for itself where it wants the line to end.
Think this idea might help you with your curves?
One way to approach this would be to first generate a set of random curves and then use a physics solver to apply repulsion forces between them to avoid clumping.
Here's a quick proof of concept:
I created this using a very niche tool (for anyone interested: Kangaroo Physics solver, a plugin for Grasshopper, visual scripting language for Rhinoceros3d) but you can probably recreate the same concept in any mainstream programming language, eg. Python.
My primary question is:
Is this alot of loops?
while ($decimals < 50000 and $remainder != "0") {
$number = floor($remainder/$currentdivider); //Always round down! 10/3 =3, 10/7 = 1
$remainder = $remainder%$currentdivider; // 10%3 =1, 10%1
$thisnumber = $thisnumber . $number;
$remainder = $remainder . 0; //10
$decimals += 1;
}
Or could I fit more into it? -without the server crashing/lagging.
I'm just wondering,
Also is there a more effiecent way of doing the above? (e.g. finidng out that 1/3 = 0.3 to 50,000 decimals.)
Finally:
I'm doing this for a pi formulae the (1 - 1/3 + 1/5 - 1/7 etc.) one,
And i'm wondering if there is a better one. (In php)
I have found one that finds pi to 2000 in 4 seconds.
But thats not what I want. I want an infinite series that converges closer to Pi
so every refresh, users can view it getting closer...
But obv. converging using the above formulae takes ALONG time.
Is there any other 'loop' like Pi formulaes (workable in php) that converge faster?
Thanks alot...
Here you have several formulas for calculating Pi:
http://mathworld.wolfram.com/PiFormulas.html
All of them are "workable" in PHP, like in any other programming language. A different question is how fast they are or how difficult they are to implement.
If the formulas converge faster or slower, it's a Math question, not about programming, so I can't help you. I can tell you that as a rule of a thumb, the less nested loops you put, the faster will be your algorithm (this is a general rule, don't take it as the absolute truth!)
Anyway, since the digits of Pi are known until a certain digit, why don't you copy it into a file and then just index it? That will be extremely fast :)
You can check previous answers to similar questions:
How can pi be calculated to a set number of digits in PHP?
https://stackoverflow.com/questions/3045020/which-is-the-best-formulae-to-find-pi
Check http://mathworld.wolfram.com/PiIterations.html (taken from the last answer). Those formulaes are using iterations and can therefor be implemented using a loop.
You should use google and search for "php implementation xxxxxxx" (where xxxxxx stands for the algorithm name you want to search for).
EDIT: Here is an implementation of Vietas formula using a while-loop in php.