Implementation of sine function in C not working - c

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.

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.

Angle in triangle by coordinates C

i have to find angle ∠BAC in triangle ABC with given coordinates. I'm trying to find cos, then use function acos(cos) and get degrees(not radian) anwser.
The input is Ax,Ay,Bx,By,Cx,Cy coordinates
#include <math.h>
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
int ax,ay,bx,by,cx,cy;
scanf("%d",&n);
for(int i = 0; i<n; i ++){
scanf("%d %d %d %d %d %d",&ax,&ay,&bx,&by,&cx,&cy);
double cosab = (ax*bx+ay*by)/ (sqrt(ax*ax+ay*ay)* sqrt(bx*bx+by*by));
cosab =180* acos(cosab)/M_PI;
printf("cosab is %0.20g\n",cosab);
}
return 0;
}
With input
8
2 1 2 3 5 5
2 1 4 3 2 3
3 1 3 5 2 3
0 0 1 0 10 0
0 0 1 0 -10 1
7 4 3 3 3 3
0 0 1 0 1 1e-5
0 0 1 0 1e-5 1
I get
cosab is 29.744881296942211
cosab is 10.304846468766044
cosab is 40.601294645004479
cosab is -1.#IND
cosab is -1.#IND
cosab is 15.255118703057764
cosab is -1.#IND
cosab is -1.#IND
But the anwser should be
36.869897645844019962
45
26.565051177077990019
0
174.28940686250035697
0
0.00057295779511172474814
89.999427042204885652
What is "-1.#IND" and what's wrong with my code?
As others have pointed out, the input coordinates are floating point, so let us read them into doubles:
double ax,ay,bx,by,cx,cy;
/* Read coordinates of A, B, and C. */
scanf("%lf%lf%lf%lf%lf%lf",&ax,&ay,&bx,&by,&cx,&cy);
∠BAC is the angle between lines AB and AC. Let us consider those as vectors AB and AC represented by their x and y components:
/* Convert to vectors AB and AC (as x and y components). */
double abx = bx - ax; /* x component of vector AB */
double aby = by - ay; /* y component of vector AB */
double acx = cx - ax; /* x component of vector AC */
double acy = cy - ay; /* y component of vector AC */
Now there is a nice formula using ATAN2 on the vector components to get the angle of rotation from one 2D vector to another1:
/*
* Get angle of rotation from vector AB to vector AC
* in the range [-M_PI, +M_PI].
*/
double rot_ab_ac = atan2(acy*abx - acx*aby, acx*abx + acy*aby);
We want the absolute angle, not a signed angle:
/* Convert to absolute angle BAC. */
double bac = fabs(rot_ab_ac);
Finally, we want the angle in degrees, not radians:
/* Convert to degrees. */
double bac_deg = bac * 180.0 / M_PI;
Note: M_PI is not defined in the C standard, but can be easily defined by a macro if necessary:
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
1 Angle Between Two Vectors 2D Formula
Input is not only integers
1e-5 is like 0.00001. Read that into a double.
// int ax,ay,bx,by,cx,cy;
double ax,ay,bx,by,cx,cy;
...
//scanf("%d %d %d %d %d %d",&ax,&ay,&bx,&by,&cx,&cy);
scanf("%lf %lf %lf %lf %lf %lf",&ax,&ay,&bx,&by,&cx,&cy);
Be careful with acos()
The |x| in acos(x) may be just a tad larger than 1.0 due to computationally issues. Best to check
// add
if (cosab > 1.0) cosab = 1.0;
else if (cosab < -1.0) cosab = -1.0;
cosab = 180 * acos(cosab) / M_PI;
Perhaps better precision
// sqrt(ax*ax+ay*ay)
hypot(ax, ay)
Other issues may exist too
Worth reviewing if proper formula is used: Law of cosines

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

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.

Calculate the function sin()

For my studies, I have to code an algorithm to calculate sin() with this function:
However, in my algorithm, I have to keep the value of X between 0 and Pi/2. So, I wrote my algorithm but all the results are wrong.
Here is my code:
double sinX(double x){
double resultat = 0;
int i;
if(x < 0 || x > M_PI_2)
x = fmod(x,M_PI_2);
for(i = 1;i<=30;i++){
resultat += -1 * ((x*x)/(2*i*(2*i+1)))*(pow(-1,i-1))*((pow(x,2*i-1))/(factorielle(2*i-1)));
}
return resultat;
}
I didn't find the reason. Can you help me?
Here the are few values of X and the result with fmod
1 / 1
2 / 0.429204
3 / 1.4292
4 / 0.858407
5 / 0.287611
6 / 1.28761
7 / 0.716815
8 / 0.146018
9 / 1.14602
10 / 0.575222
11 / 0.00442571
12 / 1.00443
13 / 0.433629
14 / 1.43363
15 / 0.862833
16 / 0.292037
17 / 1.29204
18 / 0.72124
19 / 0.150444
20 / 1.15044
and the result with the algorithm
1 / -0.158529
2 / -0.0130568
3 / -0.439211
4 / -0.101605
5 / -0.00394883
6 / -0.327441
7 / -0.0598281
8 / -0.000518332
9 / -0.234888
10 / -0.0312009
11 / -1.44477e-008
12 / -0.160572
13 / -0.0134623
14 / -0.443022
15 / -0.103145
16 / -0.00413342
17 / -0.330639
18 / -0.0609237
19 / -0.000566869
20 / -0.237499
Here is my "factorielle" definition
double factorielle(double x){
double resultat = 1;
int i;
if(x != 0){
for (i=2;i<=x;i++)
{
resultat *= i;
}
}
else{
resultat = 1;
}
return resultat;
}
And values :
1 / 1
2 / 2
3 / 6
4 / 24
5 / 120
6 / 720
7 / 5040
8 / 40320
9 / 362880
10 / 3.6288e+006
11 / 3.99168e+007
12 / 4.79002e+008
13 / 6.22702e+009
14 / 8.71783e+010
15 / 1.30767e+012
16 / 2.09228e+013
17 / 3.55687e+014
18 / 6.40237e+015
19 / 1.21645e+017
20 / 2.4329e+018
You're misunderstanding the purpose of the second formula you show. The idea is that you use that formula to compute each term in the sum from the preceding term, saving you from the need to use any pow or factorial calls.
#include <stdio.h>
double sinX(double x) {
double term, total_so_far;
int i;
term = x; /* First term in the expansion. */
total_so_far = 0.0;
for (i = 1; i <= 30; i++) {
/* Add current term to sum. */
total_so_far += term;
/* Compute next term from the current one. */
term *= -(x * x) / (2*i) / (2*i + 1);
}
return total_so_far;
}
int main(void) {
/* testing */
double x;
int i;
for (i = 0; i <= 10; i++) {
x = i / 10.0;
printf("sin(%f) is %f\n", x, sinX(x));
}
return 0;
}
And the results of running this code, on my machine:
sin(0.000000) is 0.000000
sin(0.100000) is 0.099833
sin(0.200000) is 0.198669
sin(0.300000) is 0.295520
sin(0.400000) is 0.389418
sin(0.500000) is 0.479426
sin(0.600000) is 0.564642
sin(0.700000) is 0.644218
sin(0.800000) is 0.717356
sin(0.900000) is 0.783327
sin(1.000000) is 0.841471
That should give you reasonable results for the range 0 to pi / 2. Outside that range you'll need to be a bit cleverer about the reduction you're using: simply reducing modulo pi / 2 won't give correct results. (Hint: it's safe to reduce modulo 2 * pi, since the sin function is periodic with period 2 * pi. Now use symmetries of the sin function to reduce to the range 0 to pi / 2.)
EDIT An explanation of why the current code is giving incorrect results: apart from the flawed reduction step, in your sum you start with the term i = 1. But the first term should be for i = 0 (that's the x term, while the i=1 term is the -x^3 / 3! term). A quick and dirty fix is to remove the reduction step, and to initialise your resultat variable to x rather than 0. That should give you good results for small x, and then you can figure out how to replace the reduction step. I'd be surprised if you were really intended to compute the answer using explicit factorial and power calls, though - I'm almost sure that you're expected to compute each term from the preceding one as described above.
There are two problems with your code:
sin(x+k*π/2) does not necessarily equal sin(x)
Your expression for the term is a little bit messed up. The instructions seem to suggest that you calculate the next term in the series from the previous term. Start with the value for i=0 and then use the equation in your question to compute the next term in each iteration.
Finally, I followed yours indications. Here is my final code :
double sinX(double x)
{
double result = 1.0;
double term_i = 1.0;
int i = 2;
x = fmod(x, 2*M_PI);
for(i = 2; i<= 30; i+=2)
{
term_i = (-term_i * (x*x)) / (i*(i+1));
result += term_i;
}
return x * result;
}
Idea about the number of terms with OP's posted answer.
As long as one performs some range limitation first, like fmod(), the number of terms needed can be reasonably determined dynamically. (Uses 1 to 23 iterations for x: 0 to 2*pi.)
double sinX1(double x)
{
double result = 1.0;
double term_i = 1.0;
int i = 2;
x = fmod(x, 2*M_PI);
// for(i = 2; i<= 30; i+=2)
for(i = 2; ((1.0 + term_i) != 1.0); i+=2)
{
term_i = (-term_i * (x*x)) / (i*(i+1));
result += term_i;
}
return x * result;
}

Fibonacci Recursion using Golden Ratio(Golden Number)

i can do a recursive function to compute the nth Fibonacci term as follows:
int rec (int i)
{
if(i == 1 || i == 2)
return i;
else return rec(i-1)+rec(i-2);
}
But i want to use the golden number which is 1.618 to compute the Fibonacci; but my attempt fails, i get wrong numbers:
int rec (int i)
{
if(i == 1 || i == 2)
return i;
else return 1.618*rec(i-1);
}
How can i get it to work?
The golden ratio is an irrational number, so you shouldn't necessarily expect to be able to plug an approximation of it into a formula to get an exact result.
If you want to know how to calculate the nth fibonacci number quickly, here is a page that lists a variety of methods in decreasing order of runtime (but increasing in order of implementation difficulty): https://www.nayuki.io/page/fast-fibonacci-algorithms
If you are referring to the Binet's Formula, do something like this:
long fib(int i) {
double phi = // Golden Ratio
return Math.round((Math.pow(phi, i) - Math.pow(-phi, -i)) / Math.sqrt(5));
}
Note that the above formula is not recursive. I am not aware of any recursive formulas for calculating the fib. sequence using the golden ratio.
Your math appears to be flawed, and you're rounding too often. I used this formula.
This works:
double gr = 1.618033988749895;
int rec (int i)
{
return (int)round(rec2(i)/(gr+2));
}
double rec2 (int i)
{
if (i == 1)
return gr;
else return gr*rec2(i-1);
}
Also, it doesn't really need to be recursive:
static int rec (int i)
{
return (int)round(pow(gr, i)/(gr+2);
}
I didn't check too many numbers, but it appears to be quite accurate (Java).
This is how you do this:
double gr = 1.618033988749895;
double FibGoldenRatio(int i)
{
if (i == 1 )
return 1;
return Math.Round(gr * FibGoldenRatio(i - 1));
}
Here Example of output:
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903
2971215073
4807526976
7778742049
12586269025
20365011074
32951280099
53316291173
86267571272
139583862445
225851433717
365435296162
591286729879
956722026041
1548008755920
2504730781961
4052739537881
6557470319842
10610209857723
17167680177565
27777890035288
44945570212853
72723460248141
117669030460994
190392490709135
308061521170129
498454011879264
806515533049393
1.30496954492866E+15
You can calculate the golden ratio yourself and use it to find the nth Fibonacci number.
long long fib(int n) {
double phi = (1 + sqrt(5))/2.0; // golden ratio
double phi_hat = (1 - sqrt(5))/2.0; // fraction part of golden ratio
return (pow(phi, n) - pow(phi_hat, n))/sqrt(5);
}

Resources