6

For numbers n and m I need to evaluate n % m.

The catch is n can be as big as 10^100000, m maxes out at 10^18.

unsigned long long is about 2^64 (please correct me if I'm wrong) which won't do, then I thought I could read it in array of characters, but how to calculate remainder of character.

Is there any way to reduce that number to a smaller number so it could be transferred from char array to unsigned long long (like atol but for long long instead of long).

Also I think I would be needing a faster way to do %, because time limit is 0.1s

Any help is appreciated.

ajay
  • 9,402
  • 8
  • 44
  • 71
  • 3
    Is this question from n online contest website? I suspect. – haccks Feb 18 '14 at 17:02
  • @haccks Could be, but I think I don't mind... However, I wonder how is the 100k digit number going to be input anyway? – Utkan Gezer Feb 18 '14 at 17:08
  • @haccks It is from an online judge, I am practicing programming and this is one of the problems I found, I tought it would be easy (something to relax me, I was SO wrong :)) so I read the task description, it was all fine until I saw how big n can be, naturally I had to solve it so I'm asking here for help. – user314159265 Feb 18 '14 at 17:11
  • @ThoAppelsin; Yes. It can be. There are some algos for this. This type of data and time limit is common in online contests questions. – haccks Feb 18 '14 at 17:11
  • @ThoAppelsin Code should read from stdin, what they do on site I have no idea – user314159265 Feb 18 '14 at 17:13
  • @user3287649; Do not give up. Think over it an our or 2 or 3 or a day or a week (if you really interested in solving the question). You have to give a reasonable amount of time over it. – haccks Feb 18 '14 at 17:13
  • 1
    You may also want to recall two things: (1) which arithmetic operations we use to build 10000000000-digit numbers out of 1-digit numbers, and (2) what identities exist that involve these operations in conjunction with the modulus operation. – n. m. could be an AI Feb 18 '14 at 17:21
  • You have to be more specific about what `(n)` is, what format it is provided in, etc. – Brett Hale Feb 18 '14 at 17:27
  • @BrettHale I'm not sure what you mean, input is n(space)m it's all I know about it. – user314159265 Feb 18 '14 at 17:39
  • 1
    Hint: The limit on `m` is 10**18 because 10**19 is the largest power of ten that fits in an unsigned 64-bit integer. Think about this: If `m` can be up to 10**18, why would you need numbers ten times that amount? – Eric Postpischil Feb 18 '14 at 17:41
  • @EricPostpischil go on... – user314159265 Feb 18 '14 at 17:44
  • @user3287649 if a1 mod m = b1 mod m and a2 mod m = b2 mod m then (a1 + a2) mod m = (b1 + b2) mod m – ciamej Feb 18 '14 at 17:47
  • @user3287649 e.g. 123456789012345 = 1*10^14 + 2*10^13 + 3*10^12 ... – ciamej Feb 18 '14 at 17:48
  • @user3287649 now you should get it! :) – ciamej Feb 18 '14 at 17:49
  • What is the input format? Is `m` before `n`? Both are presented as simple decimal numerals? – Eric Postpischil Feb 18 '14 at 18:29
  • @EricPostpischil "n m" is the order of input, both are positive numbers (0 and up) – user314159265 Feb 18 '14 at 18:38

3 Answers3

13

There are many tricks that you can do to make modular arithmetic easier. For example, suppose you want to know what 1234567890 mod 17 is, but you don't have a numeric type big enough to represent 1234567890. Well, what do we know about %, assuming all numbers are positive?

(a+b)%e == ((a%e)+(b%e))%e
(c*d)%e == ((c%e)*(d%e))%e

If you don't understand why these identities are true, go back to the definition of % and study them until you have this solid.

Now that we know that, we know that

1234567890 % 17 = (12345 * 100000 + 67890) % 17
                = ((((12345 % 17) * (100000 % 17)) % 17) + (67890 % 17)) % 17

And now you have only much smaller numbers. If those numbers are still too big, keep breaking them down until they're small enough.

I answered a very similar question on the Math StackExchange site; it might also be of help to you.

https://math.stackexchange.com/questions/91583/implementing-fermats-primality-test/91584#91584

Community
  • 1
  • 1
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
1

Or alternatively, one could replicate what a 2nd grader would do in maths class to calculate the result and the remainder of a division:

  • attempt to divide the first digit from the left
  • put down the result to the bottom right (not important for our cause)
  • calculate the remainder for that digit
  • put the next digit right next to the previous remainder

... which is basically multiplying the remainder by 10 each time and adding the subsequent digit, until we use up all our digits. How you store the numbers that user inputs from standard input is up to you, and that should be it. Here's an example:

#include <stdio.h>

int main( ){
    unsigned long long number[100000] = { 0 };
    int length = 0;
    unsigned long long divident = 0;
    char temp = 0;

    puts( "first-operand % second-operand\n" );

first:

    printf( "first-operand: " );
    temp = getchar( );
    while ( temp != 10 ){
        if ( temp <= '9' && temp >= '0' && length < 100000 ) {
            number[length] = temp - '0';
            length++;
        }
        else {
            while ( length ) {
                length--;
                number[length] = 0;
            }
            fflush( stdin );
            puts( "Invalid input, again from the beginning..." );
            goto first;
        }
        temp = getchar( );
    }


second:

    printf( "second-operand: " );
    temp = getchar( );
    while ( temp != 10 ){
        if ( temp <= '9' && temp >= '0' ) divident = divident * 10 + temp - '0';
        else {
            divident = 0;
            fflush( stdin );
            puts( "Invalid input, again from the beginning..." );
            goto second;
        }
        temp = getchar( );
    }

    puts( "The result is..." );

    length--;
    for ( long i = 0; i < length; i++ ) {
        number[i + 1] += 10 * number[i] % divident;
    }
    printf( "%lli", number[length] % divident );

    fflush( stdin );
    getchar( );

    return 0;
}

I could not really test it for big numbers, since I may not be sure of the answer, or have the time to write down 100k digits... Sorry for an answer this late, I had been convinced to do something else.

Utkan Gezer
  • 3,009
  • 2
  • 16
  • 29
1

Read all digits for n as char, and read m as long long.
Algorithm:
1. if ( strlen(n) < strlen(m) ) printf("%s", n);
2. else: if there are, get the first 17 digits (17 is max digits for long long in this case) and convert them to long long using function strtoull, example: number = strtoull(digits, tmp, 10)
3. do calculate: tmp_rest = number % m
4. convert tmp_rest to string using sprintf function, ex. sprintf(string_digits, "%lld", tmp_rest)
5. replace the first 17 digits with string_digits start from 17th place and go to the left.
6. repeat from 2. but take 17-strlen(string_digits) as start point to get another 17 digits. Repeat until there are enough digits (>=17).
7. do 2. and 3. for rest of digits ( 0 < strlen(digits) < 17 ) -> solution is tmp_rest ;)

see: http://bytes.com/topic/software-development/insights/793965-how-find-modulus-very-large-number

purplemind
  • 71
  • 3