-1

i was trying to solve the big mod problem using the following code.

#include<iostream>
#include<cmath>

using namespace std;

typedef long int li;

li m;
li mod(li b,li p)
{
    if(p==0)
        return 1;
    if(p%2==0)
    {
        return ((mod(b,p/2)%m)*mod(b,p/2)%m)%m;
        //return (li)pow(mod(b,p/2)%m,2)%m;
    }
    return (b%m*mod(b,p-1)%m)%m;
}

main()
{
    li b,p;
    while(cin>>b>>p>>m)
    {
        cout<<mod(b,p)<<endl;
    }
}

but it gives different output for ((mod(b,p/2)%m)*mod(b,p/2)%m)%m and pow(mod(b,p/2)%m,2)%m.i want to know are they not the same and if they are why are the giving different outputs.

sample input: 3 18132 17

17 1765 3

2374859 3029382 36123

output without pow function: 13 2 13195

output with pow function: 1 2 31329

test code with pow function

#include<iostream>
#include<cmath>
using namespace std;

typedef long int li;

li m;
li mod(li b,li p)
{
    if(p==0)
        return 1;
    if(p%2==0)
    {
        //return ((mod(b,p/2)%m)*mod(b,p/2)%m)%m;
        return (li)pow(mod(b,p/2)%m,2)%m;
    }
    return (b%m*mod(b,p-1)%m)%m;
}

main()
{
    li b,p;
    while(cin>>b>>p>>m)
    {
        cout<<mod(b,p)<<endl;
    }
}
Reshad
  • 220
  • 5
  • 19
  • please provide the input and output! – Willi Mentzel Apr 13 '16 at 10:46
  • Please provide working code. – Hatted Rooster Apr 13 '16 at 10:47
  • please provide ice cream! – Willi Mentzel Apr 13 '16 at 10:50
  • First of all, a few pieces of advice not directly relevant to your problem. 1. You should surely pass `m` into your function as an actual parameter, not via a global variable. (*Possible* exception: if this is going to be used for large calculations all using the same modulus.) 2. You shouldn't call it `mod` because that already has a meaning and it's a different meaning. Maybe `pmod` or `mpow` or `expmod` or something that indicates you're doing both exponentiation and remaindering. 3. You have some superfluous `%m`%s; e.g., the result of `mod` is always already "in range". – Gareth McCaughan Apr 13 '16 at 10:51
  • Oh, also 4. You shouldn't be calling `mod(b,p/2)` twice, but calling it once and multiplying the result by itself. This will make a very large difference to efficiency. – Gareth McCaughan Apr 13 '16 at 10:53
  • You've given some sample input but no sample output. Can you show us a case it definitely gets wrong? (Or, if you prefer, two cases where you're sure one of them must be wrong even if you can't tell which?) – Gareth McCaughan Apr 13 '16 at 10:54
  • thank you Gareth McCaughan, I will keep those in mind next time – Reshad Apr 13 '16 at 10:56
  • The reason you give for thinking your `mod` function is doing the wrong thing seems peculiar, for two reasons. First, taken at face value it sounds like you're calling `pow`, which is meant for use with floating-point numbers rather than integers. Second, the things you're comparing all involve `mod(b,p/2)` and no other calls to `mod`, and if there's a discrepancy between them it can't be `mod`'s fault. – Gareth McCaughan Apr 13 '16 at 10:56
  • Not quite sure but are you trying to build a powmod(a,x,m) function based on [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)? – VolkerK Apr 13 '16 at 11:04
  • Oh, another minor thing: I think you (i.e., Reshad) may be a little confused about the precedence of the `*` and `%` operators. E.g., `(b%m*mod(...)%m)%m` is actually the same as `(((b%m)*mod(...))%m)%m` which probably isn't what you had in mind since it reduces the same thing mod m twice in a row. This doesn't end up actually breaking any of your code, as it happens. – Gareth McCaughan Apr 13 '16 at 11:08
  • As you will see, I think your problem is in your test code rather than your modular-exponentiation code. Could you post that too? In particular, whatever you used to get the "with pow function" outputs? – Gareth McCaughan Apr 13 '16 at 11:10
  • #include #include using namespace std; typedef long int li; li m; li mod(li b,li p) { if(p==0) return 1; if(p%2==0) { //return ((mod(b,p/2)%m)*mod(b,p/2)%m)%m; return (li)pow(mod(b,p/2)%m,2)%m; } return (b%m*mod(b,p-1)%m)%m; } main() { li b,p; while(cin>>b>>p>>m) { cout< – Reshad Apr 13 '16 at 11:13
  • Please use the [edit "button"](http://stackoverflow.com/posts/36596017/edit) to add the (neatly formatted) code to your question text. – VolkerK Apr 13 '16 at 11:18
  • Thanks for posting the two versions of the code. I've updated my answer to explain in more detail what's going wrong with the `pow` version. – Gareth McCaughan Apr 13 '16 at 11:39

1 Answers1

0

The answers you report "without pow function" are correct answers, and your code looks OK to me. So I think your problem is in the test you're applying, not in your modular exponentiation function.

The pow function operates on (double-precision) floating-point numbers, and is not guaranteed to give exact results even when both its inputs are small integers. What is happening to you is that at some point pow is returning a value that is just a tiny bit smaller than an integer, and then you cast it to long int and get a value 1 less than you "should", and after that everything is wrong.

For instance, if you compute 3^6 mod 17 with your code, then at one point it gets 3^3 mod 17 = 10 (OK so far), then computes pow(10,2) ... and, at least on my machine with my compiler, this comes out to just a little bit less than 100. So the cast to li yields 99 instead of 100, and then we're dead.

I have tried to verify this in more detail by instrumenting your code to output intermediate values, but amusingly this typically fails because of subtleties in floating-point arithmetic. (Saving an intermediate value in a variable can cause it to be subject to an extra floating-point rounding which turns the just-less-than-an-integer value into an exact integer value.)

Gareth McCaughan
  • 19,888
  • 1
  • 41
  • 62