Map range

From Rosetta Code
Jump to: navigation, search
Task
Map range
You are encouraged to solve this task according to the task description, using any language you may know.
Given two ranges, [a1,a2] and [b1,b2]; then a value s in range [a1,a2] is linearly mapped to a value t in range [b1,b2] when:
t = b_1 + {(s - a_1)(b_2 - b_1) \over (a_2 - a_1)}

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.

Contents

[edit] ACL2

This example is incomplete. The mapping function needs to be used as well as defined. Please ensure that it meets all task requirements and remove this message.
(defun mapping (a1 a2 b1 b2 s)
(+ b1 (/ (* (- s a1)
(- b2 b1))
(- a2 a1))))

[edit] 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;

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

[edit] 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
 

[edit] 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 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)
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))))

[edit] AWK

 
# syntax: GAWK -f MAP_RANGE.AWK
BEGIN {
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

[edit] 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

[edit] 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

[edit] 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

[edit] 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;
}
 

The output is :

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

[edit] 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.

#include <iostream>
#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;
}

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

[edit] Clojure

Translation of: Python
 
(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
 

[edit] COBOL

Works with: OpenCOBOL
       IDENTIFICATION DIVISION.
PROGRAM-ID. demo-map-range.
 
DATA DIVISION.
WORKING-STORAGE SECTION.
01 i USAGE FLOAT-LONG.
 
01 mapped-num USAGE FLOAT-LONG.
 
01 a-begin USAGE FLOAT-LONG VALUE 0.
01 a-end USAGE FLOAT-LONG VALUE 10.
 
01 b-begin USAGE FLOAT-LONG VALUE -1.
01 b-end USAGE FLOAT-LONG VALUE 0.
 
01 i-display PIC --9.9.
01 mapped-display PIC --9.9.
 
PROCEDURE DIVISION.
PERFORM VARYING i FROM 0 BY 1 UNTIL i > 10
CALL "map-range" USING CONTENT a-begin, a-end, b-begin,
b-end, i, REFERENCE mapped-num
COMPUTE i-display ROUNDED = i
COMPUTE mapped-display ROUNDED = mapped-num
DISPLAY FUNCTION TRIM(i-display) " maps to "
FUNCTION TRIM(mapped-display)
END-PERFORM
.
END PROGRAM demo-map-range.
 
 
IDENTIFICATION DIVISION.
PROGRAM-ID. map-range.
 
DATA DIVISION.
LINKAGE SECTION.
01 a-begin USAGE FLOAT-LONG.
01 a-end USAGE FLOAT-LONG.
 
01 b-begin USAGE FLOAT-LONG.
01 b-end USAGE FLOAT-LONG.
 
01 val-to-map USAGE FLOAT-LONG.
 
01 ret USAGE FLOAT-LONG.
 
PROCEDURE DIVISION USING a-begin, a-end, b-begin, b-end,
val-to-map, ret.
COMPUTE ret =
b-begin + ((val-to-map - a-begin) * (b-end - b-begin)
/ (a-end - a-begin))
.
END PROGRAM map-range.

The output is identical to the output of the Common Lisp example.

[edit] Common Lisp

(defun map-range (a1 a2 b1 b2 s)
(+ b1
(/ (* (- s a1)
(- b2 b1))
(- a2 a1))))
 
(loop
for i from 0 to 10
do (format t "~F maps to ~F~C" i
(map-range 0 10 -1 0 i)
#\Newline))
Output:
0.0 maps to -1.0
1.0 maps to -0.9
2.0 maps to -0.8
3.0 maps to -0.7
4.0 maps to -0.6
5.0 maps to -0.5
6.0 maps to -0.4
7.0 maps to -0.3
8.0 maps to -0.2
9.0 maps to -0.1
10.0 maps to 0.0


[edit] D

double mapRange(in double[] a, in double[] b, in double s)
pure nothrow @nogc {
return b[0] + ((s - a[0]) * (b[1] - b[0]) / (a[1] - a[0]));
}
 
void main() {
import std.stdio;
 
immutable r1 = [0.0, 10.0];
immutable r2 = [-1.0, 0.0];
foreach (immutable s; 0 .. 11)
writefln("%2d maps to %5.2f", s, mapRange(r1, r2, s));
}
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

[edit] Emacs Lisp

(defun maprange (a1 a2 b1 b2 s)
(+ b1 (/ (* (- s a1) (- b2 b1)) (- a2 a1))))
 
(dotimes (i 10)
(princ (maprange 0.0 10.0 -1.0 0.0 i))
(terpri))

[edit] Erlang

-module(map_range).
-export([map_value/3]).
 
map_value({A1,A2},{B1,B2},S) ->
B1 + (S - A1) * (B2 - B1) / (A2 - A1).
 

[edit] 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

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

[edit] Factor

USE: locals
:: map-range ( a1 a2 b1 b2 x -- y )
x a1 - b2 b1 - * a2 a1 - / b1 + ;

Or:

USING: locals infix ;
:: map-range ( a1 a2 b1 b2 x -- y )
[infix
b1 + (x - a1) * (b2 - b1) / (a2 - a1)
infix] ;

Test run:

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 }

[edit] 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}")
}
}
}
 

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]

[edit] 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 ;

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

: 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 ;

[edit] Fortran

Works with: Fortran version 90 and later
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

[edit] Go

Basic task

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

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.

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

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

[edit] 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].")
}
 

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].

[edit] 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.

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)

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

[edit] Icon and Unicon

 
record Range(a, b)
 
# note, we force 'n' to be real, which means recalculation will
# 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
 

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

 
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
 

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]

[edit] 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

Or

maprange=:2 :0
'a1 a2'=.m
'b1 b2'=.n
b1 + ((b2-b1)%a2-a1) * -&a1
)
NB. this version precomputes the scaling ratio

Example use:

   2 4 maprange 5 11 (2.718282 3 3.141592)
7.15485 8 8.42478

or

   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

Required example:

   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

[edit] 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);
}
}

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.

[edit] JavaScript

// Javascript doesn't have built-in support for ranges
// Insted we use arrays of two elements to represent ranges
var mapRange = function(from, to, s) {
return to[0] + (s - from[0]) * (to[1] - to[0]) / (from[1] - from[0]);
};
 
var range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (var i = 0; i < range.length; i++) {
range[i] = mapRange([0, 10], [-1, 0], range[i]);
}
 
console.log(range);

Output:

[-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0]

[edit] Extra credit

Here we will use the ECMAScript 5 support for map and the _.range function from Underscore.js.

Library: Underscore.js
var mapRange = function(from, to, s) {
// mapRange expects ranges generated by _.range
var a1 = from[0];
var a2 = from[from.length - 1];
var b1 = to[0];
var b2 = to[to.length - 1];
return b1 + (s - a1) * (b2 - b1) / (a2 - a1);
};
 
// The range function is exclusive
var fromRange = _.range(0, 11);
var toRange = _.range(-1, 1);
 
// .map constructs a new array
fromRange = fromRange.map(function(s) {
return mapRange(fromRange, toRange, s);
});
 
console.log(fromRange);

Output:

[-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0]

[edit] Julia

maprange(s, a, b) = let a1 = minimum(a), a2 = maximum(a), b1 = minimum(b), b2 = maximum(b)
b1 + (s-a1) * (b2-b1) / (a2-a1)
end

By using maximum and minimum in our implementation, we can pass maprange Julia's built-in Range type to represent the ranges a and b:

julia> maprange(6, 0:10, -1:0)
-0.4

julia> maprange([0:10], 0:10, -1:0)
11-element Array{Float64,1}:
 -1.0
 -0.9
 -0.8
 -0.7
 -0.6
 -0.5
 -0.4
 -0.3
 -0.2
 -0.1
  0.0

julia> maprange(0:10, 0:10, -1:0)
-1.0:0.1:0.0

[edit] 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))

[edit] Lasso

define map_range(
a1,
a2,
b1,
b2,
number
) => (decimal(#b1) + (decimal(#number) - decimal(#a1)) * (decimal(#b2) - decimal(#b1)) / (decimal(#a2) - decimal(#a1))) -> asstring(-Precision = 1)
 
with number in generateSeries(1,10) do {^
#number
': '
map_range( 0, 10, -1, 0, #number)
'<br />'
 
^}'

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

[edit]

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]

[edit] 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


[edit] Mathematica

Such a function is already built in

 
Rescale[#,{0,10},{-1,0}]&/@Range[0,10]
 

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

[edit] Maxima

maprange(a, b, c, d) := buildq([e: ratsimp(('x - a)*(d - c)/(b - a) + c)],
lambda([x], e))$
 
f: maprange(0, 10, -1, 0);

[edit] 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));
}
}

[edit] 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

[edit] Nimrod

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

[edit] 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

[edit] 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

[edit] 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])

[edit] 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

[edit] 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 ;
 

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 !

[edit] Perl 6

use v6;
# 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)}"}
%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, $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)"}

[edit] 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

[edit] 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

[edit] 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
 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

[edit] 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

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/10
10 maps to 0
>>>

[edit] 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

[edit] REXX

(The different versions don't differ idiomatically 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.

[edit] Version 1

/*REXX program maps a number 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 /*j*/
exit /*stick a fork in it, we're done.*/
 
/*──────────────────────────────────MAPRANGE subroutine─────────────────*/
mapRange: procedure; arg a1 a2,b1 b2,x; return b1+(x-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

[edit] Version 2

/*REXX program maps a number from one range to another range.           */
 
do j=0 to 10
say right(j,3) ' maps to ' mapRange(0 10, -1 0, j)
end /*j*/
exit /*stick a fork in it, we're done.*/
 
/*──────────────────────────────────MAPRANGE subroutine─────────────────*/
mapRange: procedure; arg a1 a2,b1 b2,x; return b1+(x-a1)*(b2-b1)/(a2-a1)

[edit] Version 3

/*REXX program maps a number 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 /*j*/
/*stick a fork in it, we're done.*/

[edit] Version 4

/*REXX program maps a number from one range to another range.           */
/* 31.10.2013 Walter Pachl
/* 'translated' from version 1 without using Procedure */

do j=0 to 10
say right(j,3) ' maps to ' mapRange(0,10,-1,0,j)
end
exit /*stick a fork in it, we're done.*/
 
/*──────────────────────────────────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:

Identical to Version 1

[edit] 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

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

[edit] 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]

[edit] 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

[edit] 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)}
}

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

[edit] 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.

[edit] 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

[edit] 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
Personal tools
Namespaces

Variants
Actions
Community
Explore
Misc
Toolbox