Linearly Scale Between RGB values - scale

Is there an easy mathematical relationship for scaling between two distinct RGB (3-tuple) values. Say I want to scale from red to green (1,0,0) to (0,1,0). Or say the values are more complex how do I linearly scale from (22,183,19) to (199, 201, 3)?

Here's a simple algorithm that will generate an array of RGB tuples that represent a linear transition. I noticed you had javascript tags in your profile, so I went with that. I chose to use the max distance between any pairs to determine the number of steps rather than using a fixed number of steps (but obviously that's trivial to change).
function generateLinearTransition(start, end) {
var rDiff = end.r - start.r;
var gDiff = end.g - start.g;
var bDiff = end.b - start.b;
var steps = Math.max(Math.abs(rDiff), Math.abs(gDiff), Math.abs(bDiff));
var rStepSize = rDiff / steps;
var gStepSize = gDiff / steps;
var bStepSize = bDiff / steps;
var tuples = [start];
var current = start;
for (var i = 0; i < steps; i++) {
current = {
r: current.r + rStepSize,
g: current.g + gStepSize,
b: current.b + bStepSize,
};
tuples.push({
r: Math.floor(current.r),
g: Math.floor(current.g),
b: Math.floor(current.b)
});
}
tuples.push(end);
return tuples;
}
var a = {
r: 22,
g: 183,
b: 19
};
var b = {
r: 199,
g: 201,
b: 3
};
var results = generateLinearTransition(a, b);
for (var i = 0; i < results.length; i++) {
var current = results[i];
console.log("(" + current.r + "," + current.g + "," + current.b + ")");
}
As an aside, your example of (1,0,0) and (0,1,0) are both essentially black, so there won't be much transition there. If you used (255,0,0) (red) and (0,255,0) (green), respectively, you'd get a longer transition.
Here's a working example.

You could find the difference between each value in each tuple by substracting one from the other, divide each of those differences by the number of "steps" to get an incremental delta for each value, per step, and then at each step add that delta.
For example, to scale from (22, 183, 19) to (199, 201, 3) in, say, 4 steps:
199 - 22 = 177; 177 / 4 = 44.25
201 - 183 = 18; 18 / 4 = 4.5
3 - 19 = -16; -16 / 4 = -4
So at each step, you'd add 44.25 to the first value (r), 4.5 to the second value (g), and -4 to the third value (b). So you'd go from (22, 183, 19) to (66.25, 187.5, 15) to (110.5, 192, 11) to (154.75, 196.5, 7) to (199, 201, 3).
Basically, treat each component separately, and scale linearly from one to the other, and combine.

Related

Sherlock and Cost on Hackerrank

It's about this dynamic programming challenge.
If you have a hard time to understand the Problem then see also on AbhishekVermaIIT's post
Basically, you get as input an array B and you construct array A. Fo this array A you need the maximum possible sum with absolute(A[i] - A[i-1]), for i = 1 to N. How to construct array A? --> You can choose for every element A[i] in array A either the values 1 or B[i]. (As you will deduce from the problem description any other value between these two values doesn't make any sense.)
And I came up with this recursive Java solution (without memoization):
static int costHelper(int[] arr, int i) {
if (i < 1) return 0;
int q = max(abs(1 - arr[i-1]) + costHelper(arr, i-1) , abs(arr[i] - arr[i-1]) + costHelper(arr, i-1));
int[] arr1 = new int[i];
for (int j = 0; j < arr1.length-1; j++) {
arr1[j] = arr[j];
}
arr1[i-1] = 1;
int r = max(abs(1 - 1) + costHelper(arr1, i-1) , abs(arr[i] - 1) + costHelper(arr1, i-1));
return max(q , r);
}
static int cost(int[] arr) {
return costHelper(arr, arr.length-1);
}
public static void main(String[] args) {
int[] arr = {55, 68, 31, 80, 57, 18, 34, 28, 76, 55};
int result = cost(arr);
System.out.println(result);
}
Basically, I start at the end of the array and check what is maximizing the sum of the last element minus last element - 1. But I have 4 cases:
(1 - arr[i-1])
(arr[i] - arr[i-1])
(1 - 1) // I know, it is not necessary.
(arr[i] -1)
For the 3rd or 4th case I construct a new array one element smaller in size than the input array and with a 1 as the last element.
Now, the result of arr = 55 68 31 80 57 18 34 28 76 55 according to Hackerrank should be 508. But I get 564.
Since it has to be 508 I guess the array should be 1 68 1 80 1 1 34 1 76 1.
For other arrays I get the right answer. For example:
79 6 40 68 68 16 40 63 93 49 91 --> 642 (OK)
100 2 100 2 100 --> 396 (OK)
I don't understand what is wrong with this algorithm.
I'm not sure exactly what's happening with your particular solution but I suspect it might be that the recursive function only has one dimension, i, since we need a way to identify the best previous solution, f(i-1), both if B_(i-1) was chosen and if 1 was chosen at that point, so we can choose the best among them vis-a-vis f(i). (It might help if you could add a description of your algorithm in words.)
Let's look at the brute-force dynamic program: let m[i][j1] represent the best sum-of-abs-diff in A[0..i] when A_i is j1. Then, generally:
m[i][j1] = max(abs(j1 - j0) + m[i-1][j0])
for j0 in [1..B_(i-1)] and j1 in [1..B_i]
Python code:
def cost(arr):
if len(arr) == 1:
return 0
m = [[float('-inf')]*101 for i in xrange(len(arr))]
for i in xrange(1, len(arr)):
for j0 in xrange(1, arr[i-1] + 1):
for j1 in xrange(1, arr[i] + 1):
m[i][j1] = max(m[i][j1], abs(j1 - j0) + (m[i-1][j0] if i > 1 else 0))
return max(m[len(arr) - 1])
That works but times out since we are looping potentially 100*100*10^5 iterations.
I haven't thought through the proof for it, but, as you suggest, apparently we can choose only from either 1 or B_i for each A_i for an optimal solution. This allows us to choose between those directly in a significantly more efficient solution that won't time out:
def cost(arr):
if len(arr) == 1:
return 0
m = [[float('-inf')]*2 for i in xrange(len(arr))]
for i in xrange(1, len(arr)):
for j0 in [1, arr[i-1]]:
for j1 in [1, arr[i]]:
a_i = 0 if j1 == 1 else 1
b_i = 0 if j0 == 1 else 1
m[i][a_i] = max(m[i][a_i], abs(j1 - j0) + (m[i-1][b_i] if i > 1 else 0))
return max(m[len(arr) - 1])
This is a bottom-up tabulation but we could easily convert it to a recursive one using the same idea.
Here is the javascript code with memoization-
function cost(B,n,val) {
if(n==-1){
return 0;
}
let prev1=0,prev2=0;
if(n!=0){
if(dp[n-1][0]==-1)
dp[n-1][0] = cost(B,n-1,1);
if(dp[n-1][1]==-1)
dp[n-1][1] = cost(B,n-1,B[n]);
prev1=dp[n-1][0];
prev2=dp[n-1][1];
}
prev1 = prev1 + Math.abs(val-1);
prev2 = prev2+ Math.abs(val-B[n]);
return Math.max(prev1,prev2);
}
where B->given array,n->total length,val-> 1 or B[n], value considered by the calling function.
Initial call -> Math.max(cost(B,n-2,1),cost(B,n-2,B[n-1]));
BTW, this took me around 3hrs, rather could have easily done with iteration method. :p
//dp[][0] is when a[i]=b[i]
dp[i][0]=max((dp[i-1][0]+abs(b[i]-b[i-1])),(dp[i-1][1]+abs(b[i]-1)));
dp[i][1]=max((dp[i-1][1]+abs(1-1)),(dp[i-1][0]+abs(b[i-1]-1)));
Initially all the elements in dp have the value of 0.
We know that we will get the answer if at any i the value is b[i] or 1. So the final answer is :
max(dp[n-1][0],dp[n-1][1])
dp[i][0] signifies a[i]=b[i] and dp[i][1] signifies a[i]=1.
So at every i we want the maximum of [i-1][0] (previous element is b[i-1]) or [i-1][1] (previous element is 1)

Calculating possible permutations in a grid with the given length?

I have a 4x4 grid full of letters. How can I calculate all possible routes from any point to any point that consist of 2 to 10 points?
All points within a route must be connected to another point within the same route vertically, horizontally or diagonally. For example you can go from A to B, A to E and A to F but not A to C.
Each point can be used only once in a route.
Here's an example of 25 possible permutations:
+---+---+---+---+
| A | B | C | D |
+---+---+---+---+
| E | F | G | H |
+---+---+---+---+
| I | J | K | L |
+---+---+---+---+
| M | N | O | P |
+---+---+---+---+
- AB
- ABC
- ABCD
- ABCDH
- ABCDHG
- ABCDHGF
- ABCDHGFE
- ABCDHGFEI
- ABCDHGFEIJ
- AE
- AEI
- AEIM
- AEIMN
- AEIMNJ
- AEIMNJF
- AIEMNJFB
- AIEMNJFBC
- AIEMNJFBCG
- AFKP
- PONM
- FGKL
- NJFB
- MNJGD
Now I should clear the question. I'm not asking HOW to get all the permutations. I'm asking what is the total amount of the possible permutations (i.e. an integer) and how to calculate it.
As mentioned in the comments the question can be answered with basic DFS in java starting at top left at (0,0)
EDIT: I added if(count(visited)>10) return; for the constraint
static int count=0;
static int count(boolean[][] b){
int r = 0;
for(int i=0;i<b.length;i++){
for(int j=0;j<b[0].length;j++){
if(b[i][j]) r++;
}
}
return r;
}
static boolean[][] copy(boolean[][] arr){
boolean [][] r = new boolean[arr.length][];
for(int i = 0; i < arr.length; i++)
r[i] = arr[i].clone();
return r;
}
static void dfs(int i, int j,boolean[][] visited) {
visited[i][j] = true;
if(count(visited)>10) return;
count++;
for (int k=-1;k<2;k++) {
for (int l=-1;l<2;l++) {
int r = i+k;
int c = j+l;
if (r>-1 && r<visited.length && c>-1 && c<visited.length && !visited[r][c]){
dfs(r,c,copy(visited));
}
}
}
}
public static void main(String args[]) {
boolean[][] visited = {
{false, false, false, false},
{false, false, false, false},
{false, false, false, false},
{false, false, false, false}
};
// dfs(row,column,initialize all to false)
dfs(0,0,visited);
System.out.println(count-1);
}
The above script just goes through each permutation and increments count every time since this includes the starting point (for example (0,0)) i have at the bottom count-1
Output: 105837 (edited from my incorrect original 1012519)
for 2x2 starting at same place i get 15. Which you can see from running
static int count=0;
static int count(boolean[][] b){
int r = 0;
for(int i=0;i<b.length;i++){
for(int j=0;j<b[0].length;j++){
if(b[i][j]) r++;
}
}
return r;
}
static boolean[][] copy(boolean[][] arr){
boolean [][] r = new boolean[arr.length][];
for(int i = 0; i < arr.length; i++)
r[i] = arr[i].clone();
return r;
}
static void dfs(int i, int j,boolean[][] visited,String str) {
visited[i][j] = true;
if (count(visited)>10) return;
count++;
str+="("+i+","+j+")";
System.out.println(str+": "+count);
for (int k=-1;k<2;k++) {
for (int l=-1;l<2;l++) {
int r = i+k;
int c = j+l;
if (r>-1 && r<visited.length && c>-1 && c<visited.length && !visited[r][c]){
dfs(r,c,copy(visited),str);
}
}
}
}
public static void main(String args[]) {
boolean[][] visited = {
{false, false},
{false, false}
};
dfs(0,0,visited,"");
// "count-1" to account for the starting position
System.out.println(count-1);
}
Output:
(0,0): 1
(0,0)(0,1): 2
(0,0)(0,1)(1,0): 3
(0,0)(0,1)(1,0)(1,1): 4
(0,0)(0,1)(1,1): 5
(0,0)(0,1)(1,1)(1,0): 6
(0,0)(1,0): 7
(0,0)(1,0)(0,1): 8
(0,0)(1,0)(0,1)(1,1): 9
(0,0)(1,0)(1,1): 10
(0,0)(1,0)(1,1)(0,1): 11
(0,0)(1,1): 12
(0,0)(1,1)(0,1): 13
(0,0)(1,1)(0,1)(1,0): 14
(0,0)(1,1)(1,0): 15
(0,0)(1,1)(1,0)(0,1): 16
15
the same script with 4x4 instead last 6 lines of output are:
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(1,2)(0,3): 105834
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(1,2)(1,3): 105835
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(1,2)(2,3): 105836
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(2,0): 105837
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(2,0)(1,0): 105838
105837
The requirements for your problem are complex enough that I doubt there is a simple mathematical calculation--at least I cannot think of one. Here is recursive Python code to find your path count.
SIDE = 4 # Length of side of grid
MAXLEN = 10 # Maximum path length allowed
SIDE2 = SIDE + 2
DIRS = ( # offsets for directions
-1 * SIDE2 - 1, # up & left
-1 * SIDE2 + 0, # up
-1 * SIDE2 + 1, # up & right
0 * SIDE2 - 1, # left
0 * SIDE2 + 1, # right
1 * SIDE2 - 1, # down & left
1 * SIDE2 + 0, # down
1 * SIDE2 + 1, # down & right
)
def countpaths(loc, pathlen):
"""Return the number of paths starting at the point indicated by
parameter loc of length at most parameter pathlen, not repeating
points or using points marked False in global variable isfree[]."""
global isfree
pathcnt = 1 # count sub-path of just this one point
if pathlen > 1:
isfree[loc] = False
for dir in DIRS:
if isfree[loc + dir]:
pathcnt += countpaths(loc + dir, pathlen - 1)
isfree[loc] = True
return pathcnt
# Init global boolean array variable to flag which points are still available
isfree = [1 <= r <= SIDE and 1 <= c <= SIDE
for r in range(SIDE2) for c in range(SIDE2)]
# Use the symmetries of the square grid to find count of paths in grid
allpathcnt = 0
for r in range(1, (SIDE + 1) // 2 + 1): # do a triangular slice of the grid
for c in range(1, r + 1):
# Find the number of similar (by symmetry) points in the grid
if 2 * r - 1 == SIDE:
if r == c:
sym = 1 # center of entire grid
else:
sym = 4 # center of column
else:
if r == c:
sym = 4 # diagonal
else:
sym = 8 # other
# Add paths starting at this kind of point removing those of length 1
allpathcnt += sym * (countpaths(r * SIDE2 + c, MAXLEN) - 1)
print('Total path count is ' + str(allpathcnt))
This code takes into account the requirement that paths have lengths between 2 and 10 by limiting the path length to 10 and removing the paths of length 1. The requirement that points are not repeated is fulfilled by using array isfree[] to note which points are still free (True) and which are already used or should not be used (False).
Python is a somewhat slow language, so I increased speed by moving some calculations out of the inner recursions. I used a surrounding border of always-False points around your 4x4 grid, removing the need for explicit bounds checking. I used a one-dimensional list rather than two-dimensional and pre-coded the offsets from each cell to neighboring cells in constant DIRS (for "directions"). I used a final optimization by not using all 16 starting points. There are 4 corner points like A, 8 side points like B, and 4 center points like F, so I just found the numbers of paths from A, B, and F and calculated what the total would be for starting at all points.
This version of my code can handle any size square grid and maximum path length. I checked my code by varying SIDE and MAXLEN separately to 1, 2, and 3, and checking the results for each point by hand.
The final answer I get is
1626144
I was interested to note that the section of code taking the most space is the part that determines the symmetries of a point in the grid. I have found other, more concise ways to do this, but they are all much less readable.

Determining the average angle

I'm developing an application that involves getting the camera angle in a game. The angle can be anywhere from 0-359. 0 is North, 90 is East, 180 is South, etc. I'm using an API, which has a getAngle() method in Camera class.
How would I find the average between different camera angles. The real average of 0 and 359 is 179.5. As a camera angle, that would be South, but obviously 0 and 359 are both very close to North.
You can think of it in terms of vectors. Let θ1 and θ2 be your two angles expressed in radians. Then we can determine the x and y components of the unit vectors that are at these angles:
x1 = sin(θ1)
y1 = cos(θ1)
x2 = sin(θ2)
y2 = cos(θ2)
You can then add these two vectors, and determine the x and y components of the result:
x* = x1 + x2
y* = y1 + y2
Finally, you can determine the angle of this resulting vector:
θavg = tan-1(y*/x*)
or, even better, use atan2 (a function supported by many languages):
θavg = atan2(y*, x*)
You will probably have to separately handle the cases where y* = 0 and x* = 0, since this means the two vectors are pointing in exactly opposite directions (so what should the 'average' be?).
It depends what you mean by "average". But the normal definition is the bisector of the included acute angle. You must put both within 180 degrees of each other. There are many ways to do this, but a simple one is to increment or decrement one of the angles. If the angles are a and b, then this will do it:
if (a < b)
while (abs(a - b) > 180) a = a + 360
else
while (abs(a - b) > 180) a = a - 360
Now you can compute the simple average:
avg = (a + b) / 2
Of course you may want to normalize one more time:
while (avg < 0) avg = avg + 360
while (avg >= 360) avg = avg - 360
On your example, you'd have a=0, b=359. The first loop would increment a to 360. The average would be 359.5. Of course you could round that to an integer if you like. If you round up to 360, then the final set of loops will decrement to 0.
Note that if your angles are always normalized to [0..360) none of these loops ever execute more than once. But they're probably good practice so that a wild argument doesn't cause your code to fail.
You want to bisect the angles not average them. First get the distance between them, taking the shortest way around, then divide that in half and add to one of the angles. Eg:
A = 355
B = 5
if (abs(A - B) < 180) {
Distance = abs(A - B)
if (A < B) {
Bisect = A + Distance / 2
}
else {
Bisect = B + Distance / 2
}
}
else {
Distance = 360 - abs(A - B)
if (A < B) {
Bisect = A - Distance / 2
}
else {
Bisect = B - Distance / 2
}
}
Or something like that -- "Bisect" should come out to zero for the given inputs. There are probably clever ways to make the arithmetic come out with fewer if and abs operations.
In a comment, you mentioned that all "angles" to be averaged are within 90 degrees to each other. I am guessing that there is really only one camera, but it moves around a lot, and you are creating some sort of picture stability mechanism for the camera POV.
In any case, there is only the special case where the camera may be in the 270-359 quadrant and the 0-89 quadrant. For all other cases, you can just take a simple average. So, you just need to detect that special case, and when it happens, treat the angles in the 270-359 quadrant as -90 to -1 instead. Then, after computing the simple average, adjust it back into the 270-359 quadrant if necessary.
In C code:
int quadrant (int a) {
assert(0 <= a && a < 360);
return a/90;
}
double avg_rays (int rays[], int num) {
int i;
int quads[4] = { 0, 0, 0, 0 };
double sum = 0;
/* trivial case */
if (num == 1) return rays[0];
for (i = 0; i < num; ++i) ++quads[quadrant(rays[i])];
if (quads[0] == 0 || quads[3] == 0) {
/* simple case */
for (i = 0; i < num; ++i) sum += rays[i];
return sum/num;
}
/* special case */
for (i = 0; i < num; ++i) {
if (quadrant(rays[i]) == 3) rays[i] -= 360;
sum += rays[i];
}
return sum/num + (sum < 0) * 360;
}
This code can be optimized at the expense of clarity of purpose. When you detect the special case condition, you can fix up the sum after the fact. So, you can compute sum and figure out the special case and do the fix up in a single pass.
double avg_rays_opt (int rays[], int num) {
int i;
int quads[4] = { 0, 0, 0, 0 };
double sum = 0;
/* trivial case */
if (num == 1) return rays[0];
for (i = 0; i < num; ++i) {
++quads[quadrant(rays[i])];
sum += rays[i];
}
if (quads[0] == 0 || quads[3] == 0) {
/* simple case */
return sum/num;
}
/* special case */
sum -= quads[3]*360;
return sum/num + (sum < 0) * 360;
}
I am sure it can be further optimized, but it should give you a start.

Math Function For Getting An Increasing/Decreasing Percentage

Is there a function or set of functions in php that will help me solve line 1 of this problem:
Noofdays factorial (for 5days) = 5+4+3+2+1
BasicValue = 200/ 15 =13.3
DailyDosage= Daynumber x basicValue
Decreasing dosage for 200 milligram prescription example: Day1 - 67, Day2 - 53, Day 3 - 40,Day 4 - 27, Day 5 - 13
Where 200 Needs to be a variable and NoofDays needs to be a variable.
1+2+...+n = n⋅(n+1)/2, if that's what you are asking.
Not really sure about what you are having problems with here. But the below seems to do what you want.
$currentDay = 4;
$noOfDays = 5;
$milligram = 200;
$basicValue = $milligram / array_sum(range($noOfDays, 1,-1));
$dailyDosage = round($currentDay * $basicValue);
factorial would be 5*4*3*2*1 = 120, not (sum) 5+4+3+2+1 = 15.
$Noofdays = 5;
$totalAmount = 200;
$dayThreeAmount = calculateDosage(3, $Noofdays, $totalAmount);
function calculateDosage($day, $totalDays, $totalAmount)
{
return ($totalAmount / ($totalDays * ($totalDays+1) / 2)) * ($totalDays - $day + 1);
}
I'm assuming sum is what you wanted...
EDIT: Doh, divide not multiply...

Math - mapping numbers

How do I map numbers, linearly, between a and b to go between c and d.
That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.
My brain is fried.
If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
Y = (X-A)/(B-A) * (D-C) + C
That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.
Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
This evenly spreads the numbers from the first range in the second range.
It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages.
Here is a simple implementation:
final static double EPSILON = 1e-12;
public static double map(double valueCoord1,
double startCoord1, double endCoord1,
double startCoord2, double endCoord2) {
if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
throw new ArithmeticException("/ 0");
}
double offset = startCoord2;
double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
return ratio * (valueCoord1 - startCoord1) + offset;
}
I am putting this code here as a reference for future myself and may be it will help someone.
As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
In addition to #PeterAllenWebb answer, if you would like to reverse back the result use the following:
reverseX = (B-A)*(Y-C)/(D-C) + A
Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
How you handle the rounding is up to you.
if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map
use this formula (linear mapping)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Where X is the number to map from A-B to C-D, and Y is the result:
Take the linear interpolation formula, lerp(a,b,m)=a+(m*(b-a)), and put C and D in place of a and b to get Y=C+(m*(D-C)). Then, in place of m, put (X-A)/(B-A) to get Y=C+(((X-A)/(B-A))*(D-C)). This is an okay map function, but it can be simplified. Take the (D-C) piece, and put it inside the dividend to get Y=C+(((X-A)*(D-C))/(B-A)). This gives us another piece we can simplify, (X-A)*(D-C), which equates to (X*D)-(X*C)-(A*D)+(A*C). Pop that in, and you get Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A)). The next thing you need to do is add in the +C bit. To do that, you multiply C by (B-A) to get ((B*C)-(A*C)), and move it into the dividend to get Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A)). This is redundant, containing both a +(A*C) and a -(A*C), which cancel each other out. Remove them, and you get a final result of: Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
TL;DR: The standard map function, Y=C+(((X-A)/(B-A))*(D-C)), can be simplified down to Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;
int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;
println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
stepF += rate;
println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);
With checks on divide by zero, of course.

Resources