-4

Tl;dr: Why does C++ see a difference between x/y*y and x/(y*y)?

I was doing some tasks at CodeWars and had to calculate variable and assign the result (whole exercise at the bottom):

bmi = weight / height ^ 2

if bmi <= 30.0 return "Overweight"

test values: weight = 86.7, height = 1.7

The formula that I used is double bmi = weight / (height*height) and for if-statement later it is else if (bmi > 25 && bmi <= 30) return "Overweight"; else return "Obese";

and test value calculated with formula is equal to 30. But when I run the code, my return was Obese. I wrote line to print out the result of calculation, it showed 30. But when I changed formula to double bmi = weight / height / height, the correct value is returned. Therefore, the problem is in the formula, but why is C++ see a difference between x/y/y and x/(y*y), even though it prints out the same result?

Given exercise:

Write function bmi that calculates body mass index (bmi = weight / height ^ 2).

if bmi <= 18.5 return "Underweight"

if bmi <= 25.0 return "Normal"

if bmi <= 30.0 return "Overweight"

if bmi > 30 return "Obese

My code:

#include <iostream>
#include <string>

// I created two functions to use two formulas for BMI
std::string bmi(double, double);
std::string bmi2(double, double);   

int main()
{
  std::cout << bmi(86.7, 1.7) << std::endl << std::endl;  // Calling the function
  std::cout << bmi2(86.7, 1.7); 
}

std::string bmi(double w, double h) 
{
  double bmi = w/(h*h); // Formula for BMI  
  std::cout <<"Calculated with w/(h*h): "<< bmi << std::endl;

  if (bmi <= 18.5)
    return "Underweight";
  else if(bmi>18.5 && bmi <= 25.0)
    return "Normal";
  else if (bmi>25 && bmi <= 30)
    return "Overweight";    // It should return this
  else 
    return "Obese";         // But goes with that
}

std::string bmi2(double w, double h) 
{
  double bmi = w/h/h;   // Formula for BMI
  std::cout <<"Calculated with w/h/h: "<< bmi << std::endl;

  if (bmi <= 18.5)
    return "Underweight";
  else if(bmi>18.5 && bmi <= 25.0)
    return "Normal";
  else if (bmi > 25 && bmi <= 30)
    return "Overweight";
  else
    return "Obese";
}
Swordfish
  • 12,971
  • 3
  • 21
  • 43
  • Just in passing, the `>` tests aren't needed. If `bmi <= 18.5` the `else if` won't be reached. It just needs to test for `bmi <= 25.0`. – Pete Becker Nov 24 '18 at 18:09

1 Answers1

2

Because arithmetic operators are evaluated from left to right, and by inserting parentheses around y * y you change the order of execution. The order matters because of floating point errors, on which you can find any number of articles around the internet. In short, integers can be represented precisely up to a certain number, but fractions will almost always be slightly inaccurate, which is why you should never test for exact equality of floats and doubles.

Arshia001
  • 1,854
  • 14
  • 19