Map range

From Rosetta Code
Revision as of 21:42, 5 March 2012 by Mark Clements (talk | contribs) (Re-add Axiom task)
Task
Map range
You are encouraged to solve this task according to the task description, using any language you may know.

Given two ranges, and ; then a value in range is linearly mapped to a value in range when:

The task is to 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.


Ada

<lang Ada>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;</lang>

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

AutoHotkey

Translation of: C

<lang AutoHotkey> 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 </lang>

Axiom

Axiom provides a Segment domain for intervals. The following uses a closure for a mapRange function over fields, which provides for some generality. <lang Axiom>)abbrev package TESTP TestPackage TestPackage(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)</lang>

Use:<lang Axiom>f := mapRange(1..10,a..b) [(xi,f xi) for xi in 1..10]</lang> Output:<lang Axiom> 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))))</lang>

bc

<lang 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</lang>

Output:

[0, 10] => [-1, 0]
0
   => -1.000000
2
   => -.800000
4
   => -.600000
6
   => -.400000
8
   => -.200000
10
   => 0.000000

Bracmat

Translation of: C

<lang bracmat>( ( 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
   )

);</lang> 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

<lang 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; } </lang>

The output is :

<lang>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</lang>

C++

This example defines a template function to handle the mapping, using two std::pair objects to define the source and destination ranges. It returns the provided value mapped into the target range.

It's not written efficiently; certainly, there can be fewer explicit temporary variables. The use of the template offers a choice in types for precision and accuracy considerations, though one area for improvement might be to allow a different type for intermediate calculations.

<lang cpp>#include <iostream>

  1. include <utility>

template<typename tVal> tVal map_value(std::pair<tVal,tVal> a, std::pair<tVal, tVal> b, tVal inVal) {

 tVal inValNorm = inVal - a.first;
 tVal aUpperNorm = a.second - a.first;
 tVal normPosition = inValNorm / aUpperNorm;
 tVal bUpperNorm = b.second - b.first;
 tVal bValNorm = normPosition * bUpperNorm;
 tVal outVal = b.first + bValNorm;
 return outVal;

}

int main() {

 std::pair<float,float> a(0,10), b(-1,0);
 for(float value = 0.0; 10.0 >= value; ++value)
   std::cout << "map_value(" << value << ") = " << map_value(a, b, value) << std::endl;
 return 0;

}</lang>

Output:

map_value(0) = -1
map_value(1) = -0.9
map_value(2) = -0.8
map_value(3) = -0.7
map_value(4) = -0.6
map_value(5) = -0.5
map_value(6) = -0.4
map_value(7) = -0.3
map_value(8) = -0.2
map_value(9) = -0.1
map_value(10) = 0

Clojure

Translation of: Python

<lang clojure> (defn maprange [[a1 a2] [b1 b2] s] (+ b1 (/ (* (- s a1) (- b2 b1)) (- a2 a1))))

> (doseq [s (range 11)]

      (printf "%2s maps to %s\n" s (maprange [0 10] [-1 0] 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/10

10 maps to 0 </lang>

D

<lang d>import std.stdio;

double maprange(double[] a, double[] b, double s) {

   return  b[0] + ((s - a[0]) * (b[1] - b[0]) / (a[1] - a[0]));

}

void main() {

   auto r1 = [0.0, 10.0];
   auto r2 = [-1.0, 0.0];
   foreach (s; 0 .. 11)
       writefln("%2d maps to %5.2f", s, maprange(r1, r2, s));

}</lang>

 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

Erlang

<lang erlang>-module(map_range). -export([map_value/3]).

map_value({A1,A2},{B1,B2},S) ->

   B1 + (S - A1) * (B2 - B1) / (A2 - A1).

</lang>

Euphoria

<lang euphoria>function map_range(sequence a, sequence b, atom s)

   return b[1]+(s-a[1])*(b[2]-b[1])/(a[2]-a[1])

end function

for i = 0 to 10 do

   printf(1, "%2g maps to %4g\n", {i, map_range({0,10},{-1,0},i)})

end for</lang>

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

Factor

<lang factor>USE: locals

map-range ( a1 a2 b1 b2 x -- y )
  x a1 - b2 b1 - * a2 a1 - / b1 + ;</lang>

Or: <lang factor>USING: locals infix ;

map-range ( a1 a2 b1 b2 x -- y )
  [infix
    b1 + (x - a1) * (b2 - b1) / (a2 - a1)
  infix] ;</lang>

Test run: <lang factor>10 iota [| x | 0 10 -1 0 x map-range ] map . ! { -1 -9/10 -4/5 -7/10 -3/5 -1/2 -2/5 -3/10 -1/5 -1/10 }</lang>

Fantom

<lang fantom> class FRange {

 const Float low
 const Float high
 // in constructing a range, ensure the low value is smaller than high
 new make (Float low, Float high)
 {
   this.low = ( low <= high ? low : high )
   this.high = ( low <= high ? high : low )
 }
 // return range as a string
 override Str toStr () { "[$low,$high]" }
 
 // return a point in given range interpolated into this range
 Float remap (Float point, FRange given)
 {
   this.low + (point - given.low) * (this.high - this.low) / (given.high - given.low)
 }

}

class Main {

 public static Void main ()
 {
   range1 := FRange (0f, 10f)
   range2 := FRange (-1f, 0f)
   11.times |Int n|
   {
     m := range2.remap (n.toFloat, range1)
     echo ("Value $n in ${range1} maps to $m in ${range2}")
   }
 }

} </lang>

Output:

Value 0 in [0.0,10.0] maps to -1.0 in [-1.0,0.0]
Value 1 in [0.0,10.0] maps to -0.9 in [-1.0,0.0]
Value 2 in [0.0,10.0] maps to -0.8 in [-1.0,0.0]
Value 3 in [0.0,10.0] maps to -0.7 in [-1.0,0.0]
Value 4 in [0.0,10.0] maps to -0.6 in [-1.0,0.0]
Value 5 in [0.0,10.0] maps to -0.5 in [-1.0,0.0]
Value 6 in [0.0,10.0] maps to -0.4 in [-1.0,0.0]
Value 7 in [0.0,10.0] maps to -0.30000000000000004 in [-1.0,0.0]
Value 8 in [0.0,10.0] maps to -0.19999999999999996 in [-1.0,0.0]
Value 9 in [0.0,10.0] maps to -0.09999999999999998 in [-1.0,0.0]
Value 10 in [0.0,10.0] maps to 0.0 in [-1.0,0.0]

Forth

<lang forth>\ linear interpolation

lerp ( b2 b1 a2 a1 s -- t )
 fover f-
 frot frot f- f/
 frot frot fswap fover f- frot f*  
 f+ ;
test 11 0 do 0e -1e 10e 0e i s>f lerp f. loop ;</lang>

There is less stack shuffling if you use origin and range instead of endpoints for intervals. (o = a1, r = a2-a1)

<lang forth>: lerp ( o2 r2 r1 o1 s -- t ) fswap f- fswap f/ f* f+ ;

test 11 0 do -1e 1e 10e 0e i s>f lerp f. loop ;</lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>program Map

 implicit none
 
 real :: t
 integer :: i
 do i = 0, 10
   t = Maprange((/0.0, 10.0/), (/-1.0, 0.0/), real(i)) 
   write(*,*) i, " maps to ", t
 end do 

contains

function Maprange(a, b, s)

 real :: Maprange
 real, intent(in) :: a(2), b(2), s

 Maprange = (s-a(1)) * (b(2)-b(1)) / (a(2)-a(1)) + b(1) 

end function Maprange end program Map</lang>

Go

Basic task <lang go>package main

import "fmt"

type rangeBounds struct {

   b1, b2 float64

}

func mapRange(x, y rangeBounds, n float64) float64 {

   return y.b1 + (n - x.b1) * (y.b2 - y.b1) / (x.b2 - x.b1)

}

func main() {

   r1 := rangeBounds{0, 10}
   r2 := rangeBounds{-1, 0}
   for n := float64(0); n <= 10; n += 2 {
       fmt.Println(n, "maps to", mapRange(r1, r2, n))
   }

}</lang> Output:

0 maps to -1
2 maps to -0.8
4 maps to -0.6
6 maps to -0.4
8 maps to -0.19999999999999996
10 maps to 0

Extra credit

First, a function literal replaces the mapping function specified by the basic task. This allows a simpler parameter signature and also allows things to be precomputed for efficiency. newMapRange checks the direction of the first range and if it is decreasing, reverses both ranges. This simplifies an out-of-range check in the function literal. Also, the slope and intercept of the linear function are computed. This allows the range mapping to use the slope intercept formula which is computationally more efficient that the two point formula.

Second, ", ok" is a Go idiom. It takes advantage of Go's multiple return values and multiple assignment to return a success/failure disposition. In the case of this task, the result t is undefined if the input s is out of range. <lang go>package main

import "fmt"

type rangeBounds struct {

   b1, b2 float64

}

func newRangeMap(xr, yr rangeBounds) func(float64) (float64, bool) {

   // normalize direction of ranges so that out-of-range test works
   if xr.b1 > xr.b2 {
       xr.b1, xr.b2 = xr.b2, xr.b1
       yr.b1, yr.b2 = yr.b2, yr.b1
   }
   // compute slope, intercept
   m := (yr.b2 - yr.b1) / (xr.b2 - xr.b1)
   b := yr.b1 - m*xr.b1
   // return function literal
   return func(x float64) (y float64, ok bool) {
       if x < xr.b1 || x > xr.b2 {
           return 0, false // out of range
       }
       return m*x + b, true
   }

}

func main() {

   rm := newRangeMap(rangeBounds{0, 10}, rangeBounds{-1, 0})
   for s := float64(-2); s <= 12; s += 2 {
       t, ok := rm(s)
       if ok {
           fmt.Printf("s: %5.2f  t: %5.2f\n", s, t)
       } else {
           fmt.Printf("s: %5.2f  out of range\n", s)
       }
   }

}</lang> Output:

s: -2.00  out of range
s:  0.00  t: -1.00
s:  2.00  t: -0.80
s:  4.00  t: -0.60
s:  6.00  t: -0.40
s:  8.00  t: -0.20
s: 10.00  t:  0.00
s: 12.00  out of range

Groovy

<lang groovy> def mapRange(a1, a2, b1, b2, s) {

   b1 + ((s - a1) * (b2 - b1)) / (a2 - a1)

}

(0..10).each { s ->

   println(s + " in [0, 10] maps to " + mapRange(0, 10, -1, 0, s) + " in [-1, 0].")

} </lang> Output:

0 in [0, 10] maps to -1 in [-1, 0].
1 in [0, 10] maps to -0.9 in [-1, 0].
2 in [0, 10] maps to -0.8 in [-1, 0].
3 in [0, 10] maps to -0.7 in [-1, 0].
4 in [0, 10] maps to -0.6 in [-1, 0].
5 in [0, 10] maps to -0.5 in [-1, 0].
6 in [0, 10] maps to -0.4 in [-1, 0].
7 in [0, 10] maps to -0.3 in [-1, 0].
8 in [0, 10] maps to -0.2 in [-1, 0].
9 in [0, 10] maps to -0.1 in [-1, 0].
10 in [0, 10] maps to 0 in [-1, 0].

Haskell

Rather than handling only floating point numbers, the mapping function takes any number implementing the Fractional typeclass, which in our example also includes exact Rational numbers. <lang haskell>import Data.Ratio import Text.Printf

-- Map a value from the range [a1,a2] to the range [b1,b2]. We don't check -- for empty ranges. mapRange :: (Fractional a) => (a, a) -> (a, a) -> a -> a mapRange (a1,a2) (b1,b2) s = b1+(s-a1)*(b2-b1)/(a2-a1)

main = do

 -- Perform the mapping over floating point numbers.
 putStrLn "---------- Floating point ----------"
 mapM_ (\n -> prtD n . mapRange (0,10) (-1,0) $ fromIntegral n) [0..10]
 
 -- Perform the same mapping over exact rationals.
 putStrLn "---------- Rationals ----------"
 mapM_ (\n -> prtR n . mapRange (0,10) (-1,0) $ n%1) [0..10]
 
   where prtD :: PrintfType r => Integer -> Double -> r
         prtD n x = printf "%2d -> %6.3f\n" n x
         prtR :: PrintfType r => Integer -> Rational -> r
         prtR n x = printf "%2d -> %s\n" n (show x)</lang>

Output:

---------- Floating point ----------
 0 -> -1.000
 1 -> -0.900
 2 -> -0.800
 3 -> -0.700
 4 -> -0.600
 5 -> -0.500
 6 -> -0.400
 7 -> -0.300
 8 -> -0.200
 9 -> -0.100
10 ->  0.000
---------- Rationals ----------
 0 -> (-1) % 1
 1 -> (-9) % 10
 2 -> (-4) % 5
 3 -> (-7) % 10
 4 -> (-3) % 5
 5 -> (-1) % 2
 6 -> (-2) % 5
 7 -> (-3) % 10
 8 -> (-1) % 5
 9 -> (-1) % 10
10 -> 0 % 1

Icon and Unicon

<lang Unicon> record Range(a, b)

  1. note, we force 'n' to be real, which means recalculation will
  2. be using real numbers, not integers

procedure remap (range1, range2, n : real)

 if n < range2.a | n > range2.b then fail # n out of given range
 return range1.a + (n - range2.a) * (range1.b - range1.a) / (range2.b - range2.a)

end

procedure range_string (range)

 return "[" || range.a || ", " || range.b || "]"

end

procedure main ()

 range1 := Range (0, 10)
 range2 := Range (-1, 0)
 # if i is out of range1, then 'remap' fails, so only valid changes are written
 every i := -2 to 12 do {
   if m := remap (range2, range1, i)
     then write ("Value " || i || " in " || range_string (range1) || 
                 " maps to " || m || " in " || range_string (range2))
 }

end </lang>

Icon does not permit the type declaration, as Unicon does. For Icon, replace 'remap' with:

<lang Icon> procedure remap (range1, range2, n)

 n *:= 1.0
 if n < range2.a | n > range2.b then fail # n out of given range
 return range1.a + (n - range2.a) * (range1.b - range1.a) / (range2.b - range2.a)

end </lang>

Output:

Value 0 in [0, 10] maps to -1.0 in [-1, 0]
Value 1 in [0, 10] maps to -0.9 in [-1, 0]
Value 2 in [0, 10] maps to -0.8 in [-1, 0]
Value 3 in [0, 10] maps to -0.7 in [-1, 0]
Value 4 in [0, 10] maps to -0.6 in [-1, 0]
Value 5 in [0, 10] maps to -0.5 in [-1, 0]
Value 6 in [0, 10] maps to -0.4 in [-1, 0]
Value 7 in [0, 10] maps to -0.3 in [-1, 0]
Value 8 in [0, 10] maps to -0.2 in [-1, 0]
Value 9 in [0, 10] maps to -0.1 in [-1, 0]
Value 10 in [0, 10] maps to 0.0 in [-1, 0]

J

<lang j>maprange=:2 :0

 'a1 a2'=.m
 'b1 b2'=.n
 b1+((y-a1)*b2-b1)%a2-a1

) NB. this version defers all calculations to runtime, but mirrors exactly the task formulation</lang>

Or

<lang j>maprange=:2 :0

 'a1 a2'=.m
 'b1 b2'=.n
 b1 + ((b2-b1)%a2-a1) * -&a1

) NB. this version precomputes the scaling ratio</lang>

Example use:

<lang j> 2 4 maprange 5 11 (2.718282 3 3.141592) 7.15485 8 8.42478</lang>

or

<lang j> adjust=:2 4 maprange 5 11 NB. save the derived function as a named entity

  adjust 2.718282 3 3.141592

7.15485 8 8.42478</lang>

Required example:

<lang j> 0 10 maprange _1 0 i.11 _1 _0.9 _0.8 _0.7 _0.6 _0.5 _0.4 _0.3 _0.2 _0.1 0</lang>

Java

<lang java>public class Range { public static void main(String[] args){ for(float s = 0;s <= 10; s++){ System.out.println(s + " in [0, 10] maps to "+ mapRange(0, 10, -1, 0, s)+" in [-1, 0]."); } }

public static double mapRange(double a1, double a2, double b1, double b2, double s){ return b1 + ((s - a1)*(b2 - b1))/(a2 - a1); } }</lang> Output:

0.0 in [0, 10] maps to -1.0 in [-1, 0].
1.0 in [0, 10] maps to -0.9 in [-1, 0].
2.0 in [0, 10] maps to -0.8 in [-1, 0].
3.0 in [0, 10] maps to -0.7 in [-1, 0].
4.0 in [0, 10] maps to -0.6 in [-1, 0].
5.0 in [0, 10] maps to -0.5 in [-1, 0].
6.0 in [0, 10] maps to -0.4 in [-1, 0].
7.0 in [0, 10] maps to -0.30000000000000004 in [-1, 0].
8.0 in [0, 10] maps to -0.19999999999999996 in [-1, 0].
9.0 in [0, 10] maps to -0.09999999999999998 in [-1, 0].
10.0 in [0, 10] maps to 0.0 in [-1, 0].

The differences in 7, 8, and 9 come from double math. Similar issues show even when using float types.

JavaScript

<lang JavaScript>mapRange = function(t, from, to) { return to[0]+(t-from[0])*(to[1]-to[0])/(from[1]-from[0]); }</lang>

K

<lang K> f:{[a1;a2;b1;b2;s] b1+(s-a1)*(b2-b1)%(a2-a1)}

  +(a; f[0;10;-1;0]'a:!11)

((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))</lang>

<lang logo>to interpolate :s :a1 :a2 :b1 :b2

 output (:s-:a1) / (:a2-:a1) * (:b2-:b1) + :b1

end

for [i 0 10] [print interpolate :i 0 10 -1 0]</lang>

Lua

<lang lua>function map_range( a1, a2, b1, b2, s )

   return b1 + (s-a1)*(b2-b1)/(a2-a1)

end

for i = 0, 10 do

   print( string.format( "f(%d) = %f", i, map_range( 0, 10, -1, 0, i ) ) )

end</lang>


Mathematica

Such a function is already built in <lang Mathematica> Rescale[#,{0,10},{-1,0}]&/@Range[0,10] </lang>

Output: {-1., -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.}

Nemerle

<lang 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));
   }

}</lang>

Objeck

<lang 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));
     };
   }
 }

} </lang>

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

<lang 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</lang>

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

PARI/GP

Usage (e.g.): map([1,10],[0,5],8.) <lang parigp>map(r1,r2,x)=r2[1]+(x-r1[1])*(r2[2]-r2[1])/(r1[2]-r1[1])</lang>

Pascal

<lang 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.</lang> 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

Perl

<lang Perl>#!/usr/bin/perl -w use 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 ; </lang> 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

<lang perl6>use v6;

  1. Author: P. Seebauer

sub the_function(Range $a, Range $b, $s ) {

 my ($a1, $a2, $b1, $b2) = ($a, $b)».bounds;
 return $b1 + (($s-$a1) * ($b2-$b1) / ($a2-$a1));

}

for ^11 -> $x {say "$x maps to {the_function(0..10,-1..0, $x)}"}</lang>

%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: <lang perl6>sub getmapper(Range $a, Range $b) {

 my ($a1, $a2, $b1, $b2) = ($a, $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)"}</lang>

PicoLisp

<lang 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) ) )</lang>

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

<lang 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; </lang> 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

PureBasic

<lang purebasic>Structure RR

 a.f
 b.f

EndStructure

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 function

If 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))
 Next

EndIf</lang>

 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

<lang 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.1

10 maps to 0</lang>

REXX

(The different versions don't differ idiomaticly but just in style.)

All program versions could be made more robust by checking if the high and low ends of rangeA aren't equal.

version 1

<lang rexx> /*REXX program maps numbers from one range to another range. */

rangeA='0 10' rangeB='-1 0'

     do j=0 to 10
     say right(j,3) ' maps to ' mapRange(rangeA, rangeB, j)
     end

exit

/*─────────────────────────────────────MapRANGE subroutine──────────────*/ mapRange: procedure; arg a1 a2,b1 b2,x; return b1+(x-a1)*(b2-b1)/(a2-a1) </lang> 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

<lang rexx> /*REXX program maps numbers from one range to another range. */

     do j=0 to 10
     say right(j,3) ' maps to ' mapRange(0 10, -1 0, j)
     end

exit

/*─────────────────────────────────────MapRANGE subroutine──────────────*/ mapRange: procedure; arg a1 a2,b1 b2,x; return b1+(x-a1)*(b2-b1)/(a2-a1) </lang>

version 3

<lang rexx> /*REXX program maps numbers from one range to another range. */

rangeA='0 10'; parse var rangeA a1 a2 rangeB='-1 0'; parse var rangeB b1 b2

     do j=0 to 10
     say right(j,3) ' maps to ' b1+(x-a1)*(b2-b1)/(a2-a1)
     end

</lang>

Ruby

<lang 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

11.times do |s|

 s *= 1.0  # force floating point
 print s, " maps to ", map_range((0..10), (-1..0), s), "\n"

end</lang>

Numeric#quo acts like Numeric#/ but gives more precise result when both operands are Integers.

Output using floating-point arithmetic:

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.30000000000000004
8 maps to -0.19999999999999996
9 maps to -0.09999999999999998
10 maps to 0.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).

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

Scala

<lang 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)))</lang>

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

<lang 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;</lang>

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

Tcl

<lang tcl>package require Tcl 8.5 proc rangemap {rangeA rangeB value} {

   lassign $rangeA a1 a2
   lassign $rangeB b1 b2
   expr {$b1 + ($value - $a1)*double($b2 - $b1)/($a2 - $a1)}

}</lang> Demonstration (using a curried alias to bind the ranges mapped from and to): <lang tcl>interp alias {} demomap {} rangemap {0 10} {-1 0} for {set i 0} {$i <= 10} {incr i} {

   puts [format "%2d -> %5.2f" $i [demomap $i]]

}</lang> 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. <lang Ursala>#import flo

f((("a1","a2"),("b1","b2")),"s") = plus("b1",div(minus("s","a1"),minus("a2","a1")))

  1. cast %eL

test = f* ((0.,10.),(-1.,0.))-* ari11/0. 10.</lang> 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 <lang Ursala>f(("a1","a2"),("b1","b2")) "s" = ...</lang> 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.