If I had realized this thread was a sticky I'd have posted my findings here to begin with. It's actually a little more complicated than this. The game is run in "ticks" (equivalent to frames), the speed is measured in pixels per tick, and you can't have a fraction of a tick; the layer will move a distance equal to the speed*ticks. 1 block length is equal to 32 pixels.

What makes it dicey is that the number of ticks are a bit off from what is expected.

0.1 second = 7 ticks

0.2 = 14 ticks

0.3 = 21 ticks

0.4 = 27 ticks

0.5 = 33 ticks

0.6 = 40 ticks

0.7 = 47 ticks

0.8 = 53 ticks

0.9 = 59 ticks

1.0 = 66 ticks

1.1 = 73 ticks

1.2 = 79 ticks

1.3 = 85 ticks

1.4 = 92 ticks

1.5 = 99 ticks

1.6 = 105 ticks

1.7 = 111 ticks

1.8 = 118 ticks

1.9 = 125 ticks

2.0 = 131 ticks

8.0 = 521 ticks

No wonder it's so hard to prevent cycling layers from getting farther and farther off if you don't use the same speed and delay both ways. A 2 second delay isn't even the same as two 1-second delays!

The number of ticks for a given number of seconds appears to be:

(seconds*65)+1, rounded to the nearest ODD number if it ends in .5

Normally .5 is rounded to the nearest even number, but presumably it's rounded before the 1 is added, resulting in it rounding towards odd numbers instead.

In that case the distance moved (in pixels) is:

((seconds*65)+1, rounded to the nearest ODD number if it ends in .5)*speed

The extra 1 is what tends to throw off the timing of layers. For example, a speed of -1 for 2 seconds and a speed of 2 for 1 second moves the layer -131 and then +132, causing it to go further off by 1 each cycle.

However, moving it by -1 for 1 second and +2 for 0.5 seconds does work because the number of ticks for 1 second is twice the number for 0.5 seconds. Another solution is to split up the first delay, so you have the layer moving -1 for 1 second, then -1 for 1 second again, then +2 for 1 second.