I have a simple function that takes a float parameter x
in the range [-1.0, 2.0]
and maps it to range [0.0, 1.0]
such that values below 0.0 are mapped to 1.0 and values above 1.0 are mapped to 0.0:
float wrap_ternary(x) {
// result is between [0.0, 1.0]
return x < 0.0 ? x 1.0 : x > 1.0 ? x - 1.0 : x;
}
I want to convert that function to use math expressions instead of conditionals. I've come up with the following algorithm:
float wrap_mod(x) {
return (((x 1.0) % 2.0 1.0) % 1.0);
}
However the edge wrapping of this algorithm is inclusive i.e. 1.0/2.0 are mapped to 0.0 whereas the ternary version would map these values to 1.0:
X | wrap_ternary | wrap_mod | wrong |
---|---|---|---|
-1.0 | 0.0 | 0.0 | |
-0.5 | 0.5 | 0.5 | |
0.0 | 0.0 | 0.0 | |
0.5 | 0.5 | 0.5 | |
1.0 | 1.0 | 0.0 | x |
1.5 | 0.5 | 0.5 | |
2.0 | 1.0 | 0.0 | x |
How would I modify my algorithm so that it produces the same results as the ternary version? I've tried to subtract EPSILON from my modulo but that didn't really work... I just can't wrap my head around this. No pun intended.
CodePudding user response:
The frac
function, which returns the fractional part of a float, seems to have the behaviour you want for all inputs other than 1.0
and 2.0
. So this would work:
float wrap_ternary(x) {
return (x == 1.0 || x == 2.0) ? 1.0 : frac(x);
}
CodePudding user response:
This might work as expected, though...
float wrap_somehow(x) {
return 0.5 - (frac(1.5 - abs(x - 0.5)) - 0.5) * sign(x - 0.5);
}