Your task is to write a program that takes as input a height (in meters) and weight (in kilograms), and outputs the corresponding BMI category.

BMI is a measure of the ratio of your weight to your height. It's dated and inaccurate for many people, but that doesn't matter here!

BMI can be calculated using the following equation:

BMI = (mass in kilograms) / (height in meters)^2

The categories will be defined as follows:

  • BMI < 18.5: "Underweight"

  • 18.5 <= BMI < 25: "Normal"

  • 25 <= BMI: "Overweight"

For the sake of the challenge, I'm ignoring all the "extreme" categories. Also, since some numbers like "25" sit between 2 categories, I adjusted the bounds slightly so there's a definite answer.

You can write either a function, or a full program.


Input can be in any reasonable form. Two numbers (or strings), either as 2 separate arguments, or as a single string. An array/list of 2 numbers, a dictionary with "weight" and "height" keys... Decimal values should be supported. You can assume the input will always be valid (no negative values, and height will never be 0).


Output will be a string containing the case-insensitive category names. The strings must match the category names exactly as above, ignoring case. It can be output to the stdout, returned (in the case of a function), or written to file.

Test Cases (weight, height => result):

80, 1 =>   "Overweight"
80, 2 =>   "Normal"
80, 3 =>   "Underweight"

50, 1 =>   "Overweight"
50, 1.5 => "Normal"
50, 2 =>   "Underweight"

Edge Cases:

41, 1.5 => "Underweight" (18.2 BMI)
42, 1.5 => "Normal" (18.667 BMI)

56, 1.5 => "Normal" (24.889 BMI)
57, 1.5 => "Overweight" (25.3 BMI)

73, 2 =>   "Underweight" (18.25 BMI)
74, 2 =>   "Normal" (18.5 BMI)

99, 2 =>  "Normal" (24.75 BMI)
100, 2 => "Overweight" (25 BMI)

Here's some pseudocode that shows an example implementation:

function bmi_category(weight, height):
    var bmi = (weight / (height**2))

    if (bmi < 18.5):
        return "Underweight"

    if (18.5 <= bmi < 25):
        return "Normal"

    if (25 <= bmi):
        return "Overweight"

This is code-golf, so the fewest number of bytes wins.

(Yes, this task is exceedingly trivial in most languages. Most of the challenges lately seem to be harder than normal, so I thought I'd post a more accessible one).

NOTE! An hour after I posted this challenge, I had to modify the ranges slightly since the ranges as stated had "holes" as pointed out in the comments. Please see the new ranges.


32 Answers 32


Jelly, 24 bytes


Try it online!


Calculates the BMI, doubles it, compares that with the greater than operator with each of the numbers 37 and 50 (18.5 and 25 doubled), sums the resulting ones and zeros (yielding 1, 2, or 0 for Normal, Underweight, and Overweight respectively) and indexes into the list of strings ["Normal","Underweight","Overweight"].

÷÷⁹Ḥ“%2‘>Sị“$⁽¿“;ṅẒ“&ċ)» - Main link: weight, height
÷                        - weight ÷ height
  ⁹                      - right argument, height
 ÷                       - ÷ by height again to get the BMI
   Ḥ                     - double the BMI
    “%2‘                 - list of code page indexes [37,50]
        >                - greater than? (vectorises) - i.e [18.5>bmi, 25>bmi]
         S               - sum -- both:=2 (Underweight), just 50:=1 (Normal) or neither:=0 (Overweight)
          ị              - index into (1-based)
           “$⁽¿“;ṅẒ“&ċ)» - compressed list of strings ["Normal","Underweight","Overweight"]
                         - implicit print
  • 1
    \$\begingroup\$ Wow. Talk about obfuscation. If this is golf, I think you got a hole in one! Or 24... \$\endgroup\$ – Cullub Feb 7 '17 at 17:36
  • 2
    \$\begingroup\$ @cullub it is 24 characters and 24 bytes - Jelly uses it's own code-page linked to by the word "bytes" in the heading, mothereff.in is counting Unicode I believe. \$\endgroup\$ – Jonathan Allan Feb 7 '17 at 18:14
  • 1
    \$\begingroup\$ @TheBitByte, yes, take a look at the TIO link counter "24 chars, 24 bytes (SBCS)" or count it by hand using the code-page linked to by bytes in the heading. \$\endgroup\$ – Jonathan Allan Feb 7 '17 at 18:20
  • \$\begingroup\$ ... as hex: 1C 1C 89 AF FE 25 32 FC 3E 53 D8 FE 24 8D 0B FE 3B F0 BD FE 26 E8 29 FB \$\endgroup\$ – Jonathan Allan Feb 7 '17 at 18:28

Python, 69 bytes

lambda w,h:["UOnvd"[w/h/h>20::2]+"erweight","Normal"][18.5<=w/h/h<25]

Try it online!

Compare to 72 bytes:

lambda w,h:"Underweight"*(w/h/h<18.5)or"Normal"*(w/h/h<25)or"Overweight"

TI-Basic, 58 54 bytes

If 2C≤37
If C≥26

Also, for fun, here's a more compact version that is more bytes:

Prompt A,B
sub("UNDERWEIGHTNORMAL      OVERWEIGHT ",sum(A/B²≥{18.5,25})11+1,11

All I can say is, thank you for making this case-insensitive ;)

P.S. Input takes graph input to X and Y similar to Prompt X,Y

  • \$\begingroup\$ Also, I've looked at this multiple times, and I don't think there's any way to save bytes even though the last two share the string ERWEIGHT \$\endgroup\$ – Timtech Feb 6 '17 at 22:06
  • \$\begingroup\$ Out of curiosity, how would it have changed your answer if I enforced case-sensitivity? \$\endgroup\$ – Carcigenicate Feb 8 '17 at 5:54
  • 1
    \$\begingroup\$ @Carcigenicate In TI-Basic, the lowercase letters are two bytes each. Thus, it would have increased the byte count by a lot. \$\endgroup\$ – Timtech Feb 8 '17 at 13:33
  • 1
    \$\begingroup\$ Ah, I see. That's odd. \$\endgroup\$ – Carcigenicate Feb 8 '17 at 14:48
  • 1
    \$\begingroup\$ @Carcigenicate It's important to remember that this version of TI-Basic was introduced in 1990 as a calculator language... no one knew I'd be golfing it 27 years later \$\endgroup\$ – Timtech Mar 29 '17 at 19:03

Mathematica, 67 bytes


Uses the fact that a[b,c][[Sign@d]] returns a if d equals 0, returns b if d is positive, and returns c if d is negative. ⌊...⌋ is Mathematica's Floor function using the three-byte characters U+230A and U+230B. Couldn't figure out how to do better than using weight twice.

  • 3
    \$\begingroup\$ Surprised Mathematica doesn't have a built-in for this \$\endgroup\$ – Daniel Feb 7 '17 at 11:26
  • 1
    \$\begingroup\$ you have to go to the fan fiction for that ;) \$\endgroup\$ – Greg Martin Feb 7 '17 at 17:04

Ruby, 91 77 74 67 bytes

First naive try:

->(w,h){case w/h/h
when 0..18.5
when 18.5..25

Second try with ”inspiration“ from previous answers:


Third try:


Fourth try:


Try it online!

  • \$\begingroup\$ reitermarkus from homebrew-cask?! Woah, didn't expect to see you here! :o \$\endgroup\$ – numbermaniac Mar 29 '17 at 8:13
  • 1
    \$\begingroup\$ @numbermaniac, haha, yes, it's me! 😂 \$\endgroup\$ – reitermarkus Mar 29 '17 at 13:33

JavaScript (ES6), 70 67 64 63 bytes

Saved 4B thanks to Arnauld







This answer is quite trivial, though there is one clever trick: Underweight and Overweight both end in erweight, so we only have to change those characters.

I assumed that Normal means a BMI between 25 (exclusive) and 18.5 (inclusive). Underweight means a BMI less than 18.5, and Overweight means a BMI greater than or equal to 25.

  • 1
    \$\begingroup\$ Now the answer doesn't contain any ES7 features ;-) \$\endgroup\$ – ETHproductions Feb 8 '17 at 15:02

C, 81 bytes

f(float m,float h){m/=h*h;puts(m<26?m<18.6?"Underweight":"Normal":"Overweight");}

05AB1E, 28 bytes

n/©37;‹®25‹O’‚Š‰ß î ‚â‰ß’#è

Uses the CP-1252 encoding. Try it online!


QBIC, 61 58 bytes


@Luke used the Force and chopped off two bytes. Thanks!

The rules change saved another byte.


::          gets weight and height as a and b
m=a/b^2     Calculates BMI
~m<18.5|    If BMI < 18.5 then
?@Und`      Print the string literal 'Und' (which is now A$)
+@erweight` and the string literal 'erweight'  (which is now B$)
\~m>=25|    else if the BMI is greater than or equal to 25
?@Ov`+B     Print 'Ov' and B$ ('erweight')
\?@Normal   Else, if we're here, BMI is normal.

Python 2, 72 bytes

lambda a,b:"UNOnovdreemrrawwlee ii gg hh tt"[(18.6<a/b/b)+(a/b/b>25)::3]

Try it online!

  • \$\begingroup\$ How do you get the colours for Python? I never figured it out. \$\endgroup\$ – user63571 Feb 6 '17 at 22:51
  • \$\begingroup\$ @JackBates It's just <!-- language-all: lang-python --> which TIO automatically inserted for me. \$\endgroup\$ – James Feb 6 '17 at 22:52

Python 3, 97 95 bytes


Full program.

Multiply by five to save a byte. Thanks Jonathan Allan.

Line by line:

  1. Map the two space separated user input numbers to ints. Unpack to a and b.

  2. Calculate

  3. If the bmi is between 18.6 and 25, inclusive, the expression on the right will evaluate to True. Booleans can be 0 or 1 when used as list indexes, so we get either "Normal" or the constructed string in the zero index. "erweight" is a shared suffix for the remaining two options, so it doesn't need to be repeated. Then we use the [start:stop:step] pattern of Python list/string slicing. c>18.6 will evaluate to either 0 or 1 (False or True) and becomes our start. Stop isn't indicated so we go to the end of the literal. Step is 2 so we take every second index. If start start evaluates to 1, we get "Ov", otherwise we get "Und". Either way, we append "erweight" to what we got and we have our final output.

  • 1
    \$\begingroup\$ Write it as a function for 79: def f(h,w):c=h/w/w;print(["UOnvd"[c>18.6::2]+"erweight","Normal"][18.6<=c<=25]) \$\endgroup\$ – Jonathan Allan Feb 6 '17 at 22:24
  • \$\begingroup\$ If you multiply up by five first you can save a byte by comparing to 93 and 125. If you use a lambda you have to calculate c in both places but don't need to name the function or use print(), so can do lambda h,w:["UOnvd"[h/w/w*5>93::2]+"erweight","Normal"][93<=h/w/w*5<=125] for 73. \$\endgroup\$ – Jonathan Allan Feb 6 '17 at 22:33
  • \$\begingroup\$ ...actually because you will be calculating c twice the multiply by 5 costs more than it saves in the lambda, so just lambda h,w:["UOnvd"[h/w/w>18.6::2]+"erweight","Normal"][18.6<=h/w/w<=25] for 72 \$\endgroup\$ – Jonathan Allan Feb 6 '17 at 22:34
  • \$\begingroup\$ Jonathan Allan Somebody already did it as just a function. \$\endgroup\$ – mypetlion Feb 6 '17 at 22:36
  • \$\begingroup\$ That's OK, your way will out-golf them :D \$\endgroup\$ – Jonathan Allan Feb 6 '17 at 22:37

R, 89 84 80 74 bytes


With a nod to StewieGriffin's Octave answer, creates an array of strings, then sums the result of BMI < c(18.5,25) and references the array at that position + 1.

First argument needs to be height, then weight; if that's not allowed, then


works for 4 more bytes.


Clojure, 63 bytes

#(condp <(/ %(* %2 %2))25"Overweight"18.5"Normal""Underweight")
  • \$\begingroup\$ Damn. As always, this is a shorter version of what I was thinking of. \$\endgroup\$ – Carcigenicate Feb 7 '17 at 0:19

dc, 58 bytes


Takes input as 2 space separated numbers in the format <mass> <height> . Outputs a string on a separate line.

Try it online!


For the purposes of this explanation, the input is 80 1.

Fk                                                         # Set decimal precision to `16`.
  [Ov]                                                     # Push the string "Ov" onto the main stack.
                                                           # Main Stack: [[Ov]]
      ?2^/d                                                # Take and evaluate input, squaring the 2nd one, and the dividing by the first one by the 2nd. Then duplicate the result.
                                                           # Main Stack: [[Ov],80.000000000000000,80.000000000000000]
           [[Normal]pq][[Und]26]sasb                       # Push and store the executable macros "[Normal]pq" and "[Und]26" on registers "a" and "b", respectively.
                                                           # Main Stack: [[Ov],80.000000000000000,80.000000000000000], reg. a: [[[Normal]pq]], reg. b: [[[Und]26]]
                                    18.5>a25>b             # Push, "18.5" onto stack, and then pop top 2 values. If "18.5 > (top of stack)", then execute the macro on top of reg. "a", which in turn pushes the string "Und" onto the main stack followed by the number 26.
                                                           # The "26" will automatically prompt the next comparison to not execute the macro on top of reg. "b", regardless of the value on top of the main stack.
                                                           # Otherwise, if "18.5 <= (top of stack) < 25", then execute "b"s macro, which in turn pushes the string "Normal" onto the main stack, outputs it, then quits the program.
                                                           # In this case, Main stack: [[Ov]], reg. a: [[[Normal]pq]], reg. b: [[[Und]26]]
                                              n[erweight]p # If "Normal" has not been output, only then will the program get to this point. Here, it will output whatever string, either "Und" or "Ov", on top of the main stack, followed by "erweight" and a new line.

Octave, 64 bytes


Try it online

This is an anonymous function that takes two input arguments, h (height) and w (weight).

The function creates a cell array containing there strings 'Underweight','Normal','Overweight', and outputs string number 3-sum(2*w/h^2<'%2').

Yes, that one looks a bit strange. We want the first string if w/h^2<=18.5, the second string if (w/h^2 > 18.5) & (w/h^2 < 25) and the third string if none of the above conditions are true. Instead of creating a bunch of comparisons, we could simply compare the string to: w/h^2 < [18.5, 25], which would return one of the following arrays [1 1], [0 1], [0,0] for Underweight, Normal and Overweight respectively.

[18.5,25] takes 9 bytes, which is a lot. What we do instead, is multiply the BMI by 2, and compare the result with [37, 50], or '%2' in ASCII. This saves three bytes.


Perl 6, 59 bytes

{<Overweight Normal Underweight>[sum 18.5,25 X>$^a/$^b**2]}

How it works

{                                                         }  # A lambda.
                                               $^a/$^b**2    # Compute BMI from arguments.
                                     18.5,25 X>              # Compare against endpoints.
                                 sum                         # Add the two booleans together.
 <Overweight Normal Underweight>[                        ]   # Index into hard-coded list.

Too bad the string erweight has to be repeated, but all variations I tried in order to avoid that ended up increasing the overall byte count:

  • With string substitution, 62 bytes:

    {<Ov_ Normal Und_>[sum 18.5,25 X>$^a/$^b**2].&{S/_/erweight/}}
  • With string interpolation, 67 bytes:

    {$_='erweight';("Ov$_","Normal","Und$_")[sum 18.5,25 X>$^a/$^b**2]}
  • Rough translation of xnor's Python solution, 65 bytes:

    {$_=$^a/$^b**2;25>$_>=18.5??"Normal"!!<Und Ov>[$_>19]~"erweight"}

PowerShell, 81 bytes


Try it online!


The main bit that needs explaining is 18.5,25 -lt $b (where I'm substituting $b for the BMI which is calculated in place in the code). Most operators in PowerShell, when given an array on the left side, return an array of items that satisfy the test, instead of returning a boolean value. So this will return an empty array if $b is smaller than 18.5, an array containing only 18.5 if it's in the middle, and an array containing both 18.5 and 25 if it's larger than 25.

I use the count of the elements as an index into an array of the strings, so count 0 gets element 0 which is 'Underweight', etc.


OCaml, 93 bytes

let b w h=if w/.h/.h<18.5 then"underweight"else if w/.h/.h>=25.0 then"overweight"else"normal"
  • \$\begingroup\$ No, this is a function. \$\endgroup\$ – reitermarkus Mar 29 '17 at 13:39

Python, 75 74 bytes

lambda h,w:18.5<=w/h/h<=25and"normal"or["ov","und"][25>w/h/h]+"erwe‌​ight"

Try it online!

Fairly basic solution that takes advantage of other people's techniques for solving it.

Thanks @ovs for saving a byte.


1. 73 bytes

lambda h,w:"normal"if 18.5<=w/h/h<=25 else"uonvd"[25<w/h/h::2]+"erweight"

I rejected this as it was too similar to another answer I saw.

2. 71 bytes

lambda h,w:"normal"if 18.5<w/h/h<25 else"uonvd"[25<w/h/h::2]+"erweight"

I rejected this because, despite working on all the tests in the question, there are some numbers it can fail on as it's missing the = in the <=.

  • \$\begingroup\$ You don't need the space between 25 and else - but anyway, using short circuiting and/or (as @ovs commented) is shorter. \$\endgroup\$ – FlipTack Feb 7 '17 at 19:21
  • \$\begingroup\$ @FlipTack: regarding the space between 25 and else, you definitely do need it with some (most?) interpreters (including CPython, IIRC). If you write it as 25else, the 25e is interpreted as the start of a scientific-notation numeric literal, and the interpreter then baulks when there are no following digits. \$\endgroup\$ – Mac Feb 8 '17 at 3:44

C#, 63 62 61 bytes

Saved 1 more byte thanks to TheLethalCoder.

Saved 1 byte thanks to anonymous user.


A pretty straightforward anonymous function. The whole trick is using the ternary operator to return directly (thus omitting the return keyword, a pair of curly braces and a variable declaration and assignment).

Full program with test cases:

using System;

class BodyMassIndex
    static void Main()
        Func<double, Func<double, string>> f =

        // test cases:
        Console.WriteLine(f(80)(1));  // "Overweight"
        Console.WriteLine(f(80)(2));  // "Normal"
        Console.WriteLine(f(80)(3));  // "Underweight"
        Console.WriteLine(f(50)(1));  // "Overweight"
        Console.WriteLine(f(50)(1.5));  // "Normal"
        Console.WriteLine(f(50)(2));  // "Underweight"

Common Lisp, 89 87 85 84 83 bytes

A function:

(lambda(w h)(if(< #1=(/ w(* h h))18.5)'underweight(if(< #1#25)'normal'overweight)))

Example of usage:

((lambda(w h)(if(< #1=(/ w(* h h))18.5)'underweight(if(< #1#25)'normal'overweight)))150 2)

Try it online! (I added printing function to see output in TIO)

Ideas for improvement are welcomed.


MATL, 54 45 44 42 bytes


Try it at matl.suever.net

Starts off by calculating the BMI and doubling it U\E, then creates the vector [37 50] with the string literal '%2'. Compares the BMI to this vector and uses if statements to get the answer, taking advantage of normal as a predefined literal 17Y0.

  • \$\begingroup\$ You can replace [BC]UQ with '%2' and save 2 bytes. \$\endgroup\$ – sundar - Reinstate Monica Jul 17 '18 at 18:17

Java 8, 61 bytes


Assign to a DoubleFunction<DoubleFunction<String>> and call thusly:

  • \$\begingroup\$ You can spare one byte by reusing w: w->h->(w/=h*h)<18.5?"Underweight":w<25?"Normal":"Overweight". \$\endgroup\$ – Olivier Grégoire Feb 7 '17 at 20:33
  • \$\begingroup\$ @OlivierGrégoire Nope :( Error: local variables referenced from a lambda expression must be final or effectively final Can't assign to w. \$\endgroup\$ – David Conrad Feb 7 '17 at 21:04
  • 1
    \$\begingroup\$ Oh... I checked with inlined stuff like int w = ... , h = ... ; System.out.println((w/=h*h)<18.5?"Underweight":w<25?"Normal":"Overweight"), sorry :) \$\endgroup\$ – Olivier Grégoire Feb 7 '17 at 23:09
  • \$\begingroup\$ @OlivierGrégoire No problem. I wish Java allowed it. \$\endgroup\$ – David Conrad Feb 7 '17 at 23:15

dc, 64 bytes


Try it online!

  • \$\begingroup\$ Dang it! Just beat me by a few seconds. I was about to post mine, until I saw this. Anyways, here is another 64 byte answer: 3k[Overweight]??2^/dsp[[Normal]][[Underweight]]sasb25>blp18.5>ap. \$\endgroup\$ – R. Kap Feb 7 '17 at 1:16
  • \$\begingroup\$ @R.Kap You can actually get yours to be one byte shorter than mine by omitting one of the question marks. \$\endgroup\$ – Mitchell Spector Feb 7 '17 at 1:22
  • \$\begingroup\$ Oh yeah, I forgot that I could do that. You can post that as your own if you want. \$\endgroup\$ – R. Kap Feb 7 '17 at 1:25
  • \$\begingroup\$ No, that's fine -- go ahead and post it yourself, it's your solution. (You can credit me for one byte if you want.) \$\endgroup\$ – Mitchell Spector Feb 7 '17 at 1:26
  • \$\begingroup\$ By the way, I was able to get it down to 58 bytes. :) \$\endgroup\$ – R. Kap Feb 7 '17 at 2:30

Javascript (ES6), 63 bytes




console.log(f(80, 1));
console.log(f(80, 2));
console.log(f(80, 3));


Swift, 97 bytes

{(w:Float,h)->String in return 18.5<=w/h/h&&w/h/h<25 ?"normal":"\(w/h/h>25 ?"ov":"und")erweight"}

Japt, 46 bytes


Try it online!

Inspired by @Luke's answer.



Decompresses to :


Japt has an implicit input U. The second input is V.

Japt uses the shoco library for string compression. Backticks are used to decompress strings.

Unicode shortcuts used:

² : **2
© : &&
¨ : >=
½ : .5
º : ((

PHP, 121 bytes

function f($a,$b){$i=$a/($b*$b);$x = 18.5;print ($i<$x?"Underweight":($i>=$x&&$i<25?"Normal":($i>=25?"Overweight":"")));}

Try it online!


Scala, 124 bytes

val x="erweight"
def b(i:Float,a:Float):Any=i/a/a match{case z if(z<18.5)=>"Und"+x
case z if(z<25)=>"Normal"
case z=>"Ov"+x}

REXX, 113 bytes

arg m h
  when b<18.5 then say 'UND'e
  when b>=25 then say 'OV'e
  otherwise say Normal

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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