# Re-map a number from one range to another?

Discussion in 'Scripting' started by mgear, Jan 14, 2012.

Not open for further replies.
1. ### mgear

Joined:
Aug 3, 2010
Posts:
9,401
What would be the closest thing to this in unity? (js or c#)

from other language:
//Re-maps a number from one range to another.
float m = map(value, low1, high1, low2, high2);

http://processing.org/reference/map_.html

Visual Explanation:

reference: https://victorkarp.wordpress.com/20...-numbers-to-another-range-visually-explained/

*nevermind, found this (not tested yet)..

Code (csharp):
1.
2. // c#
3. float map(float s, float a1, float a2, float b1, float b2)
4. {
5.     return b1 + (s-a1)*(b2-b1)/(a2-a1);
6. }
7.

Last edited: Apr 21, 2022
Fenikkel, Ruslank100, raul3d and 6 others like this.
2. ### Jessy

Joined:
Jun 7, 2007
Posts:
7,325
That code works fine, but you could write it more clearly. You can make an extension method to float:
Code (csharp):
1. public static class ExtensionMethods {
2.
3. public static float Remap (this float value, float from1, float to1, float from2, float to2) {
4.     return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
5. }
6.
7. }
That will allow this pretty decent syntax:
Code (csharp):
1. Debug.Log(2.Remap(1, 3, 0, 10));    // 5

Last edited: Jan 14, 2012
3. ### Justice777

Joined:
Jan 7, 2018
Posts:
2
I would use "Map" instead of "ReMap" to be consistent with other tools and use the argument names inputFrom, inputTo, outputFrom, outputTo, to be more clear.

But thanks for the function!

VeganBurrito86 and iGAMONIC like this.
4. ### RazaTech

Joined:
Feb 27, 2015
Posts:
178
In case if any body could not understand upper code.

Code (CSharp):
1.  public static float Remap (this float from, float fromMin, float fromMax, float toMin,  float toMax)
2.     {
3.         var fromAbs  =  from - fromMin;
4.         var fromMaxAbs = fromMax - fromMin;
5.
6.         var normal = fromAbs / fromMaxAbs;
7.
8.         var toMaxAbs = toMax - toMin;
9.         var toAbs = toMaxAbs * normal;
10.
11.         var to = toAbs + toMin;
12.
14.     }

5. ### brando_slc

Joined:
Jan 4, 2017
Posts:
7
Testing the above methods... Raza's code worked when changing the range to include negative numbers, but Jessy's method, as far as I can tell, does not.

6. ### eisenpony

Joined:
May 8, 2015
Posts:
974
They both work okay for me: https://dotnetfiddle.net/4zTuVI

The algebra is the same in the two methods, they just use different names and Raza shows his work step by step. Basically, start by normalizing your position in the first vector and then multiply the normalized position by the second vector and finally add the second vector's starting position.

Code (csharp):
1. using System;
2.
3. public class Program
4. {
5.     public static void Main()
6.     {
7.         var r = new Random();
8.         for (var i = 0; i < 100; i ++)
9.         {
10.             var x1 = r.Next(int.MinValue, int.MaxValue);
11.             var x2 = r.Next(int.MinValue, int.MaxValue);
12.             var y1 = r.Next(int.MinValue, int.MaxValue);
13.             var y2 = r.Next(int.MinValue, int.MaxValue);
14.             var p = r.Next(int.MinValue, int.MaxValue);
15.
16.             var jessy = JessyMap(p, x1, x2, y1, y2);
17.             var razza = RazzaMap(p, x1, x2, y1, y2);
18.
19.             if(jessy == razza)
20.                 Console.WriteLine(\$"Same result for arguments {p}, {x1}, {x2}, {y1}, {y2}");
21.             else
22.                 Console.WriteLine(\$"Bad result for arguments {p}, {x1}, {x2}, {y1}, {y2}");
23.         }
24.     }
25.
26.     public static float JessyMap (float value, float from1, float to1, float from2, float to2) {
27.         return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
28.     }
29.
30.     public static float RazzaMap (float from, float fromMin, float fromMax, float toMin,  float toMax)
31.     {
32.         var fromAbs  =  from - fromMin;
33.         var fromMaxAbs = fromMax - fromMin;
34.
35.         var normal = fromAbs / fromMaxAbs;
36.
37.         var toMaxAbs = toMax - toMin;
38.         var toAbs = toMaxAbs * normal;
39.
40.         var to = toAbs + toMin;
41.
43.     }
44. }

Bunny83 and ToroidGames like this.
7. ### eisenpony

Joined:
May 8, 2015
Posts:
974
Here's another way of looking at the same problem. Imagine drawing both ranges on a number line but then rotating the second range to be perpendicular, so you have two number lines: an x an y dimension.

You might be able to see that in order to translate from one range to the other, we can use a linear equation:
y = mx + c
where:
m = the slope of the line (the ratio of range2 / range1)
c = the y intercept of the line (the difference between where range2 and range1 start, multiplied by the slope)
y = dependent variable
x = independent variable

Code (csharp):
1. public static float Map (this float x, float x1, float x2, float y1,  float y2)
2. {
3.   var m = (y2 - y1) / (x2 - x1);
4.   var c = y1 - m * x1; // point of interest: c is also equal to y2 - m * x2, though float math might lead to slightly different results.
5.
6.   return m * x + c;
7. }

8. ### kru

Joined:
Jan 19, 2013
Posts:
452
If you want to use unity methods:
Code (csharp):
1. float aValue;
2. float normal = Mathf.InverseLerp(aLow, aHigh, value);
3. float bValue = Mathf.Lerp(bLow, bHigh, normal);

9. ### fizzd

Joined:
Jul 30, 2013
Posts:
21
Jessy's code totally confused me until i realised that what he meant by 'from' and 'to' were totally non-intuitive to me. I thought it meant 'range we're mapping from' and 'range we're mapping to'.

but actually we're using 'from1..to1' to 'from2..to2', instead of 'from1..from2' to 'to1..to2'.
Just in case someone else might have come here to save thinking time and made a mistake from it, since this result comes up first on google.

10. ### harm-zesbaans

Joined:
Mar 21, 2013
Posts:
3
Sheer elegance

11. ### seejayjames

Joined:
Jan 28, 2013
Posts:
691
Put it in a utilityScript class and make it static, so you can use it in any script by calling

mappedValue = utilityScript.remap(5, 1, 10, -50, 100);

Code (CSharp):
1. public static float remap(float val, float in1, float in2, float out1, float out2)
2.     {
3.         return out1 + (val - in1) * (out2 - out1) / (in2 - in1);
4.     }

(p.s. Mathf, still waiting...)

laurajhchen, d2clon, crb471 and 3 others like this.
12. ### seejayjames

Joined:
Jan 28, 2013
Posts:
691
Overloaded version with clamping on the input and output values. The original one has no clamping on anything, so you can input and output values outside the ranges (may not be what you want).

Code (CSharp):
1. // Full version, clamping settable on all 4 range elements (in1, in2, out1, out2)
2.     public static float remap(float val, float in1, float in2, float out1, float out2,
3.         bool in1Clamped, bool in2Clamped, bool out1Clamped, bool out2Clamped)
4.     {
5.         if (in1Clamped == true && val < in1) val = in1;
6.         if (in2Clamped == true && val > in2) val = in2;
7.
8.         float result = out1 + (val - in1) * (out2 - out1) / (in2 - in1);
9.
10.         if (out1Clamped == true && result < out1) result = out1;
11.         if (out2Clamped == true && result > out2) result = out2;
12.
13.         return result;
14.     }

13. ### crb471

Joined:
Jul 8, 2013
Posts:
11
This marks the 1000th time I've gone on here to copy paste this code.

Can someone from Unity please put this in Mathf?

14. ### PraetorBlue

Joined:
Dec 13, 2012
Posts:
7,907
Code (CSharp):
1.     public static float Remap(float input, float oldLow, float oldHigh, float newLow, float newHigh) {
2.         float t = Mathf.InverseLerp(oldLow, oldHigh, input):
3.         return Mathf.Lerp(newLow, newHigh, t);
4.     }
Edit: I'm not the first one in this thread, oops ;D

Eristen and seejayjames like this.
15. ### seejayjames

Joined:
Jan 28, 2013
Posts:
691
I originally used names like "low" and "high" as well, but I found it unintuitive, because the ranges can be reversed. (Though my "clamped" version disallows reversed ranges.)
+1000 for adding at least a basic version to Mathf...

16. ### Riplyn

Joined:
Oct 3, 2018
Posts:
2
Freya Holmer talks about remapping in her Indiecade talk (@ 21 minutes):

17. ### Bunny83

Joined:
Oct 18, 2010
Posts:
3,967
Right, generally when you want a clamped version, it's usually best to just clamp the normalized value. The normalized value is always in the range 0 to +1, so clamping there is trivial. For example imagine you want to map the range
"20 to 10" and your input value is "12". It means we subtract the "first" bounds and divide by the difference. So we get

``(12-20) / (10-20) ---> (-8) / (-10) ---> 0.8``

So clamping the normalized value between 0 and 1 would give you the right result. That means if you want to write a single method that does a remap that clamps, you can simply do

Code (CSharp):
1. public static float RemapClamped(this float aValue, float aIn1, float aIn2, float aOut1, float aOut2)
2. {
3.     float t = (aValue - aIn1) / (aIn2 - aIn1);
4.     t = Mathf.Clamp(t);
5.     return aOut1 + (aOut2 - aOut1) * t;
6. }
Or without any Mathf dependency by inlining the clamp

Code (CSharp):
1. public static float RemapClamped(this float aValue, float aIn1, float aIn2, float aOut1, float aOut2)
2. {
3.     float t = (aValue - aIn1) / (aIn2 - aIn1);
4.     if (t > 1f)
5.         return aOut2;
6.     if(t < 0f)
7.         return aOut1;
8.     return aOut1 + (aOut2 - aOut1) * t;
9. }
It doesn't really make much sense to clamp the inputs / outputs seperately as clamping one would automatically clamp the other as well since we make a mapping between those ranges. So if you clamp the input to stay in the input range, the output will also be in the output range since that's the definition of our remap function.

In my second version we could set "t" to 1 when it's larger than 1. However since we know that the final equation will evaluate to, we can directly return the correct result. This is also better for numerical stability. At dodgy range values, clamping t to 1 may not yield "aOut2" because even aOut1 and (-aOut1) mathematically cancel each other, due to floating point rounding issues the result may be slightly off. So directly returning the proper upper / lower bounds is not only faster, but also more stable. So such an expression would 100% of the time evaluate to true if we run into the upper bounds of the output range

Code (CSharp):
1. float val =  7;
2. if (val.RemapClamped(20,10, 5, 200) == 200)
likewise this would also work reliably

Code (CSharp):
1. float val =  21;
2. if (val.RemapClamped(20,10, 5, 200) == 5)

Greenhapi and seejayjames like this.
18. ### SparrowGS

Joined:
Apr 6, 2017
Posts:
2,536
1) create a utility class that contains general-use code that you use on most projects
2) put this code there (and any other you use often)
3) import said script into all new projects.
4) profit? (actually yeah, you save time and time = money)

PraetorBlue likes this.
19. ### seejayjames

Joined:
Jan 28, 2013
Posts:
691
Agreed, and that's what I do, including some list-based methods like randomize. But at some point it would just be nice to have them in the library...several other languages (Processing, Max/MSP) do, so they're very straightforward to use. Also just having them readily available means you're aware of them, maybe before realizing you even need them

Eristen likes this.
20. ### dvelasco

Joined:
Jul 23, 2014
Posts:
7
That was actually a beautiful description of NURBS math! Quite elegant and informative (right after the remap discussion)..

21. ### Blubber5463

Joined:
May 1, 2022
Posts:
1
This works, however it clamps the return value between bLow and bHigh. The processing map function allows you to enter a value that exceeds the range of aLow and aHigh, returning the desired value.

22. ### Bunny83

Joined:
Oct 18, 2010
Posts:
3,967
Yes, sure. Most map function actually do clamp or some libraries may provide both a clamped and an unclamped version. Have a look at my implementaion above. You can simply remove the clamp and you get the unclamped versions.

Like this:
Code (CSharp):
1.
2.     // unclamped
3.     public static float Remap(this float aValue, float aIn1, float aIn2, float aOut1, float aOut2)
4.     {
5.         float t = (aValue - aIn1) / (aIn2 - aIn1);
6.         return aOut1 + (aOut2 - aOut1) * t;
7.     }
As it was mentioned already, this is all elementary school math

23. ### curbol

Joined:
Oct 29, 2015
Posts:
8
I turned this into an extension method with tuple parameters which I think makes it more clear:

Code (CSharp):
1.   public static float Remap(this float value, (float min, float max) from, (float min, float max) to)
2.     => (value - from.min) / (from.max - from.min) * (to.max - to.min) + to.min;

CDCappa and Bunny83 like this.
24. ### Tomsterk

Joined:
Nov 23, 2012
Posts:
10
Welcome back everyone. If you're here for this method, Unity has added it to their Mathematics package, which i believe is default

https://docs.unity3d.com/Packages/com.unity.mathematics@1.2/api/Unity.Mathematics.math.remap.html

usage is quite simple

Code (CSharp):
1. using Unity.Mathematics;
2.
3. //...
4.
5. //Returns the result of a non-clamping linear remapping of a value x from [a, b] to [c, d].
6. float newValue = math.remap(a, b, c, d, x);
So, if i wanted to remap value 50 from range 0-100 onto the new range 20-40, it would be

Code (CSharp):
1. float newValue = math.remap(0, 100, 20, 40, 50);

25. ### Ziplock9000

Joined:
Jan 26, 2016
Posts:
360
Unfortunately they only have a non-clamping version.

Here's a version that clamps the input range
Code (CSharp):
1.     float clamped_remap(float input_min, float input_max, float output_min, float output_max, float value)
2.     {
3.         if (value < input_min)
4.         {
5.             return output_min;
6.         }
7.         else if (value > input_max)
8.         {
9.             return output_max;
10.         }
11.         else
12.         {
13.             return (value - input_min) / (input_max - input_min) * (output_max - output_min) + output_min;
14.         }
15.     }

Last edited: Jul 10, 2023
Celezt, Bauschen and mgear like this.