Videos
In reviewing your code and the comments above, often times it comes down to the context of the problem being solved. In this case, since the program is working with integer values, and the "pow" function is meant for floating point functionality as noted in the good comments above, it would be wise to devise an alternative to using that function which only involves integers.
In this case with the context of what the program is trying to accomplish, one could write a small integer type power function, or even simpler, just utilize a simple loop to derive the power of an integer digit. Following is a quick refactored bit of code that replaces the "pow" function with a "for" loop.
while (num1 > 0)
{
remainder = num1 % 10;
/* Replacement of the function with a loop */
//rem = pow(remainder, number_of_digits);
rem = 1;
for (int i = 0; i < number_of_digits; i++)
{
rem = rem * remainder;
}
/* End of replacement */
printf("the rem is %d\n", rem);
total = total + rem;
printf("the total is %d\n", total);
num1 = num1 / 10;
}
Testing this out with your value of "153" and with a four-digit test number results in the following terminal output.
@Vera:~/C_Programs/Console/Armstrong/bin/Release$ ./Armstrong
Enter the number you want to check : 153
the rem is 27
the total is 27
the rem is 125
the total is 152
the rem is 1
the total is 153
The number entered is an armstrong number
@Vera:~/C_Programs/Console/Armstrong/bin/Release$ ./Armstrong
Enter the number you want to check : 1634
the rem is 256
the total is 256
the rem is 81
the total is 337
the rem is 1296
the total is 1633
the rem is 1
the total is 1634
The number entered is an armstrong number
Keep in mind, this is just one of an assortment of methods that can be used to provide the desired solution. But give that a try and see if it meets the spirit of your project.
By reviewing the comments above, I have written the program: Hope this helps
#include<stdio.h>
#include<math.h>
int main(){
int n,i,cnt=0,sum = 0;
printf("Enter number: ");
scanf("%d",&n);
for(i=n;i!=0;cnt++,i/=10);
for(i=n;i!=0;sum += (int)round(pow(i%10,cnt)),i/=10);
printf(sum==n?"Armstrong":"Not Armstrong");
return 0;
}
Something popped in my head: It's really simple to use pow() with unsigned integers...
int my_pow(unsigned int x, unsigned int y)
{
int it;
for(it = 0; it != y; ++it) x *= x;
return x;
}But what about using double vars? How is this thing even possible?
EDIT: Disregard this post, I had a brain fart, thinking I needed pow() to square a number. derp
All the guys who tell me that multiplication is super duper fast, have clearly never looked upon the implementation of pow() in glibc.
I couldn't find it, but this post https://stackoverflow.com/a/40824893 went down the usual header rabbit hole and tracked it down.
https://github.com/lattera/glibc/blob/master/sysdeps/ieee754/dbl-64/e_pow.c
I can already see I can throw out most of the checks for my specific usecase and make it a billion times faster by default without having to benchmark it.
The people say you have to use ln linus linux I don't remember what the natural something nubmer is called, and the e number. Man, that's already 2 imaginary values you have to use and already 2 other functions like man how can this ever be fast.
Is there some cheap trick with a good accuracy?
Maybe I should look at the musl implementation they at least focus on readability even if it's not the fastest possible, maybe that should be my first place to get an idea what's going on.
EDIT: Ok, maybe not, I literally died 💀 trying to read this
If you're curious how the pow function might be implemented in practice, you can look at the source code. There is a kind of "knack" to searching through unfamiliar (and large) codebases to find the section you are looking for, and it's good to get some practice.
One implementation of the C library is glibc, which has mirrors on GitHub. I didn't find an official mirror, but an unofficial mirror is at https://github.com/lattera/glibc
We first look at the math/w_pow.c file which has a promising name. It contains a function __pow which calls __ieee754_pow, which we can find in sysdeps/ieee754/dbl-64/e_pow.c (remember that not all systems are IEEE-754, so it makes sense that the IEEE-754 math code is in its own directory).
It starts with a few special cases:
if (y == 1.0) return x;
if (y == 2.0) return x*x;
if (y == -1.0) return 1.0/x;
if (y == 0) return 1.0;
A little farther down you find a branch with a comment
/* if x<0 */
Which leads us to
return (k==1)?__ieee754_pow(-x,y):-__ieee754_pow(-x,y); /* if y even or odd */
So you can see, for negative x and integer y, the glibc version of pow will compute pow(-x,y) and then make the result negative if y is odd.
This is not the only way to do things, but my guess is that this is common to many implementations. You can see that pow is full of special cases. This is common in library math functions, which are supposed to work correctly with unfriendly inputs like denormals and infinity.
The pow function is especially hard to read because it is heavily-optimized code which does bit-twiddling on floating-point numbers.
The C Standard
The C standard (n1548 §7.12.7.4) has this to say about pow:
A domain error occurs if x is finite and negative and y is finite and not an integer value.
So, according to the C standard, negative x should work.
There is also the matter of appendix F, which gives much tighter constraints on how pow works on IEEE-754 / IEC-60559 systems.
The second question (why does it return a domain error) is already covered in the comments, but adding for completeness: pow takes two real numbers and returns a real number. Applying a rational exponent on a negative number takes you out of the domain of real numbers into the domain of complex numbers, which the result of this function (a double) can't represent.
If you're curious about the actual implementation, well, there are many and it depends on many factors, such as architecture and level of optimisation. It's quite difficult to find one that reads easily, but FDLIBM (Freely Distributable LIBM) has one which has at least has a good explanation in the comments:
/* __ieee754_pow(x,y) return x**y
*
* n
* Method: Let x = 2 * (1+f)
* 1. Compute and return log2(x) in two pieces:
* log2(x) = w1 + w2,
* where w1 has 53-24 = 29 bit trailing zeros.
* 2. Perform y*log2(x) = n+y' by simulating muti-precision
* arithmetic, where |y'|<=0.5.
* 3. Return x**y = 2**n*exp(y'*log2)
*
* Special cases:
* 1. (anything) ** 0 is 1
* 2. (anything) ** 1 is itself
* 3. (anything) ** NAN is NAN
* 4. NAN ** (anything except 0) is NAN
* 5. +-(|x| > 1) ** +INF is +INF
* 6. +-(|x| > 1) ** -INF is +0
* 7. +-(|x| < 1) ** +INF is +0
* 8. +-(|x| < 1) ** -INF is +INF
* 9. +-1 ** +-INF is NAN
* 10. +0 ** (+anything except 0, NAN) is +0
* 11. -0 ** (+anything except 0, NAN, odd integer) is +0
* 12. +0 ** (-anything except 0, NAN) is +INF
* 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
* 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
* 15. +INF ** (+anything except 0,NAN) is +INF
* 16. +INF ** (-anything except 0,NAN) is +0
* 17. -INF ** (anything) = -0 ** (-anything)
* 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
* 19. (-anything except 0 and inf) ** (non-integer) is NAN
*
* Accuracy:
* pow(x,y) returns x**y nearly rounded. In particular
* pow(integer,integer)
* always returns the correct integer provided it is
* representable.
*
* Constants :
* The hexadecimal values are the intended ones for the following
* constants. The decimal values may be used, provided that the
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
So, in short, the mechanism is as you described it and relies on calculating the logarithm first, but with many special cases that need to be accounted for.