I have a recursive function g3, which I cannot understand what is the logic behind it, and what it actually does in general case.
double g3(double n) {
if (n <= 1)
{
return 2;
}
double temp = g3(n / 2);
return temp * temp;
}
For 1 I got 2
For 2 I got 4
For 3 I got 16
For 4 I got 16
Can you help me understand what it does?
You could start by analyzing the cases, going from stop clause up, and looking not only on the "number" but what it represents:
g3(1) = 2 = 2^1
g3(2) = g3(1)^2 = 2^2
g3(4) = g3(2)^2 = (2^2)^2 = 2^4
g3(8) = g3(4)^2 = (2^4)^2 = 2^8
g3(16) = g3(8)^2 = (2^8)^2 = 2^16
So, this is pretty clear (I hope) what happens when n = 2^k for some integer k.
Can you prove it?
Can you repeat the process to answer what happens when n != 2^k for some integer k ?
Related
The computational cost will only consider how many times c = c+1; is executed.
I want to represent the Big O notation to use n.
count = 0; index = 0; c = 0;
while (index <= n) {
count = count + 1;
index = index + count;
c = c + 1;
}
I think if the "iteration of count" is k and "iteration of index" is n, then k(k+1)/2 = n.
So, I think O(root(n)) is the answer.
Is that right solution about this question?
Is that right solution about this question?
This is easy to test. The value of c when your while loop has finished will be the number of times the loop has run (and, thus, the number of times the c = c + 1; statement is executed). So, let us examine the values of c, for various n, and see how they differ from the posited O(√n) complexity:
#include <stdio.h>
#include <math.h>
int main()
{
printf(" c root(n) ratio\n"); // rubric
for (int i = 1; i < 10; ++i) {
int n = 10000000 * i;
int count = 0;
int index = 0;
int c = 0;
while (index < n) {
count = count + 1;
index = index + count;
c = c + 1;
}
double d = sqrt(n);
printf("%5d %8.3lf %8.5lf\n", c, d, c / d);
}
return 0;
}
Output:
c root(n) ratio
4472 3162.278 1.41417
6325 4472.136 1.41431
7746 5477.226 1.41422
8944 6324.555 1.41417
10000 7071.068 1.41421
10954 7745.967 1.41416
11832 8366.600 1.41419
12649 8944.272 1.41420
13416 9486.833 1.41417
We can see that, even though there are some 'rounding' errors, the last column appears reasonably constant (and, as it happens, an approximation to √2, which will generally improve as n becomes larger) – thus, as we ignore constant coefficients in Big-O notation, the complexity is, as you predicted, O(√n).
Let's first see how index changes for each loop iteration:
index = 0 + 1 = 1
index = 0 + 1 + 2 = 3
index = 0 + 1 + 2 + 3 = 6
...
index = 0 + 1 + ... + i-1 + i = O(i^2)
Then we need to figure out how many times the loop runs, which is equivalent of isolating i in the equation:
i^2 = n =>
i = sqrt(n)
So your algorithm runs in O(sqrt(n)) which also can be written as O(n^0.5).
So, I have to make a work for college and it consists in creating an algorithm.
The algorithm must find couples of numbers which satisfy a certain condition, which is: the sum from 1 to n (exlusive) results the same as the sum from n+1 to m (inclusive).
At the final, the algorithm must give at least 15 couples.
The first couple is 6 and 8, because from 1 to n (exclusive) (6) is 1+2+3+4+5 = 15 and from n+1 to m is 8+7 = 15.
The algorithm I created is the following one:
int main() {
int count = 0;
unsigned int before = 0;
unsigned int after = 0;
unsigned int n = 1;
unsigned int m = 0;
do {
before += n - 1;
after = n + 1;
for (m = after + 1; after < before; m++) {
after += m;
}
if (before == after) {
printf("%d\t%d\n", n, (m - 1));
count++;
}
n++;
} while (count < 15);
}
This is actually OK, but some of the output are not correct, and its also crap, in terms of complexity, and since I am studying Complexity of Algorithms, it would be good to find some algorithm better than this one.
I also tried doing it in Java, but using int is not good for this problem and using long, it takes hours and hours to compute.
The numbers I have found so far:
6 and 8
35 and 49
204 and 288
1189 and 1681
6930 and 9800
40391 and 57121
The following ones may be incorrect:
100469 and 107694
115619 and 134705
121501 and 144689
740802 and 745928
1250970 and 1251592
2096128 and 2097152
2100223 and 2101246
4196352 and 8388608
18912301 and 18912497
Your results are incorrect beyond the first 6: the range of type unsigned int is insufficient to store the sums. You should use type unsigned long long for before and after.
Furthermore, your algorithm becomes very slow for large values because you recompute after from scratch for each new value of before, with a time complexity of O(N2). You can keep 2 running sums in parallel and reduce the complexity to quasi-linear.
Last but not least, there are only 12 solutions below UINT32_MAX, so type unsigned long long, which is guaranteed to have at least 64 value bits is required for n and m as well. To avoid incorrect results, overflow should be tested when updating after.
Further tests show that the sums after and before exceed 64 bits for values of m around 8589934591. A solution is to subtract 262 from both before and after when they reach 263. With this modification, the program can keep searching for larger values of n and m much beyond 32-bits.
Here is an improved version:
#include <stdio.h>
int main() {
int count = 0;
unsigned long long n = 1;
unsigned long long m = 2;
unsigned long long before = 0;
unsigned long long after = 2;
for (;;) {
if (before < after) {
before += n;
n++;
after -= n;
} else {
m++;
/* reduce values to prevent overflow */
if (after > 0x8000000000000000) {
after -= 0x4000000000000000;
before -= 0x4000000000000000;
}
after += m;
while (before > after) {
after += n;
n--;
before -= n;
}
}
if (before == after) {
printf("%llu\t%llu\n", n, m);
count++;
if (count == 15)
break;
}
}
printf("%d solutions up to %llu\n", count, m);
return 0;
}
Output (running time 30 minutes):
6 8
35 49
204 288
1189 1681
6930 9800
40391 57121
235416 332928
1372105 1940449
7997214 11309768
46611179 65918161
271669860 384199200
1583407981 2239277041
9228778026 13051463048
53789260175 76069501249
313506783024 443365544448
15 solutions up to 443365544448
Your initial brute force program as posted above generates plenty of data for you to analyze. The people in the question's comments recommended the "sum of an arithmetic series" formula instead of your repeated addition, but the fact is that it still would run slow. It's surely an improvement, but it's still not good enough if you want something usable.
Believe it or not, there are some patterns to the values of n and m, which will require some math to explain. I'll be using the functions n(i), m(i), and d(i) = m(i) - n(i) to represent the values of n, m, and the difference between them, respectively, during iteration i.
You found the first six couples:
i n(i) m(i) d(i)
== ====== ====== ======
1 6 8 2
2 35 49 14
3 204 288 84
4 1189 1681 492
5 6930 9800 2870
6 40391 57121 16730
Notice that 6+8 = 14, 35+49 = 84, 204+288 = 492, etc. It so happens that, in the general case, d(i+1) = m(i) + n(i) (e.g. d(2) = m(1) + n(1) = 6 + 8 = 14).
So now we know the following:
d(7)
= n(6) + m(6)
= 40391 + 57121
= 97512
# m(i) = n(i) + d(i)
m(7) = n(7) + 97512
Another way of looking at it since m(i) = n(i) + d(i) is d(i+1) = d(i) + 2n(i):
d(7)
= n(6) + d(6) + n(6)
= d(6) + 2n(6)
= 16730 + 2(40391)
= 97512
d(i) also happens to be useful for computing n(i+1):
n(i+1) = 2d(i+1) + n(i) + 1
n(7) = 2d(7) + n(6) + 1
= 2(97512) + 40391 + 1
= 235416
From there, it's easy to determine things:
i n(i) m(i) d(i)
== ====== ====== ======
1 6 2 8
2 35 14 49
3 204 84 288
4 1189 492 1681
5 6930 2870 9800
6 40391 16370 57121
7 235416 332928 97512
But what about a starting condition? We need a way to find 6 in the first place, and that starting case can be computed by working backward and using substitution:
n(1) = 2d(1) + n(0) + 1
6 = 2(2) + n(0) + 1
5 = 4 + n(0)
1 = n(0)
d(1) = d(0) + 2n(0)
2 = d(0) + 2(1)
2 = d(0) + 2
0 = d(0)
m(0) = n(0) + d(0)
= 1 + 0
= 1
Note that n(0) = m(0) (1 = 1), but it is not a couple. For a pair of numbers to be a couple, the numbers must not be the same.
All that's left is to compute the sum. Since the integers from 1 to n-1 (i.e. 1 to n, excluding n) form an arithmetic series and the series starts at 1, you can use the formula
n(n - 1)
S(n) = --------
2
Below is a program that uses all of this information. You'll notice I'm using a multiplication function mul in place of the multiplication operator. The function's result is used to end the loop prematurely when an unsigned overflow (i.e. wraparound) is encountered. There are probably better ways to detect the wraparound behavior, and the algorithm could be better designed, but it works.
#include <errno.h>
#include <limits.h>
#include <stdio.h>
typedef unsigned long long uval_t;
/*
* Uses a version of the "FOIL method" to multiply two numbers.
* If overflow occurs, 0 is returned, and errno is ERANGE.
* Otherwise, no overflow occurs, and the product m*n is returned.
*/
uval_t mul(uval_t m, uval_t n)
{
/*
* Shift amount is half the number of bits in uval_t.
* This allows us to work with the upper and lower halves.
* If the upper half of F is not zero, overflow occurs and zero is returned.
* If the upper half of (O+I << half_shift) + L is not zero,
* overflow occurs and zero is returned.
* Otherwise, the returned value is the mathematically accurate result of m*n.
*/
#define half_shift ((sizeof (uval_t) * CHAR_BIT) >> 1)
#define rsh(v) ((v) >> half_shift)
#define lsh(v) ((v) << half_shift)
uval_t a[2], b[2];
uval_t f, o, i, l;
a[0] = rsh(m);
a[1] = m & ~lsh(a[0]);
b[0] = rsh(n);
b[1] = n & ~lsh(b[0]);
f = a[0] * b[0];
if (f != 0)
{
errno = ERANGE;
return 0;
}
o = a[0] * b[1];
i = a[1] * b[0];
l = a[1] * b[1];
if (rsh(o+i + rsh(l)) != 0)
{
errno = ERANGE;
return 0;
}
return lsh(o+i) + l;
}
int main(void)
{
int i;
uval_t n = 1, d = 0;
uval_t sum = 0;
#define MAX 15
for (i = 1; i <= MAX; i++)
{
d += n * 2;
n += d * 2 + 1;
sum = mul(n, n - 1) / 2;
if (sum == 0)
break;
printf("%2d\t%20llu\t%20llu\t%20llu\n", i, n, n+d, sum);
}
return 0;
}
This yields 12 lines of output, the last being this one:
12 1583407981 2239277041 1253590416355544190
Of course, if you don't care about the sums, then you can just avoid computing them entirely, and you can find all 15 couples just fine without even needing to check for overflow of a 64-bit type.
To go further with the sums, you have a few options, in order of most to least recommended:
use a "bignum" library such as GNU MP, which is similar to Java's java.math.BigInteger class and which has its own printf-like function for displaying values; if you're on Linux, it may already be available
use your compiler's 128-bit type, assuming it has one available, and create your own printing function for it if necessary
create your own "big integer" type and the associated necessary addition, subtraction, multiplication, division, etc. printing functions for it; a way that allows for easy printing is that it could just be two unsigned long long values glued together with one representing the lower 19 decimal digits (i.e. the max value for it would be 999 9999 9999 9999 9999), and the other representing the upper 19 digits for a total of 38 digits, which is 1038-1 or 127 bits
The fact that the full 15 sums required don't fit in 64 bits, however, makes me concerned that the question was perhaps worded badly and wanted something different from what you wrote.
Edit
To prove this works, we must first establish some rules:
For any values n and m, 0 ≤ n < m must be true, meaning n == m is forbidden (else we don't have a couple, a.k.a. "ordered pair").
n and m must both be integers.
With that out of the way, consider an algorithm for computing the sum of an arithmetic series starting at a and ending at, and including, b with a difference of +1 between each successive term:
(b - a + 1)(b + a)
S(a, b) = ------------------
2
b² - a² + b + a
= ---------------
2
b(1 + b) + a(1 - a)
= -------------------
2
If such a series begins at a=1, you can derive a simpler formula:
b(b + 1)
S(b) = --------
2
Applying this to your problem, you want to know how to find values such that the following is true:
S(n-1) = S(n+1, m)
After applying the arguments, the result looks like this:
(n-1)n m(1 + m) + (n+1)[1 - (n+1)]
------ = ---------------------------
2 2
(n-1)n = m(1 + m) + (n+1)(1 - n - 1)
n² - n = m² + m + (n+1)(-n)
n² - n = m² + m - n² - n
2n² = m² + m
While not important for my purposes, it's perhaps worth noting that m² + m can be rewritten as m(m+1), and the 2n² signifies that one or both of m and m+1 must be divisible by 2. In addition, one must be a perfect square while the other must be twice a perfect square due to the requirement that at least one expression must be divisible by 2. In other words, 2n² = m(m+1) = 2x²y². You can find another equally valid solution using x and y to generate the values of n and m, but I won't demonstrate that here.
Given the equations for n(i+1), m(i+1), and d(i+1):
d(i+1) = d(i) + 2n(i)
= m(i) + n(i)
n(i+1) = 2d(i+1) + n(i) + 1
= 2m(i) + 3n(i) + 1
m(i+1) = d(i+1) + n(i+1)
= 3m(i) + 4n(i) + 1
And the starting conditions:
n(0) = 1
d(0) = 0
m(0) = 1
We can determine whether they actually work by substituting i+2 in place of i in all cases and finding whether we end up with the same equation. Assuming f(n(i)) = 2n²(i) and g(m(i)) = m(i) ⋅ (m(i) + 1), the equation f(n(i+2)) = g(m(i+2)) reduces to f(n(i)) = g(m(i)), proving the equations work for any couple:
f(n(i+2))
= g(m(i+2))
f(2m(i+1) + 3n(i+1) + 1)
= g((3m(i+1) + 4n(i+1) + 1))
2 ⋅ (12m(i) + 17n(i) + 6)²
= (17m(i) + 24n(i) + 8) ⋅ (17m(i) + 24n(i) + 8 + 1)
2 ⋅ (144m²(i) + 408m(i)⋅n(i) + 144m(i) + 289n²(i) + 204n(i) + 36)
= 289m²(i) + 816m(i)⋅n(i) + 289m(i) + 576n²(i) + 408n(i) + 72
288m²(i) + 816m(i)⋅n(i) + 288m(i) + 578n²(i) + 408n(i) + 72
= 289m²(i) + 816m(i)⋅n(i) + 289m(i) + 576n²(i) + 408n(i) + 72
2n²(i)
= m²(i) + m(i)
f(n(i))
= g(m(i))
If you're lost toward the end, I simply subtracted 288m²(i) + 816m(i)⋅n(i) + 288m(i) + 576n²(i) + 408n(i) + 72 from both sides of the equation, yielding 2n²(i) = m²(i) + m(i).
This is a question from one of the old exams from algorithms and data structure that I recently came upon. I'm having a hard time understanding the solution.
I need to find big-O, big-ϴ and big-Ω bounds of a function:
void recursion(int n) {
int i;
if (n == 0) {
return;
}
for (i = 0; i < n; i++) {
recursion(i);
}
}
The solution is 2^n for all three and I can't understand why. I've tried writing things down and I can't even get close to the solution. I would appreciate if anyone would explain where the 2^n comes from here.
Let's look at a simpler recursion which is known to be O(2^n)
void fib(int n) {
if (n < 3) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
Here you can see, for the non-trivial case of n > 2, this will result in 2^(n-2) calls to itself. For example, if n = 5:
n = 5
n = 4
n = 3
n = 2
n = 1
n = 2
n = 3
n = 2
n = 1
There are 8 (2^3) recursive calls, because each call with n > 2 spawns two more recursive calls, so fib(n+1) has twice as many recursive calls as fib(n).
So for your example:
n = 3
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
so we get 7 recursive calls when n = 3
for n = 4
n = 4
n = 3
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
Here, we have 15 calls. Looking at the execution tree above, you can see that recusrsion(4) is basically recursion(3) + recursion(3) + 1
n = 4
n = 3 // + 1
n = 2 //
n = 1 //
n = 0 // recursion(3)
n = 0 //
n = 1 //
n = 0 //
n = 0 //
n = 2 //
n = 1 //
n = 0 // recursion(3)
n = 0 //
n = 1 //
n = 0 //
n = 0 //
So in general, recursion(n + 1) will have one more recursive calls than 2 * recursion(n)....which is basically doubling for every +1 to n....which is O(2^n)
Let's denote the total runtime as f(n). Due to the loop in the function the f(n) is actually a sum of f(i) for i between 0 and n-1. That's a sum of n items. Let's try to simplify the expression. A standard trick in such situations is to find a complimentary equation. Let's see what is the value of f(n-1). Similary to the previous case, it's a sum of f(i) for i between 0 and n-2. So now we have 2 equations:
f(n)=f(1)+...+f(n-1)
f(n-1)=f(1)+...+f(n-2)
Let's subtract second from the first:
f(n)-f(n-1)=f(n-1)
--> f(n)=2f(n-1)
Now this is a homogeneous linear recurrence relation with constant coefficients.
The solution is immediate (see the link for more details):
f(n)=f(1)*2n=2n
Since this smells like a homework question, this answer is incomplete by design.
The usual trick behind these kind of problems is to create a recurrence equation. That is, the time complexity of recursion(k+1) is somehow related to the complexity of recursion(k). Just writing down the recurrence itself is not sufficient to prove the complexity, you have to demonstrate why the recurrence is true. But, for 2n, this suggests that recursion(k+1) takes twice as long as recursion(k).
Let T(k) denote the time complexity of recursion(k). Since recursion(0) returns immediately, let T(0) = 1. For k > 0, given the iterative implementation of recursion Thus You can inductively prove that T(k) = 2k.
r(n) = r(n-1)+r(n-2)+...+r(0) // n calls.
r(n-1) = r(n-2)+r(n-3)+...+r(0) // n-1 calls.
r(n-2) = r(n-3)+r(n-4)+...+r(0) // n-2 calls.
.
.
.
r(1) = r(0) // 1 call.
r(0) = return; // 0 call.
So,
r(n) = r(n-1)+r(n-2)+...+r(0) // n calls.
= 2 * (r(n-2)+...+r(0)) // 2 * (n - 1) calls.
= 2 * ( 2 * (r(n-3)+...+r(0)) ) // 2 * 2 * (n - 2) calls.
.
.
.
This follows that =>
2^(n-1) * (n - (n-1))
And that would be
2^n calls...
I have some 2 numbers of 128 bits. Let it be the same number:
A=282434364544378924672110924168367615433
B=282434364544378924672110924168367615433
It is necessary to add them modulo numbers
340282366920938463460374607431768211337
To represent 128-bit numbers, I use two 64-bit arrays
low_A = A.aa[0];
low_B = B.aa[0];
low_M = M.aa[0];
high_A = A.aa[1];
high_B = B.aa[1];
high_M = M.aa[1];
Thus, selecting the lower and upper parts (we can roughly say that in this way the numbers will be presented to the 64th number system).
The problem is that when adding the numbers A and B, an overflow occurs physically. The transfer is performed to a non-existent bit, although the binary representation remains true. If there was a transfer, we certainly already know that the given number is greater than the modulus.
How then do we explain to the machine what the result should be
A+B-M
if (high_A <= ULLONG_MAX - high_B) flag_h = 0; else flag_h = 1;
if (flag_h) {
int car = 0;
high_A = high_A - high_M;
high_B = high_B - high_M;
high_C = high_A + high_B + high_M;
if (low_C <= low_M)
{
low_C = low_M - low_C;
low_C = ULLONG_MAX - low_C + 1;
car = 1;
}
else { low_C = low_C - low_M; }
high_C -= car;
}
I tried to do this in the above manner, but still the program finds it wrong.
I explain what I wanted to do. I tried to make a mathematical formula (A-M) + (B-M) + M = (A + B-M). I'm trying to subtract from the senior and junior level.
Let's show on the numbers
_ 51
38
1) 8-1 = 7, 7 more will have to be subtracted
2) We simulate a loan at the senior level
3) 10-7 = 9 + 1 - 7 = 3
4) Set loan flag in the unit
5) 5 - 3 - flag = 1
6) 13
I found the solution to the problem, began to subtract from the higher order, here is the code
if (flag_h)
{
int car = 0;
unsigned __int64 temp1,temp2;
if (high_C < high_M)
{
temp1 = high_M - high_C;
high_C = ULLONG_MAX - temp1 + 1;
}
else { high_C = high_C - high_M; }
if (low_C < low_M) {
temp2 = low_M - low_C;
low_C = ULLONG_MAX - temp2 + 1;
high_C--;
}
else { low_C = low_C - low_M; }
}
So, my basic problem is that I'm trying to write a program for a small project I'm working on for fun.
Basically, my issue is this: I need to take user input, as an int, say 15, then manipulate the number so that it returns the result of 1 + 5, being 6. Or for another example say the number is 29, will give you 2 + 9 = 11, which would then need to be reduced down again to 1 + 1 = 2. That could probably be handled easily, but I'm stuck on how to actually split the int apart without having to take the numbers in one by one. I guess it's possible to with RegEx, but I was looking for a more efficient method.
This is not a particularly good job for a regex. The usual way would be to get individual digits as the remainder after dividing by 10.
A sample code is here:
int sum_of_digits(int n)
{
if(n < 10)
{
return n;
}
int sum = 0;
while( n > 0)
{
sum += n % 10;
n /= 10;
}
return sum_of_digits(sum);
}
int main()
{
int n1 = sum_of_digits(29);
int n2 = sum_of_digits(15);
}
In C, this would do the trick for two digits:
digit_sum = my_int%10 + my_int/10
I think the quickest way here is to use / (divide) and % (modulus) operators to traverse your integer.
int base = 15;
int acum = 0;
while (base > 0) {
acum = acum + (base % 10);
base = base / 10;
};
// At this point, base = 0 and acum = 6
// if acum > 10, then assign it to base and start again.