-1

To wrap a number within a number system, you associate an index with a repeating set where the 0th index is always 0. eg, an index set table would be as follows for the range 0 thru 4

 INDEX: 0,1,2,3,4,5,6,7,8,9,10,11,12
 RESULT:0,1,2,3,4,0,1,2,3,4,0,1,2,3

you can see this is similar to a modulus, until you do negative numbers, for example, a range -3 to 3, the relationship would look like

INDEX | RESULT
    -9|-2
    -8|-1
    -7|0
    -6|1
    -5|2
    -4|3
    -3|-3
    -2|-2
    -1|-1
     0|0
     1|1
     2|2
     3|3
     4|-3
     5|-2
     6|-1

and so on, and so fourth.

This can be applied to a set of decimals as well. I want to write a function that can wrap a float for a range, but to optimize it, I don't want to use IF statements or loops. I'd like to have a mathematical solutions, so that processing this is straightforward, and quick, without interrupting the processor train.

How would one implement a system such as so?

any guidance on this would be awesome!

tuskiomi
  • 190
  • 1
  • 15
  • Welcome to Stack Overflow. Please take the time to read [The Tour](http://stackoverflow.com/tour) and refer to the material from the [Help Center](http://stackoverflow.com/help/asking) what and how you can ask here. – πάντα ῥεῖ Jun 14 '17 at 03:39
  • Thanks. I've been here before, but tend to delete my accounts due to the bad reception of questions – tuskiomi Jun 14 '17 at 03:42
  • Just ask valid questions. – πάντα ῥεῖ Jun 14 '17 at 03:45
  • I do, but they're usually esoteric or, so simple they get downvoted – tuskiomi Jun 14 '17 at 03:46
  • Well, I linked you to the relevant material to read. – πάντα ῥεῖ Jun 14 '17 at 03:51
  • My question fits well with the help center, no? It asks about a specific algorithm with very strict inputs, outputs, source. The only thing I'm missing is some source, which i attempt to replace with tables of data. – tuskiomi Jun 14 '17 at 03:53
  • If you don't have (even examplary) c++ code, don't use the [tag:c++] tag. – πάντα ῥεῖ Jun 14 '17 at 03:59
  • But then how are people supposed to know what i mean by no ifs or loops? For all i know, they may give a solution in a stack based language, which won't translate well to c++ – tuskiomi Jun 14 '17 at 04:02
  • @raymondchen i saw that but i don't think that's a valid solution that handles negatives.... i may be wrong – tuskiomi Jun 14 '17 at 04:04
  • Show examples for ranges `-5..-2, -3..1, 2..5` – MBo Jun 14 '17 at 05:21
  • It works for negatives because `floor` rounds toward negative infinity Even the OP asks about the negatives case. There is also a performance comparison that shows the `if` version is faster, so just use the `if`. – Raymond Chen Jun 14 '17 at 14:09

1 Answers1

3

Let assume we got wrap open range (a0,a1) where a0<0 and a1>0 and input number is x I would start experimenting with

x' = ((x/a0) - floor(x/a0))*a0 // negative x
x' = ((x/a1) - floor(x/a1))*a1 // positive x

Now the only problem how to decide which one to use without branching (if statements). I would use binary bit manipulation integer representation of float value. The sign bit is the MSB and float is 32 bit. So first obtain sign value of float and then convert it to 0 or 1:

unsigned int *px=(unsigned int*)&x;
float a=(unsigned int)(px[0]>>31);

Beware that unsigned int must be the same bit-width or less (but then use correct bit-shift of coarse) than float I usually use DWORD for such thing but not all compilers know such a type (it should be defined also in windows.h btw). Now just use it to select between the two equations. When I put all together in C++:

float wrap(float x,float a0,float a1)
    {
    float a;
    a=x/a0; a0*=(a-floor(a));   // x<=0
    a=x/a1; a1*=(a-floor(a));   // x>=0
    unsigned int *px=(unsigned int*)&x; // px is integer representaion of x
    a=(unsigned int)(px[0]>>31);    // a = 0 for x>=0 and a = 1 for x<=0
    // now just combine
    a0*=(    a);
    a1*=(1.0-a);
    return a0+a1;
    }

Here result for range (-3,+3)

   x   |    x'
---------------
 -6.25 |  -0.25
 -6.00 |   0.00
 -5.75 |  -2.75
 -5.50 |  -2.50
 -5.25 |  -2.25
 -5.00 |  -2.00
 -4.75 |  -1.75
 -4.50 |  -1.50
 -4.25 |  -1.25
 -4.00 |  -1.00
 -3.75 |  -0.75
 -3.50 |  -0.50
 -3.25 |  -0.25
 -3.00 |   0.00
 -2.75 |  -2.75
 -2.50 |  -2.50
 -2.25 |  -2.25
 -2.00 |  -2.00
 -1.75 |  -1.75
 -1.50 |  -1.50
 -1.25 |  -1.25
 -1.00 |  -1.00
 -0.75 |  -0.75
 -0.50 |  -0.50
 -0.25 |  -0.25
---------------
  0.00 |   0.00
---------------
  0.25 |   0.25
  0.50 |   0.50
  0.75 |   0.75
  1.00 |   1.00
  1.25 |   1.25
  1.50 |   1.50
  1.75 |   1.75
  2.00 |   2.00
  2.25 |   2.25
  2.50 |   2.50
  2.75 |   2.75
  3.00 |   0.00
  3.25 |   0.25
  3.50 |   0.50
  3.75 |   0.75
  4.00 |   1.00
  4.25 |   1.25
  4.50 |   1.50
  4.75 |   1.75
  5.00 |   2.00
  5.25 |   2.25
  5.50 |   2.50
  5.75 |   2.75
  6.00 |   0.00
  6.25 |   0.25
Spektre
  • 49,595
  • 11
  • 110
  • 380