0

I have a very simple little function that is supposed to verify the values in the passed vector:

bool Verify( std::vector<std::pair<float, float>> const & source) {
    // The lookup table must be changing linearly on input
    float delta_x{};
    for (unsigned i = 1; i < source.size(); i++) {
        auto input_delta = std::abs(source[i].first - source[i-1].first);
        if (i == 1) {
            delta_x = input_delta;
        } else {
            std::cout << "LUT"
              << "Expected step: '" << std::setprecision(10) << delta_x << "'."
              << " measured step[" << i << "]: '"
              << std::setprecision(10) << input_delta << "'"
              << (input_delta-delta_x)
              << ":" << source[i].first << "-" << source[i-1].first << std::endl;
        if (delta_x != input_delta) {
            return false;
        }
     }
  }

  return true;
}

It seems fairly straightforward. However, it fails. When I pass a simple vector like this:

    std::vector<std::pair<float, float>>kDecodeLut{
  {  -1.326, 101.3974},
  {   6.174, 96.0049 },
  {  13.674, 91.5644 },
  {  21.174, 87.5549 },
  {  28.674, 83.7873 },
  {  36.174, 80.1683 },
  {  43.674, 76.6441 },
  {  51.174, 73.1802 },
  {  58.674, 69.7524 }};

The values that the Verify method sees are not exactly the same as in the vector. Here is the printout:

LUTExpected step: '7.5'. measured step[2]: '7.5'0:13.67399979-6.173999786
LUTExpected step: '7.5'. measured step[3]: '7.5'0:21.17399979-13.67399979
LUTExpected step: '7.5'. measured step[4]: '7.5'0:28.67399979-21.17399979
LUTExpected step: '7.5'. measured step[5]: '7.5'0:36.17399979-28.67399979
LUTExpected step: '7.5'. measured step[6]: '7.5'0:43.67399979-36.17399979
LUTExpected step: '7.5'. measured step[7]: '7.5'0:51.17399979-43.67399979
LUTExpected step: '7.5'. measured step[8]: '7.5'0:58.67399979-51.17399979

It appears as if there was some number conversion from the original kDecodeLut vector to the internal variable inside Verify.

Was there really some sort of conversion? I didn't intend for the kDecodeLut vector to be copied or modified in any form. What else can explain this behavior?


Edit: I've added the code to print the values before calling Verify and they come out as expected.

 for (unsigned i = 1; i < kTiltWingDecodeLut.size(); i++) {
  std::cout << "LUT"
            << ":" << kTiltWingDecodeLut[i].first << "-" << kTiltWingDecodeLut[i-1].first << std::endl;
}
Verify(kTiltWingDecodeLut);

Here is the output

LUT:6.174--1.326
LUT:13.674-6.174
LUT:21.174-13.674
LUT:28.674-21.174
LUT:36.174-28.674
LUT:43.674-36.174
LUT:51.174-43.674
LUT:58.674-51.174
LUTExpected step: '7.5'. measured step[2]: '7.5'0:13.67399979-6.173999786
LUTExpected step: '7.5'. measured step[3]: '7.5'0:21.17399979-13.67399979
LUTExpected step: '7.5'. measured step[4]: '7.5'0:28.67399979-21.17399979
LUTExpected step: '7.5'. measured step[5]: '7.5'0:36.17399979-28.67399979
LUTExpected step: '7.5'. measured step[6]: '7.5'0:43.67399979-36.17399979
LUTExpected step: '7.5'. measured step[7]: '7.5'0:51.17399979-43.67399979
LUTExpected step: '7.5'. measured step[8]: '7.5'0:58.67399979-51.17399979
ilya1725
  • 4,496
  • 7
  • 43
  • 68
  • 5
    Why do you think that there was a number conversion? Because the output is something like `6.173999786` instead of `6.174`? That is because a float number can not store numbers of arbitrary precision and the actual number that it holds is often slightly off. When you create the vector, the first number is stored from the beginning, not `6.174`. – pschill Jun 29 '17 at 07:34
  • 1
    6.174 is likely stored as 6.173999786 and I would argue that Verify actually does get the exact same numbers as you passe in. – André Jun 29 '17 at 07:35
  • I have a bit of code that prints the values _before_ `Verify` and the numbers come out as `6.174`. – ilya1725 Jun 29 '17 at 13:59
  • Show us that code then. We need a [mcve]. – HolyBlackCat Jun 29 '17 at 14:09
  • 1
    Possible duplicate of [comparing double values in C++](https://stackoverflow.com/questions/12278523/comparing-double-values-in-c) – Mgetz Jun 29 '17 at 14:27
  • 1
    Please read about [mcve] again and try to come up with something that is in fact one. All words in the title are significant so pay attention to what they mean. – n. m. could be an AI Jun 29 '17 at 14:30
  • http://floating-point-gui.de – Arne Vogel Jun 29 '17 at 14:56

1 Answers1

2

This is a case of rounding. As you can see on this page, 6.174, when converted to 32-bit floating point is more like 6.1739998. The actual representation is explained on that page: 2^2*1.5434999 (1.10001011001000101101000 in binary.) The 64-bit floating point value uses the additional binary bits of 01110010101100000010000011001 in the multiplier after those of the 32-bit value.

If you use the same setprecision(10) to print the before values, you will see the same numbers.

Khouri Giordano
  • 796
  • 3
  • 9
  • You are right, @Khouri. I did add `std::setprecision(10)` to before code and it prints the same values. – ilya1725 Jun 29 '17 at 14:46
  • BTW, as defined by `FLT_DIG` in ``, a 32-bit floating point value is only good for 6 digits. `FLT_DECIMAL_DIG` is defined as 9, meaning it only takes 9 decimal digits to uniquely identify a 32-bit floating point value. This is a bit confusing with `setprecision` because **digits**, which starts at the first digit, is not the same as **decimal place values**, which starts at the decimal place. – Khouri Giordano Jun 29 '17 at 14:54