0

I am building a world with polar and cartesian coordinate systems as well as a 3d coordinate system. My coordinates are all expressed as floats. I started writing my tests and then coded from there. Everything was fine until I started tetsing precise values, then I started having issues.

Here is an example test:

TEST_METHOD(TestAngleFromPointUsingRelativeCoordsQuandrant1_1)
{
   // ARRANGE
   TwoDCoordinate testPoint = TwoDCoordinate(10, 10);
   PolarCoordinate expected = PolarCoordinate(45.0F, 14.142136F);

   // ACT
   PolarCoordinate actual = CoordinateConverter::ConvertFrom2DToPolar(testPoint);
   TwoDCoordinate convertedCoord = CoordinateConverter::ConvertFromPolarTo2D(actual, TwoDCoordinate(0.0F, 0.0F));

   // ASSERT
   ActAndAssertOnConversion(expected, actual);
}

The value 14.142136 is a little too precise for my wants, 14.142 would be just fine. So I went and studied more of std methods and found std::stof. Based on that I wrote this function:

float BaseTester::RoundFloatTo(float fnum, int round_digits)
{
     std::string::size_type sz;
     std::ostringstream oss;
     oss << std::fixed << std::showpoint;
     oss << std::setprecision(round_digits);
     oss << fnum;
     std::string buffer = oss.str();
     return std::stof(buffer, &sz);
}

I thought my troubles were over until I looked at the output of precisions from 5 to 0. For the float 14.142136 I got:

  1. 5 = 14.1421404
  2. 4 = 14.1421003
  3. 3 = 14.1420002
  4. 2 = 14.1400003
  5. 1 = 14.1000004
  6. 0 = 14.0000000

This is NOT what I was expecting at all! I was hoping that the number of digits would decrease with decreased precision and round up or down appropriately. Like this:

  1. 5 = 14.14214
  2. 4 = 14.1421
  3. 3 = 14.142
  4. 2 = 14.14
  5. 1 = 14.1
  6. 0 = 14.0

Clearly I am doing something wrong here, anyone have a great idea for me?

ScottyMacDev
  • 163
  • 1
  • 8
  • 3
    You've just discovered that your number "14.142" cannot be accurately represented as a floating point number with exact precision. Because that's how floating point math works. See the duplicate question for more information. – Sam Varshavchik Feb 25 '18 at 14:54
  • 1
    You are returning a float. Print the string (buffer) instead! – Captain Giraffe Feb 25 '18 at 14:54

1 Answers1

1

Multiple misunderstandings on your side:

  • Setting the precision only applies to how the float is rendered to buffer. Not to the float you are casting it back to.
  • When casting back to float you are subject to rounding errors again.
  • What you actually are trying to do, is checking whether two numbers are within a certain bias of each other. This has nothing to do with rounding.
Ext3h
  • 5,713
  • 17
  • 43
  • Thanks for going out of your way pointing out everything wrong and not offering one useful suggestion! – ScottyMacDev Feb 25 '18 at 15:07
  • 1
    @ScottyMacDev the solution is to return a `std::string` from `RoundFloatTo()` instead of a float if you want to keep the precision. Don't convert it back to a float or a double. Either of these will not keep the precision because of the linked duplicate. – drescherjm Feb 25 '18 at 15:43
  • @drescherjm Except that is not the solution. Using a rounding operation is wrong for a unit test. What must be checked, is if the actual result is within a range of the expected result. Rounding leads to wrong results, for expected results close to the steps in the rounding function. – Ext3h Feb 26 '18 at 06:55