2

First of all, I would clarify that I am new to programming and started with c++ recently. There was a problem related to Legendre's formula in my math textbook and I thought about making a program related to it. It takes a number from user n, and finds the highest power of n which divides n!

It runs fine for a lot of numbers but messes up for a few others and it is completely random. This is a snippet from the code.

#include <iostream>
#include <math.h>

using namespace std;

int prime(int);
int calc(int, int);
int main()
{
    int n;
    int hpf=2;
    cout<<"This program finds highest power x that divides x!"<<endl;
    cout << "Enter number : " << endl;
    cin>>n;
    for(int i=2; i<=n; i++)
    {
        bool p=prime(i);
        if(p==true && n%i==0)
            hpf=i;
    }
    cout<<"The highest prime factor of the number is : "<<hpf<<endl;
    int p=calc(hpf, n);
    cout<<"The highest power of "<<n<<" that divides "<<n<<"!"<<" is : "<<p;
    return 0;
}

calc(int f, int n)
{
    int c=0 , d=1, power=1, i=0;
    while(i>=0)
    {
        int x= pow(f,power+i);
        if(i>0 && n%x==0)
            d++;
        if(x<=n)
        {
            c+=n/x;
            i++;
        }
        else
            break;
    }
    return c/d;
}

prime(int n)
{
   bool isPrime = true;
   for(int i = 2; i <= n/2; i++)
    {
      if (n%i == 0)
      {
         isPrime = false;
         break;
      }
    }
   return isPrime;
}

I pass the highest prime factor of n and the number n itself to int calc(int, int).

Now here is the problem:

when I input n=9, I get

Enter number :
9
The highest prime factor of the number is : 3
The highest power of 9 that divides 9! is : 2

on the other hand, if I input 25, I get

Enter number :
25
The highest prime factor of the number is : 5
The highest power of 25 that divides 25! is : 6

This is clearly wrong, the highest power should be 3.

It also works for bigger numbers accurately, but not all.

PS: I use codeblocks.

  • 2
    You may want to check what the biggest number an `int` can hold is on your platform and see if 25! fits in an `int`. My guess is that you're out of luck. [numeric_limits/max](https://en.cppreference.com/w/cpp/types/numeric_limits/max) – Ted Lyngmo Mar 21 '20 at 13:33
  • 2
    25! will not fit a 64-bit variable either. – Weather Vane Mar 21 '20 at 13:35
  • @WeatherVane Exactly. It would have to be a 128 bit `int`. `gcc` has `__int128` as an extension that could work. – Ted Lyngmo Mar 21 '20 at 13:39
  • 7
    Also keep in mind that `pow` is a double-precision floating point function, so may not be completely accurate (and cannot represent large 64-bit integers exactly). – Tom Karzes Mar 21 '20 at 13:39
  • I know about the limits of int data type, what I do here is use the Legendre's formula, which doesn't need you to find factorial of the number to solve this problem.(Just like how you don't need to find the factorial to find trailing 0's). Should I edit to include the entire code for clarification. – AspiringEngineer Mar 21 '20 at 15:04
  • 2
    Yes, probably. Or at the very least, a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) if you could. –  Mar 21 '20 at 15:09
  • I believe you want the square root of `n`, not `n/2` to determine whether a number is prime. –  Mar 21 '20 at 16:08
  • 1
    As Tom Karzes already said, your problem is with the `pow` function or with the quality of its implementation. It is a floating-point function and may not give the accurate result when used with integers. I get the desired result with your code, but if I force a non-optimal implementation with `#define pow(a, b) exp(log(a) * (b))`, I get bad results, too. (But different ones. Hm.) Perhaps you should implement an [integer power function](https://stackoverflow.com/questions/101439/the-most-efficient-way-to-implement-an-integer-based-power-function-powint-int) for your problem. – M Oehm Mar 21 '20 at 16:25
  • @Chipster The largest factor can never exceed n/2. – AspiringEngineer Mar 21 '20 at 16:31
  • @M Oehm Ok I will look that up. Thanks for help. – AspiringEngineer Mar 21 '20 at 16:31
  • Alteratively, or perhaps better, you can keep a "running" power: You start with `i = 1` and then calculate `x = pow(f, i)` in each cycle. You could just as well not calculate `x` all over again, but multply it with the base each time: `x = x * f` to get the power. – M Oehm Mar 21 '20 at 16:32
  • @AspiringEngineer You're right, now that you mention it. I guess it's technically just more efficient to use the square root. Nevermind, then. –  Mar 21 '20 at 16:33
  • 2
    As to Chipster's comment: The largest factor won't be greater than `n / 2`, but you only need to check numbers where `i*i <= n`, because if `n` is divisible by `i` that means `i*j == n`. Now `i` will be smaller than `sqrt(n)` and `j` will be greater unless `n` is a square and `i == j`. But beware: `sqrt()` is a floating-point function too and may have the similar issues as `pow` ... – M Oehm Mar 21 '20 at 16:39
  • @MOehm Oh, okay. Clearly I misunderstood. –  Mar 21 '20 at 16:49
  • @M Ohem Yeah, I learnt about that a few hours back, but I am habituated to using n/2. I do realize using sqrt(n) is more efficient – AspiringEngineer Mar 21 '20 at 16:49

1 Answers1

0

I'm not sure why exactly it works for 9 and not for 25(your program seems fine, but you probably have a problem when you calculate d or something), although both are squares of primes and your code seems to take care of that, but I do know why it doesn't work with number like 12. This happens because your code only looks at the highest prime factor and ignores the others. This will give you the true result when the other prime factors appear less frequently then the biggest one, but in all other cases this assumption leads to wrong results, because the highest is then also limited by smaller primes. So a correct solution has to take care of all prime factors.

For that you first need to factor the number(getting the prime factors and their power!). You can just google that if you are unsure how to do that. I don't want to include it here because then the answer would get to long.

Then you need to find how often the number is present in the factorial. As you already know(at least you used it in your code) you can count by summing up the occurence as a factor of each power of the prime in every factor of the factorial which can be done through division like this:

n/p¹ + n/p² + n/p³ + n/p⁴ + …

That can be put into a simple function(using a simple self-made power calculation):

int occurenceInFaculty(int factor, int faculty) {
    int sum = 0;
    for(int power = factor; power <= faculty; power *= factor) { // Go through all powers
        sum += faculty/power;
    }
    return sum;
}

Now you can calculate the occurrence for each of the prime factors of your number and if you divide by the power of that prime factor in the factorization you get an upper limit for the highest power. Then all that's left to do is take the minimum over all prime factors and you are done. Assuming one possible way of storing the prime factorization here is what the resulting code could look like:

Somewhere in the beginning of your code:

typedef struct {
    int prime;
    int power;
} PrimeFactor;

Assuming a prime factorization method like this:

PrimeFactor* factorization(int number, int* factors) {
    // Factorize here. Return a pointer to an array of PrimeFactors and set the pointer factors to the arrays length.
}

And then the calculation part:

int number = 25; // Put your number here.
int length = 0;
PrimeFactor* factors = factorization(25, &length);
int min = number; // Some reasonable upper border because n! < n^n
for(int i = 0; i < length; i++) {
    if(occurenceInFaculty(factors[i].prime, number)/factors[i].power < min)
        min = occurenceInFaculty(factors[i].prime, number)/factors[i].power;
}

This program also gets 25 right!

QuantumDeveloper
  • 737
  • 6
  • 15