Work with big numbers as array [closed] - php

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have to use big numbers for RSA so I use arrays:
$number1 = array(1234567, 7898765);
$number2 = array(9876543, 2123456);
How can I multiply them with a fast algorithm and calculate modular multiplicative inverse?

You'll probably want to use either gmp or bcmath. These are php libraries designed for dealing with large numbers and computations.

Algorithm
To say that b is the modular inverse mod m of a is to say that
a * b = 1 (mod m)
for any integer a, there exist such an inverse b if and only if a and b are relatively prime. Using the extended euclidean algorithm we can find an x and y such that a * x + m * y = 1. From that is is apparent that a * x = 1 (mod m), therefore x is the modular inverse of a.
Code
I know you want it within PHP but I have C++ version maybe you can convert it into PHP later on.
int x = px;
int y = py;
//Setup initial variables
//Maintain throughout that ax * px + bx * py = x and that ay * px + by * py = y
int ax = 1;
int ay = 0;
int bx = 0;
int by = 1;
//Perform extended gcd
while(x)
{
if(x <= y)
{
int m = y / x;
y -= m * x;
ay -= ax * m;
by -= bx * m;
}
else
{
swap(x, y);
swap(ax, ay);
swap(bx, by);
}
}
//you can assert that ay * px + by * py = y = gcd(px, py)
//you can assert that ax * px + bx * py = x = 0
//If we're taking the modular inverse of px (mod py), then for it to exist gcd(px, py) = 1
//If it does exist, it is given by ay (mod py)
int inverse = ay % py;
if(inverse < 0) inverse += py;

Related

PHP Generate number based on chance

What I want to do is generate a float between 1.00 to 200.00, let's call this number X. The X determines how much a user "wins", think of it like a multiplier on a casino. The user bets 10$, X is 23.21, the user wins 10*23.21.
If the house and the user should have the same odds (+/- 0) in the long run, the chance of X being, for example, 200.00 should be 1/199 - 1/200. This means Y=1/(X-1) - 1/X where Y = percentage of the chance of X.
The percentage Y should be randomized and I was thinking to do a frand(0, 100, 15). Where:
function frand($min, $max, $decimals = 0)
{
$scale = pow(10, $decimals);
return mt_rand($min * $scale, $max * $scale) / $scale;
}
This means we will know Y, and therefor the next step should be using Y=1/(X-1) - 1/X to determine X. However, I do not know how I can achieve this in PHP. Other ways for the same function:
Y = 1/(X - 1) - 1/X
X^2 - X = 1/Y
X(X - 1) = 1/
So, my question is; how do I solve the X OR is there a better way to achieve what I am trying?

Percentage increase or decrease between two values

How do I calculate the percentage of increase or decrease of two numbers in PHP?
For example: (increase)100, (decrease)1 = -99%
(increase)1, (decrease)100 = +99%
Before anything else you need to have a solid understanding of the meaning of percentages and how they are computed.
The meaning of "x is 15% of y" is:
x = (15 * y) / 100
The arithmetic operations with percentages are similar. If a increases with 12% (of its current value) then:
a = a + (12 * a) / 10
Which is the same as:
a = 112 * a / 100
Subtracting 9% (of its current value) from b is:
b = b - (9 * b) / 100
or
b = b * 91 / 100
which actually is 91% of the value of b (100% - 9% of b).
Turn the above a, b, x, y into PHP variables (by placing $ in front of them), terminate the statements with semicolons (;) and you get valid PHP code that performs percentage operations.
PHP doesn't provide any particular function that helps working with percentages. As you can see above, there is no need for them.
My 2 cents ;)
Using PHP
function pctDiff($x1, $x2) {
$diff = ($x2 - $x1) / $x1;
return round($diff * 100, 2);
}
Usage:
$oldValue = 1000;
$newValue = 203.5;
$diff = pctDiff($oldValue, $newValue);
echo pctDiff($oldValue, $newValue) . '%'; // -79.65%
Using Swift 3
func pctDiff(x1: CGFloat, x2: CGFloat) -> Double {
let diff = (x2 - x1) / x1
return Double(round(100 * (diff * 100)) / 100)
}
let oldValue: CGFloat = 1000
let newValue: CGFloat = 203.5
print("\(pctDiff(x1: oldValue, x2: newValue))%") // -79.65%

Combining RGB and grayscale colors

I'm looking for a way to combine a RGB color with a grayscale color.
I am looking into this for a gradient generator that uses stored colors and a template (pre-made style properties for most venders) to create a CSS3 gradient.
I am sure their is a simple solution, but I can not seem to find it. I am not looking for anyone to make me a custom function, I just need to know how to make the function.
Your general approach will probably consist of three parts:
Convert the RGB color to HSL.
Keep the hue and saturation, but apply the luminosity of the desired greyscale color.
Convert this HSL triple back to RGB.
Wikipedia has a great page on the HSL colorspace, including conversion formulas. This information was used to create some JavaScript conversion functions by Michael Jackson (yes, I'm serious):
rgbToHsl(r,g,b)
/**
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* #param Number r The red color value
* #param Number g The green color value
* #param Number b The blue color value
* #return Array The HSL representation
*/
function rgbToHsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
hslToRgb(h,s,l)
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* #param Number h The hue
* #param Number s The saturation
* #param Number l The lightness
* #return Array The RGB representation
*/
function hslToRgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [r * 255, g * 255, b * 255];
}
Since you said you're not looking for anyone to make you a custom function, I trust you'll find little trouble adapting these functions to PHP and leveraging them for your needs. ;)
You can subtract the RGB channels with the brightness of the greyscale colour.
In javascript:
var grey = {r:123,g:123,b:123};
var color = {r:216,g:205,b:120};
var clamp = function(a,b,x){return Math.min(Math.max(a,x),b);}
var mixed = {
r:clamp(0,255,color.r-(255-grey.r)),
g:clamp(0,255,color.g-(255-grey.g)),
b:clamp(0,255,color.b-(255-grey.b))
};// the final combined color.
Hope this can help you.

Algorithm for difference of products of large integers

I'm searching for an algorithm to solve differences of the type ab-cd, where a, b, c, and d are integers at the edge of the type capacity, i.e. ab overflows or loses digits depending on the actual representation on the machine. I cannot use arbitrary precision math; one of the platforms will be a SQL database.
I consider something like decomposing the product into (a'+a'')b-(c'+c'')d and then somehow iterate the way down. But probably there is a much more efficient method or at least a clever idea how to do the decomposition. Unfortunately in most cases a,b; c,d; a,c; b,d are coprime, so reduction at least is not simple.
Any ideas?
WARNING
This method is only partially functional. There are cases that it can't solve.
Taken from your text:
I'm searching for an algorithm to solve differences of the type ab-cd,
where a, b, c, and d are integers at the edge of the type capacity,
As I understand you want to calculate (a * b) - (c * d) avoiding a numeric overflow. And you want to solve this with an algorithm.
The first thing we need to recognize is that the result of (a * b) - (c * d) may not fit in the data type. I'll not try to solve those cases.
So, I'll search for different ways to calculate "ab-cd". What I've found is this:
(a * b) - (c * d) = ((a - c) * b) - (c * (d - b))
You can re-order the variables to get different products and therfore increasing the chance of finding a case that will allow you to calculate the operation without the dreaded numeric overflow:
((a - d) * b) - (d * (c - b))
((b - c) * a) - (c * (d - a))
((a - c) * b) - (c * (d - b))
((b - d) * c) - (b * (c - a))
((a - d) * c) - (a * (c - b))
((b - c) * d) - (b * (d - a))
((a - c) * d) - (a * (d - b))
Also notice that this are still differences of products, meaning that you can apply them recursively until you find one that works. For example:
Starting with:
(a * b) - (c * d)
=>
Using the transformation:
((a - d) * b) - (d * (c - b))
=>
By substitution:
(e * b) - (d * f)
=>
Rinse an repeat:
((e - f) * b) - (f * (d - b))
Of course we need to make sure we aren't going to run into a numeric overflow by doing this. Thankfully it is also possible to test if a particular product will cause a numeric overflow (without actually doing the product) with the following approach:
var max = MaxValue;
var min = MinValue;
if (a == 0 || b == 0)
{
return false;
}
else
{
var lim = a < 0 != b < 0 ? min : max;
if ((a < 0 == b < 0) == a < 0)
{
return lim / a > b;
}
else
{
return lim / a < b;
}
}
Also, it is also possible to test if a particular difference will cause a numeric overflow (without actually doing the difference) with the following approach:
var max = MaxValue;
var min = MinValue;
if (a < 0 == b < 0)
{
return true;
}
else
{
if (a < 0)
{
if (b > 0)
{
return min + b < a;
}
else
{
return min - b < a;
}
}
else
{
if (b > 0)
{
return max - b > a;
}
else
{
return max + b > a;
}
}
}
With that it is possible to pick an expression from the eight above that will allow you to calculate without the numeric overflow.
But... Sometimes none of those works. And it seems to be that there are cases where not even their combinations works (ie. rinse and repeat dosn't work)*. Maybe there are other identities that can complete the picture.
*: I did try using some heuristic to explore the combinations and also did try random exploration, there is the risk that I didn't pick good heuristics and I didn't have "luck" with the random. That's why I can't tell for sure.
I want to think that I've done some progress... But with respect to the original problem I've ultimately failed. May be I'll get back to this problem when I have more time... or may be I'll just play video games.
The standard way I know of to address this type of issues is to do what humans do with numbers beyond one digit, which is the limit of our natural counting with fingers. We carry numbers forward.
For example, let's say the limit of numbers in your numeric calculator is 256 (2^8). To get the difference of (243*244)-(242*245), we would need to decompose the numbers into
Label | Part 1 (shifted 2 right) | Part 2 (remainder)
a 2 43
b 2 44
c 2 42
d 2 45
You'd need an array to store the individual digits of the result, or a string. I think an array is faster, but a string more convenient and visible (for debugging).
(a*b)-(c*d)
=> a1*b1 shift4 + a1*b2 shift2 + a2*b1 shift2 + a2*b2
- c1*d1 shift4 + c1*d2 shift2 + c2*d1 shift2 + c2*d2
=> 987654321 (right-aligned string positioning)
+ 4xxxx
+ 88xx
+ 86xx
+ 1892
- 4xxxx
- 90xx
- 84xx
- 1890
==========
2
A naive implementation would work through each step independently, pushing each digit into place and carrying it forward where necessary. There are probably tomes of literature about optimizing these algorithms, such as breaking this into array slots of 2 digits each (since your register of number-limit 256 can handle the addition of 2 2-digit numbers easily).
If your products are near the limits of Int32 you can use Int64.
You can use BC Math Functions to work with large number which on both 32 bit & 64 bit systems
Example Of Large Numbers
$a = "4543534543543534543543543543545";
$b = "9354354546546756765756765767676";
$c = "5654656565656556565654656565656";
$d = "4556565656546546546546546356435" ;
var_dump(calculate($a, $b, $c, $d));
Output
string '257010385579862137851193415136408786476450997824338960635377204776397393100227657735978132009487561885957134796870587800' (length=120)
Function Used
function calculate($a, $b, $c, $d)
{
return bcmul(bcmul(bcmul(bcsub($a, $c),bcsub($a, $d)),bcsub($b, $c)),bcsub($b, $d));
}
After playing a little bit more I found a simpler algorithm following my original idea. It may be somewhat slower than the combined multiplication because it requires real multiplication and division instead of only shifts and addition, but I didn't benchmark it so far concerning the performance in an abstract language.
The idea is the following rewrite ab-cd = (a'+q*d)b-cd = a'b-(c-qb)d = a'b-c'd
The algorithm seems to convert the fastest if you order ab-cd as a>b and c>d, i.e. reduce the biggest numbers and maximize q.
q=(int)floor((a>c)? a/d : c/b);
a -= q*d;
c -= q*b;
Now reorder and start again. You can finish as soon as all numbers are small enough for safe multiplication, any number becomes smaller than 2 or even negative, or you find the same value for any of the numbers on both sides.

Draw parallel lines along a path - PHP GD

I need to draw something like a subway map (multiple routes along the same path) using PHP's image library. Here's an example:
*********
******** *
******* * *
* * *
* * *
* * *
* * *
* * *
* * *
* * *
* * *
* * *
* * *
* * ********************
* *********************
**********************
It's easy enough to draw one line along this path. I don't know how to draw multiple lines that follow the path but have an equal amount of space between them.
For a given point A, and more lines through it, for the first points you'll have to decide whether points go 'inside'(B) the track, or 'outside'(C):
********C
D******A *
Q*****B * *
* * *
* E *
Now, you can calculate the offset of your point B to point A as a path from with length=offset (5px for instance) along the angle the which is half the clockwise angle between AE & AD for the 'inside' B (or the clockwise angle from AD to AE for the 'outside' C, or just use a negative offset later on). You'll want point B on a distance of 5px from A along the line through A with an angle angle AE + ((angle AD - angle AE) / 2)
I'm by no means a Math wiz, and the only time I needed to calculate angles like those were in javascript, I'll give it as an example, rewrite to PHP as you please (anybody who does know math, feel free to laugh & correct when needed):
var dx = b.x - a.x;
var dy = b.y - a.y;
if(dx == 0 && dy == 0){
answer = 0;
} else if(dx > 0 && dy >= 0 ){
answer = Math.atan(dy/dx);
} else if(dx <= 0 && dy > 0){
answer = Math.atan(dx/dy) + (Math.PI * 0.5);
} else if(dx <= 0 && dy <= 0){
answer = Math.atan(dy/dx) + Math.PI;
} else if(dx >= 0 && dy <= 0){
answer = Math.atan(dy/dx) + (Math.PI * 1.5);
}
So, in a grid where D=(0,10),A=(10,10), E=(20,20):
The angle through AE = 45° (PI/4 rad),through AD = 180° (PI rad)
The angle through AB is then (45 + ((180-45)/2))=> 112.5° (5/8 PI rad)
5px offset from A=(10,10) through angle 112.5° gives you this location for B:
Bx = Ax + (cos(angle) * 5) = +/- 8.1
By = Ay + (sin(angle) * 5) = +/- 14.6
At the 'sibling' point Q next to starting point D you have no previous path to reference / calculate an angle from, so I'd take the perpendicular: angle DQ = angle DA + 90° (PI/2 rad) (in the example you could just do Dy+5, but maybe you don't always start parallel to one of the 2 axis)
Rinse and repeat for all other points, draw lines between the calculated coordinates.
To complement Wrikken's answer, here's an actual code sample using Objective-C and the cocos2d-iphone engine reconstructed from this thread and others. The atan is not needed, instead the cross product is used, see the C function at the end of the code sample and this link.
I also simply switched the sign of the offset vector from A to B in order to get the vector from A to C. This avoids calling cosf/sinf twice.
PS: This code runs in a for loop from i = 0 to i < numVertices.
CGPoint splinePoint = splinePoints[i];
CGPoint prevPoint = (i == 0) ? splinePoint : splinePoints[i - 1];
CGPoint railPoint = splinePoint;
CGPoint nextPoint = (i == (numVertices-1)) ? splinePoint : splinePoints[i + 1];
CGPoint toPrevPoint = ccpSub(railPoint, prevPoint);
CGPoint toNextPoint = ccpSub(railPoint, nextPoint);
float angleToPrevPoint = ccpAngleSigned(kAngleOriginVector, toPrevPoint);
float angleToNextPoint = ccpAngleSigned(kAngleOriginVector, toNextPoint);
float offsetAngle = 0.0f;
if (i > 0 && i < (numVertices - 1))
{
offsetAngle = angleToNextPoint + ((angleToPrevPoint-angleToNextPoint) / 2);
}
else if (i == 0)
{
offsetAngle = angleToNextPoint + M_PI_2;
}
else
{
offsetAngle = angleToPrevPoint + M_PI_2;
}
CGPoint offsetLeftRail, offsetRightRail, offsetRail;
offsetRail.x = cosf(offsetAngle) * railOffsetFromCenter;
offsetRail.y = sinf(offsetAngle) * railOffsetFromCenter;
offsetLeftRail = ccpAdd(railPoint, offsetRail);
offsetRightRail = ccpAdd(railPoint, ccpMult(offsetRail, -1.0f));
if (isPointToTheLeftOfLine(prevPoint, railPoint, offsetLeftRail))
{
leftRailSplinePoints[i] = offsetLeftRail;
rightRailSplinePoints[i] = offsetRightRail;
}
else
{
leftRailSplinePoints[i] = offsetRightRail;
rightRailSplinePoints[i] = offsetLeftRail;
}
BOOL isPointToTheLeftOfLine(CGPoint start, CGPoint end, CGPoint test)
{
return ((end.x - start.x) * (test.y - start.y) -
(end.y - start.y) * (test.x - start.x)) > 0;
}
This helped me to draw the rails on the railtrack:

Categories