pointer bug in a void function makes a variable receive -nan - c

This is a very simple program, it just calculate the area of a triangle using Heron's formula, but I wanted to over complicate things a bit, so I made some functions that have pointers as parameters, which, in this case, they pretty much work like c++ references.
It works like that : it takes 3 sides (a,b,c) and calculates the area. The only problem is, whenever I enter a, I receive as an output -nan, which I did not understand why this happened.
When this sort of thing happens, is easy to blame the pointers, although is more likely the scanf or printf functions aren't behaving well.
If anyone could please explain to me why this is happening and how I can fix things up, I would be much thankful.
My code is bellow :
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
void CalculateSemiPerimeter(double a, double b, double c, double *result)
{
*result = ((a+b+c)/2.0);
}
void heron(double *semiPerimeter, double a, double b, double c, double *result) //note that semiPerimeter and result have the same adresses
{
double sub1 = (*semiPerimeter - a);
double sub2 = (*semiPerimeter - b);
double sub3 = (*semiPerimeter - c);
double mult = (*semiPerimeter*(sub1)*(sub2)*(sub3)); //this part may be wrong
*result = mult;
}
int main()
{
double a, b, c, result;
scanf("%lf, %lf, %lf", &a, &b, &c);
CalculateSemiPerimeter(a,b,c, &result);
heron(&result, a, b, c, &result);
result = sqrt(result);
printf("%.2lf", result);
}
and here's a example of an input :
>>5
which brings as output :
-nan

At least these issues:
Unchecked input
The return value of scanf() was unchecked. If a,b,c were successfully written, scanf() returns 3.
// scanf("%lf, %lf, %lf", &a, &b, &c);
if (scanf("%lf, %lf, %lf", &a, &b, &c) != 3) {
fprintf(stderr, "Input failure.\n");
return EXIT_FAILURE;
}
This would happen if input was "1 2 3" as the format expects "1,2,3" - commas between the numbers.
Further, code should sanitize inputs, checking if any are negative.
Advanced: Computational error
With extreme values, say when a much greater than b and b much greater than c, *semiPerimeter - a may result in severe loss of precession or even a negative number leading to a later trouble with sqrt(some_negative).
Instead code could be more careful and reduce computational errors. Rather than form sub1 with (a + b + c)/2 - a, use (-a + b + c)/2. This reduces cancellation error.
One level of improvement:
// Return the result and no need to pass in semiPerimeter.
// void heron(double *semiPerimeter, double a, double b, double c, double *result)
double heron(double a, double b, double c) {
double semiPerimeter = (a + b + c)/2;
double sub1 = (-a + b + c)/2;
double sub2 = ( a - b + c)/2;
double sub3 = ( a + b - c)/2;
return semiPerimeter * sub1 * sub2 * sub3;
}
Still with pathological inputs (unreal triangle lengths), the return value of heron() may be negative.
result = heron(a, b, c);
if (result < 0.0) {
; // TBD code that reports error.
} else {
result = sqrt(result);
...
}
2nd level of improvement:
Sort a, b, c by magnitude, greatest to least.
Change to below to further reduce cancelation error.
double sub3 = ( a + (b - c))/2;

Related

the programme codes of language c about input and output are wrong,could somebody help me find the fault?

I have the following code in c
#include <stdio.h>
int main(void)
{
int a, b, c, sum;
double d, p;
sum = a + b + c;
printf("请输入三个整数:");
scanf("%d %d %d", &a, &b, &c);
d = sum / 3;
printf("3个整数的平均值是:d=%.2f", d);
p = a / sum * 100;
printf(",第一个数占和的比例是:p=%4.2f%%", p);
}
It is about entering three integers from the keyboard, average them, and calculate the ratio of the first number to the sum of the three numbers. The output result retains 2 decimal places .
I cannot find where is wrong.
The two main issues are:
You calculate sum with uninitialized values for a, b and c. Move that calculation to after a successful scanf() to ensure those variables are set.
You probably want to do the calculations of d and p with double, rather than integer, precision. I make use of automatic type conversion via fractional constants. The other two options are to change the type of sum from an int to a double, or explicitly use a type cast (see answer by #FeihuLiu).
Minor issues:
Original code was formatted poorly (since fixed by one of our friends :-).
Optional for main() but it's a good idea to return an integer as your declaration said you would.
(not fixed) If you don't use p or d for anything else, consider just eliminating them in favor of doing the calculation call to printf()
It's generally a good idea to reduce the scope of variables so I moved those definitions to just before they are used.
#include <stdio.h>
int main(void) {
printf("请输入三个整数:");
int a, b, c;
if (scanf("%d %d %d", &a, &b, &c) != 3) {
// TBD: translate error message
printf("scanf failed\n");
return 1;
}
int sum = a + b + c;
double d = sum / 3.0;
printf("3个整数的平均值是:d=%.2f", );
double p = 100.0 * a / sum;
printf(",第一个数占和的比例是:p=%4.2f%%", p);
return 0;
}
Besides the sum problem, integer division will result in integer. You can use the following code:
#include <stdio.h>
int main(void) {
int a, b, c, sum;
double d, p;
printf("请输入三个整数:");
scanf("%d %d %d", &a, &b, &c);
sum = a + b + c;
d = (double) sum / 3;
printf("3个整数的平均值是:d=%.2f", d);
p = (double) a / sum * 100;
printf(",第一个数占和的比例是:p=%4.2f%%", p);
}

numerical integration using a pointer to a function always return 0

I am trying to use the function that I was given by my professor to calculate the integral of a polynomial function (polynomial such as: ax^2+bx+c). the function is:
double numbericalIntegration(double a ,double b ,double(*func)(double)){
double delta = (b - a)/32;
double sum=0, x;
for(x= a+0.5*delta; x<b ; x+=delta)
{
sum+=(*func)(x);
}
return sum*delta;
}
I changed a lot in order to integrate a polynomial function. but I was get the answer 0. why is that? and I'd appreciate if anybody tried to correct my work. my code is:
double integralPoly(double x, double a, double b, double c){
return (a*pow(x,3))/3 +(b*pow(x,2))/2 + (c*x);
}
double numbericalIntegration(double a ,double b ,double(*func)(double,double,double,double), double firstNum, double secondNum, double thirdNum){
double delta = (b - a)/32;
double sum=0, x;
for(x= a+0.5*delta; x<b ; x+=delta)
{
sum+=(*func)(x, firstNum, secondNum, thirdNum);
}
return sum*delta;
}
int main()
{
double (*func)(double,double,double,double);
func = integralPoly;
double sum = numbericalIntegration(2,4,func,1,1,4);
printf("sum = %d",sum);
return 0;
}
You need to change two things. First your polynomial function doesn't make any sense. You said it needs to be in the form of ax^2+bx+c but in your code polynomial is (ax^3)/3+(bx^2)/2+c*x. Your function should be:
double integralPoly(double x, double a, double b, double c){
return (a*pow(x,2)) +(b*x) + c;
}
Also you need to change your printf. %d is integer type specifier and you need double, so you need to use %f for example:
printf("sum = %f",sum);
Now the output of your program is:
sum = 32.666016
which is correct for your parameters.

Potential Pointer issue C programming

I've been working through this problem, and I believe I have an error in where my pointers within my struct are pointing. However, I can't seem to figure out where I'm going wrong.
My code is meant to take in 2 complex numbers, then multiply and divide them, and then spit out both answers.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct complex_t
{
double real; // real part
double imag; // imaginary part
} complex_t;
// Multiplication Function //
void *multiply()
{
struct complex_t a, b, c;
c.real == ((a.real * b.real) - (a.imag * b.imag));
c.imag == ((a.imag * b.real) + (a.real * b.imag));
if ( c.imag >= 0 )
printf("Multiplication = %d + %di\n", c.real, c.imag); // Postive Imaginary case
else
printf("Multiplication = %d %di\n", c.real, c.imag); // Negative Imaginary case
}
// Division Function //
void *divide()
{
int numer1, numer2, denom;
struct complex_t a, b, c;
if ( b.real == 0 || b.imag == 0 ) // Case to Avoid Dividing by 0
printf("Division by 0 + 0i is not allowed.");
else
{
numer1 = ((a.real * b.real) + (a.imag * b.imag));
numer2 = ((a.imag * b.real) - (a.real * b.imag));
denom = ((b.real * b.real) + (b.imag * b.imag));
c.real == (numer1/denom);
c.imag == (numer2/denom);
if (numer2/denom >= 0)
printf("Division = %d + %di \n", c.real, c.imag); // Postive Imaginary case
else
printf("Division = %d %di \n", c.real, c.imag); // Negative imaginary case
}
}
// Main - to execute the two functions //
int main() {
struct complex_t a, b, c;
printf("Enter a and b where a + ib, for the first complex number.");
printf("\na = ");
scanf("%d", &a.real);
printf("b = ");
scanf("%d", &a.imag);
printf("Enter c and d where c + id, for the second complex number.");
printf("\nc = ");
scanf("%d", &b.real);
printf("d = ");
scanf("%d", &b.imag);
multiply();
divide();
return 0;
}
This is an example of what this program is producing:
Multiplication = 69144 -4196352i
Division = -13339222 0i
Any tips as to where I can start figuring this error out would be great.
C is an exact language. There is no such thing as syntax that is close enough. This is a great strength in C, but it is one hurdle beginning programmers have to come to terms with and understand before any real learning can take place. That includes understanding what each part of each line does, including the format strings. If you don't fully understand what each part of each line is doing -- look it up. Read the man pages, search for further information, until you do. It will save you a ton of time in the long run.
One of the things you can do that will, above all, help you find the problems in your code is to compile with Warnings enabled. That means including at least -Wall -Wextra in your compile string. For example, in your code, the screen was littered with warnings, including code with no apparent function and expected double but have int. Those things are telling you, you can try and run your code -- but DO NOT expect it to work right. You have to fix those, before you can have reasonable confidence that you will get more than garbage (or a crash) out of your code.
Another primary bit of learning that must take place is Always initialize your variables (to zero if nothing else). Attempting to access an uninitialized variable is Undefined Behavior. (it's anybody's guess what will happen.)
That being said. You had part of the code right. Your issues basically took slowing down, reading what the compiler was telling you was wrong, fixing it, and trying again. That's the key to C, slow down and get it right.
Enough blather -- are you going to help or not? Of course. Read through the following. Understand why the changes were necessary, and you will be able to consider it a good bit of learning for the day. However, the fixes in the code below, are not near as important as the guidance above for approaching C programming. (give a man a fish....):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
double real; // real part
double imag; // imaginary part
} complex_t;
// Multiplication Function //
void multiply (complex_t *a, complex_t *b, complex_t *c) {
/* struct complex_t a, b, c; */
c->real = ((a->real * b->real) - (a->imag * b->imag));
c->imag = ((a->imag * b->real) + (a->real * b->imag));
if (c->imag >= 0)
printf ("\nMultiplication = %f + %fi\n", c->real, c->imag); // Postive Imaginary case
else
printf ("\nMultiplication = %f %fi\n", c->real, c->imag); // Negative Imaginary case
}
// Division Function //
void divide (complex_t *a, complex_t *b, complex_t *c) {
int numer1, numer2, denom;
/* struct complex_t a, b, c; */
if (b->real == 0 || b->imag == 0) // Case to Avoid Dividing by 0
printf ("Division by 0 + 0i is not allowed.");
else {
numer1 = ((a->real * b->real) + (a->imag * b->imag));
numer2 = ((a->imag * b->real) - (a->real * b->imag));
denom = ((b->real * b->real) + (b->imag * b->imag));
c->real = (numer1 / denom);
c->imag = (numer2 / denom);
if (numer2 / denom >= 0)
printf ("\nDivision = %f + %fi \n", c->real, c->imag); // Postive Imaginary case
else
printf ("\nDivision = %f %fi \n", c->real, c->imag); // Negative imaginary case
}
}
// Main - to execute the two functions //
int main () {
complex_t a = { 0, 0 }, b = { 0, 0 }, c = { 0, 0 };
printf ("\nEnter a and b where a + ib, for the first complex number.\n\n");
printf (" a (a.real) = ");
scanf ("%lf", &a.real);
printf (" b (a.imag) = ");
scanf ("%lf", &a.imag);
printf ("\nEnter c and d where c + id, for the second complex number.\n\n");
printf (" c (b.real) = ");
scanf ("%lf", &b.real);
printf (" d (b.imag) = ");
scanf ("%lf", &b.imag);
multiply (&a, &b, &c);
divide (&a, &b, &c);
printf ("\n");
return 0;
}
output:
$ ./bin/divmult
Enter a and b where a + ib, for the first complex number.
a (a.real) = 10
b (a.imag) = 3
Enter c and d where c + id, for the second complex number.
c (b.real) = 5
d (b.imag) = 5
Multiplication = 35.000000 + 65.000000i
Division = 1.000000 + 0.000000i
void *multiply()
The values of struct variables a and b are not initialized within this function you should be passing the scanned values in main() to this function as well as divide()
There is no reason here I see why you are returning void *. Pass parameters by reference or by value.

largest number without conditional operator

can any one please elaborate how to find largest of four numbers without using conditional operator.for 3 numbers i have done but for four numbers how to write different comparisons.
There is a standard way to compute min or max in 2's complement arithmetics without using conditionals:
int max(int a, int b){
unsigned diff = b - a; // negative if a > b
int sign = -(diff >> (sizeof(int) * CHAR_BIT - 1)); // -1 if a > b, 0 otherwise
return (a & sign) | (b & ~sign);
}
it can be easily scaled.
void main()
{
int a, b;
printf("Enter a and b:");
scanf("%d %d", &a, &b);
printf("Maximum number is %d", max(a, b));
getch();
}
int max(int a, int b)
{
int c, temp;
c = a - b;
temp = c + abs(c);
// To check if the difference is negative or not
if(temp) //As suggested by R..
return b;
else
return a;
}
This code is for compare two numbers. Make this comparison for all numbers.
you can find max of two number a,b by using following trick:
(abs(a+b)+abs(a-b))/2
Extend the trick for as many numbers you want.

C File Input/Trapezoid Rule Program

Little bit of a 2 parter. First of all im trying to do this in all c. First of all I'll go ahead and post my program
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
#include <string.h>
double f(double x);
void Trap(double a, double b, int n, double* integral_p);
int main(int argc, char* argv[]) {
double integral=0.0; //Integral Result
double a=6, b=10; //Left and Right Points
int n; //Number of Trapezoids (Higher=more accurate)
int degree;
if (argc != 3) {
printf("Error: Invalid Command Line arguements, format:./trapezoid N filename");
exit(0);
}
n = atoi(argv[2]);
FILE *fp = fopen( argv[1], "r" );
# pragma omp parallel
Trap(a, b, n, &integral);
printf("With n = %d trapezoids....\n", n);
printf("of the integral from %f to %f = %.15e\n",a, b, integral);
return 0;
}
double f(double x) {
double return_val;
return_val = pow(3.0*x,5)+pow(2.5*x,4)+pow(-1.5*x,3)+pow(0*x,2)+pow(1.7*x,1)+4;
return return_val;
}
void Trap(double a, double b, int n, double* integral_p) {
double h, x, my_integral;
double local_a, local_b;
int i, local_n;
int my_rank = omp_get_thread_num();
int thread_count = omp_get_num_threads();
h = (b-a)/n;
local_n = n/thread_count;
local_a = a + my_rank*local_n*h;
local_b = local_a + local_n*h;
my_integral = (f(local_a) + f(local_b))/2.0;
for (i = 1; i <= local_n-1; i++) {
x = local_a + i*h;
my_integral += f(x);
}
my_integral = my_integral*h;
# pragma omp critical
*integral_p += my_integral;
}
As you can see, it calculates trapezoidal rule given an interval.
First of all it DOES work, if you hardcode the values and the function. But I need to read from a file in the format of
5
3.0 2.5 -1.5 0.0 1.7 4.0
6 10
Which means:
It is of degree 5 (no more than 50 ever)
3.0x^5 +2.5x^4 −1.5x^3 +1.7x+4 is the polynomial (we skip ^2 since it's 0)
and the Interval is from 6 to 10
My main concern is the f(x) function which I have hardcoded. I have NO IDEA how to make it take up to 50 besides literally typing out 50 POWS and reading in the values to see what they could be.......Anyone else have any ideas perhaps?
Also what would be the best way to read in the file? fgetc? Im not really sure when it comes to reading in C input (especially since everything i read in is an INT, is there some way to convert them?)
For a large degree polynomial, would something like this work?
double f(double x, double coeff[], int nCoeff)
{
double return_val = 0.0;
int exponent = nCoeff-1;
int i;
for(i=0; i<nCoeff-1; ++i, --exponent)
{
return_val = pow(coeff[i]*x, exponent) + return_val;
}
/* add on the final constant, 4, in our example */
return return_val + coeff[nCoeff-1];
}
In your example, you would call it like:
sampleCall()
{
double coefficients[] = {3.0, 2.5, -1.5, 0, 1.7, 4};
/* This expresses 3x^5 + 2.5x^4 + (-1.5x)^3 + 0x^2 + 1.7x + 4 */
my_integral = f(x, coefficients, 6);
}
By passing an array of coefficients (the exponents are assumed), you don't have to deal with variadic arguments. The hardest part is constructing the array, and that is pretty simple.
It should go without saying, if you put the coefficients array and number-of-coefficients into global variables, then the signature of f(x) doesn't need to change:
double f(double x)
{
// access glbl_coeff and glbl_NumOfCoeffs, instead of parameters
}
For you f() function consider making it variadic (varargs is another name)
http://www.gnu.org/s/libc/manual/html_node/Variadic-Functions.html
This way you could pass the function 1 arg telling it how many "pows" you want, with each susequent argument being a double value. Is this what you are asking for with the f() function part of your question?

Resources