Map range: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added PicoLisp)
(Forth)
Line 53: Line 53:
map_value(10) = 0
map_value(10) = 0
</pre>
</pre>

=={{header|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>

=={{header|J}}==
=={{header|J}}==



Revision as of 18:12, 30 November 2010

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.

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.


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

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>

J

<lang j>maprange=:2 :0

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

)</lang>

Or

<lang j>maprange=:2 :0

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

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

  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>

PicoLisp

<lang PicoLisp>(scl 1) (let (A1 0 A2 10.0 B1 -1.0 B2 0)

  (for Val (range 0 10.0 1.0)
     (prinl
        (format
           (+ B1 (*/ (- Val A1) (- B2 B1) (- A2 A1)))
           *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

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