pow() function in C problems [duplicate] - c

This question already has answers here:
Strange behaviour of the pow function
(5 answers)
Closed 5 years ago.
I am having some problems with pow() function in C. When ever run this code, 153 as input, the sum evaluates to 152. However if I dont use pow() function and instead use a for loop to get the value of Nn, the sum evaluates to 153. Can anyone help please explain me this difference?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
int main(void) {
unsigned int i, n, sum = 0, N, a = 1, j;
char num[100], x[2] = { 0 };
printf("Determining an armstrong number\n\n"
"Enter a number: ");
fflush(stdin);
gets(num);
n = strlen(num);
for (i = 0; i < n; i++) {
a = 1;
x[0] = num[i];
N = atoi(x);
/* for (j = 1; j <= n; j++)
a *= N;
*/
sum += pow(N, n);
}
n = atoi(num);
if (sum == n)
printf("\nIt is an Armstrong number!\n");
else
printf("\nIt is not an Armstrong number!\n");
return 0;
}

Your C implementation, including its math library, has a bad implementation of pow that returns inaccurate results. (A good pow implementation returns an exact result when the mathematical result is exactly representable in the floating-point format.) For example, for pow(7, 2), your pow may be returning a value slightly under 49. When this is converted to an unsigned int (in the addition to sum), it is truncated, resulting in 48.
To work around this defect in your library, do not use pow for integer arithmetic. Write your own integer arithmetic to get the result you desire. In some circumstances, using round(pow(N, n)) may suffice, but there are considerations of the range of values for which this will work (wide integers may be able to represent integers that double cannot) and sometimes performance. (Another workaround is to get a better C implementation.)

Related

Weird compilation issues

#include <stdlib.h>
#include <math.h>
#include <stdio.h>
int rev (int N);
int rev(int N){
return ((N <= 9)) ? N : rev(N / 10) + ((N % 10) * (pow(10, (floor(log10(abs(N))))))) ;
}
int main(void){
int r, n;
scanf("%d", &n);
r = rev(n);
printf("%d %d", r, n);
return EXIT_SUCCESS;
}
A simple code just to find out the reverse of a number. Everything is fine. Until I put a number with more than 2 digits. Things behave weirdly, somehow the last digit is always 0 of the reversed number. I have checked out in online compilers where things behave just fine. However the problem arises when I run the code on my own machine. I am on Windows 10 with MINGw. Could you guys suggest me a solution. I previously had problems where the value stored in an int matrix changes to huge values which is practically impossible to store in int due to it's size.
Using the pow and floor function, working with floats will not always round the way you'd expect.
As already commented, work with integers.
Propose doing this digit-by-digit, and sticking with integers. A proposal for your rev() function:
int rev(unsigned int N)
{
unsigned int res = 0;
while(N>0)
{
// pick off lowest digit
unsigned int digit = N%10;
// put into result, moving up all previous digits by doing *10
res = 10*res+digit;
// remove this digit from input value
N/=10;
}
return res;
}

Factorial function only counts to 12

This factorial function starts giving wrong results with 13 and above. I have no idea why.
#include <stdio.h>
int fatorial (int p);
int main() {
int x = 13;
int test = fatorial(x);
printf("%d", test);
}
int fatorial (int p) {
if (p <= 0)
return 1;
else
return p*fatorial(p-1);
}
for x = 0, 1, 2 ...12 it prints the right result, but for 13! it prints 1932053504 which is not correct.
For x=20 it prints -210213273 for example.
I know that this is not the best way to do a factorial. Its my homework tho, it HAS to be this way.
If you try this you will get the maximum value that int can hold:
#include <stdio.h>
#include <limits.h>
int main(void)
{
printf("%d\n", INT_MAX);
}
Your code causes overflow.
You could get a few more numbers if you use a bigger type, but not by very much. You could use this:
unsigned long long fatorial (unsigned long long p) {
if (p <= 0)
return 1;
else
return p*fatorial(p-1);
}
It won't get you far though. If you want bigger than that you need to find a library for bigger integers or create some custom solution. One such library is https://gmplib.org/ but that is likely out of scope for your homework.
And btw, a condition like p <= 0 is not good. It indicates that the factorial of a negative number is always one, which is false.
It is because after 12, the result of factorial of any number exceeds the size of int.
you can try the following code:
#include<stdio.h>
int main()
{
int a[100],n,counter,temp,i;
a[0]=1;
counter=0;
printf("Enter the number: ");
scanf("%d",&n);
for(; n>=2; n--)
{
temp=0;
for(i=0; i<=counter; i++)
{
temp=(a[i]*n)+temp;
a[i]=temp%10;
temp=temp/10;
}
while(temp>0)
{
a[++counter]=temp%10;
temp=temp/10;
}
}
for(i=counter; i>=0; i--)
printf("%d",a[i]);
return 0;
}
The result of the function is too big. I think big int would work better for your purposes. Big int allows you to have bigger numbers. Also, this is what I would do.
int x = the number you want to factorialize
int ans = 1;
(Then instead of all of those functions)
for(var i = x; i > 0; i--) {
ans = ans*i;
}
System.out.println(ans);
Javascript link: https://jsfiddle.net/8gxyj913/
I need to get to 100!
100! is about 9.332622e+157. Simply using standard integer types is insufficient. 32-bit int is good to 12!. With 64-bit integer math, code could get to about 21!
Could use floating point math and give up precision.
Instead consider a string approach.

Casting float to int doesn't work properly in C

I tried to solve a task on codewars and happened something strange, in one case casting worked as usual and in the second o got strange behavior. Here is the code:
#include <stdio.h>
#include <string.h>
#include <math.h>
int digital_root(int n) {
char tmp[30];
char *ptr;
while(n > 9){
sprintf(tmp, "%d", n);
int len = strlen(tmp);
float n_tmp = n / (pow(10, len));
n = 0;
for(int i = 1; i <=len; i++){
float t = n_tmp * (pow(10, i));
printf(" vars = [%f , %d] ", t, (int)t); //this line
n += (int) t;
n_tmp -= (int)t/pow(10,i);
}
}
return n;
}
int main()
{
digital_root(16);
return 0;
}
And the line printf(" vars = [%f , %d] ", t, (int)t); outputs: vars = [1.600000 , 1] vars = [6.000000 , 5], what is so strange. Can someone explain this behavior?
Every casting float to int is a rounding, so every time you do it, stop for a second and think: what kind of rounding do I need this time? Dropping the fractional part? floor()? ceil()? Or rounding positive float towards nearest int? If 5.999999999999 should be 6, use (int)(t+.5), not (int)t.
Or you can mimic the printf behavior and round only the smallest float fraction, which can vary (depending on the biggest value you use). (int)(t+.000001) will round both 1.9 to 1 (as it probably should), and 3.9999999999 to 4 (because it is 4 with some tiny number representation errors).
You should however know the size of a fraction which can be an actual, meaningful part of your data. Everything smaller than this fraction must be rounded. It can be either .00000001 or .5, that depends on your needs and the algorithm itself.

pow function gives unwanted result c

for an assignment i've been asked to write a program that calculates Geometric and arithmetic mean in regular c.
i wrote this function:
double Geometric_mean(int number[], int n) //number[5]={1,2,3,4,5},n=5
{
int i;
double mean = 1;
for (i = 0;i < n;i++)
{
mean =mean*number[i];
}
mean = pow(mean,1/n); //mean=120
return(mean); //mean=1
}
i get the desired result before the pow turns it to 1 instead the of the desired 2.605
Since 1and n are ints, 1/n is an euclidean division whose result is 0 for any n > 1.
You should use a double division:
#include <cstddef>
#include <cmath>
double gmean(const int data[], std::size_t datasize)
{
double product = 1.0;
for (std::size_t i = 0 ; i < datasize ; i++)
{
product *= data[i];
}
return std::pow(product, 1.0/datasize);
}
Live example.
Note that I've answer in C++. C and C++ are two separate languages and you should choose which one to use beforehand.
You using integral division pow(mean,1/n); the result of 1/n is zero if n > 1. You should convert it to float or double :
pow(mean,1.0/n);
or
pow(mean,1/(double)n);

Generate a random double between -1 and 1

I've been working on this for some time and having a lot of trouble. I want to generate a random value from -1 to 1 for a calculation. I cant use the % operator because it is for integers only. I also tried using fmod() but I'm having difficulty here too.
What I was trying to use was...
double random_value;
random_value = fmod((double) rand(),2) + (-1);
it seems like it's not correct though. I also tried to seed srand with the time, but I think im doing something wrong there because it keeps throwing this error:
"error: expected declaration specifiers or '...' before time"
code:
srand((unsigned) time(&t));
any help with these problems would be appreciate.
You can seed with time (once before all calls to rand) like this:
#include <time.h>
// ...
srand (time ( NULL));
With this function you can set the min/max as needed.
#include <stdio.h>
#include <stdlib.h>
/* generate a random floating point number from min to max */
double randfrom(double min, double max)
{
double range = (max - min);
double div = RAND_MAX / range;
return min + (rand() / div);
}
Source: [SOLVED] Random double generator problem (C Programming) at Ubuntu Forums
Then you would call it like this:
double myRand = randfrom(-1.0, 1.0);
Note, however, that this most likely won't cover the full range of precision available from a double. Without even considering the exponent, an IEEE-754 double contains 52 bits of significand (i.e. the non-exponent part). Since rand returns an int between 0 and RAND_MAX, the maximum possible value of RAND_MAX is INT_MAX. On many (most?) platforms, int is 32-bits, so INT_MAX is 0x7fffffff, covering 31 bits of range.
This will seed the random number generator and give a double in the range of -1.0 to 1.0
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
double random_value;
srand ( time ( NULL));
random_value = (double)rand()/RAND_MAX*2.0-1.0;//float in range -1 to 1
printf ( "%f\n", random_value);
return 0;
}
I think the best way to create a real random double is to use its structure. Here's an article about how float numbers are stored. As you see the only limiting condition for float to be between 1 and -1 is that the exponent value doesn't exceed 128.
Ieee754SingleDigits2Double converts string of 0s and 1s to a float variable and return it. I got it from the answers to this question.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
double Ieee754SingleDigits2Double(const char s[32])
{
double f;
int sign, exp;
unsigned int mant;
int i;
sign = s[0] - '0';
exp = 0;
for (i = 1; i <= 8; i++)
exp = exp * 2 + (s[i] - '0');
exp -= 127;
if (exp > -127)
{
mant = 1; // The implicit "1."
exp -= 23;
}
else
{
mant = 0;
exp = -126;
exp -= 23;
}
for (i = 9; i <= 31; i++)
mant = mant * 2 + (s[i] - '0');
f = mant;
while (exp > 0)
f *= 2, exp--;
while (exp < 0)
f /= 2, exp++;
if (sign)
f = -f;
return f;
}
Here's the main function:
int main(void)
{
srand ( time ( NULL));
int i;
char s[33];
for(i = 0; i < 32; i++)
{
if(i == 1)
continue;
s[i] = rand() % 2 + '0';
}
s[1] = '0';
s[32] = 0;
printf("%s\n", s);
printf("%+g\n", Ieee754SingleDigits2Double(s));
return 0;
}
Probably not a good idea to do so, but just because it works, here's a way of generating a random double between -1 and 1 included using /dev/urandom and cos():
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
int main()
{
int fd;
double x;
fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
return (1);
read(fd, &x, sizeof(x));
close(fd);
x = cos(x);
printf("%f\n", x);
return (0);
}
Similar to other answers, with a few improvements you might need to keep your code a bit safer and coherent:
#include <stdlib.h> /* srand and rand */
#include <unistd.h> /* getpid */
#include <time.h> /* time */
#include <errno.h> /* errno */
#include <math.h> /* NAN */
/* generate a float random number in a range */
float randmm(float min, float max)
{
static int first = -1;
if((first = (first<0)))
srand(time(NULL)+getpid());
if(min>=max)
return errno=EDOM, NAN;
return min + (float)rand() / ((float)RAND_MAX / (max - min));
}
Going through the code we have:
A static variable first that will guarantee you don't forget to seed the pseudo-random number generator (PRNG). The logic is simple and elegant: in the first call, first is -1, it is then compared to be less than zero, which updates it to true (value 1). The second call asks if first, now 1, is less than zero, which is false (value 0), so srand() isn't called. Third is a charm, they say, so now first, which is 0, is asked if it is less than zero, which keeps being false for this and the next iterations.
Next, you might need to guarantee that min-max is not zero, or else you will get a nasty division by zero (or NAN). For that we shall explicitly cause the correct error. Using errno.h to set the error and math.h to have NAN (not a number) macro available. It is not advisable to compare two floats for equality (like if(min==max)) so it is not a good idea to try to invert the min/max values in case min is greater, and have a third option in case they are equal. Just simplify your if with only two options: it is right, or it is not.
Finally, I've preferred to work with float instead of double to not give too much trust on what this function can generate. A 32 bits integer (which is RAND_MAX) can only do so much. To fill a float is reasonable, for all bits. float has only 23 bits for the number, plus 8 for exponent. If you use double you will be mislead and overconfident in the capacity of this function. If you need a true double, consider using /dev/urand or other proper true random number generator (TRNG).
The last line, the return, is just a simple equation. I guess you can figure that out easily. I just like to explicitly cast to float so I can see the code's intention besides the compiler's interpretation.
And of course, to use as OP want, just call as float x = randmm(-1.0, 1.0);
This answer mostly applies to people looking for random doubles on x86_64 machines.
Being a long time C user (since late 1980s), I gave up caring what the RAND_MAX value of the day is.
Also, the srand(time(NULL) indicates to me that the numbers are generated with some quasi random number generator of (at least to me) unknown quality. And all that, while you are just 1 assembly instruction away from CPU random numbers on modern x86_64 machines.
So, the code below uses rdrand via intrinsics, which is known to be a full 64bit random number as a source of randomness. This way, at least, you have sufficient bits to generate a double without further ado. If - instead - you opted for C library rand() and it returned a 32 bit value, you might have not enough bits for a 64 floating point number. And there is no randl(), randul() or alike in Ansi C, afaik.
But - if you look at the signature of the _rdrand_step() intrinsic, it seems like this instruction might fail under certain conditions. (Load related, some say). So, in the code below, it might (or might not) be a good idea to write a while() loop or something like that around the intrinsic call.
#include <stdio.h>
#include <stdint.h>
#include <immintrin.h>
#include <float.h>
int randomf64(double minVal, double maxVal, double* out) {
if (NULL == out)
return 0;
uint64_t result = 0ULL;
// cast in next line works for amd64 (x86_64) on linux at least.
int rc = _rdrand64_step((unsigned long long*)&result);
if(rc) {
double unscaled = (double)result/(double)UINT64_MAX;
*out = minVal + (maxVal - minVal) * unscaled;
return 1;
}
return 0;
}
int main(int argc, const char* argv[]) {
size_t nvals = 1;
if(argc > 1) {
nvals = atol(argv[1]);
}
// We want to see if all that "can fail under stress" thing happens...
double *values = malloc(nvals * sizeof(double));
if (NULL != values) {
for(size_t i = 0; i < nvals; ++i ) {
if(!randomf64(-100.0,100.0, &values[i])) {
printf("boom! after %lu random numbers generated.\n",
i);
free(values);
exit(-1);
}
}
for(size_t i = 0; i < nvals; ++i) {
int Digs = DECIMAL_DIG;
printf("%lu %.*e\n", i, Digs, values[i]);
}
free(values);
}
return 0;
}
If you supply an integer as a command line argument, it generates a respective
number of random doubles and stores them in a heap allocated array.
This allows for testing if that "sporadic failing" might happen. I tried several times with up to 1E6 values created in a burst and it never failed (on some cheap AMD CPU).
In order to compile this, e.g. with clang, I used:
clang -mrdrnd -O3 -std=c17 -o r64i r64intrin.c
Please note, that you have to enable the usage of the intrinsic with -mrdrnd for the compiler to be happy.
For higher precision:
double random() {
unsigned int rnd;
rnd = (rand() & 0x7fff) | ((rand() & 0x7fff) << 15);
return (double)rnd / (double)(0x3fffffff);
}
Of course it would be possible to add a full 32 bit precision or even a long precision to this. But RAND_MAx is as someone stated 15bits, and would need more calls to rand() and then 'or' them together in a similar fashion.
There are a lot of rand(min, max) solutions here, so I won't comment on that. If you need full range random double (from lowest possible to highest possible):
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
// full range uint32_t rand - from 0 to UINT32_MAX
uint32_t rand32() {
// in in mingw32 RANDMAX is 32767
#if RAND_MAX < 32768
union {
uint16_t i[2];
uint32_t l;
} n;
uint16_t t; // we need two more bits
n.i[0] = rand(); // first 16 bits
n.i[1] = rand(); // last 16 bits
t = rand();
if ((t & 0x01) != 0) { // add the MSbit
n.i[0] |= 0x8000;
}
if ((t & 0x02) != 0) { // add the MSbit
n.i[1] |= 0x8000;
}
return n.l;
#else
// USUALLY RAND_MAX is 2147483647 (or 0x7FFFFFFF) - missing the MSbit
uint32_t l;
uint32_t t;
l = rand();
t = rand();
if ((t & 0x01) != 0) { // add the MSbit
l |= 0x80000000;
}
return l;
#endif
}
// full range random double
double randDouble() {
union {
uint32_t i[2];
double d;
} num;
num.i[0] = rand32();
num.i[1] = rand32();
return num.d;
}
int main(int argc, char *argv[]) {
time_t result = time(NULL);
srand(result);
printf("random uint32: %0x08X\n", rand32());
// up to 200 digits after the decimal point. Sometimes the number is really small
printf("random double: %lE\n", randDouble());
}
After search a lot to this and getting tips from around, i create this function to generate random double number in specific range.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
double random(double min, double max)
{
//used it to generate new number each time
srand( (unsigned int) time(NULL) );
double randomNumber, range , tempRan, finalRan;
//generate random number form 0.0 to 1.0
randomNumber = (double)rand() / (double)RAND_MAX;
//total range number from min to max eg. from -2 to 2 is 4
//range used it to pivot form -2 to 2 -> 0 to 4 for next step
range = max - min
//illustrate randomNumber to range
//lets say that rand() generate 0.5 number, thats it the half
//of 0.0 to 1.0, show multiple range with randomNumber we get the
//half in range. eg 4 * 0.5 = 2
tempRan = randomNumber * range;
//add the min to tempRan to get the correct random in ours range
//so in ours example we have: 2 + (-2) = 0, thats the half in -2 to 2
finalRan = tempRan + min;
return finalRan;
}
This is working illustrating the rate % of random number in ours range.
random_value = (double)rand() * rand() / (RAND_MAX * RAND_MAX) * 2 - 1;
There is an easy way to get random value in range [-1.0; 1.0] Trigonometric function sine takes a number returned by rand() and returns value in that range.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
/* macro returning value in range [-1.0; 1.0] */
#define double_rand() ( sin(rand()) )
int main(void) {
int i;
srand(time(NULL));
/* 20 tests to show result */
for ( i = 0; i < 20; ++i )
printf("%f\n", double_rand());
return 0;
}
On linux systems don't forget to link the math library
$ gcc -Wall sin_rand.c -lm
$ ./a.out
0.014475
-0.751095
-0.650722
0.995111
-0.923760
...

Resources