Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QCOMPARE failing for doubles on Qt 5.5 only
QtWS25 Last Chance

QCOMPARE failing for doubles on Qt 5.5 only

Scheduled Pinned Locked Moved Solved General and Desktop
qt5.5testdouble
7 Posts 2 Posters 4.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Paul Colby
    wrote on 19 Aug 2015, 23:23 last edited by Paul Colby 4 Jun 2016, 00:18
    #1

    Hi,

    Short version: is there any known reason QCOMPARE or qFuzzyCompare would have changed relative accuracy (aka fuzziness) for doubles in Qt 5.5?

    I maintain an open-source project that uses Qt (Bipolar). This project uses Travis CI and AppVeyor to build and test on Linux, OSX, and Windows, for a number of different Qt versions. All of these versions are building / passing tests as expected, except for those builds that use Qt 5.5.

    Current passing platforms:

    • Linux: Qt 5.1.1, 5.2.1, 5.3.2, 5.4.1 - all 64-bit, for both gcc and clang;
    • OSX: Qt 5.3.2 - 64-bit, for both gcc and clang.
    • Windows: Qt 5.3, 5.4 - 32-bit for both mingw and msvc2013; 64-bit for msvc2013-64.

    Current failing platforms:

    • Linux: Qt 5.5, both gcc and clang;
    • OSX: (not tested; I don't have Qt 5.5 readily available for OSX at the moment).
    • Windows: Qt 5.5, all of mingw-32, msvc2013-32 and msvc2013-64.

    The nature of the failure (on all failing tests) is like:

    FAIL!  : TestTrainingSession::toTCX(training-sessions-19401412) Compared doubles are not the same (fuzzy compare)
       Actual   (aDouble): 314.405
       Expected (bDouble): 314.405
       Loc: [../../bipolar/test/polar/v2/testtrainingsession.cpp(75)]
    

    So it would appear to be related to the relative accuracy qFuzzyCompare is using.

    An example of a build run in which everything passed, except for all of the Qt 5.5 builds:

    • https://travis-ci.org/pcolby/bipolar/builds/76369109
    • https://ci.appveyor.com/project/pcolby/bipolar/build/master-105
      (note, the debug builds on AppVeyor pass because I don't run the unit tests for debug builds)

    I'm more than happy to trace the issue further, before creating a formal bug report (if it turns out to be appropriate), etc But I just wanted to first check if this is a known / expected behaviour when upgrading to Qt 5.5. I've had a quick search through these forums, the Qt bug tracker, and the Qt 5.5 release notes, and see nothing relevant. It does seem strange that I'd be the only one seeing the issue, so it might be specific to something I'm doing.

    So, is anyone aware of any such issues with Qt 5.5? Or shall I dig deeper? :)

    Thanks,

    Paul.

    1 Reply Last reply
    0
    • P Offline
      P Offline
      Paul Colby
      wrote on 20 Aug 2015, 09:49 last edited by
      #2

      Ok, so I'm doing some digging, and it turns out that the fuzzy compare is doing the correct thing... on Qt 5.5 only the doubles differ by about 0.00008%, which is more than qFuzzyCompare allows. ie the allowance has not changed (between 4.4 and 4.5), but something else has, resulting in my application getting slightly different values... I'll need to dig deeper.

      M 1 Reply Last reply 20 Aug 2015, 10:15
      0
      • P Paul Colby
        20 Aug 2015, 09:49

        Ok, so I'm doing some digging, and it turns out that the fuzzy compare is doing the correct thing... on Qt 5.5 only the doubles differ by about 0.00008%, which is more than qFuzzyCompare allows. ie the allowance has not changed (between 4.4 and 4.5), but something else has, resulting in my application getting slightly different values... I'll need to dig deeper.

        M Offline
        M Offline
        mrjj
        Lifetime Qt Champion
        wrote on 20 Aug 2015, 10:15 last edited by
        #3

        @Paul-Colby
        Good luck :)

        1 Reply Last reply
        0
        • P Offline
          P Offline
          Paul Colby
          wrote on 20 Aug 2015, 11:04 last edited by
          #4

          Thanks @mrjj :)

          I've found it!! The Qt 5.5 change was: Enhance precision of the FP conversion to strings in QVariant (8153386)

          This broke my tests, because my application code is using QVariant::toString to render XML content, then the unit test code is comparing the XML content to reference XML files. In this case, the reference files were generated using the pre-5.5 code, and so are actually less precise than the new XML content under test.

          This will be a slightly tricky one to solve in a way that supports all of Qt 5.x (desirable, but not crucial). I'll probably have to do an "is-float / is-double" check on the variant, and if so, invoke QString::number with an explicit precision that is consistent across versions. Either way, I'll have to update my XML test reference files, since they're obviously slightly lacking in precision as a result of the pre-Qt5.5 code used to generate them.

          Lots to ponder... :)

          M 1 Reply Last reply 20 Aug 2015, 11:07
          2
          • P Paul Colby
            20 Aug 2015, 11:04

            Thanks @mrjj :)

            I've found it!! The Qt 5.5 change was: Enhance precision of the FP conversion to strings in QVariant (8153386)

            This broke my tests, because my application code is using QVariant::toString to render XML content, then the unit test code is comparing the XML content to reference XML files. In this case, the reference files were generated using the pre-5.5 code, and so are actually less precise than the new XML content under test.

            This will be a slightly tricky one to solve in a way that supports all of Qt 5.x (desirable, but not crucial). I'll probably have to do an "is-float / is-double" check on the variant, and if so, invoke QString::number with an explicit precision that is consistent across versions. Either way, I'll have to update my XML test reference files, since they're obviously slightly lacking in precision as a result of the pre-Qt5.5 code used to generate them.

            Lots to ponder... :)

            M Offline
            M Offline
            mrjj
            Lifetime Qt Champion
            wrote on 20 Aug 2015, 11:07 last edited by
            #5

            @Paul-Colby
            I enjoyed your digging.
            Good work finding it and good info for others porting older apps.

            1 Reply Last reply
            0
            • P Offline
              P Offline
              Paul Colby
              wrote on 25 Aug 2016, 10:27 last edited by
              #6

              I'm not usually one to drag up old topics, but just thought it was interesting enough to follow up with some new info here :)

              The same issue (or rather a new version of it) arose in Qt 5.7... the situation is pretty well summarised in the comments I added to the Bipolar project's code:

              // Qt 5.5 increased the accuracy of QVariant::toString output for floats and
              // doubles (see qtproject/qtbase@8153386), resulting in slightly different
              // output, and QCOMPARE unit test failures.
              // https://github.com/qt/qtbase/commit/8153386397087ce4f5c8997992edf5c1fd38b8db
              //
              // Qt 5.7 added QLocale::FloatingPointShortest (see qt/qtbase@726fed0), and
              // updated QVariant to use that (instead of the Qt 5.5 change above) when
              // converting floats and doubles to string, again resulting in slightly
              // different output, and QCOMPARE unit test failures.
              // https://github.com/qt/qtbase/commit/726fed0d67013cbfac7921d3d4613ca83406fb0f
              //
              // So, QVariant floats and doubles convert (and compare) differently between
              // Qt 5.[0-4], 5.[5,6], and 5.7+.  Here we use the Qt 5.5 / 5.6 implementation
              // because its at least as accurate as 5.7+, and implementing a 5.7-compatible
              // fallback would be a major undertaking (needing to duplicate the third-party
              // double-conversion code Qt borrows from the V8 project).
              #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) && (QT_VERSION < QT_VERSION_CHECK(5, 7, 0))
                  #define VARIANT_TO_STRING(v) v.toString()
              #else // Fallback implementation based closely on Qt 5.5's qvariant.cpp
                  #ifndef DBL_MANT_DIG
                  #define DBL_MANT_DIG  53
                  #endif
                  #ifndef FLT_MANT_DIG
                  #define FLT_MANT_DIG  24
                  #endif
                  #define DBL_MAX_DIGITS10 (DBL_MANT_DIG * 30103) / 100000 + 2
                  #define FLT_MAX_DIGITS10 (FLT_MANT_DIG * 30103) / 100000 + 2
                  #define VARIANT_TO_STRING(v) \
                      (static_cast<QMetaType::Type>(v.type()) == QMetaType::Double)      \
                          ? QString::number(v.toDouble(), 'g', DBL_MAX_DIGITS10)         \
                          : (static_cast<QMetaType::Type>(v.type()) == QMetaType::Float) \
                              ? QString::number(v.toFloat(), 'g', FLT_MAX_DIGITS10)      \
                              : v.toString()
              #endif
              

              The Qt 5.7 change seems like a really good one, from a Qt-codebase maintenance perspective.

              Longer term, if this sort of change happens again (which is perfectly fine / valid for Qt to do - I'm not complaining at all), then I guess I'll make my code use an explicit float/double-to-string conversion function, and not rely on QVariant(float/double).toString in any version of Qt, just for this specific case.

              Anyway, it's been interesting :)

              Cheers.

              M 1 Reply Last reply 25 Aug 2016, 10:43
              2
              • P Paul Colby
                25 Aug 2016, 10:27

                I'm not usually one to drag up old topics, but just thought it was interesting enough to follow up with some new info here :)

                The same issue (or rather a new version of it) arose in Qt 5.7... the situation is pretty well summarised in the comments I added to the Bipolar project's code:

                // Qt 5.5 increased the accuracy of QVariant::toString output for floats and
                // doubles (see qtproject/qtbase@8153386), resulting in slightly different
                // output, and QCOMPARE unit test failures.
                // https://github.com/qt/qtbase/commit/8153386397087ce4f5c8997992edf5c1fd38b8db
                //
                // Qt 5.7 added QLocale::FloatingPointShortest (see qt/qtbase@726fed0), and
                // updated QVariant to use that (instead of the Qt 5.5 change above) when
                // converting floats and doubles to string, again resulting in slightly
                // different output, and QCOMPARE unit test failures.
                // https://github.com/qt/qtbase/commit/726fed0d67013cbfac7921d3d4613ca83406fb0f
                //
                // So, QVariant floats and doubles convert (and compare) differently between
                // Qt 5.[0-4], 5.[5,6], and 5.7+.  Here we use the Qt 5.5 / 5.6 implementation
                // because its at least as accurate as 5.7+, and implementing a 5.7-compatible
                // fallback would be a major undertaking (needing to duplicate the third-party
                // double-conversion code Qt borrows from the V8 project).
                #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) && (QT_VERSION < QT_VERSION_CHECK(5, 7, 0))
                    #define VARIANT_TO_STRING(v) v.toString()
                #else // Fallback implementation based closely on Qt 5.5's qvariant.cpp
                    #ifndef DBL_MANT_DIG
                    #define DBL_MANT_DIG  53
                    #endif
                    #ifndef FLT_MANT_DIG
                    #define FLT_MANT_DIG  24
                    #endif
                    #define DBL_MAX_DIGITS10 (DBL_MANT_DIG * 30103) / 100000 + 2
                    #define FLT_MAX_DIGITS10 (FLT_MANT_DIG * 30103) / 100000 + 2
                    #define VARIANT_TO_STRING(v) \
                        (static_cast<QMetaType::Type>(v.type()) == QMetaType::Double)      \
                            ? QString::number(v.toDouble(), 'g', DBL_MAX_DIGITS10)         \
                            : (static_cast<QMetaType::Type>(v.type()) == QMetaType::Float) \
                                ? QString::number(v.toFloat(), 'g', FLT_MAX_DIGITS10)      \
                                : v.toString()
                #endif
                

                The Qt 5.7 change seems like a really good one, from a Qt-codebase maintenance perspective.

                Longer term, if this sort of change happens again (which is perfectly fine / valid for Qt to do - I'm not complaining at all), then I guess I'll make my code use an explicit float/double-to-string conversion function, and not rely on QVariant(float/double).toString in any version of Qt, just for this specific case.

                Anyway, it's been interesting :)

                Cheers.

                M Offline
                M Offline
                mrjj
                Lifetime Qt Champion
                wrote on 25 Aug 2016, 10:43 last edited by
                #7

                @Paul-Colby
                Thank you for reporting back.
                This is very important info for people using this function as "stuff"
                will happen if you upgrade from older Qt.

                1 Reply Last reply
                1

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved