C: Finding the bin index which a value belongs to - c

I have bins where the ranges grow exponentially.
Bin 0 -> [0 <= x <= 10] (interval = 10)
Bin 1 -> [11 <= x <= 30] (interval = 20)
Bin 2 -> [31 <= x <= 70] (interval = 40)
Bin 3 -> [71 <= x <= 150] (interval = 80)
Bin 4 -> [151 <= x <= 310] (interval = 160)
... and so on.
The number of bins and first interval are known prior (in this case it is 5, and 10 respectively). x lowest possible value is 0.
What I am currently doing is a standard for-loop that multiplies by 2 each time, and then return the index of the bin if value is within the range.
Is there a smarter way of doing this?

As suggested by Weather Vane,
bin = floor( log2 ( (value + 9) / 10 ))
also:
bin = floor( log2 ( floor( (value + 9) / 10 ) ))
Integer division (i1/i2) in C is equal to trunc(i1/i2) (truncation toward zero), which is equivalent to floor(i1/i2) for non-negative integers, so there is no need to implement the inner floor.
floor(log2(i)) can be implemented quite efficiently. See the accepted answer here for a fast 32-bit and 64-bit integer implementations.
Here is the code (valid when int is 32-bit). OnlineGDB
#include <stdio.h>
const unsigned int tab32[32] = {
0, 9, 1, 10, 13, 21, 2, 29,
11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7,
19, 27, 23, 6, 26, 5, 4, 31};
unsigned int log2_32(unsigned int value)
{
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return tab32[(value * 0x07C4ACDD) >> 27];
}
int main()
{
unsigned int value = 151;
unsigned int bin = 0;
if (value > 0)
bin = log2_32( (value + 9) / 10 );
printf("value: %u, bin: %u", value, bin);
return 0;
}

The log arithmetic is cool, but you could also just build a table and use binary search to find the bin.
int find_bin(unsigned x) {
static unsigned bin_top[] = {
10u, // 0
30u, // 1
70u, // 2
150u, // 3
310u, // 4
630u, // 5
1270u, // 6
2550u, // 7
5110u, // 8
10230u, // 9
20470u, // 10
40950u, // 11
81910u, // 12
163830u, // 13
327670u, // 14
655350u, // 15
1310710u, // 16
2621430u, // 17
5242870u, // 18
10485750u, // 19
20971510u, // 20
41943030u, // 21
83886070u, // 22
167772150u, // 23
335544310u, // 24
671088630u, // 25
1342177270u, // 26
2684354550u, // 27
4294967295u, // 28
};
int lo = 0, hi = 28;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (mid > 0 && x <= bin_top[mid - 1]) hi = mid - 1;
else if (x > bin_top[mid]) lo = mid + 1;
else return mid;
}
return lo;
}
The loop will never run more than five iterations, so it's pretty quick. Bin 28 is the biggest unsigned value, which isn't the calculated one.

Related

Count ones in a segment (binary)

There is a problem which i am working on it right now and it's as the following :
there are two numbers x1 and x2 and x2 > x1.
for example x1 = 5; and x2 = 10;
and I must find the sum of ones between x1 and x2 in binary representations.
5 = 101 => 2 ones
6 = 110 => 2 ones
7 = 111 => 3 ones
8 = 1000 => 1 one
9 = 1001 => 2 ones
10= 1010 => 2 ones
so the sum will be
sum = 2 + 2 + 3 + 1 + 2 + 2 = 12 ones;
so I have managed to make a code without even transfer the numbers to binary and wasting execution time.
I noticed that the numbers of ones in every 2^n with n >= 1 is 1
Ex : 2^1 => num of ones is 1
2^2 => 1 2^15 => 1
you can test it here if you want: https://www.rapidtables.com/convert/number/decimal-to-binary.html?x=191
and between each 2^n and 2^(n+1) there are Consecutive numbers as you will see in this example :
num number of ones
2^4 = 16 1
17 2
18 2
19 3
20 2
21 3
22 3
23 4
24 2
25 3
26 3
27 4
28 3
29 4
30 4
31 5
2^5 = 32 1
so I write a code that can find how many ones between 2^n and 2^(n+1)
int t; ////turns
int bin = 1; //// numbers of ones in the binary format ,,, and 1 for 2^5
int n1 = 32; //// 2^5 this is just for clarification
int n2 = 64; //// 2^6
int *keep = malloc(sizeof(int) * (n2 - n1); ///this is to keep numbers because
/// i'll need it later in my consecutive numbers
int i = 0;
int a = 0;
n1 = 33 //// I'll start from 33 cause "bin" of 32 is "1";
while (n1 < n2) /// try to understand it now by yourself
{
t = 0;
while (t <= 3)
{
if (t == 0 || t == 2)
bin = bin + 1;
else if (t == 1)
bin = bin;
else if (t == 3)
{
bin = keep[i];
i++;
}
keep[a] = bin;
a++;
t++;
}
n1++;
}
anyway as you see I am close to solve the problem but they give me huge numbers and I must find the ones between them, unfortunately I have tried a lot of methods to calculate the "sum" using this above code and I ended up with time execution problem.
Ex: 1, 1000000000 the numbers of ones is >>> 14846928141
so can you give me a little hint what to do next, thanks in advance.
I'm doing this for CodeWar challenge: https://www.codewars.com/kata/596d34df24a04ee1e3000a25/train/c
You can solve this problem by computing the number of bits in the range 1 to n and use a simple subtraction for any subrange:
#include <stdio.h>
#include <stdlib.h>
/* compute the number of bits set in all numbers between 0 and n excluded */
unsigned long long bitpop(unsigned long long n) {
unsigned long long count = 0, p = 1;
while (p < n) {
p += p;
/* half the numbers in complete slices of p values have the n-th bit set */
count += n / p * p / 2;
if (n % p >= p / 2) {
/* all the numbers above p / 2 in the last partial slice have it */
count += n % p - p / 2;
}
}
return count;
}
int main(int argc, char *argv[]) {
unsigned long long from = 1000, to = 2000;
if (argc > 1) {
to = from = strtoull(argv[1], NULL, 0);
if (argc > 2) {
to = strtoull(argv[1], NULL, 0);
}
}
printf("bitpop from %llu to %llu: %llu\n", from, to, bitpop(to + 1) - bitpop(from));
return 0;
}
Here is a proposal for a speedup:
Find smallest y1 such that y1 >= x1 and that y1 is a power of 2
Find largest y2 such that y2 <= x2 and that y2 is a power of 2
Find p1 and p2 such that 2^p1=y1 and 2^p2=y2
Calculate the amount of 1:s between y1 and y2
Deal with x1 to y1 and y2 to x2 separately
Sum the results from 4 and 5
Let's focus on step 4. Let f(n) be the sum of ones up to (2^n)-1. We can quickly realize that f(n) = 2*f(n-1) + 2^(n-1) and that f(1)=1. This can be even further refined so that you don't have to deal with recursive calls, but I highly doubt it will be of any importance. Anyway, f(n) = n*2^(n-1)
To get the result between y1 and y2, just use f(p2)-f(p1)
For step 5, you can likely use a modified version of step 4.
EDIT:
Maybe I was to quick to say "quickly realize". Here is a way to understand it. The amounts of ones up to 2¹-1 is easy to see. The only two binary numbers below 2¹ are 0 and 1. To get the number of ones up to 2² we take the numbers below 2¹ and make a column:
0
1
Clone it:
0
1
0
1
And put 0:s before the first half and 1:s before the second half:
00
01
10
11
To get 2³ we do the same. Clone it:
00
01
10
11
00
01
10
11
And add 0 and 1:
000
001
010
011
100
101
110
111
Now it should be easy to see why f(n) = 2*f(n-1) + 2^(n-1). The cloning gives 2f(n-1) and adding the 0:s and 1:s gives 2^(n-1). If 2^(n-1) is hard to understand, remember that 2^(n-1)=(2^n)/2. In each step we have 2^n rows and half of them get an extra 1.
EDIT2:
When I looked at these columns, I got an idea for how to do step 5. Let's say that you want to find the amounts of 1:s from 10 to 15. Binary table for this would be:
10: 1010
11: 1011
12: 1100
13: 1101
14: 1110
15: 1111
Look at the interval 12-15. The last two digits in binary is a copy of the corresponding table for 0-3. That could be utilized, but I leave that to you.
EDIT 3:
This was a fun problem. I wrote some python code that does this. I get some problems with too many recursive calls, but that could be solved pretty easily, and it should not be too complicated to convert this to C:
def f(n):
return n*2**(n-1)
def numberOfOnes(x):
if(x==0):
return 0
p = floor(log(x,2))
a = f(p)
b = numberOfOnes(x-2**p)
c = x - 2**p +1
return a+b+c
I made an image so that you easier can understand what a, b and c does in the function numberOfOnes if we call it with numberOfOnes(12):
I have finally converted it to C. Of course I have used some code I found here on Stack overflow. I borrowed code for integer versions of log2 and pow, and made some small modifications.
This code is probably possible to optimize further, but it is not necessary. It is lighting fast, and I was not able to measure it's performance.
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <inttypes.h>
typedef uint64_t T;
// https://stackoverflow.com/a/11398748/6699433
const int tab64[64] = {
63, 0, 58, 1, 59, 47, 53, 2,
60, 39, 48, 27, 54, 33, 42, 3,
61, 51, 37, 40, 49, 18, 28, 20,
55, 30, 34, 11, 43, 14, 22, 4,
62, 57, 46, 52, 38, 26, 32, 41,
50, 36, 17, 19, 29, 10, 13, 21,
56, 45, 25, 31, 35, 16, 9, 12,
44, 24, 15, 8, 23, 7, 6, 5};
T log2_64 (T value) {
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return tab64[((T)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58];
}
// https://stackoverflow.com/a/101613/6699433
T ipow(T base, T exp) {
T result = 1;
for (;;) {
if (exp & 1) result *= base;
exp >>= 1;
if (!exp) break;
base *= base;
}
return result;
}
T f(T n) { return ipow(2,n-1)*n; }
T numberOfOnes(T x) {
if(x==0) return 0;
T p = floor(log2(x));
T a = f(p);
T e = ipow(2,p);
T b = numberOfOnes(x-e);
T c = x - e + 1;
return a+b+c;
}
void test(T u, T v) {
assert(numberOfOnes(u) == v);
}
int main() {
// Sanity checks
test(0,0);
test(1,1);
test(2,2);
test(3,4);
test(4,5);
test(5,7);
test(6,9);
// Test case provided in question
test(1000000000,14846928141);
}
int x1 = 5;
int x2 = 10;
int i=0;
int looper = 0;
unsigned long long ones_count = 0;
for(i=x1; i<=x2; i++){
looper = i;
while(looper){
if(looper & 0x01){
ones_count++;
}
looper >>= 1;
}
}
printf("ones_count is %llu\n", ones_count);
return 0;
OUTPUT: ones_count is 12
Here is a way to count every single bit for every value in between the two values. The shift/mask will be faster than your arithmetic operators most likely, but will still probably time out. You need a clever algorithm like the other answer suggests i think, but heres the stupid brute force way :)
This was my solution to the problem:
** = exponentiation
/ = whole number division
Consider the numbers from 1 to 16:
00001
00010
00011
00100
00101
00110
00111
01000
01001
01010
01011
01100
01101
01110
01111
10000
If you pay attention to each column, you'll notice a pattern. The bit at column index i (0,1,2 ...) from the right runs through a cycle of length 2**(i+1), that is every 2**(i+1) rows, the pattern in column i repeats itself. Notice also that the first cycle starts at the first occurrence of a 1 in a given column. The number of ones in a pattern is half of the patterns length.
Example:
i pattern
0 10
1 1100
2 11110000
3 1111111100000000
...
So, given the task of summing all ones up to n, we have to keep track of how many times each pattern repeats itself and also if a pattern fails to complete itself.
Solution:
Let x be the biggest exponent of a binary number n and let s be the sum of all ones up to n. Then, for i = (0, 1, 2, ... , x) add (n / 2**(i+1)*(2**i) to s. If the remainder is bigger than 2**i, add 2**i to s, else add the remainder. Then subtract 2**i from n and repeat the process.
Example:
n = 7 -> x = 2
(7 / 2**1)*(2**0) = 3
7 % 2**1 = 1 !> 2**0
s = 1 + 3 (4)
n = n - 2**0 (6)
(6 / 2**2)*(2**1) = 2
6 % 2**2 = 2 !> 2**1
s = s + 2 + 2 (8)
n = n - 2**1 (4)
(4 / 2**3)*(2**2) = 0
4 % 2**3 = 4 !> 2**2
s = s + 4 (12)
n = n - 2**2 (0)
s = 12
Maybe not the best explanation or the most beautiful solution, but it works fine.
In python:
def cnt_bin(n):
bits = n.bit_length()
s = 0
for i in range(bits):
s += (n // 2**(i+1))*2**i
if n % 2**(i+1) > 2**i:
s += 2**i
else:
s += (n % 2**(i+1))
n -= 2**i
return s
Then, for a range [a, b] you just compute cnt_bin(b) - cnt_bin(a-1)

How to get every digit from a number in C?

I have these variables:
int dividend;
 int divider;
And I have the function :
Divisibility7 (int num);
Those two variables will be at the main function, and the user will be asked to enter the dividend and divider, but in case the user enter the divider 7, then, the function above will be called.
The problem is that I have to follow specific criteria to do this. So let's say the user will enter with the dividend 7203. This happen :
I. Get the last digit of the number.
Last digit: 3
Ii. Multiply the last digit by 2
3 x 2 = 6
Iii. Get the value of the initial number, without the last digit.
720
Iv. Subtract the initial value without the last digit from the multiplication result.
fabs (720 - 6) = 714
V. Repeat the process until the result is a value less than or equal to 70
Vi. Compare the result with the table of contents (0, 7, 14, 21, 28, 35, 42, 49, 54, 63, 70) for
Determine whether or not the number is divisible by 7
Code :
int res;
int x;
int y;
int Divisibility7(int num) {
int res;
int x;
int y;
int z;
while(num > 70) {
x = num % 10; // get the last digit from the number
y = x * 2; // multiply the last digit by 2;
z = num/10; // get the first digits from the number
fabs(z - y); // subtract the first digits with the last digits;
}
}
In the part of the while, the final fabs(z-y) returns what I want, to be the first digits subtracting the last number, but the problem is that the while stop there, I have to do something to make this while go till 70 or less.
PS : I need to check if the final number from the iterations, it's a number multiplied by 7, how can I do that ? And I can't use mod for this.
You have not changed num in your while loop . Also you do no return the value . Hope the following code will be ok for you .
int Divisibility7(int num) {
int res,x,y,z;
while(num > 70) {
x = num % 10; // get the last digit from the number
y = x * 2; // multiply the last digit by 2;
z = num/10; // get the first digits from the number
num = abs(z - y); // subtract the first digits with the last digits;
}
if(num == 0 || num == 7 || num == 14 || num == 21 || num == 28 || num == 35 || num == 42 || num == 49 || num == 54 || num == 63 || num == 70) {
return 1;
}
else {
return 0;
}
}
Not sure, but I think this is what are you trying to do:
int main (void)
{
int number, lastDigitMultiplied;
scanf("%d", &number);
while(number > 70){
//get the last digit and multiply it by 2
lastDigitMultiplied = (number % 10) * 2;
//subtract the initial value without the last digit from the multiplication result.
number = number / 10 - lastDigitMultiplied;
}
if(abs(number) % 7 == 0)
printf("The result is %d and it is a multiple of 7", number);
else
printf("The result is %d and it is not a multiple of 7", number);
return 0;
}
for divisibility against 7, if you have a positive large bigint already formatted as a string, don't waste time with the regular method doing it 1 digit at a time.
powers of 10, mod 7, repeats every 6 rounds :
10^1 % 7 = 3 10^7 % 7 = 3 10^13 % 7 = 3
10^2 % 7 = 2 10^8 % 7 = 2 10^14 % 7 = 2
10^3 % 7 = 6 10^9 % 7 = 6 10^15 % 7 = 6
10^4 % 7 = 4 10^10 % 7 = 4 10^16 % 7 = 4
10^5 % 7 = 5 10^11 % 7 = 5 10^17 % 7 = 5
10^6 % 7 = 1 10^12 % 7 = 1 10^18 % 7 = 1
meaning, the effects of the digits mod 7 stay identical as long as they're in chunks of 6 digits at a time.
the largest multiple of 6-digits supported by double precision FP to full integer precision would be 12-digits at a time.
So the way to do it is to right-align the digits by padding leading edge zeros to ensure string length is a multiple of 12. Then simply add the digits onto each other, performing a single mod % 7 operation once every 9000 or so rounds of the addition loop
—- (that's when you run up against 2^53 limit; 9007 rounds if u wanna be pedantic about it)
example :
x = 71400535477047763120175175402859619447790
02233464423375355339031113233806609150957
x % 7 = 4
now try summing up chunks of 12 :
007140053547704776312017517540285961944779
002233464423375355339031113233806609150957
007140053547 7140053547
704776312017 711916365564
517540285961 1229456651525
944779002233 2174235653758
464423375355 2638659029113
339031113233 2977690142346
806609150957 3784299293303
----------------------------
3784299293303 % 7 = 4
it works exactly the same for any multiples of 6 : e.g. 6, 18, 24, and 30 --
00714005354770477631201751754
02859619447790022334644233753
55339031113233806609150957
312017 312017
517540 829557
285961 1115518
944779 2060297
002233 2062530
464423 2526953
375355 2902308
339031 3241339
113233 3354572
806609 4161181
150957 4312138
007140 4319278
053547 4372825
704776 5077601
----- -------
_ 5077601 % 7 = 4
00000000714005354770477631201
75175402859619447790022334644
23375355339031113233806609150957
464423375355339031 464423375355339031
113233806609150957 577657181964489988
000000007140053547 577657189104543535
704776312017517540 1282433501122061075
285961944779002233 1568395445901063308
---------------------------------------
1568395445901063308 % 7 = 4
00000000000000714005354770477
63120175175402859619447790022
33464423375355339031113233806
609150957
339031113233806609150957 339031113233806609150957
000000000000007140053547 339031113233813749204504
704776312017517540285961 1043807425251331289490465
944779002233464423375355 1988586427484795712865820
---------------------------------------------------
1988586427484795712865820 % 7 = 4
000000007140053547704776312017517
540285961944779002233464423375355
339031113233806609150957
000000007140053547704776312017 7140053547704776312017
517540285961944779002233464423 517540293101998326707009776440
375355339031113233806609150957 892895632133111560513618927397
892895632133111560513618927397 % 7 = 4

shifting a sequence of numbers in C?

I have a question about some trying to wrap around a sequence of numbers that I'm trying to shift in the C programming language. The first value that is found in the sequence of numbers I calculate via a loop gets thrown out in the end. Here is what the code looks like right now:
numbers[d] = numbers[x];
for (d = y-1; d >=0; d --){
numbers[d] = numbers[(d - 1) % y];
printf(" numbers[d] = %d \n", numbers[d]);
}
Here are the numbers[x] I calculated from my previous loop:
1, 17, 3, 15, 14, 6, 12, 8, 10
Here is what the numbers[d] currently looks like:
17, 3, 15, 14, 6, 12, 8, 10, 10
...and here is what it should look like:
17, 3, 15, 14, 6, 12, 8, 10, 1
It seems like it doesn't wrap the 1 around to the end. Is there a conditional that I am missing in my loop? Thanks!
Let's analyze your for loop, minus the printf statement.
for (d = y-1; d >=0; d --){
numbers[d] = numbers[(d - 1) % y];
}
Before you start the loop, you have the following values in numbers.
1, 17, 3, 15, 14, 6, 12, 8, 10
The value of y is 9.
In the first iteration of the loop, d = 8. (d-1)%y = 7. You replace the value of number[8] by number[7]. The array becomes:
1, 17, 3, 15, 14, 6, 12, 8, 8
In the next iteration of the loop, d = 7. (d-1)%y = 6. You replace the value of number[7] by number[6]. The array becomes:
1, 17, 3, 15, 14, 6, 12, 12, 8
When you reach the iteration where d=1, (d-1)%y = 0. You replace the value of number[1] by number[0]. The array becomes:
1, 1, 17, 3, 15, 14, 6, 12, 8
In the next iteration, d=0, (d-1)%y = -1. The statement
numbers[d] = numbers[(d - 1) % y];
is equivalent to
numbers[0] = numbers[-1];
This certainly leads to undefined behavior but it doesn't explain the other numbers in your output. Maybe the output that you posted corresponds to a different block of code.
I think the answer by #JonathanLeffler gives a solution to your algorithmic problem. I won't repeat that here.
Code
#include <stdio.h>
static const int debug = 0;
static void dump_array(const char *tag, int n, const int array[n])
{
printf("%s (%d)", tag, n);
for (int i = 0; i < n; i++)
printf("%3d", array[i]);
putchar('\n');
}
static void rot1u(int n, int numbers[n])
{
int v = numbers[n-1];
for (int d = n - 1; d >= 0; d--)
{
numbers[d] = numbers[(n + d - 1) % n];
if (debug)
printf(" numbers[%d] = %d\n", d, numbers[d]);
}
numbers[0] = v;
dump_array("Up After: ", n, numbers);
}
static void rot1d(int n, int numbers[n])
{
int v = numbers[0];
for (int d = 0; d < n; d++)
{
numbers[d] = numbers[(d + 1) % n];
if (debug)
printf(" numbers[%d] = %d\n", d, numbers[d]);
}
numbers[n-1] = v;
dump_array("Dn After: ", n, numbers);
}
int main(void)
{
int numbers[] = { 1, 17, 3, 15, 14, 6, 12, 8, 10 };
enum { N_NUMBERS = sizeof(numbers) / sizeof(numbers[0]) };
dump_array("-- Before:", N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
return 0;
}
Example output
-- Before: (9) 1 17 3 15 14 6 12 8 10
Up After: (9) 10 1 17 3 15 14 6 12 8
Dn After: (9) 1 17 3 15 14 6 12 8 10
Dn After: (9) 17 3 15 14 6 12 8 10 1
Dn After: (9) 3 15 14 6 12 8 10 1 17
Up After: (9) 17 3 15 14 6 12 8 10 1
Up After: (9) 1 17 3 15 14 6 12 8 10
You need to save the element(s) which should be rotated to the the other side before the loop, and only put it into its proper place (theem into their proper places) afterwards.
#include <stdio.h>
#include <time.h>
#define METHOD 2
#define MAX_SKIERS 20
int starting_lineup[MAX_SKIERS+1];
int main(void)
{
int i, num_skiers = 20;
srand(time(NULL));
int pos1, pos2, temp;
for (i = 0; i <= num_skiers; i++)
starting_lineup[i] = i;
for (i = 0; i < num_skiers*2; i++) {
// Generate two random positions
pos1 = rand() % num_skiers + 1;
pos2 = rand() % num_skiers + 1;
// Swap the skiers at the two positions
temp = starting_lineup[pos1];
starting_lineup[pos1] = starting_lineup[pos2];
starting_lineup[pos2] = temp;
}
printf("The starting lineup (first to last):\n");
for (i = 1; i <= num_skiers; i++)
printf("%s%d", (i == 1 ? "" : ", "), starting_lineup[i]);
putchar('\n');
return 0;
}

How to choose the best marks with specified credits in c programming?

I want to make a program to get the weighted average (formula = (mark*(credits corresponds to it))/total credits) from the best(highest) 120 credits module from the following marks and credits (the credits corresponds to the module):
module[12]={48, 77, 46, 82, 85, 43, 49, 73, 65, 48, 47, 51}
credits[12]={60, 20, 20, 20, 10, 20, 10, 10, 10, 20, 20, 10}
What I have done is bubble sort the array, so that the array is sorted by decreasing manner to know which marks is higher, as shown below:
module[12]={85, 82, 77, 73, 65, 51, 49, 48, 48, 47, 46, 43}
credits[12]={10, 20, 20, 10, 10, 10, 10, 60, 20, 20, 20, 20}
And then I need to choose the best 120 credits module from the sorted array so that the weighted average will be maximum, but then I have no idea where to start. =(
Someone help me! Thanks a lot!
EDIT:
I have tried to work out the code myself, and eventually get the following code, it works, but for some special case it stop working =(
float credits=0, result=0;
n=0;
struct{
float credits;
float result;
float n;
float addpoint;
}point;
while (credits < 120){
credits+=credits[n];
result+=(result[n]*credits[n]);
n++;
}
if (credits != 120){
credits -= credits[n-1];
result -= (result[n-1]*credits[n-1]);
point.credits = credits;
point.result = result;
point.n = (n-1)-1;
point.addpoint = n;
again: while (credits < 120){
credits+=credits[n];
result+=(result[n]*credits[n]);
n++;
}
if (credits != 120){
point.credits -= credits[point.n-1];
point.result -= result[point.n-1]*credits[point.n-1];
point.n--;
credits = point.credits;
result = point.result;
n = point.addpoint-1;
goto again;
}
}
EDIT:
Solved. Using knapsack problem code/integer linear programming by the application of glpk
The other way, which is practical for small examples like the one you've got, is to use dynamic programming. One can build up a table of "optimal score if you use the first k subjects, and want credits to add up to T". The code's a bit messy because C doesn't make it particularly easy to have dynamically sized 2d arrays, but here's a solution. Probably your professor was expecting something along these lines.
A small note, I divided all the credits (and the target credits of 120) by 10 because the common factor was redundant, but the code works just fine without that (it'll just use a tad more memory and time).
#include <stdio.h>
#include <stdlib.h>
int max(int a, int b) {
return a > b ? a : b;
}
#define GET(t, i, j, n) ((t)[(i) * (n + 1) + j])
// optimize_marks takes arrays creds and marks (both of length n),
// and finds a subset I of 0..(n-1) that maximizes
// sum(i in I)creds[i]*marks[i], such that sum(i in I)creds[i] = total.
void optimize_marks(size_t n, int *creds, int *marks, int total) {
// tbl[k * (total + 1) + T] stores the optimal score using only the
// first k subjects for a total credit score of T.
// tbl[n * (total + 1) + total] will be the final result.
// A score of -1 means that the result is impossible.
int *tbl = malloc((n + 1) * (total + 1) * sizeof(int));
for (int i = 0; i <= n; i++) {
for (int T = 0; T <= total; T++) {
if (i == 0) {
// With 0 subjects, the best score is 0 if 0 credits are
// required. If more than 0 credits are required, the result
// is impossible.
GET(tbl, i, T, total) = -(T > 0);
continue;
}
// One way to get T credits with the first i subjects is to
// get T credits with the first (i-1) subjects.
GET(tbl, i, T, total) = GET(tbl, i - 1, T, total);
// The other way is to use the marks for the i'th subject
// and get the rest of the credits with the first (i-1) subjects.
// We have to check that it's possible to use the first (i-1) subjects
// to get the remainder of the credits.
if (T >= creds[i-1] && GET(tbl, i - 1, T - creds[i-1], total) >= 0) {
// Pick the best of using and not using the i'th subject.
GET(tbl, i, T, total) = max(
GET(tbl, i, T, total),
GET(tbl, i - 1, T - creds[i-1], total) + marks[i-1] * creds[i-1]);
}
}
}
int T = total;
for (int i = n; i > 0; i--) {
if (GET(tbl, i - 1, T, total) < GET(tbl, i, T, total)) {
printf("%d %d %d\n", i, creds[i-1], marks[i-1]);
T -= creds[i-1];
}
}
}
int main(int argc, char *argv[]) {
int creds[] = {6, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1};
int marks[] = {48, 77, 46, 82, 85, 43, 49, 73, 65, 48, 47, 51};
optimize_marks(12, creds, marks, 12);
return 0;
}
The program gives the solution as the ILP program:
12 1 51
11 2 47
10 2 48
9 1 65
8 1 73
5 1 85
4 2 82
2 2 77
This is an integer linear programming problem. You want to find a vector [x1 x2 x3 ... x12] where each of the x's is either 0 or 1, such that sum(x[i] * cred[i]) = 120 and that sum(x[i] * cred[i] * marks[i]) is maximised.
There's a large body of research in how to solve such problems, but there's existing solvers out there and ready for you to use and using them is going to save you a vast amount of time over coding a solver up yourself.
Here's a module file for glpk, a free linear programming and integer linear programming solver. You can run it by installing glpk, saving this to a file then running glpsol -m <filename>
set I := 1..12;
var x{I} binary;
param cred{I};
param marks{I};
maximize s:
sum{i in I}(x[i] * cred[i] * marks[i]);
s.t. totalcreds: sum{i in I}(x[i] * cred[i]) = 120;
solve;
printf {i in I} "%d: %d %d %d\n", i, x[i], cred[i], marks[i];
data;
param cred := 1 60, 2 20, 3 20, 4 20, 5 10, 6 20, 7 10, 8 10, 9 10, 10 20, 11 20, 12 10;
param marks := 1 48, 2 77, 3 46, 4 82, 5 85, 6 43, 7 49, 8 73, 9 65, 10 48, 11 47, 12 51;
end;
The output is this:
1: 0 60 48
2: 1 20 77
3: 0 20 46
4: 1 20 82
5: 1 10 85
6: 0 20 43
7: 0 10 49
8: 1 10 73
9: 1 10 65
10: 1 20 48
11: 1 20 47
12: 1 10 51
That is, you should pick courses 2, 4, 5, 8, 9, 10, 11, 12 (ie: the courses with a '1' by them).
You should probably start by isolating all the combinaisons of credits[] elements whose sum equals 120 and store them before calculating all the means.
It would look like that :
// test for all possible combinaisons :
// [0] + [1] + [2]..., [1] + [0] + [2]...
// starting point on the array : n
while(n < 12){
// if the sum isnt equal to 120 and
// we havent covered all the array yet
if(temp < 120 && i < 12){
// if i is different from the starting point
if(i < 11 && i != n){
i++;
temp += credits[i];
// store i
}
}
if(temp >120 && i < 11){
temp -= credits[i];
// remove i
i++;
}
if(temp == 120){
// starting point ++
n++;
}
}
It's not optimal, but it could work.

Given a sorted array, output all triplets <a,b,c> such that a-b = c

Given a sorted array, output all triplets such that a-b = c.
The code I tried so far is as below; but there are following test cases-
-12 = -7 - 5
-12 = 3 - 15
-7 = -4 - 3
-7 = 3 - 10
-7 = 9 - 16
-4 = 5 - 9
3 = -4 - -7
5 = -7 - -12
5 = 15 - 10
10 = 3 - -7
10 = 15 - 5
15 = 3 - (-12)
16 = 9 - (-7)
while my program prints only-
-12 = -7 - 5
-7 = -4 - 3
-12 = 3 - 15
-7 = 3 - 10
-4 = 5 - 9
-7 = 9 - 16
5 = 15 - 10
means only the abs difference! Any suggestion ll be great help!
void binder(int*a, int n) {
int i;
for (i = 0; i < n; i++) {
int current = a[i];
int left = 0;
int right = n-1;
while (left < right) {
if ( left == i ) {
left++;
continue;
}
if (right == i) {
right--;
continue;
}
if (a[left] + a[right] < current) {
left++;
} else if (a[left] + a[right] > current) {
right--;
} else {
printf("\n %d = %d - %d",a[left],current, a[right]);
left++;
right--;
}
}
}
}
int main() {
int a[] = {-12, -7, -4, 0, 3, 5, 9, 10, 15, 16};
binder(a, 10);
return 0;
}
It seems as though the test case is also missing a triplet:
9 = 5 - (-4)
Try changing your printing from:
printf("\n %d = %d - %d",a[left],current, a[right]);
to:
printf("\n %d = %d - %d",a[left],current, a[right]);
printf("\n %d = %d - %d",a[right],current, a[left]);
This solution is O(n^3), but it should work.
void binder(int*a, int n)
{
for(int left = 0; left < n; left++)
{
for(int right = 0; right < n; right++)
{
for(int result = 0; result < n; result++)
{
if(left != right && left != result && result != right && a[left] - a[right] == a[result])
printf("\n %d = %d - %d", a[result], a[left], a[right]);
}
}
}
}
How about something like this:
HashTable table;
for b = 0 to n-1:
for c = 0 to n-1:
table[b + c] = <b, c>
end for
end for
for a = 0 to n-1:
if table[a] exists and (<b, c> in table[a] where b != a and c != a) then:
output <a, b, c>
end if
end for
So, if we consider "a=b+c", for each (b, c) pair of values, we place that in a hash table, associating it with the (b, c) pair [O(n^2)].
Then, we go through the array again and if a value appears in the hash table, and the associated pairs are for different indices, then we've found a new entry (rearranging the terms back into "a-b=c"). This step is O(n), resulting in a O(n^2) solution overall.
I think we can see this question as a variation on the "find pairs of values in an array that sum up to S, for a fixed S" problem.
If they are sorted, (and as Hanning pointed out, a-b=c is the same as a=b+c) you can start with the smallest b and c, and add them, and this should lead to the smallest a. Now while increasing b or c, a can only get bigger too, so you should have never to look back.
If you make a table of b's and c's and their sum (which should be one of the a's):
c\ b:-12 3 4 5 7 10 15 16
-12: -24, -19, -9, -7, -3, -2, 3, 4
-7: -9, -4, 6, 8, 12, 13, 18,
3: -8, -3, 7, 9, 13, 14, 19,
5: -7, -2, 8, 10, 14, 15,
9: -5, 0, 10, 12, 16,
10: -2, 3, 13, 15,
15: 3, 8, 18,
16: 4, 9, 19,
you see, that I omited the values on the lower right, because the previous value (from left) already exceeded the maximum a (15), so a higher value can't match.
Of course, for such a small number of equations, you waste much more time thinking about optimization, than you gain from omitting superfluous calculations. For much bigger sets of values, it might be useful, to optimize.
you have missed one more iteration/loop in your code. since you are using brute force strategy so analysis say that it will take O(n^3) space and you code's time complexity seems O(n^2).
here is the case which will help you to understand.
you check for :
a = b-c
and you skip the check for :
c = b-a

Resources