Price fraction

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

A friend of mine runs a pharmacy. He has a specialized function in his Dispensary application which receives a decimal value of currency and replaces it to a standard value. This value is regulated by a government department.

Task

Given a floating point value between 0.00 and 1.00, rescale according to the following table:

If(( p_Input <=0)OR( p_Input >=1)); returns 0 is input is out of rangeReturn0

; declaring the table (arbitrary delimiters in use are '§' and '|') l_List :="0.06|0.10§0.11|0.18§0.16|0.26§0.21|0.32§0.26|0.38§0.31|0.44§0.36|0.50§0.41|0.54§0.46|0.58§0.51|0.62§0.56|0.66§0.61|0.70§0.66|0.74§0.71|0.78§0.76|0.82§0.81|0.86§0.86|0.90§0.91|0.94§0.96|0.98§1.01|1.00"

Enter a fractional number between 0 and 1 ( 0 to end )!
0.7
-->0.78
Enter a fractional number ( 0 to end )!
0.32
-->0.5
Enter a fractional number ( 0 to end )!
0.12
-->0.26
Enter a fractional number ( 0 to end )!
0

The function above crashes with an array access bound error if the value passed is negative.
Also, the spec. indicates that 0.00 should be replaced with standard value 0.10, not 0.
The following is a more concise solution:

priceFraction(N)whenN<0orelseN>1->erlang:error('Values must be between 0 and 1.');priceFraction(N)whenN<0.06->0.10;priceFraction(N)whenN<0.11->0.18;priceFraction(N)whenN<0.16->0.26;priceFraction(N)whenN<0.21->0.32;priceFraction(N)whenN<0.26->0.38;priceFraction(N)whenN<0.31->0.44;priceFraction(N)whenN<0.36->0.50;priceFraction(N)whenN<0.41->0.54;priceFraction(N)whenN<0.46->0.58;priceFraction(N)whenN<0.51->0.62;priceFraction(N)whenN<0.56->0.66;priceFraction(N)whenN<0.61->0.70;priceFraction(N)whenN<0.66->0.74;priceFraction(N)whenN<0.71->0.78;priceFraction(N)whenN<0.76->0.82;priceFraction(N)whenN<0.81->0.86;priceFraction(N)whenN<0.86->0.90;priceFraction(N)whenN<0.91->0.94;priceFraction(N)whenN<0.96->0.98;priceFraction(N)->1.00.

A floating-point version wouldn't be hard -- four words would change ( , @ @ cell+ -to- f, [email protected][email protected] float+ ), EVALUATE would be replaced with a small word that forced a floating-point interpretation, and the return stack would not be used in ROUND -- but it would be strikingly unusual. See this page's discussion.

To decide which price is the standardized value of (P - price): repeat with N running from 1 to the number of rows in the Table of Price Standardization: choose row N in the Table of Price Standardization; if P is less than the upper bound entry, decide on the replacement entry.

When play begins: repeat with N running from 1 to 5: let P be a random price between 0.00 and 1.00; say "[P] -> [standardized value of P]."; end the story.

In the task definition, the first step is 0.06, the rest are 0.05
so a re-factoring can subtract 0.01 from the value and divide by 0.05 to get the step.

Working with decimal numbers in JavaScript has issues, e.g. 0.06 - 0.01 = 0.049999999999999996 due to using IEEE 754 double precision numbers that can't accurately represent all decimals. So values are multiplied by 100 and integer arithmetic is used.

Note that multiplying a string by a number produces a number, the bitwise OR (|) truncates floating point numbers to integer, making it a concise replacement for Math.floor.

This solution is somewhat straightforward but does highlight a couple of Julia features. The interval cut-offs and values are exactly represented by rational numbers. The interval to which an input value belongs is identified by applying the findfirst (true value) function to an element-wise comparison (.<) of this value to the cut-off array.

PRICFRAC(X) ;Outputs a specified value dependent upon the input value ;The non-inclusive upper limits are encoded in the PFMAX string, and the values ;to convert to are encoded in the PFRES string. NEW PFMAX,PFRES,I,RESULT SET PFMAX=".06^.11^.16^.21^.26^.31^.36^.41^.46^.51^.56^.61^.66^.71^.76^.81^.86^.91^.96^1.01" SET PFRES=".10^.18^.26^.32^.38^.44^.50^.54^.58^.62^.66^.70^.74^.78^.82^.86^.90^.94^.98^1.00" Q:(X<0)!(X>1.01) "" FOR I=1:1:$LENGTH(PFMAX,"^") Q:($DATA(RESULT)'=0) SET:X<$P(PFMAX,"^",I) RESULT=$P(PFRES,"^",I) KILL PFMAX,PFRES,I QUIT RESULT

// and a unit test to check that we haven't forgotten a branch, use 'cargo test' to execute test.//// typically this could be included in the match as those check for exhaustiveness already// by explicitly listing all remaining ranges / values instead of a catch-all underscore (_)// but f64::NaN, f64::INFINITY and f64::NEG_INFINITY can't be matched like this#[test]fn exhaustiveness_check() { let mut input_price = 0.; while input_price <= 1. { fix_price(input_price); input_price += 0.01; }}

A function of the form f\y applied to an argument x evaluates to f(x,y)

A function of the form f*| applied to a pair (x,y) where y is a list, makes a list of pairs with x on the left of each item and an item of y on the right. Then it applies f to each pair, makes a list of the right sides of those for which f returned true, and makes a separate list of the right sides of those for which f returned false.

The suffix rhr after the *| operator extracts the right side of the head of the right list from the result.

The operand to the *| operator, [email protected] is the less-or-equal predicate on floating point numbers, composed with the function ~&rlPlX which transforms a triple (u,(v,w)) to (v,u)