How to get rid of 2 numbers' common divisors - c++

So I have a function that divides a pair of numbers until they no longer have any common divisors:
void simplify(int &x, int &y){
for (int i = 2;;++i){
if (x < i && y < i){
return;
}
while (1){
if (!(x % i) && !(y % i)){
x /= i;
y /= i;
} else {
break;
}
}
}
}
How can I make it more efficient? I know one problem in this solution is that it tests for divisibility with compound numbers, when it wouldn't have any of it's factors by the time it gets to them, so it's just wasted calculations. Can I do this without the program knowing a set of primes beforehand/compute them during the function's runtime?

Use the Euclidean algorithm1:
Let a be the larger of two given positive integers and b be the smaller.
Let r be the remainder of a divided by b.
If r is zero, we are done, and b is the greatest common divisor.
Otherwise, let a take the value of b, let b take the value of r, and go to step 2.
Once you have the greatest common divisor, you can divide the original two numbers by it, which will yield two numbers with the same ratio but without any common factors greater than one.
Citation
1 Euclid, Elements, book VII, propositions 1 and 2, circa 300 BCE.
Notes
Euclid used subtraction, which has been changed here to remainder.
Once this algorithm is working, you might consider the slightly more intricate Binary GCD, which replaces division (which is slow on some processors) with subtraction and bit operations.

Sounds like a job for the C++17 library feature gcd.
#include <numeric>
void simplify(int &x, int &y)
{
const auto d = std::gcd(x, y);
x /= d;
y /= d;
}
Compiler Explorer

Related

Problem with numbers and power of numbers

Problem:
In a given range (a, b) ( a <= b, 2 <= a, b <= 1000000 ) find all natural numbers that can be expressed in format x ^ n ( x and n are natural numbers ). If there are more than one possibility to present expressed number, present it with a bigger exponential value.
U1.txt
Screen
40 110
49 = 7^2; 64 = 2^6; 81 = 3^4; 100 = 10^2;
#include <iostream>
#include <fstream>
#include <cmath>
int Power(int number, int base);
int main()
{
int a, b;
std::ifstream fin("U1.txt");
fin >> a >> b;
fin.close();
for (int i = a; i <= b; i++)
{
int max_power = 0;
int min_base = 10;
bool found = false;
for (int j = 2; j <= 10; j++)
{
int power = Power(i, j);
if (power > 0)
{
if (max_power < power) { max_power = power; }
if (min_base > j) { min_base = j; }
found = true;
}
}
if (found)
{
std::cout << i << " = " << min_base << " ^ " << max_power << "; ";
}
}
return 0;
}
int Power(int number, int base)
{
int power = (log(number) / log(base) + 0.5);
if (pow(base, power) == number)
{
return power;
}
return 0;
}
I solved the problem. However, I don't understand few things:
How the int Power(int number, int base) function works. Why the log function is used? Why after division of two log functions the 0.5 is added? I found the Idea on the Internet.
I am not sure if this solution works on all cases. I didn't know what could be the biggest value of the base number so my for (int j = 2; j <= 10; j++) loop is going from 2 to 10. If there is a number that base is bigger the solution won't work.
Are there any easier ways to solve this problem?
How does the function work?
That's something the OP should have asked to the authors of that snippet (assuming it was copied verbatim or close).
The intent seems to check if a whole number power exists, such that in combination with the integral arguments number and base the following equation is satisfied:
number = base power
The function returns it or 0 if it doesn't exist, meaning that number is not an integral power of some integral base. To do so,
it uses a property of the logarithms:
n = bp
log(n) = p log(b)
p = log(n) / log(b)
it rounds the number[1] to the "closest" integer, to avoid cases where the limited precision of floating-point types and operations would have yield incorrect results in case of a simple truncation.
In the comments I've already made the example of std::log(1000)/std::log(10), which may produce a double result close to 3.0, but less than 3.0 (something like 2.9999999999999996). When stored in an int it would be truncated to 2.
It checks if the number found is the exact power which solve the previous equation, but that comparison has the same problems I mentioned before.
pow(base, power) == number // It compares a double with an int
Just like std::log, std::pow returns a double value, making all the calculations performed with those functions prone to subtle numerical errors (either by rounding or by accumulation when multiple operations are involved). It's often preferable to use integral types and operations, if possible, when accuracy (or absolute exactness[2]) is needed.
Is the algorithm correct?
I didn't know what could be the biggest value of the base number so my for loop is going from 2 to 10
That's just wrong. One of the constraints of the problem is b <= 1'000'000, but the posted solution couldn't find any power greater than 102.
An extimate of the greatest possible base is the square root of said b.
Are there any easier ways to solve this problem?
Easiness is subjective and we don't know all the requirements and constraints of OP's assignment. I'll describe an alternative solution without posting the code I wrote to test it[3].
OP's code considers all the numbers between a and b checking for every (well, up to 10) base if there exists a whole power.
My proposal uses only integral variables, of a wide enough type, say long (any 32-bit integer is enough).
The outer loop starts from base = 2 and increments it by one at every step.
Inside this loop, exponent is set to 2 and value to base * base
If value is greater than b, the algorithm stops.
While value is less than a, updates it (multiplying it by base) and the exponent (it's incremented by one). We need to find the first power of base which is greater or equal to a.
While value is less than or equal to b, store the triplet of variables value, base and exponent in suitable container.
Consider a std::map<long, std::pair<long, long>>, it lets us associate all the values with the corresponding pair of base and exponent. Also, it could be later traversed to obtain all the values in ascending order.
The assignment requires, in case of multiple powers, to present only the one with the bigger exponent. In the example, it shows 64 = 26, ignoring 64 = 43. Note the needed one is the one with the smaller base, so that it's enough to ignore any further value if it's already present in the map.
value and exponent are updated as before.
Note that this algorithm only consider bases up to the square root of b (in the outer loop) and the number of iterations of the inner loop is much more limited (with base = 2, it would be less than 20, beeing 220 > 1'000'000. Greater bases would stop sooner and sooner).
[1] See e.g. Why do lots of (old) programs use floor(0.5 + input) instead of round(input)?
[2] See e.g. The most efficient way to implement an integer based power function pow(int, int)
[3] How do I ask and answer homework questions?

why do we iterate to root(n) to check if n is a perfect number

while checking if a number n is perfect or not why do we check till square root of (n)?
also can some body explain the if conditions in the following loop
for(int i=2;i<sqrt(n);i++)
{
if(n%i==0)
{
if(i==n/i)
{
sum+=i; //Initially ,sum=1
}
else
{
sum+=i+(n/i);
}
}
}
According to number theory, any number has at least 2 divisors (1, the number itself), and if the number A is a divisor of the number B, then the number B / A is also a divisor of the number B. Now consider a pair of numbers X, Y, such that X * Y == B. If X == Y == sqrt(B), then it is obvious that X, Y <= sqrt(B). If we try to increase Y, then we have to reduce X so that their product is still equal to B. So it turns out that among any pair of numbers X, Y, which in the product give B, at least one of the numbers will be <= sqrt(B). Therefore it is enough to find simply all divisors of number B which <= sqrt(B).
As for the loop condition, then sqrt(B) is a divisor of the number B, but we B / sqrt(B) is also a divisor, and it is equal to sqrt(B), and so as not to add this divisor twice, we wrote this if (but you have to understand that it will never be executed, because your loop is up to sqrt(n) exclusively).
It's pretty simple according to number theory:
If N has a factor i, it'll also has a factor n/i (1)
If we know all factors from 1 -> sqrt(n), the rest can be calculated by applying (1)
So that's why you only have to check from 1 -> sqrt(n). However, you code didn't reach the clause i==n/i which is the same as i == sqrt(n), so if N is a perfect square, sqrt(n) won't be calculated.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n; cin >> n;
int sum = 1;
for(int i=2;i<sqrt(n);i++)
{
if(n%i==0)
{
if(i==n/i) { sum+=i; }
else { sum+=i+(n/i); }
}
}
cout << sum;
}
Input : 9
Output : 1
As you can see, the factor 3 = sqrt(9) is missed completely. To avoid this, use i <= sqrt(n), or to avoid using sqrt(), use i <= n/i or i*i <= n.
Edit :
As #HansOlsson and #Bathsheba mentioned, there're no odd square which are perfect number (pretty easy to prove, there's even no known odd perfect number), and for even square, there's a proof here. So the sqrt(n) problem could be ignored in this particular case.
However, in other cases when you just need to iterate over the factors some error may occurred. It's better using the right method from the start, than trying to track bugs down afterward when using this for something else.
A related post : Why do we check up to the square root of a prime number to determine if it is prime?
The code uses the trick of finding two factors at once, since if i divides n then n/i divides n as well, and normally adds both of them (else-clause).
However, you are missing the error in the code: it loops while i<sqrt(n) but has code to handle i*i=n (the then-clause - and it should only add i once in that case), which doesn't make sense as both of these cannot be true at the same time.
So the loop should be to <=sqrt(n), even if there are no square perfect numbers. (At least I haven't seen any square perfect numbers, and I wouldn't be surprised if there's a simple proof that they don't exist at all.)

GMP gives wrong result of a series expansion

I am using the GMP package to implement the product of two functions which I express as a cauchy product of two convergent series.
In more detail: I am looking for a way to calculate f(x)=g(x)*h(x) where g(x) is the exponential function and h(x) is a special hypergeometric function (see below), both expressed as series.
My problem is that this works and agrees with my own approximation and wolframalpha's results for x<29, but fails for x>29. In practice I need values of about x=10^6.
The 3 formulas I used are depicted in the image below:
The Code
void invfak(mpf_t invn, unsigned int n) //Calculates inverse factorial, !/n!
{
unsigned int i;
mpf_t k;
mpf_init_set_d(k,1.0);
mpf_init_set_d(invn,0.0);
i=2;
for (i = 2; i <= n; ++i) {
mpf_mul_ui(k, k, i);
}
mpf_ui_div(invn,1.0,k);
mpf_clear(k);
}
void E2F2E(mpf_t result, long double x, unsigned int N)
{
mpf_t Q1,Q2; ///gives Nth term in series expansion of exp(x)
mpf_init_set_d(Q1,x);
mpf_init_set_d(Q2,0.0);
mpf_init_set_d(result,0.0);
mpf_pow_ui(Q1,Q1,N); /// Q1=Q1^N=x^N
invfak(Q2,N); /// Q2=1/N!
mpf_mul(result,Q1,Q2); ///result= Q1*Q2 = x^N/N!
mpf_clear(Q1);
mpf_clear(Q2);
}
void E2F2F(mpf_t result, long double x, unsigned int N)
{
mpf_t Q1,Q2,Q3; ///gives Nth term in series expansion of 2F2
mpf_init_set_d(Q1,(N+x)*(N+x));
mpf_init_set_d(Q2,-x);
mpf_init_set_d(Q3,0.0);
mpf_init_set_d(result,0.0);
mpf_pow_ui(Q2,Q2,N+2); /// Q2=Q2^(N+2)=(-x)^(N+2)
invfak(Q3,N); /// Q3=1/N!
mpf_mul(Q2,Q2,Q3); /// Q2=Q2*Q3
mpf_div(result,Q2,Q1); ///result= Q2/Q1 = .../(N+x)^2
mpf_clear(Q1); mpf_clear(Q3); mpf_clear(Q2)
}
void Exp2F2gmp(mpf_t result, long double x, unsigned int N)
{
mpf_t Q1,Qexp,Q2F2,Qsum;
mpf_init_set_d(Q1,0.0);
mpf_init_set_d(Qexp,0.0);
mpf_init_set_d(Q2F2,0.0);
mpf_init_set_d(Qsum,0.0);
mpf_init_set_d(result,0.0);
for(unsigned i = 0; i <= N; ++i){
mpf_set_d(Qsum,0.0);
mpf_set_d(Qexp,0.0);
mpf_set_d(Q2F2,0.0);
for(unsigned l = 0; l <= i; ++l){ /// a_l und b_i-l
E2F2E(Qexp,x,l);
E2F2F(Q2F2,x,i-l);
mpf_mul(Q1,Qexp,Q2F2);
mpf_add(Qsum,Qsum,Q1);
}
mpf_add(result,result,Qsum);
mpf_abs(Qsum,Qsum);
//if(mpf_cmp_d(Qsum,0.00000001)==-1){ cout << "reached precision at i="<<i; break;}
}
cout << "\n\n Result = " << result << endl;
mpf_clear(Q1);
mpf_clear(Qexp);
mpf_clear(Q2F2);
mpf_clear(Qsum);
}
The function f(x) should approximately go as f(x)=1.05x+1 and also, f(x)>0 for x>0.
But the implementation gives this:
Exp2F2gmp(Q,10,1000) = 12.3707
Exp2F2gmp(Q,20,1000) = 23.1739
Exp2F2gmp(Q,30,1000) = -35195.1
Exp2F2gmp(Q,40,1000) = -2.92079e+13
The first two values agree with Wolframalpha, the second two obviously dont.
Any kind of help would be appreciated, thank you!
This is a textbook example of catastrophic cancellation.
The terms in the 2F2 series grow to a maximum size of about exp(x), but the magnitude of the 2F2 function is about exp(-x). This means that you need to use at least log_2(exp(2x)) ~= 2.886*x extra bits of precision to compute the 2F2 series accurately, and possibly slightly more depending on how the terms are computed.
So for example, if x = 29, you need about 83 bits of precision. Your code uses the default precision of the MPF type, which I believe is something like 64 bits. You need to change the code to set the precision of all MPF variables to 64 + 2.886*x bits to get 64 accurate bits (see the GMP manual for how to do this).
In practice, the series evaluation as you have implemented is not very efficient, and will probably be too slow for x = 1e6.
One possibility is to use the Arb library (which I develop). This supports computing generalized hypergeometric functions out of the box and uses a much more efficient series evaluation strategy (in this case, using binary splitting). It also uses interval arithmetic, so you get error bounds for free and can set the precision automatically instead of predicting the needed precision in advance (but in this case predicting the precision is easy, and faster).
Here is code demonstrating how to use it:
#include "acb_hypgeom.h"
int main()
{
acb_t z, t;
acb_struct a[2];
acb_struct b[2];
double x;
acb_init(z); acb_init(t);
acb_init(a + 0); acb_init(a + 1);
acb_init(b + 0); acb_init(b + 1);
for (x = 10.0; x <= 1000000; x *= 10)
{
acb_set_d(a + 0, x);
acb_set_d(a + 1, x);
acb_set_d(b + 0, x + 1);
acb_set_d(b + 1, x + 1);
acb_set_d(z, -x);
acb_hypgeom_pfq(t, a, 2, b, 2, z, 0, 64 + 2.886 * x);
acb_neg(z, z);
acb_exp(z, z, 64);
acb_mul(t, t, z, 64);
printf("f(%f) = ", x); acb_printn(t, 20, 0); printf("\n");
}
acb_clear(z); acb_clear(t);
acb_clear(a + 0); acb_clear(a + 1);
acb_clear(b + 0); acb_clear(b + 1);
}
Here is the output:
f(10.000000) = [12.37067931727649929 +/- 5.38e-18]
f(100.000000) = [106.6161729468899444 +/- 4.93e-17]
f(1000.000000) = [1020.154983574938368 +/- 3.54e-16]
f(10000.000000) = [10063.00061277849954 +/- 2.57e-15]
f(100000.000000) = [100198.5001942224819 +/- 6.28e-14]
f(1000000.000000) = [1000626.990558714621 +/- 4.59e-13]
At x = 1e6, the evaluation takes about 20 seconds (your code would take far, far longer) as a result of 2.9 million bits being used. If this is still too slow, you need to find a better formula to compute f(x), ideally an asymptotic expansion valid when x -> infinity, or perhaps an integral representation (if there is one without cancellation issues).
Now, if your 2F2 function only depended on x in the final argument and had the first four parameters fixed, there would be a standard formula for this asymptotic expansion, but with the growing parameters involved, I'm not exactly sure how to do it. Since the upper and lower parameters almost "cancel out", it might work to treat them as constants and use the standard asymptotic series with respect to the argument, but I did not check this. Someone with more expertise in asymptotic analysis would have to comment.
It's also possible that you could use contiguous relations to reduce the 2F2 function to something with small parameters, but I'm not sure if this would be an improvement in practice.

Algorithm of calculate modulo after power

Below a piece of code to calculate the value of a^b%c,
int powermod(int a,int b,int c)
{
int ans = 1;
while(b)
{
if(b&1)
ans=(ans*a)%c;
a=(a*a)%c;
b=b>>1;
}
return ans;
}
I tried to understand the algorithm behind the code but couldn't make it.
Can someone help to explain this to me? How this works and does the algorithm behind it have a name?
It's easier to see what's going on without the "modulo c" part:
int power(int a,int b)
{
int ans = 1;
while(b)
{
if(b&1)
ans *= a;
a=a*a;
b=b>>1;
}
return ans;
}
This is a standard algorithm to compute ab by considering b one bit at a time, starting with the least significant bit. For each bit of b, if it is 1, multiply the answer by the current value of a. Then, to move to the next bit, square a and shift b to the right by 1 bit. The theory of this algorithm is that x2m + 2n = x2mx2n.
This type of algorithm is known as "exponentiation by squaring", "square-and-multiply" or "binary exponentiation".
The posted algorithm (after correction as noted in the comments) does the same thing modulo c, using the fact that (x*y)%z == ((x%z) * (y%z)) % z (that is, the modulo operation can be applied either before or multiplication). It uses this to keep a less than c despite repeated squaring.
It use the binary thinking.
ab = ab1 ab2 ... abn when b1+...+bn=b
write b in binary, you will get ab0 a2*b1 a4*b2 ... a2nbn ,bi means the ith bit in binary b. It can only be 0 or 1.
Now we find out that we don't need to calculate a2n every time, as we can get it from a2n-1
Because of (ab)%c=(a%c)(b%c)%c, this algorithm do the mod operation when multiply.

Array Division - What is the best way to divide two numbers stored in an array?

I have two arrays (dividend, divisor):
dividend[] = {1,2,0,9,8,7,5,6,6};
divisor[] = {9,8};
I need the result (dividend/divisor) as:
quotient[] = {1,2,3,4,5,6,7};
I did this using array subtraction:
subtract divisor from dividend until dividend becomes 0 or less than divisor, each time incrementing quotient by 1,
but it takes a huge time. Is there a better way to do this?
Do long division.
Have a temporary storage of size equal to the divisor plus one, and initialized to zero:
accumulator[] = {0,0,0};
Now run a loop:
Shift each digit of the quotient one space to the left.
Shift each digit of the accumulator one space to the right.
Take the next digit of the dividend, starting from the most-significant end, and store it to the least-significant place of the accumulator.
Figure out accumulator / divisor and set the least-significant place of the quotient to the result. Set the accumulator to the remainder.
Used to use this same algorithm a lot in assembly language for CPUs what didn't have division instructions.
Other than that, have you considered using BigInt class (or the equivalent thing in your language) which will already does this for you?
You can use long division http://en.wikipedia.org/wiki/Long_division
Is there a better way to do this?
You can use long division.
You can use Long division algorithm or the more general Polynomial Long Division.
Why not convert them to integers and then use regular division?
in pseudocode:
int dividend_number
foreach i in dividend
dividend_number *= 10
dividend_number += i
int divisor_number
foreach i in divisor
divisor_number *= 10
divisor_number += i
int answer = dividend_number / divisor_number;
There you go!
A is the divident.
B is the divisor.
C is the integer quotinent
R is the rest.
Each "huge" number is a vector retaining a big number. In huge[0] we retain the number of digits the number has and thren the number is memorized backwards.
Let's say we had the number 1234, then the corespoding vector would be:
v[0]=4; //number of digits
v[1]=4;
v[2]=3;
v[3]=2;
v[4]=1;
....
SHL(H,1) does: H=H*10;
SGN(A,B) Compares the A and B numbers
SUBSTRACT(A,B) does: A=A-B;
DIVIDHUGE: makes the division using the mentioned procedures...
void Shl(Huge H, int Count)
/* H <- H*10ACount */
{
memmove(&H[Count+1],&H[1],sizeof(int)*H[0]);
memset(&H[1],0,sizeof(int)*Count);
H[0]+=Count;
}
int Sgn(Huge H1, Huge H2) {
while (H1[0] && !H1[H1[0]]) H1[0]--;
while (H2[0] && !H2[H2[0]]) H2[0]--;
if (H1[0] < H2[0]) {
return -1;
} else if (H1[0] > H2[0]) {
return +1;
}
for (int i = H1[0]; i > 0; --i) {
if (H1[i] < H2[i]) {
return -1;
} else if (H1[i] > H2[i]) {
return +1;
}
}
return 0;
}
void Subtract(Huge A, Huge B)
/* A <- A-B */
{ int i, T=0;
for (i=B[0]+1;i<=A[0];) B[i++]=0;
for (i=1;i<=A[0];i++)
A[i]+= (T=(A[i]-=B[i]+T)<0) ? 10 : 0;
while (!A[A[0]]) A[0]--;
}
void DivideHuge(Huge A, Huge B, Huge C, Huge R)
/* A/B = C rest R */
{ int i;
R[0]=0;C[0]=A[0];
for (i=A[0];i;i--)
{ Shl(R,1);R[1]=A[i];
C[i]=0;
while (Sgn(B,R)!=1)
{ C[i]++;
Subtract(R,B);
}
}
while (!C[C[0]] && C[0]>1) C[0]--;
}