13
\$\begingroup\$

Your task is to calculate the amount you have to pay for prescribed medication at a pharmacy in Germany. The amount is simply based on the full price of the item, which will be your input. It is a decimal number with exactly two fractional digits (ex. 5.43). You can assume it's strictly positive. Your task is to calculate the amount a customer has to pay, according to this function:

$$ A(x)=\begin{cases} x&\text{if } x\le 5\\ 5&\text{if } 5\le x \le 50\\ 0.1x&\text{if }50\le x \le 100\\ 10&\text{if }100 \le x \end{cases} $$ or equivalently $$ A(x)=\min(x,\min(\max(0.1x,5),10)) $$

The result must be rounded to two decimal places (half up). If these are 0, they may be skipped from the output. There must not be more than 2 decimal places. You can take numbers or strings as input and output, but be aware of inexact floating point representations.

Use a comma or a point as the decimal separator.

Test cases

(Whitespace just for readability)

5.00, 5.0 and 5 are all ok.

  4.99  ->  4.99
  5.00  ->  5.00
  5.05  ->  5.00
  10.00 ->  5.00
  49.00 ->  5.00
  50.00 ->  5.00
  50.04 ->  5.00
  50.05 ->  5.01
  50.14 ->  5.01
  50.15 ->  5.02
  99.84 ->  9.98
  99.85 ->  9.99
  99.94 ->  9.99
  99.95 -> 10.00
 100.00 -> 10.00 
1000.00 -> 10.00
\$\endgroup\$
9
  • 1
    \$\begingroup\$ You should have a test case between 5 and 50; otherwise the second row of your formula isn’t tested \$\endgroup\$ Nov 19 at 15:09
  • 1
    \$\begingroup\$ A price of zero doesn't make sense in this context, so I removed the test case. \$\endgroup\$
    – corvus_192
    Nov 19 at 17:38
  • 1
    \$\begingroup\$ No, it will always be printed with two decimal places on your reciept, and that's what I'm trying to go for. \$\endgroup\$
    – corvus_192
    Nov 19 at 20:22
  • 3
    \$\begingroup\$ @corvus_192 It seems that most answers are not outputting in the correct format. \$\endgroup\$
    – alephalpha
    Nov 20 at 2:03
  • 1
    \$\begingroup\$ @corvus_192 a float of exactly 5.00 might be represented as 5.0 or 5 etc. Is a function that returns floats not valid? \$\endgroup\$ Nov 20 at 12:46

21 Answers 21

8
\$\begingroup\$

Jelly, 14 bytes

÷⁵«⁵»5«+ȷ-4ær2

A monadic Link that accepts the full price as a float and outputs the charge as a float.

Try it online!

How?

÷⁵«⁵»5«+ȷ-4ær2 - Link: Full Price           P
÷⁵             - divide Full Price by 10    P/10
  «⁵           - minimum with 10            min(10,P/10)
    »5         - maximum with 5             max(5,min(10,P/10))
      «        - minimum with Full Price    min(P,max(5,min(10,P/10)))
       +ȷ-4    - add 0.0001 (catering for banker's rounding effects below)
           ær2 - round to two decimal places
\$\endgroup\$
3
  • \$\begingroup\$ This doesn't satisfy the output requirement of always having 2 decimal places \$\endgroup\$
    – Sam Dean
    Nov 20 at 12:39
  • \$\begingroup\$ This is a monadic Link (function) and the result is a float. It is always rounded to two decimal places, but the representation of a float like 5.00 is 5.0. I have added a comment under the question as output formatting isn't part of the requirements unless clearly specified as such, and I don't feel that this challenge is about output formatting. \$\endgroup\$ Nov 20 at 12:49
  • 2
    \$\begingroup\$ @SamDean the restrictions have been relaxed. \$\endgroup\$ Nov 20 at 17:06
6
\$\begingroup\$

APL+WIN, 21 bytes

Prompts for input

2⍕(n⌊((.1×n←⎕)⌈5))⌊10

Try it online! Thanks to Dyalog Classic

\$\endgroup\$
4
  • \$\begingroup\$ You can get rid of the parentheses and write as a dfn {2⍕⍵⌊10⌊5⌈.1×⍵} \$\endgroup\$
    – Tbw
    Nov 22 at 10:13
  • \$\begingroup\$ Thanks for the comment but unfortunately my version of APL+WIN is 20 years old and does not have any of that functionality. Fortunately I can still use the basic functionality of Dyalog Classic to post my answers on TIO. \$\endgroup\$
    – Graham
    Nov 22 at 10:18
  • \$\begingroup\$ @Tbw see my comment above. Please feel free to port any of my answers into a modern APL to demonstrate how far the language has developed. \$\endgroup\$
    – Graham
    Nov 22 at 10:20
  • \$\begingroup\$ ah I see. You can actually make my solution shorter by making it tacit as 2⍕⊢⌊10⌊5⌈.1×⊢, but I'm not sure that would help in running in your case. I think I will post a solution. \$\endgroup\$
    – Tbw
    Nov 22 at 10:25
5
\$\begingroup\$

R, 39 bytes

\(x)round(.001+min(x,max(.1*x,5),10),2)

Basically using the formula given by the OP.

-5 bytes thanks to @doubleunary

-3 bytes and fix a rounding error thanks to @NickKennedy

-6 bytes since the OP removed the requirement for exactly 2 decimal places.

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ hmm... round(min(x,max(.1*x,5),10),2) \$\endgroup\$ Nov 19 at 20:52
  • \$\begingroup\$ @doubleunary obviously... thx! \$\endgroup\$
    – Evargalo
    Nov 19 at 20:56
4
\$\begingroup\$

APL (Dyalog Unicode), 13 bytes

2⍕⊢⌊10⌊5⌈.1×⊢

Try it online!

Tacit prefix function. Takes input as number. Thanks to Graham for original APL solution.

How it works:

2⍕⊢⌊10⌊5⌈.1×⊢ ⍝ Anonymous, tacit function.
         .1×⊢ ⍝ 0.1x
       5⌈      ⍝ max with 5
    10⌊        ⍝ min with 10
   ⊢⌊          ⍝ min with x (as a fork)
2⍕            ⍝ format with 2 decimal places
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Golf! \$\endgroup\$ Nov 22 at 18:58
3
\$\begingroup\$

JavaScript (Node.js), 40 bytes

x=>Math.min(x,x<50?5:(x*10+.5|0)/100,10)

Try it online!

Python 3, 45 bytes

lambda x:round(sorted([x,5,10,x/9.999])[1],2)

Try it online!

-2 from PattuX

\$\endgroup\$
3
  • 1
    \$\begingroup\$ The reason to add a small positive number here is to cater for the fact that Python's round does banker's rounding by default, which rounds half-way points to the nearest even multiple. (It also negates any floating point effects that this rounding can introduce as per the first note in the round documentation) \$\endgroup\$ Nov 19 at 14:12
  • \$\begingroup\$ @JonathanAllan As it happens, there are no floating point effects between 0.00 and 100.00, at least not using the naïve formula floor(x*10+0.5)/100 rather than round(x/10,2). \$\endgroup\$
    – Neil
    Nov 19 at 14:32
  • \$\begingroup\$ The rounding only affects the cases from 50 too 100€, i.e., the x/10 part. You can also fix it by not dividing by 10 but a slightly smaller number, saving 2 bytes: lambda x:round(sorted([x,5,10,x/9.999])[1],2) \$\endgroup\$
    – PattuX
    Nov 20 at 12:08
2
\$\begingroup\$

Retina 0.8.2, 95 92 bytes

\.

.+
$*
^(.{1000}(?=.{8995})|.(.{499,998})(?=\2{9}....)|.{0,500}).*
00$.1
0*(.+)(..)
$1.$2

Try it online! Link includes test cases. Explanation:

\.

Multiply by 100.

.+
$*

Convert to unary.

^(.{1000}(?=.{8995})|.(.{499,998})(?=\2{9}....)|.{0,500}).*
00$.1

Calculate the amount to pay, with two 0s prefixed in case the amount is less than 100.

0*(.+)(..)
$1.$2

Divide by 100.

The disjunctions are as follows:

  • .{1000}(?=.{8995}) Any amount over 9994 becomes 1000.
  • .(.{499,998})(?=\2{9}....) Any amount over 4999 becomes a tenth of its value. .(.{499,998}) is the amount to pay, between 500 and 999, but the input has to match that value plus 9 times 1 less than that value plus 4, which equals 10 times that minus 5, thus rounding half up.
  • .{0,500} Any amount below 500 is unchanged, but amounts between 500 and 4999 become 500.
\$\endgroup\$
2
\$\begingroup\$

Google Sheets / Microsoft Excel, 31 bytes

=fixed(min(10,A1,max(5,A1/10)))

Put the input in cell A1 and the formula in B1. The fixed() function also takes care of rounding.

Equivalent JavaScript (rounding issue, non-competing, 45 bytes):

x=>Math.min(10,x,Math.max(5,x/10)).toFixed(2)

\$\endgroup\$
2
\$\begingroup\$

Ruby, 42 36 bytes

->a{[a,[a/10,5].max,10].min.round 2}

Try it online!

Ruby, 38 bytes

Formatted as per initial requirement:

->a{"%.2f"%[a,[a/9.999,5].max,10].min}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ This sometimes prints 5 or 5.0 instead of 5.00 \$\endgroup\$
    – Evargalo
    Nov 19 at 20:41
  • \$\begingroup\$ @Evargalo That's ok, it was unclear, so I removed the restriction. \$\endgroup\$
    – corvus_192
    Nov 20 at 13:37
1
\$\begingroup\$

JavaScript (ES6), 45 bytes

x=>~~(Math.min(x*10,x<50?50:x,100)*10+.5)/100

Try it online!


40 bytes

This one works in theory, but fails on some test cases because of rounding errors.

x=>Math.min(x,x<50?5:x/10,10).toFixed(2)

Try it online!

\$\endgroup\$
6
  • 1
    \$\begingroup\$ x=>Math.min(x,x<50?5:(x*10+.5|0)/100,10) works for all cases and conveniently is also the same length! \$\endgroup\$
    – Neil
    Nov 19 at 20:01
  • \$\begingroup\$ @Neil Seems like l4m2 already came to the same version. \$\endgroup\$
    – Arnauld
    Nov 19 at 20:14
  • \$\begingroup\$ Huh, I hadn't even noticed... \$\endgroup\$
    – Neil
    Nov 19 at 23:11
  • \$\begingroup\$ Think you need to include the toFixed(2) in the first answer to comply with the output requirement of always having 2 decimal places \$\endgroup\$
    – Sam Dean
    Nov 20 at 12:43
  • 1
    \$\begingroup\$ @SamDean The OP has since clarified that 5, 5.0 and 5.00 are all acceptable. \$\endgroup\$
    – Arnauld
    Nov 20 at 16:21
1
\$\begingroup\$

Python, 41 bytes

lambda x:min(max(5,(x*20+1)//2/100),x,10)

Attempt This Online!

Straight-forward implementation of OP's formula. For the rounding it uses floor division resulting in integer-valued floats which - unlike tenths - are guaranteed to be represented exactly.

\$\endgroup\$
0
\$\begingroup\$

sclin, 26 bytes

dup.1*5|10,` &/100* |~100/

Try it on scline!

sclin's default real/rational number representation comes in handy here.

Explanation

Prettified code:

dup .1* 5| 10,` &/ 100* |~ 100/

Assuming input n:

  • dup .1* n * .1
  • 5| min with 5
  • 10,` &/ min with 10 and n
  • 100* |~ 100/ round 2 decimal places
\$\endgroup\$
0
\$\begingroup\$

Wolfram Language (Mathematica), 36 bytes

#~Min~Max[.1#,5]~Min~10~Round~.01&@x

Alas, we cannot save an extra byte by using infix notation with Max because multiplication has a lower precedence than passing an argument, so .1#~Max~5 is equivalent to .1(#~Max~t), rather than (.1#)~Max~t.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

PARI/GP, 44 bytes

x->printf("%.2f",min(x,min(max(x/10,5),10)))

Attempt This Online!

A port of @Evargalo's R answer.

Prints the result to stdout.

\$\endgroup\$
0
\$\begingroup\$

05AB1E, 16 (or 25) bytes

T/5‚à‚Tªß4°z+2.ò

Try it online or verify all test cases.

This outputs 5.0 or 10.0 instead of 5.00 or 10.00, like most other answers. To fix this, the following 9 bytes can be added:

т+0«6∍¦0Û

Try it online or verify all test cases.

Explanation:

T/        # Divide the (implicit) input by 10
5‚        # Pair it with 5
  à       # Pop and push the maximum of the pair
‚         # Pair it with the (implicit) input
 Tª       # Append 10 to this pair
   ß      # Pop and push the minimum of this triplet
4°        # Push 10**4: 10000
  z       # Pop and push 1/10000: 0.0001
   +      # Add it to the value
    2.ò   # Then (banker's) round it to 2 decimals

т+        # Add 100
  0«      # Append a trailing 0
    6∍    # Shorten it to length 6
      ¦   # Remove the leading 1
       0Û # Trim any leading 0s
          # (after which the result is output implicitly)
\$\endgroup\$
0
\$\begingroup\$

AWK, 48 bytes

{y=$0/10;a=y>5?y>10?10:y:5>$0?$0:5;print a+1e-4}

Try it online!


Ungolfed :

BEGIN{
    OFMT = "%.2f"
}

func min(n,m){
    return m>n?n:m
}
func max(p,q){
    return p>q?p:q
}

{
    x=min($0,min(max(0.1*$0,5),10))+0.0001
    print $1, "->", x
}
\$\endgroup\$
0
\$\begingroup\$

Scala 3, 106 100 bytes

Saved 6 bytes thanks to @corvus_192


Golfed version. Attempt This Online!

x=>BigDecimal(Seq(x,5,10,x/10).sorted.apply(1)+1e-6).setScale(2,BigDecimal.RoundingMode(4)).toDouble

Ungolfed version. Attempt This Online!

object Main {
  def f(x: Double): Double = {
    val sortedList = List(x, 5, 10, x/10).sorted
    BigDecimal(sortedList(1) + 1e-6).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
  }

  def main(args: Array[String]): Unit = {
    println(f(90))
    println(f(210))
    println(f(16))
    println(f(4.21))
    println(f(5.05))
    println(f(25.15))
    println(f(25.654321))
    println(f(75))
    println(f(75.987654))
    println(f(1000))
  }
}
\$\endgroup\$
1
  • \$\begingroup\$ 100 bytes: x=>BigDecimal(Seq(x,5,10,x/10).sorted.apply(1)+1e-6).setScale(2,BigDecimal.RoundingMode(4)).toDouble \$\endgroup\$
    – corvus_192
    Nov 20 at 13:30
0
\$\begingroup\$

Rust, 50 bytes

|x|(500f64.max(1e1*x).min(1e3).round()/1e2).min(x)

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Charcoal, 21 bytes

NθI⌊⟦θχ⌈⟦⁵∕⌊⁺·⁵×θχ¹⁰⁰

Try it online! Link is to verbose version of code. Explanation: Port of the formula given in the question, but with rounding as required. I checked all inputs from 50.00 to 99.99 and none of them had any rounding errors; even though for example 64.35*100 does not result in 6435, 64.35*10 does result in 643.5, which is then rounded to 644, with a final result of 6.44.

Nθ                      First input as a number
                θ       First input
               ×        Multiplied by
                 χ      Literal integer `10`
            ⁺           Plus
             ·⁵         Literal number `0.5`
           ⌊            Floor
          ∕             Divided by
                  ¹⁰⁰   Literal integer `100`
         ⁵              Literal integer `5`
        ⟦               Make into list
       ⌈                Take the maximum
      χ                 Predefined variable `10`
     θ                  Input number
    ⟦                   Make into list
   ⌊                    Take the minimum
  I                     Cast to string
                        Implicitly print

Formatted to two decimal places also turns out to be 21 bytes:

Nθ﹪%.2f⌊⟦θχ⌈⟦⁵∕θ⁹·⁹⁹⁹

Try it online! Link is to verbose version of code. Explanation: Uses @PattuX's observation that dividing by 9.999 before rounding suffices to compensate for floating-point errors.

\$\endgroup\$
0
\$\begingroup\$

*><>, 90 89 bytes

-1 byte by removing a semicolon that shouldn't have been there

I'm still trying to condense it using the dive u and rise O instructions, but in case I forget, here's a working version without them.

Requires running with the -i flag to receive input.

:5)?!\:5a*)?!\:9b*(?!\aa*:}*:a%:4)?v-   >$a*,n;
   ;n/    ;n5/    ;na/             \a$-+/

Explanation

x ≤ 5

:5)?!\
   ;n/
:         Duplicate the input
 5        Push 5 onto the stack
  )       Evaluate 5 > input
   ?!\   If true, redirect down
     /   Redirect left
   ;n     Print the input, and halt execution

5 ≤ x ≤ 50

:5a*)?!\
    ;n5/
:         Duplicate the input again
 5        Push 5 onto the stack
  a       Push 10 onto the stack
   *      Multiply the top to values, thus putting 50 onto the stack
    )     Evaluate 50 > input
     ?!\   If true, redirect down
       /   Redirect left
    ;n5    Push 5 onto the stack, print it, and halt execution

100 ≤ x

:aa*(?!\
    ;na/
:          Duplicate the input
 aa*       Multiply 10by 10, putting 100 onto the stack
    (      Evaluate 100 < input
     ?!\   If true, redirect down
       /   Redirect left
    ;na    Push 10 onto the stack, print it, and halt execution

50 ≤ x ≤ 100

In order to get half-up rounding, we multiply the input by 100 to make it an integer. From there we then round up/down to the nearest 10, and then divide by 1000 to get our final amount.

aa*:}*:a%:4)?v-   >$a*,n;
             \a$-+/
aa*                         Push 100 onto the stack
   :                        Duplicate the 100 on the stack
    }                       Shift the stack to the right, moving the duplicated 100 to the 0th index
     *                      Multiply the input by 100, replacing future instances of "input" with "input * 100"
      :                     Duplicate the input
       a                    Push 10 onto the stack
        %                   Push input modulo 10 onto the stack
         :                  Duplicate that value
          4                 Push 4 onto the stack
           )                Evaluate (input modulo 10) > 4
            ?v              If (input modulo 10) > 4 == true, redirect down
// If (input modulo 10) > 4 == true
             \              Redirect right
              a             Push 10 onto the stack
               $            Swap the top two values on the stack
                -           Subtract (input module 10) from 10
                 +          Add that to the input
                  /         Redirect up
// If (input modulo 10) > 4 == false
              -             Else, subtract (input module 10) from input
// After conditional
                  >         Force instruction pointer to the right
                   $        Swap the two values on the stack, making it [input, 100]
                    a*      Multiply the top value by 10, pushing 1000 onto the stack
                      ,     Divide the input by 1000
                       n;   Print the value and halt execution

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Uiua 0.3.1, 16 bytes

↧↧↥5⍜×⁅100⊃÷∘10.

See it in action

\$\endgroup\$
-1
\$\begingroup\$

Desmos, 30 actually 35 bytes

A one-liner Desmos equation for once (thanks to Aiden Chow for the fix and optimization):

f(x)=round([x,5,10,x/10].sort[2],2)

Try it on Desmos!

\$\endgroup\$
7
  • 2
    \$\begingroup\$ You say Desmos takes care of rounding but if I input 50.55 it shows 5.055 not 5.06. \$\endgroup\$ Nov 20 at 15:59
  • \$\begingroup\$ @Jonathan Allan Fixed it! \$\endgroup\$
    – Infigon
    Nov 20 at 16:38
  • \$\begingroup\$ I see the fix, however it is not rounding half-up (same now gives 5.05 not 5.06). \$\endgroup\$ Nov 20 at 17:03
  • \$\begingroup\$ If I'm not mistaken, wrapping your original answer with round(..., 2) seems to fix the issue (Desmos seems to always round half up from what I've noticed). \$\endgroup\$
    – Aiden Chow
    Nov 20 at 20:55
  • 1
    \$\begingroup\$ I just realized that x/10 can be .1x, saving another byte (I just copy-pasted the list from the aforementioned Python answer without much attention, so I didn't catch this before). \$\endgroup\$
    – Aiden Chow
    Nov 20 at 23:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.