tags:

views:

53

answers:

4

hi, i have a mathematical problem which is a bit hard to describe, but i'll give it a try anyway.

in a timeline, i have a number of frames, of which i want to skip a certain number of frames, which should be evenly distributed along the timeline.

for example i have 10 frames and i want to skip 5, then the solution is easy: we skip every second frame. 10/5 = 2

if (frame%2 == 0)
    skip();

but what if the above division does result in a floating number?

for example in 44 frames i want to skip 15 times. how can i determine the 15 frames which should be skipped?

bascially i am looking for an algorithm that distributes that 15 frames as evenly as possible along the 44 frames. it will probably look like something like skipping after 2 and then after 3 frames alternately.

thanks!

+2  A: 

You can obviously not always do it really evenly in case the number of frames you want to skip is not a divisor of the total number of frames. So if it is important to always skip at least the number of frames you want, perform a floor on the division (totalFrames/framesToSkip).

Having said that, you can apply the same trick as you proposed.

if (totalFrames % floor(totalFrames/framesToSkip) == 0)
    skip();

Note that in the case of 44 and 15 you skip much more than 15. The other posibility is to ceil instead of floor, in that case you wont skip 15 frames but 14 frames.

Yet another solution is to do a round to the nearest integer, this is a better approximation, however, you sometimes skip more than wished and sometimes less than wished but on average you have better results

Henri
thanks. yes i know i cannot exactly meet that number with the division. that's why i am asking for another way to distribute those frames that should be skipped.
clamp
+3  A: 

You could keep an additional floating point value, t, that corresponds to the next frame to skip, and update it every time you skip. Like this:

int frame_num = 44; 
int skips_num = 15; 
double dt =((double)(frame_num))/skips_num;
double t = 0.0;
...
// then, in your loop
if (frame == (int)t) {  
  skip();   
  t += dt; 
}
Igor Krivokon
This is in general equal to flooring the result since casting a floating point to an int (usually) is functionally equal to flooring. The bad part is that the behaviour is not always defined (depending on the language and OS).
Henri
@Henri: it is equal to flooring the t, but it is not equal to flooring the divisor. This approach is going to be more precise then your solution.
Unreason
Simple and efficient, though I would prefer the `floor` to be explicit rather than hidden in the cast ;)
Matthieu M.
+1  A: 

I set off to write a solution that improves on Igor's, but at the end the only improvement I really found was to explicitly state that round(t) should be used instead of (int)t. So here's Igor's solution again (with some variable names changed so it is more obvious and using round function).

int frame_num = 44; 
int skips_num = 15; 
double frames_between_skips =((double)(frame_num))/skips_num;
double next_skip = 0.0;
...
// then, in your loop
if (current_frame == round(next_skip)) {  
  skip();   
  next_skip += frames_between_skips; 
}

Using round(t) will make it be the most fair and try to drop the frame (int) that is closest to the ideal drop frame (double) while keeping the full precision timer (next_skip).

Couple of notes

  • take care if the frame starts with 0 or with 1 and adjust accordingly,
  • take care that frame_num is not > skips_num (if it is make sure you increase next_skip by more than a frame each time a frame is dropped, otherwise you'll stop increasing the next_skip and no more frames will be dropped)
Unreason
+2  A: 

It strikes me that the problem of mixing skips in with non-skips is a bit like the problem of mixing steps that go diagonally downwards with steps that go straight across when drawing a line with pixels. The line-drawing problem is solved in great detail at http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm

mcdowella
very good remark!
clamp