DEV Community

Discussion on: Daily Challenge #57 - BMI Calculator

Collapse
 
willsmart profile image
willsmart • Edited

Let's say you need to run this a few billion times times, then a more complex look up table approach might be worth it.

function indexFromBmi(bmi) {
  // turn the BMI into an ranged integer still giving with enough precision and reach for our labels
  return Math.max(0, Math.ceil((Math.min(30.5, bmi) - 18.5) / 0.5));
}
const bmi_lut = []
bmi_lut[indexFromBmi(18.5)] = 'Underweight';
bmi_lut[indexFromBmi(25)] = 'Normal';
bmi_lut[indexFromBmi(30)] = 'Overweight';
bmi_lut[indexFromBmi(30.5)] = 'Obese';

// fill in the entries below each label, so that, for example, the entry for bmi 27 will be "Overweight"
for (let index = bmi_lut.length - 1, label; index >= 0; index--) {
  if (bmi_lut[index]) label = bmi_lut[index];
  else bmi_lut[index] = label;
}

function bmiLabel(weight, height) {
  return bmi_lut[indexFromBmi(weight / height ** 2)];
}
> bmiLabel(-100000000,1)
< "Underweight"
> bmiLabel(18.5,1)
< "Underweight"
> bmiLabel(18.5001,1)
< "Normal"
> bmiLabel(25,1)
< "Normal"
> bmiLabel(25.0001,1)
< "Overweight"
> bmiLabel(30,1)
< "Overweight"
> bmiLabel(30.001,1)
< "Obese"
> bmiLabel(10000000000,1)
< "Obese"
// Test the weight/height relationship
> bmiLabel(25 * 1e20 ** 2, 1e20)
< "Normal"
// Try some heavy lifting
> for (let i=1e9; i; i--) bmiLabel(18.5,1);
< //took 23 seconds for a billion bmis in the js console just now (oldish mac pro)

(in JS because I like it, and I find it can be nice to mock up performance code in a slowish language first up.)

Collapse
 
craigmc08 profile image
Craig McIlwrath

Have you tested if your code is faster than a simpler conditional version (as most other solutions are written)?

Collapse
 
willsmart profile image
willsmart

Fair point Craig, in this case it turns out to be a bunch slower due to the complexity in indexFromBmi.
I just figured it was worth posting as an alternative approach as there are problems where luts are gold. In this case apparently not.

I'd say that here it's best to just use

function bmiLabel(weight, height) {
  const bmi = weight / height ** 2;
  return bmi <= 18.5 ? 'Underweight' : bmi <= 25 ? 'Normal' : bmi <= 30 ? 'Overweight' : 'Obese';
}

and be done with it.