Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How to proportionally convert a number in the range of -1 and 1 to a number in the range of 0 and 319
I have float noise values, between -1 and 1, for every x,y coordinate in a 2D area and I am trying to convert that to a whole number between 0 and 319 which represents a vertical z coordinate to render.
For example,
-1 = 0 and
1 = 319 but
0.12345 = ???
How would I go about implementing this efficiently?
3 answers
There is one thing to clarify when mapping a float interval to an integer interval, namely how the boundaries of the float interval shall be mapped to the boundaries of the integer interval.
Taking the example of the float interval [-1.0, +1.0], assuming here, that the endpoints of the interval can actually occur. If the target integer interval is 0..319: Which floating point interval shall be mapped to 0?
If we linearly map [-1.0, +1.0] to [0.0, 319.0] then this gives (as others have explained) the following formula: y = 159.5x + 159.5.
When rounding is done to the nearest integer this will have the following effect:
- float numbers [-1.0, −0,996865204] will be mapped to 0. This interval has a width of 0,003134796.
- float numbers [−0,996865205, −0,990595611] will be mapped to 1. This interval has a width of 0,006269593.
- float numbers [0,996865204, +1,0] will be mapped to 319. This interval has a width of 0,003134796.
You see that the ranges of float values that map to 0 and 319 are only half as wide as the ranges of float values that map to numbers from 1..318. This may be exactly what you want, or it may be acceptable, in which case the formula y = 159.5x + 159.5 is perfectly fine.
For other rounding strategies (round towards minus infinity, round towards plus infinity) the results will be different, but there will still be an asymmetry with respect to the width of the intervals for some the numbers.
If instead you want to achieve that for each target integer number the source intervals shall be equally wide, then you would have to calculate the mapping from [-1.0, +1.0] to [-0.5, 319.5). This would result in the formula y = 160.0*x + 159.5 with rounding, giving the desired numbers from 0..319, plus a special case handling of +1.0 which would have to be mapped to 319 rather than 320.
0 comment threads
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
cuzzo | (no comment) | Dec 22, 2022 at 17:34 |
You want to scale from one linear range to another. That can always be done with
y = mx + b
where X is the input value and Y the output value. M is the scale factor, and B the offset.
You want to map (-1 .. 1) to (0 .. 319). The scale factor therefore has to be 319/2 = 159.5 = m.
Now that you know M, pick any known X and Y pair and solve for B:
b = y - mx
You know that -1 maps to 0, so
y - mx = 0 - (159.5)(-1) = 159.5 = b
The final result is therefore
y = 159.5x + 159.5
Note that this method works for mapping any linear range to any other linear range.
0 comment threads
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
cuzzo | (no comment) | Dec 22, 2022 at 17:29 |
My initial approach would be to increase n
by 1 (thus shifting the original range from -1..+1 to 0..+2), turn that range into 0..+1, and then simply map from that to your 0..+319 output range.
float result = (n+1)/2 * 319;
This will map -1 to 0; 0 to 159.5; +1 to 319; and your example +0.12345 to 179.190275. (All potentially subject to float precision issues, of course.)
As for efficiency, this is a few simple math operations; I'm not sure you can get much more efficient than that. That problem is complicated by the fact that you are dealing with a floating-point value as the input.
Once you have the corresponding floating-point value, just use whatever rounding function you prefer. java.lang.Math offers e.g. floor()
and rint()
, or if you think you can do better then you can roll your own rounding function.
Had the input value n
been an integer, you could probably just have precomputed a fairly small (320 entries in this case) table and benchmarked on-need calculation and table lookup respectively on application startup and used the faster approach, paying attention to things like cache locality, but this feels as though if that's the level of optimization you are looking for, then Java is the wrong language to use to begin with.
2 comment threads