4

I'm writing a program that needs to cycle through numbers between 0-255 given mouse X position. If given number goes over 255, the difference should be subtracted, as in 0,1,2...255,254,253...3,2,1,0,1,2,3,4...255,254...

For example

Given  Output
  1      1
  2      2
 255    255
 256    254
 509     0
 510     1

I've been toying with different formulas (x mod 255) is close but when it goes over 255, goes straight to 0 rather than 254.

Another one I came up with was round( 127.5*cos(x/16)+127.5 ) it produced decent numbers but not good enough.

Am I making this too complicated? What is a formula that can produce numbers like this?

dukevin
  • 507
  • what about using a piecewise function? – Frank Vel Nov 30 '14 at 12:24
  • Shouldn't 509 given an output of 1 and 510 give an output of 2? – paw88789 Nov 30 '14 at 12:26
  • fixed thanks. @fvel could you give an example? – dukevin Nov 30 '14 at 12:27
  • 1
    If the output given $255$ is $255$ and you really want to count from $255$ down to $0$ without skipping any numbers, then the output given $509$ is $1$ and the output given $510$ is $0$. See my answer for further details. By the way, since you start counting at $1$ rather than $0,$ some answers appear to assume you want to use the $255$ numbers $1$ through $255$ rather than $256$ numbers $0$ through $255.$ – David K Nov 30 '14 at 15:18
  • @KevinDuke The function I gave you satisfy all the examples you cited. In case what you described is not really what you wanted, I think I know what you want and suggest you to try this : 255-abs(($x%510)-255) – Pyrofoux Dec 01 '14 at 12:22

7 Answers7

8

Here's a detailed solution which works for $5$ instead of $255$, but I easily extended it to your need at the end.

Let's start with a function $f(x) = x$. For $1$ to $9$ you get :

$1,2,3,4,5,6,7,8,9$

Then with $x-5$, you get :

$-4,-3,-2,-1,0,1,2,4,5$

With $\sqrt{(x-5)^2}$ you get :

$4,3,2,1,0,1,2,3,4$

Then $5-\sqrt{(x-5)^2}$ gives you :

$1,2,3,4,5,4,3,2,1$.

For $5$, the final formula is $f(x) = 5-\sqrt{(\bmod(x,9)-5)^2}$ For $255$, your final formula is then $f(x) = 255-\sqrt{(\bmod(x,509)-255)^2}$ !

PS : I saw you using PHP so here's the PHP equivalent :

return 255-abs((x%509)-255)
Pyrofoux
  • 1,758
  • 2
    This is wrong (insert values and find out, you'll get sequences like 4,3,2,0,1) and violates the specification. Also, please use the absolute value, e.g. $|x-5|$. – GDumphart Nov 30 '14 at 12:49
  • 1
    @GDumphart Fixed thank you – Pyrofoux Nov 30 '14 at 12:51
  • Yup now it works. Your final line of code seems like the optimal solution. – GDumphart Nov 30 '14 at 12:54
  • Yup, perfect. Also thanks for the explanation! http://codepad.org/UI3vsjQV (for my reference later) – dukevin Nov 30 '14 at 12:57
  • @Pyrofoux This formula actually seems to skip 1 on the descending count. Look at input 508 and 509 on the codepad link above. It's repeated all descending 1's – dukevin Dec 01 '14 at 03:52
5

Use this:

output = abs(mod(input + 252,508)-253)+1;

It works and fulfills all your specifications, I tried it in Matlab.

GDumphart
  • 2,250
  • This seems to work: http://codepad.org/gsSwf7l1 Thanks! – dukevin Nov 30 '14 at 12:57
  • Given that the period of the OP's sequence is $510$, I doubt this works, although it's not far. Notice your output can't be $0$. The patch is easy though. In Python,
    **def f(n):
        return abs((n + 254)%510 - 255)**
    
    – Jean-Claude Arbaut Dec 01 '14 at 09:32
  • @Jean-ClaudeArbaut The question asker screwed me by recently editing his question, he initially didn't include $0$s. At the time of the question, my answer was fully compliant with his demands and my code was tested twice. See the comments in the answer of 'fvel'. – GDumphart Dec 01 '14 at 09:36
  • Ah, I didn't see this, ok! +1 then, as it's by far the simplest solution. – Jean-Claude Arbaut Dec 01 '14 at 09:38
  • @Jean-ClaudeArbaut No problem, it's confusing. Thank you for the kind words, but Pyrofoux's final line of code is an even simpler solution :) – GDumphart Dec 01 '14 at 11:09
3

I'll define $f(x)$ to be the output of your function given $x.$ That is, $$\begin{eqnarray} f(1) &=& 1, \\ f(2) &=& 2, \\ f(255) &=& 255, \\ f(256) &=& 254, \\ \end{eqnarray}$$ and so forth. I also assume you meant to have $f(0) = 0$ if $0$ is in the domain of your function.

If you continue stepping down from the output $254$ (given $256$) without skipping any numbers, and you allow the output to go all the way down to $0,$ then adding $1$ to $x$ reduces $f(x)$ by $1,$ adding $2$ to $x$ reduces $f(x)$ by $2,$ and adding $253$ to $x$ reduces $f(x)$ by $253.$ That is, $$\begin{eqnarray} f(257) &=& 253, \\ f(258) &=& 252, \\ f(509) &=& 1, \\ f(510) &=& 0, \\ f(511) &=& 1, \\ f(512) &=& 2, \\ \end{eqnarray}$$ and so forth, since you want to start counting upward again once you reach $0.$

It should be clear from this that the period of your function is exactly $510.$ That is, once you reach the output $0,$ it will take $510$ additional steps (incrementing the given value by $1$ each time) to reach the next output of $0.$

The following function will do the job:

$$f(x) = |((x + 254) \mod 510) - 254|$$

You can test it with the following PHP code:

<?
for($x = 0; $x <= 1025; $x++) {
      echo($x . "  ->  " . abs((($x + 254) % 510) - 254)) . "\n";
}
?>

Look particularly at the output for inputs near $255,$ near $510,$ near $765,$ and near $1020.$

David K
  • 98,388
1

Here's what you can do. Start with the triangular wave using the definition

$$x(t,a) = \frac{2}{a}\left(t-a\left\lfloor\frac{t}{a}+\frac{1}{2}\right\rfloor\right)(-1)^{\left\lfloor\tfrac{t}{a}+\tfrac{1}{2}\right\rfloor}$$

The function you need is

$$y(t,a) = \frac{a}{2}x\left(\frac{t-a/2}{2},\frac{a}{2}\right)+\frac{a}{2}$$

where $a = 255$. This simplifies to

$$y(t,a) = \frac{a}{2}\left(1 - (-1)^{\lfloor t/a \rfloor} \left(1 - 2 \frac{t}{a} + 2 \left\lfloor \frac{t}{a}\right\rfloor\right)\right).$$

1

Look at smaller example, $3$ instead $255$.

x = 1 2 3 4 5 6 7 8 9 10
v:  1 2 3 2 1 2 3 2 1 2...

The smallest period here is 1 2 3 2. Let $(a_n)_{0..3}$ be 4 element sequence, $(a_n) = (1,2,3,2)$ numbered from zero ($a_0 = 1$). The answer is $f(x) = a_{\left(x-1 \mod 4\right)}$.

Of course, if you don't want to make this sequence in memory, you can make similar function without it. Let $m = 255*2 - 2$.

$$ f(x) = \left\{ \begin{array}{l l} x & x < 255\\ 255 - (x-255) & x \in [255; m] \\ f((x-1 \mod{m})+1) & x > m\\ \end{array} \right. $$

Tacet
  • 1,879
1

The graph of the function you desire is a triangle wave as follows:

triangle wave

To create this function, we can start with a shifted sawtooth wave $x\%255-127.5$ which looks like:

sawtooth

This when multiplied with $(-1)^{floor(\frac{x}{255})}$ will become:

enter image description here

Now all that is remaining is to shift the graph up by adding 127.5.

Therefore the final function will be:

$ (x\%255-127.5)(-1)^{floor(\frac{x}{255})}+ 127.5 $

The PHP code for this is:

<?
for($x = 1; $x <= 2500; $x++)
{
    echo(  255-abs(($x%509)-255)   ). "\n";
}
?>

This function does not skip 1 in descending count from 508 to 509.

Albert
  • 11
-1

As a single function: $$\mathrm{sgn}\left(\sin(\dfrac{\pi x}{255})\right)x \pmod{255}$$

Or piecewise: $$*\left\{\begin{matrix} x \pmod {255} &&&1\leq x\leq 255 \mod (510)\\ -x \pmod {255} &&&256\leq x\leq 510 \mod (510) \end{matrix}\right.$$

I think these should work.

Frank Vel
  • 5,339
  • The first function won't work as it will have some $0$'s at $255$. Not sure how to improve on that... – Frank Vel Nov 30 '14 at 12:34
  • Yeah this is wrong, it's trickier than that. – GDumphart Nov 30 '14 at 12:45
  • @fvel Having 0's are actually ok, I should have mentioned this – dukevin Nov 30 '14 at 12:45
  • @KevinDuke You specified otherwise though, e.g. with $f(509) = 1$, pff. – GDumphart Nov 30 '14 at 12:45
  • @GDumphart yeah I'm a dunce I was thinking 255 but forgot it's actually 256 numbers including 0. Though in the program being off by 1 isn't important – dukevin Nov 30 '14 at 12:49
  • I don't have any graphing software, but the first should work with some minor modifications I think. But I see there are already better answers given, so I'll give let this be as it is. – Frank Vel Nov 30 '14 at 12:50