1

I am trying to program a method that determines if a given number is an armstrong number. An armstrong number can be found by the steps below:

  1. Take base digits ie 456 => 4, 5, 6
  2. Power to the number of digits ie 456 has 3 digits, so pow = 3
  3. Power each base by the pow ie 4^3, 5^3, 6^3
  4. Total all sums ie 64 + 125 + 216 = 405
  5. If sum equals original number, is armstrong ie 405 != 456, so not armstrong.

    int armstrong(float number){
    
      if(number < 1){
        return 0;
    }
    else{
        float *pointer = malloc(sizeof (float)), *temp;
        if(pointer == NULL){
            printf("Error allocating memory: math::armstrong.\nReturn value 0.");
            return 0;
        }
        else{
            int temp_boolean = 1, index = 0;
            float sum = 0, original_number = number;
    
            while(temp_boolean == 1){
                if(number / 10 == 0){
                    temp_boolean = 0;
                }
                else{
                    temp = realloc(pointer, ((sizeof pointer / sizeof (float)) + 1) * sizeof (float));
                    pointer = temp;
                }
                pointer[index] = fmod(number, 10.0);
                //pointer[index] = number % 10;
                number /= 10;               
                ++index;
            }
            int i;
            for(i = 0; i < index; ++i){
                float temp_e = pointer[i];
                sum += pow(temp_e, index);
            }
            free(pointer);
            if(sum == original_number){
                return 1;
            }
            else{
                return 0;
            }
        }       
    }
    

    }

My program returns 1 if given number is an armstrong number or 0 if it is not. Now, this works fine when i have the variables and params as an int, but i want to be able to recieve bigger numbers, which is why my code has variables in float. But for some reason, it is not giving any output. It compiles fine with gcc with the -Wall option, so i don't know what im doing wrong.

I'm using notepad++ to write my program, and gcc to compile.

JShade01
  • 153
  • 12
  • 2
    Why do you `malloc(sizeof(int))` for a `float *`? – EOF Aug 13 '15 at 09:54
  • @HighPerformanceMark thanks for the post, it helped me understand float math better, however i dont think this is the case here. Some about my fmod() or around there is off when i use any other than int. If it was just a math error my program should return a value of 1. But nstead, without using int, my progran returns Nothing. – JShade01 Aug 13 '15 at 09:56
  • 1
    `temp = realloc(pointer, ((sizeof pointer / sizeof (float)) + 1) * sizeof (float));`? You don't understand `sizeof()`. – EOF Aug 13 '15 at 09:56
  • @EOF sorry i did a rough quick replace All, and my text editor didn't get that. I'll fix it, but the problem stil persists. And from what i have read, sizeof isn't a method – JShade01 Aug 13 '15 at 09:58
  • 1
    The problem is that `sizeof (pointertype)` returns the size of the `pointertype`-object, not the size of the pointed-to memory. – EOF Aug 13 '15 at 09:59
  • @DevSolar what can i use instead of float if i want really big numbers? – JShade01 Aug 13 '15 at 10:00
  • @EOF a quick google search let me find this http://stackoverflow.com/questions/6751749/size-of-a-pointer so i can correct my mistake. If you can find a better way of getting the number of elements, please do tell. – JShade01 Aug 13 '15 at 10:02
  • You need to keep track of the size of the allocation in a separate variable (I'd recommend a `size_t`). – EOF Aug 13 '15 at 10:04
  • do you know for which float values `if(number / 10 == 0)` will be true? You have to loop very often for this. – mch Aug 13 '15 at 10:38
  • @JShade01: Turned my comments into an answer. – DevSolar Aug 13 '15 at 13:40
  • Thank you everyone for your input and help, i will update the question if i run into more problems with this. – JShade01 Aug 13 '15 at 19:16

2 Answers2

4

Variables of type float support a larger range of values but achieve this by not representing every possible value in a range. For example, assuming a float is of size 32 bits and an int is 32 bits, there are some integral values that an int can represent but a float cannot.

Your code relies on an assumption, made by you, that a float can represent every integral value. In cases where that assumption is incorrect - which will at least some larger integral values - your function will malfunction.

If you want your function to work for large values, try finding a way to represent larger integral values(in the sense of exceeding the range a built in type can represent). There are many options for doing this, but one way is to pass an array of char, where every element in the array represents an integral digit (say, 0-9). The trade-off with that is that you will need to simulate all operations you use (division, modulo, summation, multiplying by a power of ten, etc) on your chosen representation.

Peter
  • 35,646
  • 4
  • 32
  • 74
3

Using float because you "want to store bigger numbers" is a bad idea. float has only ~6 digits of precision, so once you start storing millions, you're losing precision in the ones already. The double type, which is the "default" floating point size anyway, has ~15 digits of precision, but still its not the solution if you want to handle "really big integer numbers".

There are plenty of bignum libraries out there, gmplib being among them.

Other libraries sometimes include bignum support for their own purposes which you could also use, like the BN_ functions of OpenSSL. Just be on the lookout, and resist the temptation of reinventing the wheel -- bignum implementations are easy to find, and quite mature.

Aside from that, I see sum == original_number in your code -- since floating point numbers are not precise, checking them for equality is not a good idea either. (GCC's -Wfloat-equal can warn you of this, I suggest you add it to your list of enabled warnings.)

DevSolar
  • 67,862
  • 21
  • 134
  • 209