# Map range

Map range
You are encouraged to solve this task according to the task description, using any language you may know.

Given two ranges:

•   ${\displaystyle [a_{1},a_{2}]}$   and
•   ${\displaystyle [b_{1},b_{2}]}$;
•   then a value   ${\displaystyle s}$   in range   ${\displaystyle [a_{1},a_{2}]}$
•   is linearly mapped to a value   ${\displaystyle t}$   in range   ${\displaystyle [b_{1},b_{2}]}$

where:

•   ${\displaystyle t=b_{1}+{(s-a_{1})(b_{2}-b_{1}) \over (a_{2}-a_{1})}}$

Write a function/subroutine/... that takes two ranges and a real number, and returns the mapping of the real number from the first to the second range.

Use this function to map values from the range    [0, 10]    to the range    [-1, 0].

Extra credit

Show additional idiomatic ways of performing the mapping, using tools available to the language.

## ACL2

(defun mapping (a1 a2 b1 b2 s)   (+ b1 (/ (* (- s a1)               (- b2 b1))            (- a2 a1)))) (defun map-each (a1 a2 b1 b2 ss)   (if (endp ss)       nil       (cons (mapping a1 a2 b1 b2 (first ss))             (map-each a1 a2 b1 b2 (rest ss))))) (map-each 0 10 -1 0 '(0 1 2 3 4 5 6 7 8 9 10)) ;; (-1 -9/10 -4/5 -7/10 -3/5 -1/2 -2/5 -3/10 -1/5 -1/10 0)

with Ada.Text_IO;procedure Map is   type First_Range  is new Float range 0.0 .. 10.0;   type Second_Range is new Float range -1.0 .. 0.0;   function Translate (Value : First_Range) return Second_Range is      B1 : Float := Float (Second_Range'First);      B2 : Float := Float (Second_Range'Last);      A1 : Float := Float (First_Range'First);      A2 : Float := Float (First_Range'Last);      Result : Float;   begin      Result := B1 + (Float (Value) - A1) * (B2 - B1) / (A2 - A1);      return Second_Range (Result);   end;   function Translate (Value : Second_Range) return First_Range is      B1 : Float := Float (First_Range'First);      B2 : Float := Float (First_Range'Last);      A1 : Float := Float (Second_Range'First);      A2 : Float := Float (Second_Range'Last);      Result : Float;   begin      Result := B1 + (Float (Value) - A1) * (B2 - B1) / (A2 - A1);      return First_Range (Result);   end;   Test_Value : First_Range := First_Range'First;begin   loop      Ada.Text_IO.Put_Line (First_Range'Image (Test_Value) & " maps to: "                          & Second_Range'Image (Translate (Test_Value)));      exit when Test_Value = First_Range'Last;      Test_Value := Test_Value + 1.0;   end loop;end Map;
Output:
 0.00000E+00 maps to: -1.00000E+00
1.00000E+00 maps to: -9.00000E-01
2.00000E+00 maps to: -8.00000E-01
3.00000E+00 maps to: -7.00000E-01
4.00000E+00 maps to: -6.00000E-01
5.00000E+00 maps to: -5.00000E-01
6.00000E+00 maps to: -4.00000E-01
7.00000E+00 maps to: -3.00000E-01
8.00000E+00 maps to: -2.00000E-01
9.00000E+00 maps to: -1.00000E-01
1.00000E+01 maps to:  0.00000E+00

## ALGOL 68

# maps a real s in the range [ a1, a2 ] to the range [ b1, b2 ]           ## there are no checks that s is in the range or that the ranges are valid #PROC map range = ( REAL s, a1, a2, b1, b2 )REAL:    b1 + ( ( s - a1 ) * ( b2 - b1 ) ) / ( a2 - a1 ); # test the mapping #FOR i FROM 0 TO 10 DO    print( ( whole( i, -2 ), " maps to ", fixed( map range( i, 0, 10, -1, 0 ), -8, 2 ), newline ) )OD
Output:
 0 maps to    -1.00
1 maps to    -0.90
2 maps to    -0.80
3 maps to    -0.70
4 maps to    -0.60
5 maps to    -0.50
6 maps to    -0.40
7 maps to    -0.30
8 maps to    -0.20
9 maps to    -0.10
10 maps to     0.00


## AppleScript

-- rangeMap :: (Num, Num) -> (Num, Num) -> Num -> Numon rangeMap(a, b)    script        on |λ|(s)            set {a1, a2} to a            set {b1, b2} to b            b1 + ((s - a1) * (b2 - b1)) / (a2 - a1)        end |λ|    end scriptend rangeMap  -- TEST ---------------------------------------------------on run    set mapping to rangeMap({0, 10}, {-1, 0})     set xs to enumFromTo(0, 10)    set ys to map(mapping, xs)    set zs to map(approxRatio(0), ys)     unlines(zipWith3(formatted, xs, ys, zs))end run  -- DISPLAY ------------------------------------------------ -- formatted :: Int -> Float -> Ratio -> Stringon formatted(x, m, r)    set fract to showRatio(r)    set {n, d} to splitOn("/", fract)     (justifyRight(2, space, x as string) & "   ->   " & ¬        justifyRight(4, space, m as string)) & "   =   " & ¬        justifyRight(2, space, n) & "/" & dend formatted  -- GENERIC ABSTRACTIONS ----------------------------------- -- https://github.com/RobTrew/prelude-applescript -- Absolute value.-- abs :: Num -> Numon abs(x)    if 0 > x then        -x    else        x    end ifend abs -- approxRatio :: Real -> Real -> Ratioon approxRatio(epsilon)    script        on |λ|(n)            if {real, integer} contains (class of epsilon) and 0 < epsilon then                set e to epsilon            else                set e to 1 / 10000            end if             script gcde                on |λ|(e, x, y)                    script _gcd                        on |λ|(a, b)                            if b < e then                                a                            else                                |λ|(b, a mod b)                            end if                        end |λ|                    end script                    |λ|(abs(x), abs(y)) of _gcd                end |λ|            end script             set c to |λ|(e, 1, n) of gcde            ratio((n div c), (1 div c))        end |λ|    end scriptend approxRatio -- enumFromTo :: Int -> Int -> [Int]on enumFromTo(m, n)    if m ≤ n then        set lst to {}        repeat with i from m to n            set end of lst to i        end repeat        return lst    else        return {}    end ifend enumFromTo -- gcd :: Int -> Int -> Inton gcd(a, b)    set x to abs(a)    set y to abs(b)    repeat until y = 0        if x > y then            set x to x - y        else            set y to y - x        end if    end repeat    return xend gcd -- justifyLeft :: Int -> Char -> String -> Stringon justifyLeft(n, cFiller, strText)    if n > length of strText then        text 1 thru n of (strText & replicate(n, cFiller))    else        strText    end ifend justifyLeft -- justifyRight :: Int -> Char -> String -> Stringon justifyRight(n, cFiller, strText)    if n > length of strText then        text -n thru -1 of ((replicate(n, cFiller) as text) & strText)    else        strText    end ifend justifyRight -- length :: [a] -> Inton |length|(xs)    set c to class of xs    if list is c or string is c then        length of xs    else        (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)    end ifend |length| -- Lift 2nd class handler function into 1st class script wrapper -- mReturn :: First-class m => (a -> b) -> m (a -> b)on mReturn(f)    if class of f is script then        f    else        script            property |λ| : f        end script    end ifend mReturn -- map :: (a -> b) -> [a] -> [b]on map(f, xs)    tell mReturn(f)        set lng to length of xs        set lst to {}        repeat with i from 1 to lng            set end of lst to |λ|(item i of xs, i, xs)        end repeat        return lst    end tellend map -- minimum :: Ord a => [a] -> aon minimum(xs)    set lng to length of xs    if lng < 1 then return missing value    set m to item 1 of xs    repeat with x in xs        set v to contents of x        if v < m then set m to v    end repeat    return mend minimum -- ratio :: Int -> Int -> Ratio Inton ratio(x, y)    script go        on |λ|(x, y)            if 0 ≠ y then                if 0 ≠ x then                    set d to gcd(x, y)                    {type:"Ratio", n:(x div d), d:(y div d)}                else                    {type:"Ratio", n:0, d:1}                end if            else                missing value            end if        end |λ|    end script    go's |λ|(x * (signum(y)), abs(y))end ratio -- Egyptian multiplication - progressively doubling a list, appending-- stages of doubling to an accumulator where needed for binary -- assembly of a target length-- replicate :: Int -> a -> [a]on replicate(n, a)    set out to {}    if n < 1 then return out    set dbl to {a}     repeat while (n > 1)        if (n mod 2) > 0 then set out to out & dbl        set n to (n div 2)        set dbl to (dbl & dbl)    end repeat    return out & dblend replicate -- showRatio :: Ratio -> Stringon showRatio(r)    (n of r as string) & "/" & (d of r as string)end showRatio -- signum :: Num -> Numon signum(x)    if x < 0 then        -1    else if x = 0 then        0    else        1    end ifend signum -- splitOn :: String -> String -> [String]on splitOn(pat, src)    set {dlm, my text item delimiters} to ¬        {my text item delimiters, pat}    set xs to text items of src    set my text item delimiters to dlm    return xsend splitOn -- take :: Int -> [a] -> [a]-- take :: Int -> String -> Stringon take(n, xs)    set c to class of xs    if list is c then        if 0 < n then            items 1 thru min(n, length of xs) of xs        else            {}        end if    else if string is c then        if 0 < n then            text 1 thru min(n, length of xs) of xs        else            ""        end if    else if script is c then        set ys to {}        repeat with i from 1 to n            set v to xs's |λ|()            if missing value is v then                return ys            else                set end of ys to v            end if        end repeat        return ys    else        missing value    end ifend take -- unlines :: [String] -> Stringon unlines(xs)    set {dlm, my text item delimiters} to ¬        {my text item delimiters, linefeed}    set str to xs as text    set my text item delimiters to dlm    strend unlines -- zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]on zipWith3(f, xs, ys, zs)    set lng to minimum({length of xs, length of ys, length of zs})    if 1 > lng then return {}    set lst to {}    tell mReturn(f)        repeat with i from 1 to lng            set end of lst to |λ|(item i of xs, item i of ys, item i of zs)        end repeat        return lst    end tellend zipWith3
Output:
 0   ->   -1.0   =   -1/1
1   ->   -0.9   =   -9/10
2   ->   -0.8   =   -4/5
3   ->   -0.7   =   -7/10
4   ->   -0.6   =   -3/5
5   ->   -0.5   =   -1/2
6   ->   -0.4   =   -2/5
7   ->   -0.3   =   -3/10
8   ->   -0.2   =   -1/5
9   ->   -0.1   =   -1/10
10   ->    0.0   =    0/1

## AutoHotkey

Translation of: C
 mapRange(a1, a2, b1, b2, s){	return b1 + (s-a1)*(b2-b1)/(a2-a1)} out := "Mapping [0,10] to [-1,0] at intervals of 1:n" Loop 11	out .= "f(" A_Index-1 ") = " mapRange(0,10,-1,0,A_Index-1) "n"MsgBox % out

## Axiom

Axiom provides a Segment domain for intervals. The following uses a closure for a mapRange function over fields, which provides for some generality.

)abbrev package TESTP TestPackageTestPackage(R:Field) : with    mapRange: (Segment(R), Segment(R)) -> (R->R)   == add    mapRange(fromRange, toRange) ==       (a1,a2,b1,b2) := (lo fromRange,hi fromRange,lo toRange,hi toRange)      (x:R):R +-> b1+(x-a1)*(b2-b1)/(a2-a1)
Use:
f := mapRange(1..10,a..b)  [(xi,f xi) for xi in 1..10]
Output:
              b + 8a      2b + 7a      b + 2a      4b + 5a      5b + 4a
[(1,a), (2,------), (3,-------), (4,------), (5,-------), (6,-------),
9           9            3           9            9
2b + a      7b + 2a      8b + a
(7,------), (8,-------), (9,------), (10,b)]
3           9            9
Type: List(Tuple(Fraction(Polynomial(Integer))))

## AWK

 # syntax: GAWK -f MAP_RANGE.AWKBEGIN {    a1 = 0    a2 = 10    b1 = -1    b2 = 0    for (i=a1; i<=a2; i++) {      printf("%g maps to %g\n",i,map_range(a1,a2,b1,b2,i))    }    exit(0)}function map_range(a1,a2,b1,b2,num) {    return b1 + ((num-a1) * (b2-b1) / (a2-a1))}
Output:
0 maps to -1
1 maps to -0.9
2 maps to -0.8
3 maps to -0.7
4 maps to -0.6
5 maps to -0.5
6 maps to -0.4
7 maps to -0.3
8 maps to -0.2
9 maps to -0.1
10 maps to 0


## BASIC

### BBC BASIC

      @% = 5 : REM Column width      DIM range{l, h}      DIM A{} = range{}, B{} = range{}      A.l = 0 : A.h = 10      B.l = -1 : B.h = 0      FOR n = 0 TO 10        PRINT n " maps to " FNmaprange(A{}, B{}, n)      NEXT      END       DEF FNmaprange(a{}, b{}, s)      = b.l + (s - a.l) * (b.h - b.l) / (a.h - a.l)
Output:
    0 maps to    -1
1 maps to  -0.9
2 maps to  -0.8
3 maps to  -0.7
4 maps to  -0.6
5 maps to  -0.5
6 maps to  -0.4
7 maps to  -0.3
8 maps to  -0.2
9 maps to  -0.1
10 maps to     0


### Commodore BASIC

10 REM MAP RANGE20 REM COMMODORE BASIC 2.030 REM ================================40 A1 = 0 : A2 = 1050 B1 = -1 : B2 = 060 DEF FN MR(S)=B1+(S-A1)*(B2-B1)/(A2-A1)70 FOR S=0 TO 1080   PRINT S;"MAPS TO ";FN MR(S)90 NEXT
Output:
 0 MAPS TO -1
1 MAPS TO -.9
2 MAPS TO -.8
3 MAPS TO -.7
4 MAPS TO -.6
5 MAPS TO -.5
6 MAPS TO -.4
7 MAPS TO -.3
8 MAPS TO -.2
9 MAPS TO -.1
10 MAPS TO  0


### IS-BASIC

100 PROGRAM "MapRange.bas"110 LET A1=0:LET A2=10120 LET B1=-1:LET B2=0130 DEF MR(S)=B1+(S-A1)*(B2-B1)/(A2-A1)140 FOR I=0 TO 10150   PRINT I;"maps to ";MR(I)160 NEXT

## bc

/* map s from [a, b] to [c, d] */define m(a, b, c, d, s) {	return (c + (s - a) * (d - c) / (b - a))} scale = 6  /* division to 6 decimal places */"[0, 10] => [-1, 0]"for (i = 0; i <= 10; i += 2) {	/*         * If your bc(1) has a print statement, you can try	 * print i, " => ", m(0, 10, -1, 0, i), "\n"	 */	i; "   => "; m(0, 10, -1, 0, i)}quit
Output:
[0, 10] => [-1, 0]
0
=> -1.000000
2
=> -.800000
4
=> -.600000
6
=> -.400000
8
=> -.200000
10
=> 0.000000

## Bracmat

Translation of: C
( ( mapRange  =   a1,a2,b1,b2,s    .   !arg:(?a1,?a2.?b1,?b2.?s)      & !b1+(!s+-1*!a1)*(!b2+-1*!b1)*(!a2+-1*!a1)^-1  )& out$"Mapping [0,10] to [-1,0] at intervals of 1:"& 0:?n& whl ' ( !n:~>10 & out$("f(" !n ") = " flt$(mapRange$(0,10.-1,0.!n),2))    & 1+!n:?n    ));
Output:
Mapping [0,10] to [-1,0] at intervals of 1:
f( 0 ) =  -1,00*10E0
f( 1 ) =  -9,00*10E-1
f( 2 ) =  -8,00*10E-1
f( 3 ) =  -7,00*10E-1
f( 4 ) =  -6,00*10E-1
f( 5 ) =  -5,00*10E-1
f( 6 ) =  -4,00*10E-1
f( 7 ) =  -3,00*10E-1
f( 8 ) =  -2,00*10E-1
f( 9 ) =  -1,00*10E-1
f( 10 ) =  0

## C

#include <stdio.h> double mapRange(double a1,double a2,double b1,double b2,double s){	return b1 + (s-a1)*(b2-b1)/(a2-a1);} int main(){	int i;	puts("Mapping [0,10] to [-1,0] at intervals of 1:"); 	for(i=0;i<=10;i++)	{		printf("f(%d) = %g\n",i,mapRange(0,10,-1,0,i));	} 	return 0;}
Output:
Mapping [0,10] to [-1,0] at intervals of 1:
f(0) = -1
f(1) = -0.9
f(2) = -0.8
f(3) = -0.7
f(4) = -0.6
f(5) = -0.5
f(6) = -0.4
f(7) = -0.3
f(8) = -0.2
f(9) = -0.1
f(10) = 0

## Nemerle

using System;using System.Console; module Maprange{    Maprange(a : double * double, b : double * double, s : double) : double    {        def (a1, a2) = a; def (b1, b2) = b;         b1 + (((s - a1) * (b2 - b1))/(a2 - a1))    }     Main() : void    {        foreach (i in [0 .. 10])             WriteLine("{0, 2:f0} maps to {1:f1}", i, Maprange((0.0, 10.0), (-1.0, 0.0), i));    }}

## NetRexx

/* NetRexx */options replace format comments java crossref savelog symbols nobinary A    = [  0.0, 10.0 ]B    = [ -1.0,  0.0 ]incr = 1.0 say 'Mapping ['A[0]',' A[1]'] to ['B[0]',' B[1]'] in increments of' incr':'loop sVal = A[0] to A[1] by incr  say '  f('sVal.format(3, 3)') ='  mapRange(A, B, sVal).format(4, 3)  end sVal return method mapRange(a = Rexx[], b = Rexx[], s_) public static  return mapRange(a[0], a[1], b[0], b[1], s_) method mapRange(a1, a2, b1, b2, s_) public static  t_ = b1 + ((s_ - a1) * (b2 - b1) / (a2 - a1))  return t_
Output:
Mapping [0.0, 10.0] to [-1.0, 0.0] in increments of 1.0:
f(  0.000) =   -1.000
f(  1.000) =   -0.900
f(  2.000) =   -0.800
f(  3.000) =   -0.700
f(  4.000) =   -0.600
f(  5.000) =   -0.500
f(  6.000) =   -0.400
f(  7.000) =   -0.300
f(  8.000) =   -0.200
f(  9.000) =   -0.100
f( 10.000) =    0.000


## Nim

Translation of: Python
import strutils type FloatRange = tuple[s,e: float] proc mapRange(a,b: FloatRange, s): float =  b.s + (s - a.s) * (b.e - b.s) / (a.e - a.s) for i in 0..10:  let m = mapRange((0.0,10.0), (-1.0, 0.0), float(i))  echo i, " maps to ", formatFloat(m, precision = 0)
Output:
0 maps to -1
1 maps to -0.9
2 maps to -0.8
3 maps to -0.7
4 maps to -0.6
5 maps to -0.5
6 maps to -0.4
7 maps to -0.3
8 maps to -0.2
9 maps to -0.1
10 maps to 0

## Objeck

 bundle Default {  class Range {    function : MapRange(a1:Float, a2:Float, b1:Float, b2:Float, s:Float) ~ Float {      return b1 + (s-a1)*(b2-b1)/(a2-a1);    }     function : Main(args : String[]) ~ Nil {      "Mapping [0,10] to [-1,0] at intervals of 1:"->PrintLine();      for(i := 0.0; i <= 10.0; i += 1;) {        IO.Console->Print("f(")->Print(i->As(Int))->Print(") = ")->PrintLine(MapRange(0.0, 10.0, -1.0, 0.0, i));      };    }  }}
Output:
Mapping [0,10] to [-1,0] at intervals of 1:
f(0) = -1
f(1) = -0.9
f(2) = -0.8
f(3) = -0.7
f(4) = -0.6
f(5) = -0.5
f(6) = -0.4
f(7) = -0.3
f(8) = -0.2
f(9) = -0.1
f(10) = 0


## OCaml

let map_range (a1, a2) (b1, b2) s =  b1 +. ((s -. a1) *. (b2 -. b1) /. (a2 -. a1)) let () =  print_endline "Mapping [0,10] to [-1,0] at intervals of 1:";  for i = 0 to 10 do    Printf.printf "f(%d) = %g\n" i (map_range (0.0, 10.0) (-1.0, 0.0) (float i))  done
Output:
Mapping [0,10] to [-1,0] at intervals of 1:
f(0) = -1
f(1) = -0.9
f(2) = -0.8
f(3) = -0.7
f(4) = -0.6
f(5) = -0.5
f(6) = -0.4
f(7) = -0.3
f(8) = -0.2
f(9) = -0.1
f(10) = 0

If range mapping is used in a heavy computational task we can reduce the number of calculations made using partial application and currying:

let map_range (a1, a2) (b1, b2) =  let v = (b2 -. b1) /. (a2 -. a1) in  function s ->    b1 +. ((s -. a1) *. v) let () =  print_endline "Mapping [0,10] to [-1,0] at intervals of 1:";  let p = (map_range (0.0, 10.0) (-1.0, 0.0)) in  for i = 0 to 10 do    Printf.printf "f(%d) = %g\n" i (p (float i))  done

## Oforth

: mapRange(p1, p2, s)    s p1 first - p2 second p2 first - * p1 second p1 first - asFloat /    p2 first + ;
Output:
Interval newFromToStep(0, 10, 0.5) map(#[ mapRange([0, 10], [ -1, 0 ])]) println
[-1, -0.95, -0.9, -0.85, -0.8, -0.75, -0.7, -0.65, -0.6, -0.55, -0.5, -0.45, -0.4, -0.35,
-0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0]


## PARI/GP

Usage (e.g.): map([1,10],[0,5],8.)

map(r1,r2,x)=r2[1]+(x-r1[1])*(r2[2]-r2[1])/(r1[2]-r1[1])

## Pascal

Program Map(output); function MapRange(fromRange, toRange: array of real; value: real): real;  begin    MapRange := (value-fromRange[0]) * (toRange[1]-toRange[0]) / (fromRange[1]-fromRange[0]) + toRange[0];  end; var  i: integer;begin  for i := 0 to 10 do    writeln (i, ' maps to: ', MapRange([0.0, 10.0], [-1.0, 0.0], i):4:2);end.
Output:
:> ./MapRange
0 maps to: -1.00
1 maps to: -0.90
2 maps to: -0.80
3 maps to: -0.70
4 maps to: -0.60
5 maps to: -0.50
6 maps to: -0.40
7 maps to: -0.30
8 maps to: -0.20
9 maps to: -0.10
10 maps to: 0.00


### improvement doing many calculations

Tested with freepascal_32 2.6.4 .Pushing all data over the stack takes quite a long time. Precaltulating the scalefactor helps too.

Time relation doing 1E7 calculations

Org/ const / tMr

double  : 267/177/107 .. 25/16/10

extended: 363/193/123 .. 30/15/10

Output as above.

Program Map(output); type  real = double;  tRange = Array [0..1] of real;  tMapRec = record              mrFrom,              mrTo : tRange;              mrScale : real            end; function InitRange(rfrom,rTo:real):tRange;begin  InitRange[0] :=rfrom;  InitRange[1] :=rTo;end; function InitMapRec(const fromRange, toRange: tRange):tMapRec;begin  With InitMapRec do  Begin    mrFrom := fromRange;    mrTo   := toRange;    mrScale := (toRange[1]-toRange[0]) / (fromRange[1]-fromRange[0]);  end;end; function MapRecRange(const value: real;var MR :tMapRec): real;begin  with MR do    MapRecRange := (value-mrFrom[0]) * mrScale + mrTo[0];end; function MapRange(const value: real;const fromRange, toRange: tRange): real;begin  MapRange := (value-fromRange[0]) * (toRange[1]-toRange[0]) / (fromRange[1]-fromRange[0]) + toRange[0];end; var  value:real;  rFrom,rTo : tRange;  mr : tMapRec;  i: LongInt; begin  rFrom:= InitRange(  0, 10);  rTo  := InitRange( -1,  0);  mr:= InitMapRec(rFrom,rTo);   for i := 0 to 10 do  Begin    value := i;    writeln (i:4, ' maps to: ', MapRange(value,rFrom, rTo):10:6,                                  MapRecRange(value,mr):10:6);  end;end.

## Perl

#!/usr/bin/perl -wuse strict ; sub mapValue {   my ( $range1 ,$range2 , $number ) = @_ ; return ($range2->[ 0 ] +      (( $number -$range1->[ 0 ] ) * ( $range2->[ 1 ] -$range2->[ 0 ] ) ) / ( $range1->[ -1 ] -$range1->[ 0 ] ) ) ;}my @numbers = 0..10 ;my @interval = ( -1 , 0 ) ;print "The mapped value for $_ is " . mapValue( \@numbers , \@interval ,$_ ) . " !\n" foreach @numbers ;
Output:
The mapped value for 0 is -1 !
The mapped value for 1 is -0.9 !
The mapped value for 2 is -0.8 !
The mapped value for 3 is -0.7 !
The mapped value for 4 is -0.6 !
The mapped value for 5 is -0.5 !
The mapped value for 6 is -0.4 !
The mapped value for 7 is -0.3 !
The mapped value for 8 is -0.2 !
The mapped value for 9 is -0.1 !
The mapped value for 10 is 0 !


## Perl 6

Works with: rakudo version 2015-09-18
sub the_function(Range $a, Range$b, $s) { my ($a1, $a2) =$a.bounds;  my ($b1,$b2) = $b.bounds; return$b1 + (($s-$a1) * ($b2-$b1) / ($a2-$a1));} for ^11 -> $x { say "$x maps to {the_function(0..10, -1..0, $x)}" } %perl6 map_range.p6 0 maps to -1 1 maps to -0.9 2 maps to -0.8 3 maps to -0.7 4 maps to -0.6 5 maps to -0.5 6 maps to -0.4 7 maps to -0.3 8 maps to -0.2 9 maps to -0.1 10 maps to 0 A more idiomatic way would be to return a closure that does the mapping without have to supply the ranges every time: sub getmapper(Range$a, Range  $b) { my ($a1, $a2) =$a.bounds;  my ($b1,$b2) = $b.bounds; return ->$s { $b1 + (($s-$a1) * ($b2-$b1) / ($a2-$a1)) }} my &mapper = getmapper(0 .. 10, -1 .. 0);for ^11 ->$x {say "$x maps to &mapper($x)"}

## Phix

function MapRange(atom s, a1, a2, b1, b2)    return b1+(s-a1)*(b2-b1)/(a2-a1)end function for i=0 to 10 by 2 do    printf(1,"%2d : %g\n",{i,MapRange(i,0,10,-1,0)})end for
Output:
 0 : -1
2 : -0.8
4 : -0.6
6 : -0.4
8 : -0.2
10 : 0


## PicoLisp

(scl 1) (de mapRange (Val A1 A2 B1 B2)   (+ B1 (*/ (- Val A1) (- B2 B1) (- A2 A1))) )  (for Val (range 0 10.0 1.0)   (prinl      (format (mapRange Val 0 10.0 -1.0 0) *Scl) ) )
Output:
-1.0
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.1
0.0

## PL/I

 map: procedure options (main); /* 24/11/2011 */   declare (a1, a2, b1, b2) float;   declare d fixed decimal (3,1);    do d = 0 to 10 by 0.9, 10;      put skip edit ( d, ' maps to ', map(0, 10, -1, 0, d) ) (f(5,1), a, f(10,6));   end; map: procedure (a1, a2, b1, b2, s) returns (float);   declare (a1, a2, b1, b2, s) float;   return (b1 + (s - a1)*(b2 - b1) / (a2 - a1) );end map;end map;
Output:
  0.0 maps to  -1.000000
0.9 maps to  -0.910000
1.8 maps to  -0.820000
2.7 maps to  -0.730000
3.6 maps to  -0.640000
4.5 maps to  -0.550000
5.4 maps to  -0.460000
6.3 maps to  -0.370000
7.2 maps to  -0.280000
8.1 maps to  -0.190000
9.0 maps to  -0.100000
9.9 maps to  -0.010000
10.0 maps to   0.000000

## PowerShell

 function Group-Range{    [CmdletBinding()]    [OutputType([PSCustomObject])]    Param    (        [Parameter(Mandatory=$true, Position=0)] [ValidateCount(2,2)] [double[]]$Range1,         [Parameter(Mandatory=$true, Position=1)] [ValidateCount(2,2)] [double[]]$Range2,         [Parameter(Mandatory=$true, ValueFromPipeline=$true,                   Position=2)]        [double]        $Map ) Process { foreach ($number in $Map) { [PSCustomObject]@{ Index =$number                Mapping = $Range2[0] + ($number - $Range1[0]) * ($Range2[0] - $Range2[1]) / ($Range1[0] - Range1[1]) } } }}   0..10 | Group-Range (0,10) (-1,0)  Output: Index Mapping ----- ------- 0 -1 1 -0.9 2 -0.8 3 -0.7 4 -0.6 5 -0.5 6 -0.4 7 -0.3 8 -0.2 9 -0.1 10 0  ## PureBasic Structure RR a.f b.fEndStructure Procedure.f MapRange(*a.RR, *b.RR, s) Protected.f a1, a2, b1, b2 a1=*a\a: a2=*a\b b1=*b\a: b2=*b\b ProcedureReturn b1 + ((s - a1) * (b2 - b1) / (a2 - a1))EndProcedure ;- Test the functionIf OpenConsole() Define.RR Range1, Range2 Range1\a=0: Range1\b=10 Range2\a=-1:Range2\b=0 ; For i=0 To 10 PrintN(RSet(Str(i),2)+" maps to "+StrF(MapRange(@Range1, @Range2, i),1)) NextEndIf  0 maps to -1.0 1 maps to -0.9 2 maps to -0.8 3 maps to -0.7 4 maps to -0.6 5 maps to -0.5 6 maps to -0.4 7 maps to -0.3 8 maps to -0.2 9 maps to -0.1 10 maps to 0.0 ## Python >>> def maprange( a, b, s): (a1, a2), (b1, b2) = a, b return b1 + ((s - a1) * (b2 - b1) / (a2 - a1)) >>> for s in range(11): print("%2g maps to %g" % (s, maprange( (0, 10), (-1, 0), s))) 0 maps to -1 1 maps to -0.9 2 maps to -0.8 3 maps to -0.7 4 maps to -0.6 5 maps to -0.5 6 maps to -0.4 7 maps to -0.3 8 maps to -0.2 9 maps to -0.110 maps to 0 Because of Pythons strict, dynamic, typing rules for numbers the same function can give answers as fractions: >>> from fractions import Fraction>>> for s in range(11): print("%2g maps to %s" % (s, maprange( (0, 10), (-1, 0), Fraction(s)))) 0 maps to -1 1 maps to -9/10 2 maps to -4/5 3 maps to -7/10 4 maps to -3/5 5 maps to -1/2 6 maps to -2/5 7 maps to -3/10 8 maps to -1/5 9 maps to -1/1010 maps to 0>>>  ## Racket  #lang racket (define (make-range-map a1 a2 b1 b2) ;; returns a mapping function, doing computing the differences in ;; advance so it's fast (let ([a (- a2 a1)] [b (- b2 b1)]) (λ(s) (exact->inexact (+ b1 (/ (* (- s a1) b) a)))))) (define map (make-range-map 0 10 -1 0))(for ([i (in-range 0 11)]) (printf "~a --> ~a\n" i (map i)))  Output: 0 --> -1.0 1 --> -0.9 2 --> -0.8 3 --> -0.7 4 --> -0.6 5 --> -0.5 6 --> -0.4 7 --> -0.3 8 --> -0.2 9 --> -0.1 10 --> 0.0  ## REXX (The first three REXX versions don't differ idiomatically that much, but differ mostly just in style.) The first three versions support different increments (the inc variable) and an A range that is decreasing in values (that is, the 2nd number [usually the high] in the range is less than the first number in the range [usually the low]). Also, the BY (increment) is automatically adjusted (either upwards or downwards). Also, both sets of numbers in the output are aligned (vertically). ### version 1 /*REXX program maps and displays a range of numbers from one range to another range.*/rangeA = 0 10 /*or: rangeA = ' 0 10 ' */rangeB = -1 0 /*or: rangeB = " -1 0 " */parse var rangeA L Hinc= 1 do j=L to H by inc * (1 - 2 * sign(H<L) ) /*BY: either +inc or -inc */ say right(j, 9) ' maps to ' mapR(rangeA, rangeB, j) end /*j*/exit /*stick a fork in it, we're done.*//*──────────────────────────────────────────────────────────────────────────────────────*/mapR: procedure; parse arg a1 a2,b1 b2,s;=b1+(s-a1)*(b2-b1)/(a2-a1);return left('',$>=0)$
output:
        0  maps to  -1
1  maps to  -0.9
2  maps to  -0.8
3  maps to  -0.7
4  maps to  -0.6
5  maps to  -0.5
6  maps to  -0.4
7  maps to  -0.3
8  maps to  -0.2
9  maps to  -0.1
10  maps to   0


### version 2

This version demonstrates an increment (inc) of   1/2   instead of the usual unity.

Note that this REXX version also uses a different   rangeA   numbers   (they are reversed).

/*REXX program maps and displays a  range of numbers from  one range  to  another range.*/rangeA =  10   0                                       /*or:   rangeA =   '  0  10 '    */rangeB =  -1   0                                       /*or:   rangeB =   " -1   0 "    */parse  var   rangeA  L  Hinc= 1/2          do j=L  to H  by inc * (1 - 2 * sign(H<L) )  /*BY:   either   +inc  or  -inc  */          say right(j, 9)      ' maps to '      mapR(rangeA, rangeB, j)          end   /*j*/exit                                                   /*stick a fork in it, we're done.*//*──────────────────────────────────────────────────────────────────────────────────────*/mapR: procedure; parse arg a1 a2,b1 b2,s;$=b1+(s-a1)*(b2-b1)/(a2-a1);return left('',$>=0) output:  0 maps to 0 0.5 maps to -0.05 1.0 maps to -0.1 1.5 maps to -0.15 2.0 maps to -0.2 2.5 maps to -0.25 3.0 maps to -0.3 3.5 maps to -0.35 4.0 maps to -0.4 4.5 maps to -0.45 5.0 maps to -0.5 5.5 maps to -0.55 6.0 maps to -0.6 6.5 maps to -0.65 7.0 maps to -0.7 7.5 maps to -0.75 8.0 maps to -0.8 8.5 maps to -0.85 9.0 maps to -0.9 9.5 maps to -0.95 10.0 maps to -1  ### version 3 This REXX version used a function that calculates and also displays the range mapping. /*REXX program maps and displays a range of numbers from one range to another range.*/rangeA = 0 10rangeB = -1 0inc = 1call mapR rangeA, rangeB, incexit /*stick a fork in it, we're all done. *//*──────────────────────────────────────────────────────────────────────────────────────*/mapR: procedure; parse arg a1 a2, b1 b2, inc /* [↓] BY is either +inc or -inc.*/ do s=a1 to a2 by inc * (1 - 2 * sign(a2 < a1) ) t= b1 + (s-a1) * (b2-b1) / (a2-a1) say right(s, 9) ' maps to' left('', t>=0) t end /*s*/ return /* [↑] LEFT··· aligns non─negative #'s*/ output is identical to the 1st REXX version. ### Version 4 /*REXX program maps a number from one range to another range. *//* 31.10.2013 Walter Pachl *//* 'translated' from an older version 1 without using Procedure */ do j=0 to 10 say right(j,3) ' maps to ' mapRange(0,10,-1,0,j) endexit /*──────────────────────────────────MAPRANGE subroutine─────────────────*/mapRange: return arg(3)+(arg(5)-arg(1))*(arg(4)-arg(3))/(arg(2)-arg(1))/* Arguments are arg a1,a2,b1,b2,x */ Output:  0 maps to -1 1 maps to -0.9 2 maps to -0.8 3 maps to -0.7 4 maps to -0.6 5 maps to -0.5 6 maps to -0.4 7 maps to -0.3 8 maps to -0.2 9 maps to -0.1 10 maps to 0  ## Ring  # Project : Map range decimals(1)al = 0 ah = 10bl = -1 bh = 0for n = 0 to 10 see "" + n + " maps to " + maprange(al, bl, n) + nlnext func maprange(al, bl, s) return bl + (s - al) * (bh - bl) / (ah - al)  Output: 0 maps to -1 1 maps to -0.9 2 maps to -0.8 3 maps to -0.7 4 maps to -0.6 5 maps to -0.5 6 maps to -0.4 7 maps to -0.3 8 maps to -0.2 9 maps to -0.1 10 maps to 0  ## Ruby def map_range(a, b, s) af, al, bf, bl = a.first, a.last, b.first, b.last bf + (s - af)*(bl - bf).quo(al - af)end (0..10).each{|s| puts "%s maps to %g" % [s, map_range(0..10, -1..0, s)]} Numeric#quo does floating point division. Output: 0 maps to -1 1 maps to -0.9 2 maps to -0.8 3 maps to -0.7 4 maps to -0.6 5 maps to -0.5 6 maps to -0.4 7 maps to -0.3 8 maps to -0.2 9 maps to -0.1 10 maps to 0  To use rational arithmetic, delete s *= 1.0 and either require 'rational', or use Ruby 1.9 (which has Rational in the core library). (0..10).each do |s| puts "%s maps to %s" % [s, map_range(0..10, -1..0, s)]end Output: using rational arithmetic: 0 maps to -1/1 1 maps to -9/10 2 maps to -4/5 3 maps to -7/10 4 maps to -3/5 5 maps to -1/2 6 maps to -2/5 7 maps to -3/10 8 maps to -1/5 9 maps to -1/10 10 maps to 0/1  ## Rust use std::f64; fn map_range(from_range: (f64, f64), to_range: (f64, f64), s: f64) -> f64 { to_range.0 + (s - from_range.0) * (to_range.1 - to_range.0) / (from_range.1 - from_range.0)} fn main() { let input: Vec<f64> = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]; let result = input.into_iter() .map(|x| map_range((0.0, 10.0), (-1.0, 0.0), x)) .collect::<Vec<f64>>(); print!("{:?}", result);} Output: [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0]  ## Scala def mapRange(a1:Double, a2:Double, b1:Double, b2:Double, x:Double):Double=b1+(x-a1)*(b2-b1)/(a2-a1) for(i <- 0 to 10) println("%2d in [0, 10] maps to %5.2f in [-1, 0]".format(i, mapRange(0,10, -1,0, i))) Output:  0 in [0, 10] maps to -1,00 in [-1, 0] 1 in [0, 10] maps to -0,90 in [-1, 0] 2 in [0, 10] maps to -0,80 in [-1, 0] 3 in [0, 10] maps to -0,70 in [-1, 0] 4 in [0, 10] maps to -0,60 in [-1, 0] 5 in [0, 10] maps to -0,50 in [-1, 0] 6 in [0, 10] maps to -0,40 in [-1, 0] 7 in [0, 10] maps to -0,30 in [-1, 0] 8 in [0, 10] maps to -0,20 in [-1, 0] 9 in [0, 10] maps to -0,10 in [-1, 0] 10 in [0, 10] maps to 0,00 in [-1, 0] ## Seed7  include "seed7_05.s7i";  include "float.s7i"; const func float: mapRange (in float: a1, in float: a2, in float: b1, in float: b2, ref float: s) is    return b1 + (s-a1)*(b2-b1)/(a2-a1); const proc: main is func  local    var integer: number is 0;  begin    writeln("Mapping [0,10] to [-1,0] at intervals of 1:");    for number range 0 to 10 do      writeln("f(" <& number <& ") = " <& mapRange(0.0, 10.0, -1.0, 0.0, flt(number)) digits 1);    end for;  end func;
Output:
Mapping [0,10] to [-1,0] at intervals of 1:
f(0) = -1.0
f(1) = -0.9
f(2) = -0.8
f(3) = -0.7
f(4) = -0.6
f(5) = -0.5
f(6) = -0.4
f(7) = -0.3
f(8) = -0.2
f(9) = -0.1
f(10) = 0.0


## Sidef

func map_range(a, b, x) {    var (a1, a2, b1, b2) = (a.bounds, b.bounds);    x-a1 * b2-b1 / a2-a1 + b1;} var a = 0..10;var b = -1..0; for x in a {    say "#{x} maps to #{map_range(a, b, x)}";}
Output:
0 maps to -1
1 maps to -0.9
2 maps to -0.8
3 maps to -0.7
4 maps to -0.6
5 maps to -0.5
6 maps to -0.4
7 maps to -0.3
8 maps to -0.2
9 maps to -0.1
10 maps to 0

## Stata

The following program will map a variable to a new variable. It accepts if and in conditions.

program define maprange	version 15.1	syntax varname(numeric) [if] [in], ///		from(numlist min=2 max=2) to(numlist min=2 max=2) ///		GENerate(name) [REPLACE]	tempname a b c d h	sca a'=:word 1 of from''	sca b'=:word 2 of from''	sca c'=:word 1 of to''	sca d'=:word 2 of to''	sca h'=(d'-c')/(b'-a')	cap confirm variable generate'	if "replace'"=="replace" & !_rc {		qui replace generate'=(varlist'-a')*h'+c' if' in'	}	else {		if "replace'"=="replace" {			di in gr "(note: variable generate' not found)"'		}		qui gen generate'=(varlist'-a')*h'+c' if' in'	}end

Example

clearset obs 11gen x=_n-1maprange x if mod(x,2)==0, gen(y) from(0 10) to(-10 10)maprange x if mod(x,2)!=0, gen(y) from(0 10) to(-100 100) replacelist

Output

     +----------+
|  x     y |
|----------|
1. |  0   -10 |
2. |  1   -80 |
3. |  2    -6 |
4. |  3   -40 |
5. |  4    -2 |
|----------|
6. |  5     0 |
7. |  6     2 |
8. |  7    40 |
9. |  8     6 |
10. |  9    80 |
|----------|
11. | 10    10 |
+----------+

## Swift

import Foundation func mapRanges(_ r1: ClosedRange<Double>, _ r2: ClosedRange<Double>, to: Double) -> Double {  let num = (to - r1.lowerBound) * (r2.upperBound - r2.lowerBound)  let denom = r1.upperBound - r1.lowerBound   return r2.lowerBound + num / denom} for i in 0...10 {  print(String(format: "%2d maps to %5.2f", i, mapRanges(0...10, -1...0, to: Double(i))))}
Output:
 0 maps to -1.00
1 maps to -0.90
2 maps to -0.80
3 maps to -0.70
4 maps to -0.60
5 maps to -0.50
6 maps to -0.40
7 maps to -0.30
8 maps to -0.20
9 maps to -0.10
10 maps to  0.00

## Tcl

package require Tcl 8.5proc rangemap {rangeA rangeB value} {    lassign $rangeA a1 a2 lassign$rangeB b1 b2    expr {$b1 + ($value - $a1)*double($b2 - $b1)/($a2 - $a1)}} Demonstration (using a curried alias to bind the ranges mapped from and to): interp alias {} demomap {} rangemap {0 10} {-1 0}for {set i 0} {$i <= 10} {incr i} {    puts [format "%2d -> %5.2f" $i [demomap$i]]}
Output:
 0 -> -1.00
1 -> -0.90
2 -> -0.80
3 -> -0.70
4 -> -0.60
5 -> -0.50
6 -> -0.40
7 -> -0.30
8 -> -0.20
9 -> -0.10
10 ->  0.00


## Ursala

The function f is defined using pattern matching and substitution, taking a pair of pairs of interval endpoints and a number as parameters, and returning a number.

#import flo f((("a1","a2"),("b1","b2")),"s") = plus("b1",div(minus("s","a1"),minus("a2","a1"))) #cast %eL test = f* ((0.,10.),(-1.,0.))-* ari11/0. 10.
Output:
<
-1.000000e+00,
-9.000000e-01,
-8.000000e-01,
-7.000000e-01,
-6.000000e-01,
-5.000000e-01,
-4.000000e-01,
-3.000000e-01,
-2.000000e-01,
-1.000000e-01,
0.000000e+00>

A more idiomatic way is to define f as a second order function

f(("a1","a2"),("b1","b2")) "s" = ...

with the same right hand side as above, so that it takes a pair of intervals and returns a function mapping numbers in one interval to numbers in the other.

An even more idiomatic way is to use the standard library function plin, which takes an arbitrarily long list of interval endpoints and returns a piecewise linear interpolation function.

## WDTE

let mapRange r1 r2 s =>    +        (at r2 0)        (/            (*                (-                    s                    (at r1 0)                )                (-                    (at r2 1)                    (at r2 0)                )            )            (-                (at r1 1)                (at r1 0)            )        )    ; let s => import 'stream';let str => import 'strings'; s.range 10-> s.map (@ enum v => [v; mapRange [0; 10] [-1; 0] v])-> s.map (@ print v => str.format '{} -> {}' (at v 0) (at v 1) -- io.writeln io.stdout)-> s.drain;
Output:
0 -> -1
1 -> -0.9
2 -> -0.8
3 -> -0.7
4 -> -0.6
5 -> -0.5
6 -> -0.4
7 -> -0.3
8 -> -0.2
9 -> -0.1

## XPL0

include c:\cxpl\codes; func real Map(A1, A2, B1, B2, S);real A1, A2, B1, B2, S;return B1 + (S-A1)*(B2-B1)/(A2-A1); int I;[for I:= 0 to 10 do    [if I<10 then ChOut(0, ^ );  IntOut(0, I);    RlOut(0, Map(0., 10., -1., 0., float(I)));    CrLf(0);    ];]
Output:
 0   -1.00000
1   -0.90000
2   -0.80000
3   -0.70000
4   -0.60000
5   -0.50000
6   -0.40000
7   -0.30000
8   -0.20000
9   -0.10000
10    0.00000


## Yabasic

sub MapRange(s, a1, a2, b1, b2)    return b1+(s-a1)*(b2-b1)/(a2-a1)end sub for i = 0 to 10 step 2    print i, " : ", MapRange(i,0,10,-1,0)next

## zkl

fcn mapRange([(a1,a2)], [(b1,b2)], s) // a1a2 is List(a1,a2)   { b1 + ((s - a1) * (b2 - b1) / (a2 - a1)) } r1:=T(0.0, 10.0); r2:=T(-1.0, 0.0);foreach s in ([0.0 .. 10]){   "%2d maps to %5.2f".fmt(s,mapRange(r1,r2, s)).println();}
Output:
 0 maps to -1.00
1 maps to -0.90
2 maps to -0.80
3 maps to -0.70
4 maps to -0.60
5 maps to -0.50
6 maps to -0.40
7 maps to -0.30
8 maps to -0.20
9 maps to -0.10
10 maps to  0.00