1

I have to write a program where I check if an int is a prime number. If it is, I have to cut the most significant digit and check if the new number is prime, again I cut the most significant digit and check again, until my number is 1 digit long.

For example if I have 547, I check if it is prime. After I've verified that it is, I cut the 5 and check if 47 is prime, then I check if 7 is prime.

The only part of the code I need is the one to cut the number. I'm sorry if I cannot include my code, but at the moment I have no idea how to do it. Could you suggest a solution both in an arithmetic way and by using a function? (if a function that can do that exists)

By arithmetic I mean, just by using standard mathematical operations, I know for example how to cut the least significant digit:

num = num / 10;

So that 547 would become just 54 and so on.

trent
  • 25,033
  • 7
  • 51
  • 90
Davide
  • 185
  • 1
  • 9
  • Is this for USACO training superprime rib? :) For that problem, you should use dynamic programming to build the superprime numbers for each length from 1 to 8. – abacles Jan 21 '18 at 23:04

6 Answers6

6

Use the modulo operation. For example, to keep the least significant 2 digits of a decimal number num, use num % 100. It will produce a number between 0 and 99 that is the remainder of dividing num by 100, which is basically the least two significant digits.

Aziz
  • 20,065
  • 8
  • 63
  • 69
  • 1
    The problem is that I don't know in advance the length of the number. It could even be 6-7 digits long. – Davide Jan 21 '18 at 21:05
  • 2
    @Paglie98 Use base-10 log to find the number of decimal digits. Refer to this: https://stackoverflow.com/questions/24176789/how-does-using-log10-correctly-calculate-the-length-of-a-integer – Aziz Jan 21 '18 at 21:06
  • 1
    @paglie98 then use a loop. – machine_1 Jan 21 '18 at 21:07
  • 1
    @Aziz : The log10() suggestion is a necessary part of the answer - you should add it to the answer rather than just a link in a comment. – Clifford Jan 21 '18 at 22:03
  • @Paglie98 any integer loop will be more effective than log or pow functions – 0___________ Jan 21 '18 at 22:32
  • @Aziz: Using logarithms is prone to errors of floating-point arithmetic. It is not generally a good solution for arithmetic with integers. – Eric Postpischil Jan 22 '18 at 01:21
3

The number of significant decimal digits can be determined by log10(). That can then be used to generate the integer power of 10 value necessary to remove the MSD by modulo arithmetic:

#include <math.h>
#include <stdint.h>

uint32_t remove_msd( uint32_t i )
{
    return i % (int)pow( 10, floor( log10(i) ) ) ;
}

Note however that due to the limitations of IEEE 754 64-bit double precision floating-point, the solution will only work for positive integer values less than 253. Here I have enforced uint32_t data type to remain within this restriction (even more restrictive). You could equally use an assert for the valid range if you were to use 64 bit integers.

The following is a more general solution for int but is arguably no longer "just by using standard mathematical operations" as requested:

#include <stdlib.h>

int remove_msd( int i )
{
    int a = abs( i ) ;
    int m = 1 ;
    while( a > 10 )
    {
        a /= 10 ;
        m *= 10 ;
    }

    return i % m ;
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Using `log10` in this way will fail in several situations, including: (a) The integer format can express integers the floating-point format cannot (e.g., 64-bit integers with 53-bit floating-point significands), so the conversion of the `log10` argument introduces error. (b) The `log10` implementation returns results with too much error. (c) `i` is zero or negative. – Eric Postpischil Jan 22 '18 at 01:20
  • @EricPostpischil ; Completely agree - the solution has restricted validity, but the question does state: "_... just by using standard mathematical operations..._", so I assume he wanted an _expression_ rather than an _algorithm_. Moreover the statement "..._check if an int is a prime number_..." suggests a type restriction to `int`. I realise that an `int` may be 64 bit, but that is not the case on Windows or Linux at least: https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models. Moreover in most contexts a prime is positive. I have modified the answer. – Clifford Jan 22 '18 at 13:41
  • Yes in this program the numbers are positive. Thanks for the answer! I actually liked you second approach better! – Davide Jan 23 '18 at 19:33
  • @Paglie98 : I agree, the second is better; it simply did not meet your expressed criteria. The first is a mathematician's answer that is less sympathetic to digital computing limitations or efficiency considerations. – Clifford Jan 24 '18 at 10:17
2

Here is a general solution (intended to work for any int value, even negative [which you might not need], and without risking floating-point errors or integer overflow).

#include <limits.h>
#include <stdio.h>


int RemoveLeadingDigit(int x)
{
    //  t is the number undergoing examination.
    int t = x;

    //  p is the power of 10 needed to restore the position of the leading digit.
    int p = 1;

    /*  Reduce t until it is a single digit (positive or negative).  At
        the same time, track the power of 10 needed to restore t to its
        original scale.
    */
    while (t <= -10 || 10 <= t)
    {
        t /= 10;
        p *= 10;
    }

    /*  Now that t is a single digit, restore it to its original position,
        remove it from x, and return the resulting value.
    */
    return x - t*p;
}


static void Try(int x)
{
    printf("%d with leading digit removed is %d.\n", x, RemoveLeadingDigit(x));
}


int main(void)
{
    Try(0);
    Try(1);
    Try(9);
    Try(10);
    Try(89);
    Try(98);
    Try(99);
    Try(-987654321);
    Try(-1);
    Try(INT_MAX);
    Try(INT_MIN);
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
1

Using log pow functions is the overkill especially on the small uC or uP

#include <stdio.h>
#include <limits.h>

int mst(int num)
{
    long z;
    long tmp = num;

    for(z = 10; z < INT_MAX; z *= 10) 
    {
        if( !(num / z)) break;
    }
    return (tmp % (z / 10));
}

int main(void) {
    printf("%d \n", mst(3456));
    printf("%d \n", mst(-35456));
    return 0;
}

just add some checks for the border issues (that is the homework :))

0___________
  • 60,014
  • 4
  • 34
  • 74
1

You can write a function to return an array of all primes found using your rules, for example :

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct IntArray {
    int size;
    int* data;
};

int IsPrime(const int in) {
    int possiblePrimeCount = in/2;
    for(int i = 2; i <= possiblePrimeCount; ++i) {
        if( in % i == 0 )
            return 0;
    }
    return in > 1 ? 1 : 0;
}

struct IntArray GetPrimes(const int in) {
    int inCopy = in;
    int len = 1;
    while(inCopy /= 10) {
        ++len;
    }

    inCopy = in;    
    int divisor = pow(10, len-1);
    int outSize = 0;
    int* out = NULL;
    for(int i = 0; i < len; ++i) {
        if(IsPrime(inCopy) > 0) {
            out = realloc(out, ++outSize);
            out[outSize-1] = inCopy;

            inCopy %= divisor;
            divisor /= 10;
        }
        else{
            break;
        }
    }
    return (struct IntArray) { .size = outSize, .data = out };
}

int main(void) {
    struct IntArray primes = GetPrimes(23);

    for(int i = 0; i < primes.size; ++i) {
        printf("%d\n", primes.data[i]);
    }

    free(primes.data);
    return 0;
}
George
  • 2,101
  • 1
  • 13
  • 27
  • But the question was not finding primes. It is specifically about removing the MSD from a decimal representation of a prime _already found_. – Clifford Jan 24 '18 at 10:20
1

You could also use a non-mathematical method for removing the MSD:

unsigned int remove_msd(unsigned int start)
{
    char  buf[100];
    unsigned int ret = 0;
    sprintf(buf, "%u", start);
    buf[0] = ' ';
    sscanf(buf, " %u", &ret);
    return(ret);
}
TonyB
  • 927
  • 6
  • 13
  • You can simply convert `&buf[1]` rather then blanking `buf[0]`, and `sscanf()` will ignore leading space in a `%u` conversion in any case, so just `"%u"` is needed rather than `" %u"`. – Clifford Jan 24 '18 at 10:29