This is GUARANTEED to map ANY range to ANY range
I wrote this method, which follows precisely the algebraic formula for mapping a number from one range to another. The calculations are done with doubles to maintain precision, then at the end, it will return a Double with however many decimal places you specify in the method arguments.
It is not necessary to name the low and high ends of a range as low or high because it makes no difference if one end is lower or higher than the other end of either range, the method will still map the number correctly.
For example, if you stated any range as [-100 to 300] or [300 to -100] it would not make any difference. The remap will still come out accurately.
Here is how you would use the method in your code:
mapOneRangeToAnother(myNumber, fromRangeA, fromRangeB, toRangeA, toRangeB, decimalPrecision)
Here is an example of how to use the method:
Source range: -400 to 800
Destination range: 10000 to 3500
Number to re-map: 250
double sourceA = -400;
double sourceB = 800;
double destA = 10000;
double destB = 3500;
double myNum = 250;
double newNum = mapOneRangeToAnother(myNum,sourceA,sourceB,destA,destB,2);
Result: 6479.17
And if you need an integer back, just pass in 0 decimal places for precision and cast the result to int like this:
int myResult = (int) mapOneRangeToAnother(myNumber, 500, 200, -350, -125, 0);
Or you could declare the method to return an int and remove the decimalPrecision argument, then change the last two lines to:
int calcScale = (int) Math.pow(10, 0);
return (int) Math.round(finalNumber * calcScale) / calcScale;
In the OPs question, they would use the function like this:
int myResult = (int) mapOneRangeToAnother(input, input_start, input_end, output_start, output_end, 0);
and here is the method:
Edit: As was pointed out by @CoryGross, if the same number is passed into the method for both end points of the from
range, there will be a divide by zero. And since this method is supposed to calculate a new number based on two RANGEs of numbers, if either range has the same value for its end points, the calculated result will be meaningless, so we need to return null in that case.
This example was written in Java
public static Double mapOneRangeToAnother(double sourceNumber, double fromA, double fromB, double toA, double toB, int decimalPrecision ) {
double deltaA = fromB - fromA;
double deltaB = toB - toA;
if(deltaA == 0 || deltaB == 0) { //One set of end-points is not a range, therefore, cannot calculate a meaningful number.
return null;
}
double scale = deltaB / deltaA;
double negA = -1 * fromA;
double offset = (negA * scale) + toA;
double finalNumber = (sourceNumber * scale) + offset;
int calcScale = (int) Math.pow(10, decimalPrecision);
return (double) Math.round(finalNumber * calcScale) / calcScale;
}
In my use case, I needed to fade out the opacity of a JavaFX Control, but since opacity is a number from 0 to 1, I simply used the method to remap the range 1 to 100 (based on a for loop that incremented an int from 0 to 100) to the range 0 to 1 and it worked perfectly.
Though I know now that I could have created my loop by changing the increment from 1 to something like .01 like this:
for(double x=0; x<=1; x+=.01 {
//Code to change controls opacity
}
I just pointed this out for anyone that might be doing something similar to what I was doing. The method works perfectly as described.
:-)