Program to find Heat Index and Wind Chill (C Program) - c

I am having some trouble with the output of my program and can't figure out where I am going wrong. The Temperatures seem to be converting from celsius to Fahrenheit correctly, but when it comes to the the wind chill and heat index values, they are incorrect. This makes me think that something is wrong with the way I'm calculating them in my functions? If I could get an explanation to where my logic is wrong that would be great. Thanks in advance and sorry for my poor formatting!
#include <stdio.h>
#include <math.h>
#define L_Limit -20
#define U_Limit 50
#define c1 -42.379
#define c2 2.04901523
#define c3 10.14333127
#define c4 -0.22475541
#define c5 -6.83783E-3
#define c6 -5.481717E-2
#define c7 1.22874E-3
#define c8 8.5282E-4
#define c9 -1.99E-6
#define d1 35.74
#define d2 0.6125
#define d3 35.75
#define d4 0.4275
double compute_heat_index(int num1, int num2);
double compute_wind_chill(int num1, int num2);
double compute_heat_index(int num1, int num2)
{
int celsius;
double humid=.40;
double celsius_f=0, heat_index=0;
int ext1=0;
for(celsius=1;celsius<=num2;celsius++)
{
printf("%d\t", celsius);
celsius_f=(celsius*(9/5))+32;
printf("%2.2lf\t", celsius_f);
for(humid=.40;humid<=1;humid=humid+.10)
{
heat_index=c1+(c2*celsius_f)+(c3*humid)+. (c4*humid*celsius_f)+(c5*pow(celsius,2))+(c6*pow(humid,2))+(c7*pow(celsius,2)*humid)+(c8*celsius*pow(humid,2))+(c9*pow(celsius,2)*pow(humid,2));
if(heat_index<80)
printf("x\t");
else
printf("%2.2lf/t", heat_index);
}
if(celsius_f>100)
{
ext1++;
}
humid=.40;
celsius_f=0;
heat_index=0;
}
return heat_index;
}
double compute_wind_chill(int num1, int num2)
{
int celsius, wind=5;
double celsius_f=0, wind_chill=0;
int ext2=0;
for(celsius=1;celsius<=num2;celsius++)
{
printf("%d\t", celsius);
celsius_f=(celsius*(9/5))+32;
printf("%lf\t", celsius_f);
for(wind=5;wind<=40;wind=wind+5)
{
wind_chill=d1+(d2*celsius_f)-(d3*wind)+(d4*celsius_f*wind);
if(wind_chill>50)
printf("x\t");
else
printf("%lf\t", wind_chill);
}
if(celsius_f<-20)
{
ext2++;
}
wind=5;
celsius_f=0;
wind_chill=0;
}
return wind_chill;
}
int main(void)
{
double num1, num2;
int ext1=0, ext2=0;
printf("Input a range of values using two numbers:\n");
scanf("\n%lf%lf", &num1, &num2);
while(num1<L_Limit&&num1>U_Limit&&num2<L_Limit&&num2<U_Limit)
{
printf("Range of Values are Invalid!\n");
scanf("\n%lf%lf", &num1, &num2);
}
printf("Celsius\tFahrenheit\t5mph\t10mph\t15mph\t20mph\t25mph\t30mph\t35mph\t40mph\n");
compute_wind_chill(num1, num2);
printf("\nTotal Extreme Values: %d", ext1);
compute_heat_index(num1, num2);
printf("\nTotal Extreme Values: %d", ext2);
return 0;
}

While I make no comment on the correctness of your stoichiometric calculations (though I provide links and hints at the end), the following will help you find the problem, not only here, but hopefully in all future code you write as well. You are making things harder on yourself than they need be just by how you are formatting your code. Unless you are competing in a contest to see how few lines you can use, then for goodness sake, make things easier on yourself by 'opening up' you code a bit. This will make it much easier for you, and anyone helping you, to follow the logic of your code and find logic errors. For example, it is almost impossible to spot logic errors in:
heat_index=c1+(c2*celsius_f)+(c3*humid)+. (c4*humid*celsius_f)+(c5*pow(celsius,2))+(c6*pow(humid,2))+(c7*pow(celsius,2)*humid)+(c8*celsius*pow(humid,2))+(c9*pow(celsius,2)*pow(humid,2));
(of course your compiler will loudly complain about the errouneous '.' at the end of the first line)
It is much more readable written as:
heat_index = c1 + (c2 * celsius_f) + (c3 * humid) +
(c4 * humid * celsius_f) + (c5 * pow (celsius, 2)) +
(c6 * pow (humid, 2)) + (c7 * pow (celsius, 2) * humid) +
(c8 * celsius * pow (humid, 2)) +
(c9 * pow (celsius, 2) * pow (humid, 2));
or even:
heat_index = c1 +
(c2 * celsius_f) +
(c3 * humid) +
(c4 * humid * celsius_f) +
(c5 * pow (celsius, 2)) +
(c6 * pow (humid, 2)) +
(c7 * pow (celsius, 2) * humid) +
(c8 * celsius * pow (humid, 2)) +
(c9 * pow (celsius, 2) * pow (humid, 2));
NOTE: above you can easily see the misuse of celsius where celsius_f (Fahrenheit) should be used. Also note there is no need for pow (celsius_f, 2) where celsius_f * celsius_f will do the job.
Do the same for your output. Make it easy for you to read so it will be easier for others to read as well.
(I'm getting old and maybe your young-eyes have no trouble with code without spaces, it is much easier on me to help you if your code is adequately spaced and properly indented and your output looks like something other than spaghetti strung across the screen)
Avoid using 'magic numbers' in your code, e.g.
for(wind=5;wind<=40;wind=wind+5)
If you need constants in your code, declare them as required. That way, there is only one place you need to change the value, easily found at the top, instead of picking though your code to find them. You have declared a large number for your wet-bulb/dry-blub calculations, a few more for your limits is all that is required, e.g.
#define HMIN .40 /* define needed constants */
#define HMAX 1.0 /* avoid putting 'magic' */
#define HSTEP 0.1 /* numbers in your code */
#define WMIN 5
#define WMAX 40
#define WSTEP 5
...
for (wind = WMIN; wind <= WMAX; wind = wind + WSTEP)
Note: your HMIN, HMAX, HSTEP values will change when you correct your units (see last paragraph).
It appears you are wanting to return the values of ext1 and ext2 from your compute_wind_chill and compute_heat_index functions. If so, then your function type should match your return type needed. If you are wanting to indicate whether a extreme value was encountered by returning ext1 and ext2, then you should change your function type to int and assign the return to ext1 and ext2 in main, e.g.
int compute_heat_index (int num1, int num2);
int compute_wind_chill (int num1, int num2);
...
ext1 = compute_wind_chill (num1, num2);
printf ("\nTotal Extreme Values: %d\n", ext1);
...
ext2 = compute_heat_index (num1, num2);
printf ("\nTotal Extreme Values: %d\n", ext2);
Next, there is no need to make multiple calls to, e.g. printf when one will do. For example:
printf("%d\t", celsius);
celsius_f=(celsius*(9/5))+32;
printf("%2.2lf\t", celsius_f);
can be easily replaced with a single printf call just by logically ordering your celsius_f calculation, e.g.
celsius_f = (celsius * (9 / 5)) + 32;
printf ("%d\t% .2lf\t", celsius, celsius_f);
Why you declare num1 and num2 as double in main is a complete mystery. You pass them as int to your functions (where I assume num1 is supposed to be the lower loop value for temp in the functions instead of the hardcoded 1 you have). While you are free to allow users to enter e.g. 45.3 and read it as a double, and pass it as an int, it doesn't really make much logical sense. Here, the value of 45 is all that is ever used on your code. If you are reading as a double just to prevent error if a user enters 45.3, then that is a legitimate reason, but why a user would rather enter 45.3 instead of just 45 is another matter...
Your limit testing for values less/greater than L_Limit/U_Limit is a bit creative. It is better to simply put the values in ascending order to simplify the test, e.g.
/* VALIDATE all user input */
if (scanf ("%lf %lf", &num1, &num2) != 2) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
if (num1 > num2) { /* get values in ascending order */
double tmp = num1;
num1 = num2;
num2 = tmp;
}
while (num1 < L_Limit || num2 > U_Limit) { /* simple test */
Formatting your output is just something that takes a little more attention to detail. While I'm no fan of tab ('\t') formatting, I've made a quick attempt to clean things up a little to make the output more legible. Similarly, when you need an additional newline character, do not use the variadic printf ("\n");, there is no reason for the overhead just to output one character, use putchar ('\n'); instead. (note: you don't make that mistake, but I had to add a newline so it was worth mentioning here).
When you compile your code, always compile with warnings enabled, e.g. -Wall -Wextra in your compile string. You can add -pedantic for a few additional checks and there are a multitude of additional individual checks you can impose. Above all, do not accept code until it compiles cleanly, without warnings. Read the warnings you get. The compilers are quite good now at explaining exactly where the problem is and what you are doing wrong. (you can learn a lot of C, just by listening to what your compiler is telling you).
You can compile your code with something similar to the following:
$ gcc -Wall -Wextra -pedantic -std=gnu11 -Ofast -o bin/windchill windchill.c
Finally, putting it altogether, you could reformat your code and incorporate the changes above into something like the following that should make finding your stoichiometric logic error much easier. I have put my additional thoughts in the comments below:
#include <stdio.h>
#include <math.h>
#define L_Limit -20
#define U_Limit 50
#define c1 -42.379
#define c2 2.04901523
#define c3 10.14333127
#define c4 -0.22475541
#define c5 -6.83783E-3
#define c6 -5.481717E-2
#define c7 1.22874E-3
#define c8 8.5282E-4
#define c9 -1.99E-6
#define d1 35.74
#define d2 0.6125
#define d3 35.75
#define d4 0.4275
#define HMIN .40 /* define needed constants */
#define HMAX 1.0 /* avoid putting 'magic' */
#define HSTEP 0.1 /* number in your code */
#define WMIN 5
#define WMAX 40
#define WSTEP 5
/* you only need prototypes if you do not define your functions
* until AFTER the code that makes use of them. Moving the
* definitions AFTER main() makes the prototypes make sense,
* otherwise, just omit them...
*/
int compute_heat_index (int num1, int num2);
int compute_wind_chill (int num1, int num2);
int main (void) {
double num1 = L_Limit - 1.0, /* num1 & num2 should be int */
num2 = U_Limit + 1.0;
int ext1 = 0, ext2 = 0;
printf ("Input a range of temps in deg. C, (e.g. t1 t2): ");
/* VALIDATE all user input */
if (scanf ("%lf %lf", &num1, &num2) != 2) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
if (num1 > num2) { /* get values in ascending order */
double tmp = num1;
num1 = num2;
num2 = tmp;
}
while (num1 < L_Limit || num2 > U_Limit) { /* simple test */
fprintf (stderr, "error: values must be between %d - %d.\n",
L_Limit, U_Limit);
printf ("Input a range of temps in deg. C, (e.g. t1 t2): ");
if (scanf ("%lf %lf", &num1, &num2) != 2) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
}
/* make the output format easy to read */
printf ("\nDeg. C\t Deg. F\t 5mph\t 10mph\t 15mph\t"
" 20mph\t 25mph\t 30mph\t 35mph\t 40mph\n");
ext1 = compute_wind_chill (num1, num2);
printf ("\nTotal Extreme Values: %d\n", ext1);
printf ("\nDeg. C\t Deg. F\t 40%%\t 50%%\t 60%%\t"
" 70%%\t 80%%\t 90%%\t 100%%\n");
ext2 = compute_heat_index (num1, num2);
printf ("\nTotal Extreme Values: %d\n", ext2);
return 0;
}
/* comput and output heat index between num1 and num2 */
int compute_heat_index (int num1, int num2)
{
int celsius, ext1 = 0;
double humid = HMIN, celsius_f = 0, heat_index = 0;
for (celsius = num1; celsius <= num2; celsius++)
{
celsius_f = (celsius * (9 / 5)) + 32;
printf ("%d\t% .2lf\t", celsius, celsius_f);
for (humid = HMIN; humid <= HMAX; humid = humid + HSTEP)
{
heat_index = c1 + (c2 * celsius_f) + (c3 * humid) +
(c4 * humid * celsius_f) + (c5 * pow (celsius, 2)) +
(c6 * pow (humid, 2)) + (c7 * pow (celsius, 2) * humid) +
(c8 * celsius * pow (humid, 2)) +
(c9 * pow (celsius, 2) * pow (humid, 2));
if (heat_index < 80)
printf ("x\t");
else
printf ("% .2lf\t", heat_index);
}
putchar ('\n');
if (celsius_f > 100) {
ext1++;
}
}
return ext1;
}
/* comput and output wind chill between num1 and num2 */
int compute_wind_chill (int num1, int num2)
{
int celsius, wind = WMIN, ext2 = 0;
double celsius_f = 0, wind_chill = 0;
for (celsius = num1; celsius <= num2; celsius++)
{
celsius_f = (celsius * (9 / 5)) + 32;
printf ("%d\t% .2lf\t", celsius, celsius_f);
for (wind = WMIN; wind <= WMAX; wind = wind + WSTEP)
{
wind_chill = d1 + (d2 * celsius_f) - (d3 * wind) +
(d4 * celsius_f * wind);
if (wind_chill > 50)
printf (" x\t");
else
printf ("% .2lf\t", wind_chill);
}
putchar ('\n');
if (celsius_f < -20) {
ext2++;
}
}
return ext2;
}
Example Use/Output
$ ./bin/windchill
Input a range of temps in deg. C, (e.g. t1 t2): 45 55
error: values must be between -20 - 50.
Input a range of temps in deg. C, (e.g. t1 t2): 45 50
Deg. C Deg. F 5mph 10mph 15mph 20mph 25mph 30mph 35mph 40mph
45 77.00 x x 40.41 26.25 12.09 -2.07 -16.23 -30.40
46 78.00 x x 47.44 35.42 23.39 11.37 -0.66 -12.68
47 79.00 x x x 44.58 34.69 24.80 14.92 5.03
48 80.00 x x x x 45.99 38.24 30.49 22.74
49 81.00 x x x x x x 46.07 40.45
50 82.00 x x x x x x x x
Total Extreme Values: 0
Deg. C Deg. F 40% 50% 60% 70% 80% 90% 100%
45 77.00 99.68 99.21 98.74 98.27 97.80 97.32 96.85
46 78.00 101.06 100.58 100.10 99.61 99.13 98.65 98.17
47 79.00 102.43 101.93 101.44 100.95 100.46 99.96 99.47
48 80.00 103.78 103.28 102.78 102.27 101.77 101.27 100.76
49 81.00 105.13 104.61 104.10 103.59 103.07 102.56 102.04
50 82.00 106.46 105.93 105.41 104.89 104.36 103.84 103.31
Total Extreme Values: 0
note: one glaring error is your integer division error in your conversion to Fahrenheit. You can remedy that by insuring floating point division of your conversion factor:
celsius_f = (celsius * (9.0 / 5)) + 32;
Making that one change will have a dramatic impact on your calculations, e.g.
$ ./bin/windchill
Input a range of temps in deg. C, (e.g. t1 t2): 45 50
Deg. C Deg. F 5mph 10mph 15mph 20mph 25mph 30mph 35mph 40mph
45 113.00 x x x x x x x x
46 114.80 x x x x x x x x
47 116.60 x x x x x x x x
48 118.40 x x x x x x x x
49 120.20 x x x x x x x x
50 122.00 x x x x x x x x
Total Extreme Values: 0
Deg. C Deg. F 40% 50% 60% 70% 80% 90% 100%
45 113.00 170.20 168.93 167.65 166.37 165.09 163.81 162.53
46 114.80 173.15 171.84 170.54 169.23 167.92 166.61 165.30
47 116.60 176.09 174.75 173.42 172.08 170.74 169.40 168.06
48 118.40 179.01 177.65 176.28 174.92 173.55 172.18 170.81
49 120.20 181.92 180.53 179.14 177.74 176.35 174.95 173.56
50 122.00 184.82 183.40 181.98 180.55 179.13 177.71 176.28
Total Extreme Values: 0
You have some more work to do... You can start by reviewing The Heat Index Equation (which appears to be where your constants come from -- but note you are missing the correction factors and you need to pay careful attention to the units of humidity). Then follow up by looking at Wind Chill paying careful attention to the exponent on the wind. When you correct your formula, you will then need to link against the math library, so add -lm to your compile string. (that's little-'L'm). Once you correct your logic, you should see something similar to the following output.
(note: with the extreme values over a temperature range from -20 to 50, I get 164 wind_chill extremes and 332 heat_index extremes)
$ ./bin/windchill
Input a range of temps in deg. C, (e.g. t1 t2): 10 45
Wind Chill:
Deg. C Deg. F 5mph 10mph 15mph 20mph 25mph 30mph 35mph 40mph
10 50.00 47.77 45.59 44.19 43.15 42.31 41.59 40.98 40.43
11 51.80 49.87 47.80 46.48 45.50 44.70 44.02 43.44 42.92
12 53.60 51.96 50.02 48.77 47.84 47.09 46.45 45.90 45.41
13 55.40 54.06 52.23 51.06 50.19 49.48 48.88 48.36 47.90
14 57.20 56.16 54.45 53.35 52.53 51.87 51.31 50.82 50.39
15 59.00 58.26 56.66 55.64 54.88 54.26 53.74 53.28 52.88
16 60.80 60.36 58.88 57.93 57.22 56.65 56.16 55.74 55.37
17 62.60 62.45 61.09 60.22 59.57 59.04 58.59 58.21 57.86
18 64.40 x 63.30 62.51 61.91 61.43 61.02 60.67 60.35
19 66.20 x 65.52 64.80 64.26 63.82 63.45 63.13 62.85
20 68.00 x 67.73 67.09 66.60 66.21 65.88 65.59 65.34
21 69.80 x x 69.38 68.95 68.60 68.31 68.05 67.83
22 71.60 x x x 71.29 70.99 70.74 70.51 70.32
23 73.40 x x x x 73.38 73.16 72.98 72.81
24 75.20 x x x x x x x x
...
Total Extreme Values: 0
Heat Index:
Deg. C Deg. F 40% 50% 60% 70% 80% 90% 100%
...
26 78.80 x x x x x x x
27 80.60 80.35 81.35 82.55 83.94 85.53 87.32 89.31
28 82.40 81.80 83.21 85.01 87.20 89.78 92.75 96.10
29 84.20 83.49 85.39 87.86 90.91 94.53 98.74 103.51
30 86.00 85.44 87.89 91.10 95.07 99.80 105.29 111.55
31 87.80 87.64 90.71 94.72 99.68 105.58 112.42 120.21
32 89.60 90.10 93.85 98.73 104.74 111.86 120.11 129.49
33 91.40 92.81 97.32 103.13 110.25 118.66 128.38 139.39
34 93.20 95.77 101.11 107.92 116.20 125.97 137.21 149.92
35 95.00 98.99 105.22 113.09 122.61 133.78 146.60 161.07
36 96.80 102.46 109.65 118.65 129.47 142.11 156.57 172.84
37 98.60 106.18 114.40 124.60 136.78 150.95 167.10 185.24
38 100.40 110.16 119.47 130.93 144.54 160.30 178.20 198.26
39 102.20 114.39 124.87 137.65 152.75 170.15 189.87 211.90
40 104.00 118.88 130.58 144.76 161.40 180.52 202.11 226.17
41 105.80 123.62 136.62 152.25 170.51 191.40 214.91 241.05
42 107.60 128.61 142.98 160.13 180.07 202.79 228.28 256.56
43 109.40 133.85 149.66 168.40 190.08 214.68 242.22 272.70
44 111.20 139.35 156.66 177.06 200.53 227.09 256.73 289.45
45 113.00 145.10 163.99 186.10 211.44 240.01 271.81 306.83
Total Extreme Values: 97
Look things over and let me know if you have further questions.

Look here:
celsius_f=(celsius*(9/5))+32;
In C 9/5 is not equal to 9/5 as in real math, here integer divided by integer is equal to integer too, rounded to lower value. So here 9/5 is equal to 1, not 1.8. You should use float variable type, for example
celsius_f=(celsius*(9.0/5))+32;
Another mistake is here:
compute_wind_chill(num1, num2);
printf("\nTotal Extreme Values: %d", ext1);
You are displaying float result as integer.

Related

Floating-point numbers are not printed

I am trying to create a conversion table using the C programing language. I want to convert the temperature from -250 °F to 250 °C increments of 10. However, I am not getting the Celsius output:
#include <p18f458.h>
#include <stdio.h>
#pragma config WDT = OFF
#define LOWER -250 /* lower limit of table */
#define UPPER 250 /* upper limit */
#define STEP 10 /* step size */
void main(void)
{
int fh, cel;
cel = (fh - 32) * 5 / 9;
for (fh = LOWER; fh <= UPPER; fh = fh + STEP)
printf("%d \t %6.1f\n", fh, cel);
while(1);
}
Fahrenheit Celsius
-250
-240
-230
-220
-210
-200
-190
-180
-170
-160
-150
-140
-130
-120
-110 .......
The code runs on a PIC18F458 microcontroller.
Recalculate each time
Use floating point math
// dddd123456789012ffffff
puts(" Fahrenheit Celsius");
// cel = (fh - 32) * 5 / 9;
for (fh = LOWER; fh <= UPPER; fh = fh + STEP) {
double cel = (fh - 32.0) * 5.0 / 9.0;
printf(" %4d %6.1f\n", fh, cel);
}
If wanting to avoid floating point types and math, use a scaled integer math to calculate decidegrees to achieve "%6.1f" like output. Scale temperature by 10. Integer division truncates the fraction, so add a signed offset of 5 to form a rounded result.
int offset = (fh - 32) > 0 : 5 : -5;
int deci_celcuis = ((fh - 32) * 10 * 5 + offset) / 9;
Printing is a little tricky. Various approaches exist.
int whole = deci_celcuis/10;
int frac = deci_celcuis%10;
char *sign = (whole < 0 || frac < 0) ? "-", "";
printf(" %4d %s%d.%d\n", fh, sign, abs(whole), abs(frac));
As others have noted: 1) use floating point to avoid integer division and truncation errors, 2) recalculate values inside the loop.
It would be a shame to miss this opportunity to produce parallel tables of F->C and also C->F for the given range.
#define LOWER -250
#define UPPER 250
#define STEP 10
int main() {
puts( " F C C F" );
for( int i = UPPER; i >= LOWER; i -= STEP ) {
printf( "%6.0f %6.0f", (double)i, (i - 32.0) * 5.0 / 9.0 );
printf( " " );
printf( "%6.0f %6.0f\n", (double)i, i * 9.0 / 5.0 + 32.0 );
}
return 0;
}
F C C F
250 121 250 482
240 116 240 464
230 110 230 446
220 104 220 428
210 99 210 410
200 93 200 392
// omitted...
-220 -140 -220 -364
-230 -146 -230 -382
-240 -151 -240 -400
-250 -157 -250 -418
Ordinary mercury thermometers condition people to expect warmer temperatures at the top, and cooler temperatures 'below'... This table reverses the sequence presented in the OP to conform to people's expectations.
cel = (fh - 32) * 5 / 9;
This statement is outside the loop, hence it will only ever print once.
. Add it in the loop and your code would work as expected.

Roots of equation in C

I am relatively new to C, and am trying to improve myself in it. I made a calculator and added the quadratic equation solver to it, cause i know the formula of finding the roots. But i am faced with two problems.
Code:
#include <stdio.h>
#include <maths.h>
#include <stdlib.h>
#include <windows.h>
main(){
float A1, A2, A, B, C, ans, Z;
printf("Welcome to Quadratic Equation solver. Enter the coefficient of X^2, followed by\nthe coefficient of X, followed by the integer value.\n\nEnter values: ");
scanf("%f%f%f", &A, &B, &C);
CheckF = (B * B - 4 * A * C);
if (CheckF < 0) {
system("COLOR B4");
printf("This calculator HeX, currently cannot handle complex numbers.\nPlease pardon my developer. I will now redirect you to the main menu.\n");
system("pause");
system("cls");
system("COLOR F1");
goto Start;
} else if (CheckF >= 0) {
Z = pow(CheckF, 1/2);
A1 = (-B + Z)/(A+A);
A2 = (-B - Z)/(A+A);
if (A1 == A2) {
ans = A1;
printf("\nRoot of equation is %f (Repeated root)\n", ans);
Sleep(250);
} else if (A1 != A2) {
printf("Roots of equation are %f and %f \n", A1, A2);
Sleep(250);
}
}
}
Problem 1:
When i run the code and input 3 32 2, mathematically the output should be Roots of equation are -0.06287 and -10.6038, that i double checked with my sharp calculator. However, the output that i got was was off: Roots of equation are -5.166667 and -5.500000 i am totally unsure why is it not computing the correct roots of the equation.
Problem 2:
Some roots do not have the coefficient of X^2, for example (2X + 2), which can be solved to get repeated roots of -2, (6X - 3), which gives us that x is 0.5 repeated. However, according to the quadratic equation, which is divided by 2A, will never work, as it is divided by 0. What is the possible way out of this situation? Is it to check if A = 0 then do something else? Any help will be appreciable.
integer division
pow(CheckF, 1/2) is 1.0 as 1/2 is integer division with a quotient of 0.
// Z = pow(CheckF, 1/2);
Z = pow(CheckF, 1.0/2.0);
// or better
Z = sqrt(CheckF);
// Even better when working with `float`.
// Use `float sqrtf(float)` instead of `double sqrt(double)`.
Z = sqrtf(CheckF);
Best - re-write using double instead of float. Scant reason for using float here. double is the C goto floating point type.
Other issue
//#include <maths.h>
#include <math.h>
// main() {
int main(void) {
// CheckF = (B * B - 4 * A * C);
float CheckF = (B * B - 4 * A * C);
// goto Start;
Use an auto formater
I see some problems with the code. First, I suggest you to use double instead of float. They offer much better precision and an ideal calculator needs precision. Secondly, you do:
Z = pow(CheckF, 1/2);
You should use sqrt(CheckF) since there is a dedicated function in C for square roots! The following works for me so if you fix the above two problems, your code will probably work.
int main() {
double A1, A2, A, B, C, ans, Z;
printf("Welcome to Quadratic Equation solver. Enter the coefficient of X^2, followed by\nthe coefficient of X, followed by the integer value.\n\nEnter values: ");
A = 3;
B = 32;
C = 2;
double CheckF = (B * B - 4 * A * C);
if (CheckF >= 0) {
Z = sqrt(CheckF);
A1 = (-B + Z) / (A + A);
A2 = (-B - Z) / (A + A);
if (A1 == A2) {
ans = A1;
printf("\nRoot of equation is %f (Repeated root)\n", ans);
} else if (A1 != A2) {
printf("Roots of equation are %f and %f \n", A1, A2);
}
}
}

Implementation of sine function in C not working

I have attempted to implement the sine function in C, yet I am getting weird results. Here are the three functions I am using to calculate sine:
#define PI 3.14159265358979323846
#define DEPTH 16
double sine(long double);
long double pow(long double, unsigned int);
unsigned int fact(unsigned int);
double sine(long double x) {
long double i_x = x *= PI/180;
int n = 3, d = 0, sign = -1;
// fails past 67 degrees
for (; d < DEPTH; n += 2, d++, sign *= -1) {
x += pow(i_x, n) / fact(n) * sign;
}
return x;
}
long double pow(long double base, unsigned int exp) {
double answer = 1;
while (exp) {
answer *= base;
exp--;
}
return answer;
}
unsigned int fact(unsigned int n) {
unsigned int answer = 1;
while (n > 1) {
answer *= n--;
}
return answer;
}
To test it I have been testing it against the built in sine function as follows:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
main() {
for (int i = 0; i <= 180; i++) {
printf("sin(%i) = %lf, %lf\n", i, sine(i), sin(i*3.14159265358979323846/180));
}
exit(EXIT_SUCCESS);
}
Up through 67 degrees, it calculates the same as the built in function. Though, as it increases past 67 it typically strays gets further and further from the actual value.
Here is an example output:
>> sin(100) = 0.987711, 0.984808
>> sin(101) = 0.986885, 0.981627
>> sin(102) = 0.987056, 0.978148
>> sin(103) = 0.988830, 0.974370
>> sin(104) = 0.993060, 0.970296
>> sin(105) = 1.000948, 0.965926
>> sin(106) = 1.014169, 0.961262
>> sin(107) = 1.035052, 0.956305
>> sin(108) = 1.066807, 0.951057
>> sin(109) = 1.113846, 0.945519
>> sin(110) = 1.182194, 0.939693
>> sin(111) = 1.280047, 0.933580
>> sin(112) = 1.418502, 0.927184
>> sin(113) = 1.612527, 0.920505
>> sin(114) = 1.882224, 0.913545
>> sin(115) = 2.254492, 0.906308
>> sin(116) = 2.765192, 0.898794
>> sin(117) = 3.461969, 0.891007
...
>> sin(180) = 8431648.192239, 0.000000
Does anybody know why this is happening? I am using Visual Studio 2017 on Windows 7, if that provides any useful information.
Each time your for loop progresses, n is increased by 2 and hence for DEPTH = 16, near the end of loop you have to calculate factorials of numbers as big as 30 and you are using unsigned int that can only store values as big as 2^32 = 4294967296 ~= 12! and this causes overflow in your factorial function which in turn gives you the wrong factorial.
Even if you used long double for it and I already stated in my comments that long double in MSCRT is mapped to double (Reference) you'd still see some anomalies probably at larger angles because although double can store values as big as 1.8E+308 but it loses its granularity at 2^53 = 9007199254740992 ~= 18! (i.e. 2^53 + 1 stored as a double is equal to 2^53). So once you go up in angles, the effect of this behavior becomes larger and larger to the point that it is noticeable in the 6 decimal precision that you are using with printf().
Although you are on the right track, you should use a bignum library like GMP or libcrypto. They can perform these calculations without the loss of precision.
BTW, since your are developing on Windows 7 that means you are either using x86 or x86-64. On these platforms, x87 is capable of performing extended precision (as per 754 standard) operations with 80 bits but I am unaware of compiler intrinsics that can give you that capability without resorting to assembly code.
I also would like to direct your attention to range reduction techniques. Although I still recommend using bignum libs, if you are good between 0 and 90 degrees (0 and 45 if I'm to be more strict), you can compute the sine() of all other angles just by simple trigonometric identities.
UPDATE:
Actually I'm gonna correct myself about using doubles in factorial calculations. After writing a simple program I verified that when I usedouble to store factorials, they are correct even if I go upper than 18. After giving it some thought I realized that in the case of factorials, the situation with double's granularity is a little bit more complex. I'll give you an example to make it clear:
19! = 19 * 18 * ... * 2 * 1
in this number 18, 16, 14, ... , 2 are all multiples of 2 and since a multiplication by 2 is equivalent to a shift to the left in binary representation, all lower bits in 19! are already 0 and hence when double's rounding kicks in for integers greater than 2^53, these factorials are unaffected. You can compute the number of least significant zeroes in the binary representation of 19! by counting the number of 2's which is 16. (for 20!, it is 18)
I'm gonna go up to 1.8e+308 and check if all the factorials are unaffected or not. I'll update you with the results.
UPDATE 2:
If we use doubles to hold factorials, they are affected by rounding from 23! onward. It can be easily shown, because 2^74 < 23! < 2^75 which means that at least 75 bits of precision is required to represent it, but since 23! has 19 least significant bits with the value of 0, so it needs 75 - 19 = 56 which is larger than 53 bits provided by double.
For 22!, it is 51 bits (you can calculate it yourself).
There are multiple issues in your code:
You redefine the standard function pow() with a different prototype. This may cause problems when you link the program as en executable. Use a different anme such as pow_int.
You should define the pow_int and fact functions as static before the sine function. It may allow for better optimisation at compile time.
Indeed fact is limited by the range of type unsigned int which is much less than the precision of type long double. Factorials beyond 12 have an incorrect value, causing a loss of precision.
You could actually compute the terms incrementally, saving a lot of computations and avoiding potential loss of precision.
The prototype for main() without arguments is int main(void)
The computation of PI/180 is performed as double, which is less precise than long double. You should write the expression as x = x * PI / 180;
DEPTH should be increased to improve the precision. At least 4 more terms bring a substantial improvement.
You should apply a range reduction: taking advantage of the sine function symmetric and periodic nature, computation can be performed with fewer terms on x modulo 90 or even 45 degrees.
Here is a modified version:
#include <stdio.h>
#include <math.h>
#define PI_L 3.14159265358979323846264338327950288L
#define PI 3.14159265358979323846264338327950288
#define DEPTH 24
double sine(long double x) {
long double res, term, x2, t1;
int phase;
x = remquol(x, 90, &phase);
if (phase & 1)
x = 90 - x;
x = x * PI_L / 180; // convert x to radians
x2 = x * x; // pre-compute x^2
// compute the sine series: x - x^3/3! + x^5/5! ...
res = term = x; // the first term is x
for (int n = 1; n < DEPTH; n += 4) {
// to reduce precision loss, compute 2 terms for each iteration
t1 = term * x2 / ((n + 1) * (n + 2));
term = t1 * x2 / ((n + 3) * (n + 4));
// update the result with the difference of the terms
res += term - t1;
}
if (phase & 2)
res = -res;
return (double)res;
}
int main(void) {
printf("deg sin sine delta\n\n");
for (int i = 0; i <= 360; i += 10) {
double s1 = sin(i * PI / 180);
double s2 = sine(i);
printf("%3i %20.17f %20.17f %g\n", i, s1, s2, s2 - s1);
}
return 0;
}
The output is:
deg sin sine delta
0 0.00000000000000000 0.00000000000000000 0
10 0.17364817766693033 0.17364817766693036 2.77556e-17
20 0.34202014332566871 0.34202014332566871 0
30 0.49999999999999994 0.50000000000000000 5.55112e-17
40 0.64278760968653925 0.64278760968653936 1.11022e-16
50 0.76604444311897801 0.76604444311897801 0
60 0.86602540378443860 0.86602540378443860 0
70 0.93969262078590832 0.93969262078590843 1.11022e-16
80 0.98480775301220802 0.98480775301220802 0
90 1.00000000000000000 1.00000000000000000 0
100 0.98480775301220802 0.98480775301220802 0
110 0.93969262078590843 0.93969262078590843 0
120 0.86602540378443882 0.86602540378443860 -2.22045e-16
130 0.76604444311897812 0.76604444311897801 -1.11022e-16
140 0.64278760968653947 0.64278760968653936 -1.11022e-16
150 0.49999999999999994 0.50000000000000000 5.55112e-17
160 0.34202014332566888 0.34202014332566871 -1.66533e-16
170 0.17364817766693025 0.17364817766693036 1.11022e-16
180 0.00000000000000012 -0.00000000000000000 -1.22465e-16
190 -0.17364817766693047 -0.17364817766693036 1.11022e-16
200 -0.34202014332566866 -0.34202014332566871 -5.55112e-17
210 -0.50000000000000011 -0.50000000000000000 1.11022e-16
220 -0.64278760968653925 -0.64278760968653936 -1.11022e-16
230 -0.76604444311897790 -0.76604444311897801 -1.11022e-16
240 -0.86602540378443837 -0.86602540378443860 -2.22045e-16
250 -0.93969262078590821 -0.93969262078590843 -2.22045e-16
260 -0.98480775301220802 -0.98480775301220802 0
270 -1.00000000000000000 -1.00000000000000000 0
280 -0.98480775301220813 -0.98480775301220802 1.11022e-16
290 -0.93969262078590854 -0.93969262078590843 1.11022e-16
300 -0.86602540378443860 -0.86602540378443860 0
310 -0.76604444311897812 -0.76604444311897801 1.11022e-16
320 -0.64278760968653958 -0.64278760968653936 2.22045e-16
330 -0.50000000000000044 -0.50000000000000000 4.44089e-16
340 -0.34202014332566855 -0.34202014332566871 -1.66533e-16
350 -0.17364817766693127 -0.17364817766693036 9.15934e-16
360 -0.00000000000000024 0.00000000000000000 2.44929e-16
As can be seen above, the sine() function seems more precise than the standard sin function on my system: sin(180 * M_PI / 128) should be 0 precisely. Similarly, sin(150 * M_PI / 128) should be 0.5 exactly.
Your way of polynomial series evaluation is numerically unstable. Try horner's method which is more stable than power calculations.
Your problem is here:
for (; d < DEPTH; n += 2, d++, sign *= -1) {
x += pow(i_x, n) / fact(n) * sign;
}
You are using d < DEPTH in error when it should be n < DEPTH, d is irrelevant to your computations within the loop. The following should work -- although I have not compiled to test.
for (; n < DEPTH; n += 2, sign *= -1) {
x += pow(i_x, n) / fact(n) * sign;
}
note: a DEPTH of 12 (e.g. Taylor Series expansion with terms 1, 3, 5, ... 11) is sufficient for 3e-10 error -- 3 ten billionths at 60-degrees. (though error increases as angle increases between 0-360, a DEPTH of 20 will keep error less than 1.0e-8 over the entire range.)
Enabling compiler warnings would have caught the unused d in sine.
Here is an example of code with the changes (note: Gnu provides a constant M_PI for PI):
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#define DEPTH 16
/* n factorial */
uint64_t nfact (int n)
{
if (n <= 0) return 1;
uint64_t s = n;
while (--n)
s *= n;
return s;
}
/* y ^ x */
double powerd (const double y, const int x)
{
if (!x) return 1;
double r = y;
for (int i = 1; i < x; i++)
r *= y;
return r;
}
double sine (double deg)
{
double rad = deg * M_PI / 180.0,
x = rad;
int sign = -1;
for (int n = 3; n < DEPTH; n += 2, sign *= -1)
x += sign * powerd (rad, n) / nfact (n);
return x;
}
int main (void) {
printf (" deg sin sine\n\n");
for (int i = 0; i < 180; i++)
printf ("%3d %11.8f %11.8f\n", i, sin (i * M_PI / 180.0), sine (i));
return 0;
}
Example Use/Output
$ ./bin/sine
deg sin sine
0 0.00000000 0.00000000
1 0.01745241 0.01745241
2 0.03489950 0.03489950
3 0.05233596 0.05233596
4 0.06975647 0.06975647
5 0.08715574 0.08715574
6 0.10452846 0.10452846
7 0.12186934 0.12186934
8 0.13917310 0.13917310
9 0.15643447 0.15643447
10 0.17364818 0.17364818
11 0.19080900 0.19080900
12 0.20791169 0.20791169
13 0.22495105 0.22495105
14 0.24192190 0.24192190
15 0.25881905 0.25881905
16 0.27563736 0.27563736
17 0.29237170 0.29237170
18 0.30901699 0.30901699
19 0.32556815 0.32556815
20 0.34202014 0.34202014
21 0.35836795 0.35836795
22 0.37460659 0.37460659
23 0.39073113 0.39073113
24 0.40673664 0.40673664
25 0.42261826 0.42261826
26 0.43837115 0.43837115
27 0.45399050 0.45399050
28 0.46947156 0.46947156
29 0.48480962 0.48480962
30 0.50000000 0.50000000
31 0.51503807 0.51503807
32 0.52991926 0.52991926
33 0.54463904 0.54463904
34 0.55919290 0.55919290
35 0.57357644 0.57357644
36 0.58778525 0.58778525
37 0.60181502 0.60181502
38 0.61566148 0.61566148
39 0.62932039 0.62932039
40 0.64278761 0.64278761
41 0.65605903 0.65605903
42 0.66913061 0.66913061
43 0.68199836 0.68199836
44 0.69465837 0.69465837
45 0.70710678 0.70710678
46 0.71933980 0.71933980
47 0.73135370 0.73135370
48 0.74314483 0.74314483
49 0.75470958 0.75470958
50 0.76604444 0.76604444
51 0.77714596 0.77714596
52 0.78801075 0.78801075
53 0.79863551 0.79863551
54 0.80901699 0.80901699
55 0.81915204 0.81915204
56 0.82903757 0.82903757
57 0.83867057 0.83867057
58 0.84804810 0.84804810
59 0.85716730 0.85716730
60 0.86602540 0.86602540
61 0.87461971 0.87461971
62 0.88294759 0.88294759
63 0.89100652 0.89100652
64 0.89879405 0.89879405
65 0.90630779 0.90630779
66 0.91354546 0.91354546
67 0.92050485 0.92050485
68 0.92718385 0.92718385
69 0.93358043 0.93358043
70 0.93969262 0.93969262
71 0.94551858 0.94551858
72 0.95105652 0.95105652
73 0.95630476 0.95630476
74 0.96126170 0.96126170
75 0.96592583 0.96592583
76 0.97029573 0.97029573
77 0.97437006 0.97437006
78 0.97814760 0.97814760
79 0.98162718 0.98162718
80 0.98480775 0.98480775
81 0.98768834 0.98768834
82 0.99026807 0.99026807
83 0.99254615 0.99254615
84 0.99452190 0.99452190
85 0.99619470 0.99619470
86 0.99756405 0.99756405
87 0.99862953 0.99862953
88 0.99939083 0.99939083
89 0.99984770 0.99984770
90 1.00000000 1.00000000
91 0.99984770 0.99984770
92 0.99939083 0.99939083
93 0.99862953 0.99862953
94 0.99756405 0.99756405
95 0.99619470 0.99619470
96 0.99452190 0.99452190
97 0.99254615 0.99254615
98 0.99026807 0.99026807
99 0.98768834 0.98768834
100 0.98480775 0.98480775
101 0.98162718 0.98162718
102 0.97814760 0.97814760
103 0.97437006 0.97437006
104 0.97029573 0.97029573
105 0.96592583 0.96592583
106 0.96126170 0.96126170
107 0.95630476 0.95630476
108 0.95105652 0.95105652
109 0.94551858 0.94551858
110 0.93969262 0.93969262
111 0.93358043 0.93358043
112 0.92718385 0.92718385
113 0.92050485 0.92050485
114 0.91354546 0.91354546
115 0.90630779 0.90630779
116 0.89879405 0.89879405
117 0.89100652 0.89100652
118 0.88294759 0.88294759
119 0.87461971 0.87461971
120 0.86602540 0.86602540
121 0.85716730 0.85716730
122 0.84804810 0.84804810
123 0.83867057 0.83867057
124 0.82903757 0.82903757
125 0.81915204 0.81915204
126 0.80901699 0.80901699
127 0.79863551 0.79863551
128 0.78801075 0.78801075
129 0.77714596 0.77714596
130 0.76604444 0.76604444
131 0.75470958 0.75470958
132 0.74314483 0.74314482
133 0.73135370 0.73135370
134 0.71933980 0.71933980
135 0.70710678 0.70710678
136 0.69465837 0.69465836
137 0.68199836 0.68199835
138 0.66913061 0.66913060
139 0.65605903 0.65605902
140 0.64278761 0.64278760
141 0.62932039 0.62932038
142 0.61566148 0.61566146
143 0.60181502 0.60181501
144 0.58778525 0.58778523
145 0.57357644 0.57357642
146 0.55919290 0.55919288
147 0.54463904 0.54463901
148 0.52991926 0.52991924
149 0.51503807 0.51503804
150 0.50000000 0.49999996
151 0.48480962 0.48480958
152 0.46947156 0.46947152
153 0.45399050 0.45399045
154 0.43837115 0.43837109
155 0.42261826 0.42261820
156 0.40673664 0.40673657
157 0.39073113 0.39073105
158 0.37460659 0.37460651
159 0.35836795 0.35836786
160 0.34202014 0.34202004
161 0.32556815 0.32556804
162 0.30901699 0.30901686
163 0.29237170 0.29237156
164 0.27563736 0.27563720
165 0.25881905 0.25881887
166 0.24192190 0.24192170
167 0.22495105 0.22495084
168 0.20791169 0.20791145
169 0.19080900 0.19080873
170 0.17364818 0.17364788
171 0.15643447 0.15643414
172 0.13917310 0.13917274
173 0.12186934 0.12186895
174 0.10452846 0.10452803
175 0.08715574 0.08715526
176 0.06975647 0.06975595
177 0.05233596 0.05233537
178 0.03489950 0.03489886
179 0.01745241 0.01745170
Error Check based on DEPTH
In response to the comment regarding computing the error, you investigate the error associated with Taylor-Series expansions for both sin and cos base on the number of terms by varying DEPTH and setting an max error of EMAX 1.0e-8 using something similar to the following for the range of 0-360 (or 0-2PI),
#define DEPTH 20
#define EMAX 1.0e-8
...
/* sine as above */
...
/* cos with taylor series expansion to n = DEPTH */
long double cose (const long double deg)
{
long double rad = deg * M_PI / 180.0,
x = 1.0;
int sign = -1;
for (int n = 2; n < DEPTH; n += 2, sign *= -1)
x += sign * powerd (rad, n) / nfact (n);
return x;
}
int main (void) {
for (int i = 0; i < 180; i++) {
long double sinlibc = sin (i * M_PI / 180.0),
coslibc = cos (i * M_PI / 180.0),
sints = sine (i),
costs = cose (i),
serr = fabs (sinlibc - sints),
cerr = fabs (coslibc - costs);
if (serr > EMAX)
fprintf (stderr, "sine error exceeds limit of %e\n"
"%3d %11.8Lf %11.8Lf %Le\n",
EMAX, i, sinlibc, sints, serr);
if (cerr > EMAX)
fprintf (stderr, "cose error exceeds limit of %e\n"
"%3d %11.8Lf %11.8Lf %Le\n",
EMAX, i, coslibc, costs, cerr);
}
return 0;
}
If you check, you will find that for anything less than DEPTH 20 (10 terms in each expansion), error will exceed 1.0e-8 for higher angles. Surprisingly, the expansions are very accurate over the first quadrant for values of DEPTH as low as 12 (6-terms).
Addemdum - Improved Taylor-Series Accuracy Using 0-90 & Quadrants
In the normal Taylor-Series expansion, error grows as angle grows. And... because some just can't not tinker, I wanted to further compare accuracy between the libc sin/cos and the Taylor-Series if computations were limited to 0-90 degrees and the remainder of the period from 90-360 were handled by quadrant (2, 3 & 4) mirroring of results from 0-90. It works -- marvelously.
For example, the results of handing only angles 0-90 and bracketing angles between 90 - 180, 180 - 270 and 270 - 360 with an initial angle % 360 produces results comparable to the libc math lib functions. The maximum error between the libc and 8 & 10 term Taylor-Series expansions were, respectably:
Max Error from libc sin/cos
With TSLIM 16
sine_ts max err at : 90.00 deg -- 6.023182e-12
cose_ts max err at : 270.00 deg -- 6.513370e-11
With TSLIM 20
sine_ts max err at : 357.00 deg -- 5.342948e-16
cose_ts max err at : 270.00 deg -- 3.557149e-15
(with a large number of angles showing no difference at all)
The tweaked versions of sine and cose with Taylor-Series were as follows:
double sine (const double deg)
{
double fp = deg - (int64_t)deg, /* save fractional part of deg */
qdeg = (int64_t)deg % 360, /* get equivalent 0-359 deg angle */
rad, sine_deg; /* radians, sine_deg */
int pos_quad = 1, /* positive quadrant flag 1,2 */
sign = -1; /* taylor series term sign */
qdeg += fp; /* add fractional part back to angle */
/* get equivalent 0-90 degree angle, set pos_quad flag */
if (90 < qdeg && qdeg <= 180) /* in 2nd quadrant */
qdeg = 180 - qdeg;
else if (180 < qdeg && qdeg <= 270) { /* in 3rd quadrant */
qdeg = qdeg - 180;
pos_quad = 0;
}
else if (270 < qdeg && qdeg <= 360) { /* in 4th quadrant */
qdeg = 360 - qdeg;
pos_quad = 0;
}
rad = qdeg * M_PI / 180.0; /* convert to radians */
sine_deg = rad; /* save copy for computation */
/* compute Taylor-Series expansion for sine for TSLIM / 2 terms */
for (int n = 3; n < TSLIM; n += 2, sign *= -1) {
double p = rad;
uint64_t f = n;
for (int i = 1; i < n; i++) /* pow */
p *= rad;
for (int i = 1; i < n; i++) /* nfact */
f *= i;
sine_deg += sign * p / f; /* Taylor-series term */
}
return pos_quad ? sine_deg : -sine_deg;
}
and for cos
double cose (const double deg)
{
double fp = deg - (int64_t)deg, /* save fractional part of deg */
qdeg = (int64_t)deg % 360, /* get equivalent 0-359 deg angle */
rad, cose_deg = 1.0; /* radians, cose_deg */
int pos_quad = 1, /* positive quadrant flag 1,4 */
sign = -1; /* taylor series term sign */
qdeg += fp; /* add fractional part back to angle */
/* get equivalent 0-90 degree angle, set pos_quad flag */
if (90 < qdeg && qdeg <= 180) { /* in 2nd quadrant */
qdeg = 180 - qdeg;
pos_quad = 0;
}
else if (180 < qdeg && qdeg <= 270) { /* in 3rd quadrant */
qdeg = qdeg - 180;
pos_quad = 0;
}
else if (270 < qdeg && qdeg <= 360) /* in 4th quadrant */
qdeg = 360 - qdeg;
rad = qdeg * M_PI / 180.0; /* convert to radians */
/* compute Taylor-Series expansion for sine for TSLIM / 2 terms */
for (int n = 2; n < TSLIM; n += 2, sign *= -1) {
double p = rad;
uint64_t f = n;
for (int i = 1; i < n; i++) /* pow */
p *= rad;
for (int i = 1; i < n; i++) /* nfact */
f *= i;
cose_deg += sign * p / f; /* Taylor-series term */
}
return pos_quad ? cose_deg : -cose_deg;
}
Rabbit-trail end found...
Changing the angle range in main to -90 to 90 will still cover the whole sine range. but as the Taylor serie is starting from zero the DEPTH value can be reduced to 7. As earlier mentioned, making the fact function 64 bits unsigned
will fix the 67 degree problem.

Why Is This Factorial Algorithm Not Accurate

Sorry I feel stupid asking this and am prepared to lose half of my points asking this but why does this algorithm not work? It works up to a point. After the number 13 the factorials are a little off. For instance the numbers do not entirely match in the hundreds thousands place and onward.
#include <stdio.h>
float factorial(unsigned int i) {
if (i <= 1) {
return 1;
}
return i * factorial(i - 1);
}
int main() {
int i = 13;
printf("Factorial of %d is %f\n", i, factorial(i));
return 0;
}
Here's the output:
Factorial of 13 is 6227020800.000000
Here is an example of inaccurate output:
Factorial of 14 is 87178289152.000000
The output for the number 14 should actually be this (from mathisfun.com)
14 87,178,291,200
I changed the return type to float to obtain more accurate output but I obtained this code for the most part from here: https://www.tutorialspoint.com/cprogramming/c_recursion.htm
EDIT: If I change to the return type to double the output is accurate up to 21.I am using the %Lf string formatter for the output in the printf function.
Simple. float cannot accurately store integers above 16777216 without loss of precision.
int is better than float. But try long long so you can properly store 19 digits.
OP is encountering the precision limits of float. For typical float, whole number values above 16777216.0f are not all exactly representable. Some factorial results above this point are exactly representable.
Let us try this with different types.
At 11!, the float results exceeds 16777216.0f and is exactly correct.
At 14!, the float result is imprecise because of limited precision.
At 23!, the double result is imprecise because of limited precision.
At 22!, the answer exceeds my uintmax_t range. (64-bit)
At 35!, the answer exceeds my float range.
At 171!, the answer exceeds my double range.
A string representation is accurate endlessly until it reaches buffer limitations.
#include <stdint.h>
#include <string.h>
#include <stdio.h>
uintmax_t factorial_uintmax(unsigned int i) {
if (i <= 1) {
return 1;
}
return i * factorial_uintmax(i - 1);
}
float factorial_float(unsigned int i) {
if (i <= 1) {
return 1;
}
return i * factorial_float(i - 1);
}
double factorial_double(unsigned int i) {
if (i <= 1) {
return 1;
}
return i * factorial_double(i - 1);
}
char * string_mult(char *y, unsigned base, unsigned x) {
size_t len = strlen(y);
unsigned acc = 0;
size_t i = len;
while (i > 0) {
i--;
acc += (y[i] - '0') * x;
y[i] = acc % base + '0';
acc /= base;
}
while (acc) {
memmove(&y[1], &y[0], ++len);
y[0] = acc % base + '0';
acc /= base;
}
return y;
}
char *factorial_string(char *dest, unsigned int i) {
strcpy(dest, "1");
for (unsigned m = 2; m <= i; m++) {
string_mult(dest, 10, m);
}
return dest;
}
void factorial_test(unsigned int i) {
uintmax_t u = factorial_uintmax(i);
float f = factorial_float(i);
double d = factorial_double(i);
char s[2000];
factorial_string(s, i);
printf("factorial of %3d is uintmax_t: %ju\n", i, u);
printf(" float: %.0f %s\n", f, "*" + (1.0 * f == u));
printf(" double: %.0f %s\n", d, "*" + (d == u));
printf(" string: %s\n", s);
}
int main(void) {
for (unsigned i = 11; i < 172; i++)
factorial_test(i);
return 0;
}
Output
factorial of 11 is uintmax_t: 39916800
float: 39916800
double: 39916800
string: 39916800
factorial of 12 is uintmax_t: 479001600
float: 479001600
double: 479001600
string: 479001600
factorial of 13 is uintmax_t: 6227020800
float: 6227020800
double: 6227020800
string: 6227020800
factorial of 14 is uintmax_t: 87178291200
float: 87178289152 *
double: 87178291200
string: 87178291200
factorial of 20 is uintmax_t: 2432902008176640000
float: 2432902023163674624 *
double: 2432902008176640000
string: 2432902008176640000
factorial of 21 is uintmax_t: 14197454024290336768
float: 51090940837169725440 *
double: 51090942171709440000 *
string: 51090942171709440000
factorial of 22 is uintmax_t: 17196083355034583040
float: 1124000724806013026304 *
double: 1124000727777607680000 *
string: 1124000727777607680000
factorial of 23 is uintmax_t: 8128291617894825984
float: 25852017444594485559296 *
double: 25852016738884978212864 *
string: 25852016738884976640000
factorial of 34 is uintmax_t: 4926277576697053184
float: 295232822996533287161359432338880069632 *
double: 295232799039604119555149671006000381952 *
string: 295232799039604140847618609643520000000
factorial of 35 is uintmax_t: 6399018521010896896
float: inf *
double: 10333147966386144222209170348167175077888 *
string: 10333147966386144929666651337523200000000
factorial of 170 is uintmax_t: 0
float: inf *
double: 72574156153079940453996357155895914678961840000000... *
string: 72574156153079989673967282111292631147169916812964...
factorial of 171 is uintmax_t: 0
float: inf *
double: inf *
string: 12410180702176678234248405241031039926166055775016...
Someone posted a similar question a while back. The consensus was if you're writing it for work use a big number library (like GMP) and if it's a programming exercise write up a solution using a character array.
For example:
/* fact50.c
calculate a table of factorials from 0! to 50! by keeping a running sum of character digits
*/
#include <stdio.h>
#include <string.h>
int main (void)
{
printf ("\n Table of Factorials\n\n");
// length of arrays = 65 character digits
char str[] =
"00000000000000000000000000000000000000000000000000000000000000000";
char sum[] =
"00000000000000000000000000000000000000000000000000000000000000001";
const int len = strlen (str);
int index;
for ( int i = 0; i <= 50; ++i ) {
memcpy (str, sum, len);
for ( int j = 1; j <= i - 1; ++j ) {
index = len - 1;
int carry = 0;
do {
int digit = (sum[index] - '0') + (str[index] - '0') + carry;
carry = 0;
if ( digit > 9 ) {
carry = 1;
digit %= 10;
}
sum[index] = digit + '0';
--index;
}
while ( index >= 0 );
}
printf ("%2i! = ", i);
for ( index = 0; sum[index] == '0'; ++index )
printf ("%c", '.');
for ( ; index < len; ++index )
printf ("%c", sum[index]);
printf ("\n");
}
return 0;
}
Why Is This Factorial Algorithm Not Accurate
There's nothing wrong in your algorithm as such. It is just that the data types you use have a limit for the highest number they can store. This will be a problem no matter which algorithm you choose. You can change the data types from float to something like long double to hold something bigger. But eventually it will still start failing once the factorial value exceeds the capacity of that data type. In my opinion, you should put an a condition in your factorial function to return without calculating anything if the passed in argument is greater than a value that your chosen datatype can support.
float can represent a wider range of numbers than int, but it cannot represent all the values within that range - as you approach the edge of the range (i.e., as the magnitudes of the values increase), the gap between representable values gets wider.
For example, if you cannot represent values between 0.123 and 0.124, then you also cannot represent values between 123.0 and 124.0, or 1230.0 and 1240.0, or 12300.0 and 12400.0, etc. (of course, IEEE-754 single-precision float gives you a bit more precision than that).
Having said that, float should be able to represent all integer values up to 224 exactly, so I'm going to bet the issue is in the printf call - float parameters are "promoted" to double, so there's a representation change involved, and that may account for the lost precision.
Try changing the return type of factorial to double and see if that doesn't help.
<gratuitous rant>
Every time I see a recursive factorial function I want to scream. Recursion in this particular case offers no improvement in either code clarity or performance over an iterative solution:
double fac( int x )
{
double result = 1.0;
while ( x )
{
result *= x--;
}
return result;
}
and can in fact result in worse performance due to the overhead of so many function calls.
Yes, the definition of a factorial is recursive, but the implementation of a factorial function doesn't have to be. Same for Fibonacci sequences. There's even a closed form solution for Fibonacci numbers
Fn = ((1 + √5)n - (1 - √5)n) / (2n * √5)
that doesn't require any looping in the first place.
Recursion's great for algorithms that partition their data into relatively few, equal-sized subsets (Quicksort, tree traversals, etc.). For something like this, where the partitioning is N-1 subsets of 1 element? Not so much.
</gratuitous rant>

how to put in mathematical equation in C

I've been trying to look up on Google how to put in an equation in my program but wasn't able to find any. How do you include:
x = ( -b + √b2 - 4ac ) / 2a
in the program?
Here's my code:
{
int a, b, c;
float x;
//statements
printf("Enter three integers: ");
scanf("%d %d %d", &a, &b, &c);
//computeforX
x = ( -b + √b2 - 4ac ) / 2a
printf("The value of x is %.1f", x);
return 0;
}
Assuming we're talking about C (or C++) here, you will need to investigate the sqrt function, and maybe also the pow function as well (although that's unnecessary because b-squared can be computed as b*b).
Note that you will need to convert all of your input values to float or double before you start the calculation, otherwise you will not get the intended result.
You need a table to allow you to translate:
a+b -> a+b
a-b -> a-b
a/b -> a/b
ab -> a*b
√x -> sqrt(x)
x² -> x*x (If you want to square something more complicated it might be best to use a temporary variable for the value to be squared, breaking your equation up into pieces.)
Note that if you divide an int by an int in C you get an int. So better convert those ints to doubles before dividing.
If we are dealing with C++ it would be something like
#include <iostream.h>
#include <cmath>
int main ()
{
//Declare Variables
double x,x1,x2,a,b,c;
cout << "Input values of a, b, and c." ;
cin >>a >>b >>c;
if ((b * b - 4 * a * c) > 0)
cout << "x1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a)" &&
cout << "x2 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a)";
if else ((b * b - 4 * a * c) = 0)
cout << "x = ((-b + sqrt(b * b - 4 * a * c)) / (2 * a)"
if else ((b * b - 4 * a * c) < 0)
cout << "x1 = ((-b + sqrt(b * b - 4 * a * c) * sqrt (-1)) / (2 * a) &&
cout << "x2 = ((-b + sqrt(b * b - 4 * a * c) * sqrt (-1)) / (2 * a);
return (0);
}
Now why do i have this wierd feeling I just did someone's first semester programming class' homework?
Granted its been years and I don't even know if that will compile but you should get the idea.
I am really depressed looking the quality of above answers and help, which has been given.
I hope to improve the content of this thread.
One can compile the C file below with the command line gcc file.c -o file -lm.
Herewith a possible solution in C:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main(){
int da, db, dc;
double x, a,b,c;
//statements
printf("Enter three integers: ");
scanf("%d %d %d", &da, &db, &dc);
a = (double)da;
b = (double)db;
c = (double)dc;
//computeforX
x = (double) ( -b + sqrt(b * b) - 4 * a * c ) / ( 2 * a ) ;
printf("The value of x is %g \n", x);
return 0;
}

Resources