1

I am a new C-learner and trying to find Vampire Numbers from 10 to 1 million.

Vampire Number: http://en.wikipedia.org/wiki/Vampire_number

The code is ready but, It doesn't work as It is supposed to. It just continues searching for a long time without printing anything and a while later prints enormous numbers. I couldn't figure out what the problem is and this is what code looks like:

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

#define true 1
#define false 0

int main(void){
   int i,j,t,s,m,n,counter=0;

   for(i=10; i<100; i++){
      m = Control2Digits(i);
      if(m == true){
         counter++;
         printf("%d.Vampire number: %d \n", counter, i);
      }
   }

   for(j=1000; j<10000; j++){
     m = Control4Digits(j);
     if(m == true){
         counter++;
         printf("%d.Vampire number: %d \n", counter , j);
      }
   }

   for(t=100000; t<1000000; t++){
      for(s=100000; s<1000000; s++){
         m = Control6Digits(s,t);
         if(m == true){
            n = (s*t);
            counter++;
            printf("%d.Vampire number: %d \n", counter, n);
         }
      }
   }
}

int Control2Digits(int number){
   int n1,n2;

   n1 = number%10;
   n2 = (number-n1)/10;

   if(n1*n2 == number)
      return true;

   return false;

}

int calculate4(int s1, int s2, int s3, int s4){
   int p1,p2;
   p1 = (s1*10)*s2;
   p2 = (s3*10)*s4;
   return (p1*p2);
}

int Control4Digits(int number){

   int g1,g2;
   int t1,t2,t3,t4;

   if(number%100 == 0)
      return false;

   g1 = number/100;
   g2 = number%100;
   t1 = g1/10;
   t2 = g1%10;
   t3 = g2/10;
   t4 = g2%10;

   if(calculate4(t1,t2,t3,t4) == number)
      return true;
   else if(calculate4(t2,t1,t3,t4) == number)
      return true;
   else if(calculate4(t2,t1,t4,t3) == number)
      return true;
   else if(calculate4(t1,t2,t4,t3) == number)
      return true;
   else if(calculate4(t1,t3,t2,t4) == number)
      return true;
   else if(calculate4(t3,t1,t2,t4) == number)
      return true;
   else if(calculate4(t1,t4,t2,t3) == number)
      return true;
   else if(calculate4(t1,t3,t4,t2) == number)
      return true;
   else if(calculate4(t4,t1,t2,t3) == number)
      return true;
   else if(calculate4(t3,t1,t4,t2) == number)
      return true;
   else if(calculate4(t1,t4,t3,t2) == number)
      return true;
   else if(calculate4(t4,t1,t3,t2) == number)
      return true;

   return false;

}

int Control6Digits(int num1, int num2){
   long int k,l,m,n,c;
   k = num1%10;
   l = num2%10;

   if(k + l == 0)
      return false;
   else{
      m = (num1*num2);
      n = (num1*1000+num2);

      if(a == g)
         return true;
      c = true;
   }

   return false;
}
Sixie
  • 83
  • 1
  • 10

3 Answers3

1

Change:

p2 = (s3*10)*s3;

To:

p2 = (s3*10)*s4;

And another small piece of advice: change int and long to unsigned long long in all places within your code, in order to prevent calculation-overflow for large inputs.

barak manos
  • 29,648
  • 10
  • 62
  • 114
1
int calculate4(int s1, int s2, int s3, int s4) {
   int p1,p2;
   p1 = (s1*10)+s2;
   p2 = (s3*10)+s4;
   return (p1*p2);
}

you are rebuilding the two parts with * instead of +

then you got for example

    1.Vampire number: 1260
    2.Vampire number: 1395
    3.Vampire number: 1435
    4.Vampire number: 1530
    5.Vampire number: 1827
    6.Vampire number: 2187
    7.Vampire number: 6880
BeerBaron
  • 388
  • 6
  • 18
1

Beer Baron has already pointed out your error for the four-digit vampire numbers.

The logic for your six-digit numbers is not implemented properly and also unclear. (In the posted state, it won't compile: What is a, what is g?) If you followed your logic of the four-digit code, you'd have to check 360 combinations for each number, which is a bit much.

Also, I hope you are not surprised that your code takes so long to execute: You have two nested loops from 100,000 to 1 million, i.e of 900,000 each. That's 810 billion iterations.

Your four-digit code works in principle and is okay if you want to check single numbers for vampireness. If you want to identify all vampire numbers of a certain range, you should use a "spread" approach: Instead of iterating v = a * b from 1,000 to 10,000, try two nested loops for a and b from 10 to 100. (b doesn't have to start from 10 each time. For example, if a is 20, it suffices to start from 50 , because any product for a lower b will have less digits.)

(This method is a bit like using the Sieve of erathostenes for finding prime numbers. It's not the same, because you still have to test your suspects. A drawback of this solution is that you will not find your vampire numbers in ascending order. You will find 1395 == 15 * 93 before 1260 == 21 * 60, for example. If your numbers must be ordered, store them in an array and sort it before printing.)

You will now have to come up with an efficient method to compare the digits. A simple solution is to have an array with counters for each digit. Start with all counters equal zero, add the digits of the suspected vampire number, subtract the digits of the fangs and if you end up with all zeros again, you've found a vampire number.

Another solution is to print the alleged vampire number to a string, the two fangs to another string, sort the strings by character and compare them.

You could probably also fiddle with bit-masks, but because the count of the numbers must match, too, it is not enough to set bits for certain digits. For numbers up to one million, you can add powers of 8, for example 8^3 for the digit 3.

An approach that I like is to use products of prime numbers to identify the digits. You have to take care with integer overflow, but for numbers of up to one million, you're safe:

typedef unsigned int uint;

uint fact(uint a)
{
    static uint primes[10] = {2, 3, 5, 7, 11, 13, 17, 23, 29, 31};
    uint r = 1u;

    while (a) {
        r *= primes[a % 10];
        a /= 10;
    }

    return r;
}

Then you can test the fangs and the number like so:

v = a * b;
if (fact(a) * fact(b) == fact(v)) printf("%u\n", v);
M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • I thought that : `for(i=100; i<1000; i++){ for(j=i; j<1000; j++){ m = i*j; } }` That nested loop gives me all 6-digit numbers, which are got by multiplying two 3-digit numbers.But, the problem is I couldn't come up with a good idea about how to find out if one of them is a vampire number. – Sixie Feb 07 '14 at 18:24
  • Also, I seperated all digits as a number to get a vampire number. But, It is the last point I have come. – Sixie Feb 07 '14 at 18:28
  • @Sixie: Well, there's no need to separate anything. You have the factors `i` and `j` and the procuct `m` already, you just have to check that the digits in `1000 * i + j` and in `m` are the same. And the lowest bound can be `j = max(100 * 1000 / i, i)`. – M Oehm Feb 07 '14 at 18:32
  • `for(i=100; i<1000; i++){ for(j=i; j<1000; j++){ m = i*j; n = (1000*i)+j; p = (1000*j)+i; if(m==n || m==p) printf("%d", m); } }` If I understood you correctly. It still has problem. – Sixie Feb 07 '14 at 18:46
  • @Sixie: No, you did not understand correctly. I said that you have to check whether the digits are the same. You are just checking two possibilities. (Even worse: You are checking two cases that cannot be possible. Think about how a `x*i` cannot be equal to `1000*i` or `1000*i + j` when `x` is less than `1000`.) In my post above I have outlined various methods to check the digits and I've even provided code for one of them. – M Oehm Feb 07 '14 at 18:55