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);
}
Related
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.
given a function that takes two numbers: Mirror( num 1, num 2)
how do I check if num2 is the mirror of number 1? IN C
for example if num 1= 523 num2=325 return 1: it's its mirror otherwise returns 0
more examples
num1=566 num2:566 returns false
num1=500 num2=005 return true
the length of the two numbers is unknown
You can compute the reverse and then compare the result with your other number.
int mirror(int n,int m)
{
int rev=0;
while(n>0)
{
rev*=10;
rev+=n%10;
n/=10;
}
return rev==m ? 1 : 0;
}
Will Not work for input like 290 and 92. Here 290 reverse will be 92 which will make it mirror image if we check by just reversing the num. Which is wrong.
We can correct it by making sure that we reverse the smaller of these numbers and then checking e.g. for 29 and 920, 29 being smaller will give rev = 92 which is not same as 920 and hence the correct answer.
int mirror(int s, int l){
// swap the numbers so that s is always smaller than l
if (s > l) {
int temp = s;
s = l;
l = temp;
}
int rev=0;
while(s > 0){
rev*=10;
rev+=n%10;
n/=10;
}
return rev==l ? 1 : 0;
}
I am trying to solve INTEGER1 problem on spoj. My approach is very simple. It first calculates x(x^i=n) for all power of from 2 to 63. It then removes all the duplicates and then finally adds up the powers. But its is giving me wrong answer on spoj.
I have tried it on Ideone and my machine for many use cases but it is giving me correct result.
#include<stdio.h>
#include<math.h>
int main()
{
unsigned long long int a,b,result;
unsigned long long int power[65],temp;
int i,j;
while(1)
{
scanf("%lld",&a);
scanf("%lld",&b);
if(a==0)
break;
result=0;
power[0]=0;
power[1]=b-a+1;
a--;
for(i=2;i<64;i++)
{
power[i]=floor(pow((long double)b,(long double)1/i));
while(pow((power[i]-1),(long double)i)>=b)
{
power[i]--;
}
while(pow((power[i]+1),(long double)i)<=b)
{
power[i]++;
}
temp=floor(pow((long double)a,(long double)1/i));
while(pow((temp-1),(long double)i)>=a)
{
temp--;
}
while(pow((temp+1),(long double)i)<=a)
{
temp++;
}
power[i]-=temp;
}
for(i=63;i>=1;i--)
{
for(j=i*2;j<64;j=j+i)
{
power[i]-=power[j];
}
}
for(i=1;i<64;i++)
{
result+=i*power[i];
}
printf("%lld\n",result);
}
return 0;
}
Please help me out.
for the input
100 100
10000 100000000
100000000000 100000000000
100000000000000 100000000000000
1000000000000000 1000000000000000
0 0
your output is
2
100001508
11
14
11
but correct output is
2
100001508
11
14
15
now for finding kth root of a..doing some mathematics
let x = a ^ (1 / k) (^ denotes power NOT XOR)(this is also `kth` root of `a`)
taking natural logarithm (ln) both sides
ln x = ln (a ^ (1 / k)) = (1 / k) * ln (a) {property of log}
now taking exponent both sides
exp (ln x) = exp (ln (a) / k)
and according to log property
exp (ln x) = x
so we finally get
x = exp (ln(a) / k) which is equivalent to `kth` root of `a`
here is a function for finding it in C
remember in mathematics we use ln for finding natural logarithm which is equivalent to that of log in C
double kth_root_finder(long long int a, long long int k) {
if (k == 1) {
return a;
}
if (k == 2) {
return sqrt(a);
}
return exp(log(a) / k);
}
EDIT 1:-as the OP pointed out, there will be overflow but i don't think so it will happen..consider a case where we have
a = 1000000000000000000 and k = 2 (worst case)(ignoring second if condition)
then
exp(log(1000000000000000000) / 2) = 999999999.999999 = 1000000000(if ceil is taken)
here is a link for above..
so i don't think there is a chance of overflow..if its there please point out..
I have a code that calculates the square root of a number the following way:
void f1(int,int);
int main(){
int i=1;
int n;
scanf("%d",&n);
f1(n,i);
getch();
return 0;
}
void f1(int n,int i){
if((n*10000)-(i*i)<=0)
printf("%f",(double)i/100);
else
f1(n,i+1);
}
I don't know why using n*10000 - i*i. Can someone explain this code please?
Lets consider the example n=100. For the first bunch of recursions, we have i=1,2,3,.... Thus, for these calls, we have n*10000 - i*i >= 0. Then at some point we have i=999 and observe that n*10000 - 999*999 >= 0. The next recursive step has i=1000 and we see that n*10000 - 1000*1000 <= 0, so we print (double)i / 100, which is then just 10. As you can see, the result is just the sqare root of n=100.
In general, the smallest number i/100 satisfying n*10000 - i*i <= 0 is "quite close" to the sqare root of n, because of the following:
sqrt(n*10000) = sqrt(n)*sqrt(10000) = sqrt(n)*100
And we have:
n*10000 - i*i <= 0 | +i*i
n*10000 <= i*i | sqrt both sides
sqrt(n)*100 <= i | /100
sqrt(n) <= i/100
Thus, we are looking for the smallest number i/100 that is greater or equal to sqrt(n) and use this number as an approximation for sqrt(n).
you call the function with n and i,
now as long as i*i is smaller than n * 10000 you increase your i.
if your i*i is bigger than n * 10000 you print i / 100
eg: you call function with f1(1,1):
1*10000 >= 1*1 --> f1(1,2);
1*10000 >= 2*2 --> f1(1,3);
1*10000 >= 3*3 --> f1(1,4);
....
1*10000 >= 99*99 ->f1(1,100);
1*10000 <= 100*100 --> printf("%f",i/100.0); which gives: 1
EDIT: another example, you look for the sqare root of 8: f1(8,1);
8*10000 >= 1*1 --> f1(8,2);
8*10000 >= 2*2 --> f1(8,3);
1*10000 >= 3*3 --> f1(8,4);
....
8*10000 >= 282*282 ->f1(8,283);
8*10000 <= 283*283 --> printf("%f",i/100.0); which gives: 2.83
and 2.83 * 2.83 = 8.0089
EDIT: you may ask why n*10000, its because the calculation error gets smaller, eg: if you use n*100 and i/10 in the sqrt of 8 example you get
8*100 <= 29*29 --> 2.9
2.9 * 2.9 = 8.41 which is not good as 2.83 in the other example
That is just to add some precision.
void f1(int n,int i){
printf("value of i is=%d \n",i);
if(n-i*i<=0)
printf("%f",i);
else
f1(n,i+1);
}
this code will work for only perfect square numbers.
void f1(int n,int i){
printf("value of i is=%d \n",i);
if((n*100)-(i*i)<=0)
printf("%f",(double)i/10);
else
f1(n,i+1);
}
this code will work for all numbers but will give result for just one digit after floating point.
void f1(int n,int i){
printf("value of i is=%d \n",i);
if((n*10000)-(i*i)<=0)
printf("%f",(double)i/100);
else
f1(n,i+1);
}
this is your code which gives 2 digit point precision after floating point.
so that (n*10000)-(i*i) is necessary as per your requirement.
if you want to find for only perfect you can use first code too.
Consider this function:
void f1(int n,int i){
if((n)-(i*i)<=0)
printf("%f",i);
else
f1(n,i+1);
}
This function would recursively loop over i until i^2 >=n, it's basically the same as doing this without recursion:
void f1(int n,int i){
int i = 1;
while (i*i < n)
++i;
printf("%f",i);
}
Now the trick with the 10000 is just to add some precision emulated by large integers (note that it might overflow an int faster like that) - you calculate sqrt(100*100*n), which is 100*sqrt(n), so you divide the result by 100. This allows you to get a 2 digit precision.
because it will get the result rounded to two decimals.
for example,
n=10 the result is 3.17.
and if you want to get result rounded to 3 decimals, you can write:
if((n*1000000)-(i*i)<=0)
printf("%f",(double)i/1000);
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;
}