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\$ Commented Nov 19, 2023 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
    Commented Nov 19, 2023 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
    Commented Nov 19, 2023 at 20:22
  • 3
    \$\begingroup\$ @corvus_192 It seems that most answers are not outputting in the correct format. \$\endgroup\$
    – alephalpha
    Commented Nov 20, 2023 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\$ Commented Nov 20, 2023 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
    Commented Nov 20, 2023 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\$ Commented Nov 20, 2023 at 12:49
  • 2
    \$\begingroup\$ @SamDean the restrictions have been relaxed. \$\endgroup\$ Commented Nov 20, 2023 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
    Commented Nov 22, 2023 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
    Commented Nov 22, 2023 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
    Commented Nov 22, 2023 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
    Commented Nov 22, 2023 at 10:25
6
\$\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\$
1
  • 1
    \$\begingroup\$ hmm... round(min(x,max(.1*x,5),10),2) \$\endgroup\$ Commented Nov 19, 2023 at 20:52
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\$ Commented Nov 22, 2023 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\$ Commented Nov 19, 2023 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
    Commented Nov 19, 2023 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
    Commented Nov 20, 2023 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
    Commented Nov 19, 2023 at 20:41
  • \$\begingroup\$ @Evargalo That's ok, it was unclear, so I removed the restriction. \$\endgroup\$
    – corvus_192
    Commented Nov 20, 2023 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
    Commented Nov 19, 2023 at 20:01
  • \$\begingroup\$ @Neil Seems like l4m2 already came to the same version. \$\endgroup\$
    – Arnauld
    Commented Nov 19, 2023 at 20:14
  • \$\begingroup\$ Huh, I hadn't even noticed... \$\endgroup\$
    – Neil
    Commented Nov 19, 2023 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
    Commented Nov 20, 2023 at 12:43
  • 1
    \$\begingroup\$ @SamDean The OP has since clarified that 5, 5.0 and 5.00 are all acceptable. \$\endgroup\$
    – Arnauld
    Commented Nov 20, 2023 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
    Commented Nov 20, 2023 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\$ Commented Nov 20, 2023 at 15:59
  • \$\begingroup\$ @Jonathan Allan Fixed it! \$\endgroup\$
    – Infigon
    Commented Nov 20, 2023 at 16:38
  • \$\begingroup\$ I see the fix, however it is not rounding half-up (same now gives 5.05 not 5.06). \$\endgroup\$ Commented Nov 20, 2023 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
    Commented Nov 20, 2023 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
    Commented Nov 20, 2023 at 23:10

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