Stackoverflow,
I'm trying to write a (very) simple program that will be used to show how machine precision and flops effect functions around their root. My code is as follows:
#include <stdio.h>
#include <math.h>
int main(){
const float x = 2.2;
float sum = 0.0;
sum = pow(x,9) - 18*pow(x,8) + 144*pow(x,7) - 672*pow(x,6) + 2016*pow(x,5) -
4032*pow(x,4) + 5376*pow(x,3) - 4608*pow(x,2) + 2304*x - 512;
printf("sum = %d", sum);
printf("\n----------\n");
printf("x = %d", x);
return 0;
}
But I keep getting that sum is equal to zero. At first I thought that maybe my machine wasn't respecting the level of percision, but after printing x I discovered that the value of x is changing each time I run the program and is always huge (abs(x) > 1e6)
I have it declared as a constant so I'm even more confused as to whats going on...
FYI I'm compiling with gcc -lm
printf("sum = %d", sum);
sum is a float, not an int. You should use %f instead of %d. Same here:
printf("x = %d", x);
Reading about printf() format specifiers may be a good idea.
Related
Beginner in C language.
I suspect it may be due to overflow, but could not solve this simple exercise:
program to compute the sum of squares of all the natural numbers smaller than 10000
I initially tried:
#include <stdio.h>
int main() {
int a = 10000;
int square(int num) {
return num * num;
};
int total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %d and square is %d and total %d \n", a, square(a), total );
};
printf("total is %d ", total );
return total;
}
result: total is -1724114088
and here there's the strange thing:
...
a is 9936 and square is 98724096 and total 2063522144
a is 9935 and square is 98704225 and total -2132740927
...
So I tried to change total to long, tried to change declaring square function as long square(int num ), but nothing changed.
Could you explain why the sum turns negative ?
Is it due to overflow ? But why not resetting to 0 or positive, instead of going negative ?
how can I know how many bits for int are there in a computer that I don't know (e.g. cloud ?
E.g. I am coding here: [https://www.programiz.com/c-programming/online-compiler/]
Which is best practice to fix it ?
Do not define function in functions.
int main() {
int square() { // NO!
Functions belong at file scope:
int square() { //OK
}
int main() { //OK
}
The code compiles because compilers have extensions to the language. It's not part of the C programming language.
Could you explain why the sum turns negative ?
See ex. why the value of sum is coming out to be negative? and other questions. The sum "wraps around" on your platform.
Is it due to overflow ?
Yes.
But why not resetting to 0 or positive, instead of going negative ?
Because systems nowadays are twos-complement, it's simpler to implement a single hardware instruction for adding numbers then two separate instructions with special overflow semantics. Unsigned and signed twos-complement numbers behave the same when doing operations on them, so instead of doing special semantics on overflow, when adding signed numbers they are added the same as they would be unsigned (bits are just added) and the result is then interpreted as a signed number (in a C program), which because the most significant bit becomes set the number becomes negative.
Anyway, compiler just does not care, because signed overflow is undefined behavior compiler does not have to care. The compiler just generates a hardware instruction for signed addition, which behaves as explained above.
how can I know how many bits for int are there in a computer that I don't know
You can check your compiler documentation.
But usually it's simpler to just compile a simple C program where you use CHAR_BIT - the number of bits in a byte - and sizeof(int) - the number of bytes in an int - and inspect the output of that program. For example, a program such as:
#include <stdio.h>
#include <limits.h>
int main() {
printf("There are %d bits in int\n", (int)sizeof(int) * CHAR_BIT);
}
Note that number of bits in types does not only change with platform and operating systems, it can change with compiler, compiler versions and also compilation options.
Which is best practice to fix it ?
This depends on what behavior do you want.
To calculate bigger values use a bigger datatype - long or long long. When the language features are not enough, move your program to use some big number library.
If you want to terminate the program in case of problems - you can check for overflow and call abort() or similar if it happens.
Instead, you could have used a formula.
Sum of Squares of first N natural numbers = (N * (N + 1) * (2 * N + 1) / 6
For now, let N be 10000.
Ignoring the 6 in the formula, the sum of squares is as big as 10^12. It will not fit in an integer. You should use a data type that can accommodate bigger values, like long or long long int.
Here's the modified code.
#include <stdio.h>
int main() {
int a = 10000;
int square(int num) {
return num * num;
};
// Change int to long long int
long long int total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %d and square is %d and total %d \n", a, square(a), total );
};
// Change %d to %lld
printf("total is %lld ", total );
return total;
}
You'll need to change all uses of int to long:
#include <stdio.h>
int main() {
long a = 10000;
long square(long num) {
return num * num;
};
long total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
};
printf("total is %ld ", total );
return 0;
}
which prints total is 333283335000
EDIT
Or you could just change the total, the return type of square, and perform the appropriate casts when computing the squared values:
#include <stdio.h>
int main() {
int a = 10000;
long square(int num) {
return (long)num * (long)num;
};
long total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
};
printf("total is %ld ", total );
return 0;
}
Produces the same result shown above.
onlinegdb here
EDITED TO BE REOPENED
People, how are you doing?
So, I am trying to atribute the value 0.000010 to a variable, but it becomes a very huge number, and it shouldn't be the case of overflow, due to the type. And it is important to really be 0.000010, because it is used into a condition.
In the code below, it is the varibale dif. During debug, as double, 0.000010 becomes 4.571853192736056e-315. As float, it becomes 9.99999975e-06. If I print it, after atribution, it giver me the right value (0.000010), but debug shows me thos other things.
EDIT TO HELP COMPREHENSION:
What am I supposed to do? I have a PI value calculates as the Gregory-Leibniz series (Pi = 4 -4/3 + 4/5 - 4/7 +...). Each operation (-4/3 and + 4/5, for example) are iteractions. I need to aproximate this Pi to the constant M_PI, from math.h library with a maximum difference of X (a number entered by the user). For exemple, it is necessary 100002 iteractions in the serie to aproximate Pi and M_PI with a difference of 0.000010. So, in this exemple, the user chose dif = 0.000010 and got 100002 iteractions.
The problem, as I said, is that the variable dif (as double or float) can get to be 0.000010 (DEBUG IMAGES AFTER THE CODE).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
long int n = 0, iteractions = 0;
float Pi1 = 4.0, Pi2 = 0.0, sub = 0.0, sum = 0.0;
double dif = 0.0;
printf("Type the difference to be observed: ");
scanf("%f", &dif);
Pi1 = 4;
sub = Pi1 - M_PI;
for(n=1; sub >= dif; n++){
Pi2 = (pow(-1,n)*4)/(2*n + 1);
sum = Pi1 + Pi2;
Pi1 = sum;
sub = Pi1 - M_PI;
iteractions = iteractions + 1;
}
printf("Iteractions: %ld \n", iteractions);
return 0;
}
Image:
As Carcigenicate asked: What specifically is "it"? What is "it" "becoming"?
I suspect maybe you mean "iteracao" (because it's the only think you're printing), and I suspect maybe it's "huge" because the loop isn't behaving as you expect.
In any case:
Please read this article:
https://floating-point-gui.de/
What Every Programmer Should Know About Floating-Point Arithmetic
or
Why don’t my numbers add up?
Please update your post, clarifying exactly what the problem is, where in your code it's occurring, and what you "expected" vs. what you're seeing.
The precsion of a float is about 7 digits. You are calculating pi 3.... and want to get to within a difference of 0.000010. This is right at the limit of what a float can represent. Switching to double will give you close to 15 digits of precision.
You're using the wrong format specifier for scanf:
double dif = 0.0;
printf("Type the difference to be observed: ");
scanf("%f", &dif);
The %f format specifier expects a float *, but you're passing in a double *. These point to datatypes of different sizes and different representations. Using the wrong format specifier leads to undefined behavior which is why you're getting the wrong value.
To read a double, use %lf:
scanf("%lf", &dif);
Also, the value 0.000010 cannot be represented exactly in binary floating point, so even with this fix you'll see a value that is slightly larger or slightly smaller than the entered value.
people, thank you for the help. The right code is this one bellow.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int n = 0, iteractions = 1;
double Pi1 = 4.0, serie = 0.0, sub = 0.0, sum = 0.0;
double dif = 0.0;
printf("Type the difference to be observed: ");
scanf("%lf", &dif);
Pi1 = 4;
sub = Pi1 - M_PI;
for(n=1; sub >= dif; n++){
serie = (pow(-1,n)*4)/(double)(2*n + 1);
iteractions = iteractions + 1;
sum = Pi1 + serie;
Pi1 = sum;
sub = Pi1 - M_PI;
if(sub < 0){
sub = -1 * sub;
}
}
printf("Iteractions: %d \n", iteractions);
return 0;
}
As the name suggested, I'd like to compute cubic roots of a complex number in C. cbrt doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <cmath.h>
int main(){
double complex x, z = 1+2*I;
x = cbrt(z);
printf("z is %f + %fi \n", creal(z), cimag(z));
printf("x is %f + %fi \n", creal(x), cimag(x));
return(0);
}
The output is as follows.
z is 1.000000 + 2.000000i
x is 1.000000 + 0.000000i
cbrt doesn't work.
That function works on real values. #squeamish ossifrage
x is 1.000000 + 0.000000i is a reasonable result.
double cbrt(double x);
The cbrt functions compute the real cube root of x. C11dr §7.12.7.1 2
A good compiler with warnings fully enabled with report on the following. Save time, enable all compiler warnings.
// warning expected such as:
// warning: conversion to 'long double' from 'complex double' discards imaginary component [-Wconversion]
x = cbrt(z);
How to compute a cubic root of a complex number in C?
<cmath.h> is not part of the C standard library. Its role here is unclear.
Code can use double complex cpow(double complex, double complex);
x = cpow(z, 1.0/3.0);
...
// Ouptut
// x is 1.219617 + 0.471711i
I do not find a double complex ccbrt(double complex); in the standard library nor access to one via type-generic math <tgmath.h>.
... to compute cubic roots ...
Emphasis on plural "roots" here: to compute all 'n' roots:
int n = 3;
const double complex two_pi_i = 2.0 * asin(-1.0) * I;
double complex rotate = cexp(two_pi_i / n);
x = cpow(z, 1.0 / 3.0);
for (int k = 0; k < n; k++) {
printf("x[%d] is % f + % fi \n", k, creal(x), cimag(x));
x *= rotate;
}
Output
x[0] is 1.219617 + 0.471711i
x[1] is 1.018322 + -0.820363i
x[2] is -0.201294 + -1.292075i
I would look at this answer from the Mathematics Stack Exchange.
Essentially you want to compute the radius and angle of the Eurler formula. Then divide both the radius and angle by three (see link). So first you need to convert your complex number to Euler format. I don't have time now to figure that out, but maybe this gave you an idea at where to look.
Hope this helps!
Addition: #squeamish probably has a better idea with cpow, but as he mentioned this will only return one of the roots.
My colleague and I are studying for a test, where we have to analyze C Code. Looking through the tests from the previous years, we saw the following code, which we don't really understand:
#include <stdio.h>
#define SUM(a,b) a + b
#define HALF(a) a / 2
int main(int argc, char *argv[])
{
int big = 6;
float small = 3.0;
printf("The average is %d\n", HALF(SUM(big, small)));
return 0;
}
This code prints 0, which we don't understand at all... Can you explain this to us?
Thanks so much in advance!
The compiler's warnings (format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’) give more-than-enough information. You need to correct your format-specifier, which should be %lf, instead of %d, since you are trying to print a double value.
printf("The average is %lf\n", HALF(SUM(big, small)));
printf will treat the memory you point as however you tell it to. Here, it is treats the memory that represents the float as an int. Because the two are stored differently, you should get what is essentially a random number. It needs not be 0 always.
To get correct output
Add parentheses in macro
Use correct format specifier (%f)
Corrected Code
#include <stdio.h>
#define SUM(a, b) (a + b)
#define HALF(a) a / 2
int main() {
int big = 6;
float small = 3.0;
printf("The average is %f\n", HALF(SUM(big, small)));
return 0;
}
Output
The average is 4.500000
If you don't add parentheses, output will be 7.500000 due to operator precedence.
In case you need integer output, cast to int before printing.
printf("The average is %d\n", (int)HALF(SUM(big, small)));
Output
The average is 4
I'm currently learning the C language and I'm having trouble in the double multiplication topic.
I need to to print the original value and then the 2*value of the double.
double num = 34.39;
printf("Original value = %d, 2x original value = %d", num, num*2);
How do I make it so that the 2x value will be really 2x the original value?
Your multiplication is not the problem.
Your printf format string is. %d is not for floating-point values, but for integers, so you're seeing nonsense resulting from your broken contract with the compiler.
double num = 34.39;
printf("Original value = %lf, 2x original value = %lf", num, num*2);
%d - for int
You must use the "%f" for printf