Pradeep Barua Pradeep Barua - 13 days ago 5
C Question

Decreasing Loop Interval by 1 in C/C++

Let's say I have 15 elements. I want to group them such a way that:

group1 = 1 - 5
group2 = 6 - 9
group3 = 10 - 12
group4 = 13 - 14
group5 = 15


This way I'll get elements in each group as below:

group1 = 5
group2 = 4
group3 = 3
group4 = 2
group5 = 1


As you can see loop interval is decreasing.

I took 15 just for an example. In actual programme it's user driven parameter which can be anything (hopefully few thousand).

Now what I'm looking for is:
Whatever is in group1 should have variable "loop" value 0, group2 should have 1, group3 should have 2 and so on... "loop" is an int variable which is being used to calculate some other stuff.

=========================================================

LET'S PUT IN OTHER WORDS TOO.

=========================================================

I have an int variable called "loop". I want to assign value to it such a way that:
First n frames loop value 0 next (n -1) frames loop value 1 then next (n - 2) frames loop value 2 all the way to loop value (n - 1)

Let's say I have 15 frames on my timeline.

So n will be 5 ====>>>>> (5 + 4 + 3 + 2 + 1 = 15; as interval is decreasing by 1)

then

first 5 frames(1 - 5) loop is 0 then next 4 frames(6 - 9) loop is 1 then next 3 frames(10 - 12) loop is 2 then next 2 frames(13 - 14) loop is 3 and for last frame(15) loop is 4.

frames "loop" value
1 - 5 => 0
6 - 9 => 1
10 - 12 => 2
13 - 14 => 3
15 => 4


I've tried with modulo(%). But the issue is on frame 12 loop is 2 so (12 % (5 - 2)) remainder is 0 so it increments loop value.
The following lines are sample code which is running inside a solver. @loop is by default 0 and @Frame is current processing frame number.

int loopint = 5 - @loop;

if (@Frame % loopint == 0)
@loop += 1;


NOTE: I don't know whether I've simplified it. Please do edit if it's not clear.

Answer

If I understand this correctly, then

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[]) {
  int n = atoi(argv[1]);

  for(int i = 1; i <= n; ++i) {
    printf("%d: %f\n", i, ceil((sqrt(8 * (n - i + 1) + 1) - 1) / 2));
  }
}

is an implementation in C.

The math behind this is as follows: The 1 + 2 + 3 + 4 + 5 you have there is a Gauß sum, which has a closed form S = n * (n + 1) / 2 for n terms. Solving this for n, we get

n = (sqrt(8 * S + 1) - 1) / 2

Rounding this upward would give us the solution if you wanted the short stretches at the beginning, that is to say 1, 2, 2, 3, 3, 3, ...

Since you want the stretches to become progressively shorter, we have to invert the order, so S becomes (n - S + 1). Therefore the formula up there.

EDIT: Note that unless the number of elements in your data set fits the n * (n+1) / 2 pattern precisely, you will have shorter stretches either at the beginning or in the end. This implementation places the irregular stretch at the beginning. If you want them at the end,

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[]) {
  int n = atoi(argv[1]);

  int n2    = (int) ceil((sqrt(8 * n + 1) - 1) / 2);
  int upper = n2 * (n2 + 1) / 2;

  for(int i = 1; i <= n; ++i) {
    printf("%d: %f\n", i, n2 - ceil((sqrt(8 * (upper - i + 1) + 1) - 1) / 2));
  }
}

does it. This calculates the next such number beyond your element count, then calculates the numbers you would have if you had that many elements.