Map range

Revision as of 00:22, 26 November 2010 by MikeMol (talk | contribs) (Hope that looks nice while being clear/easily readable?)

Given two ranges, and , and a value in range

Map range is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Then a value in range is linearly mapped to a value in range where:

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 the values of the integers from the range to the range .

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


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

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>

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