Название: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 12:22 На 32-битной версии MSVC и Qt 5.9.2 наблюдается такой интересный баг... В 64-битной версии такого нет.
Коротко: Код
Результат: Значения d1 и d2 различаются после пятнадцатого знака после запятой, а именно: d1 = 1.00000000000000000000 d2 = 1.00000000000000355271. Какая-то сумасшедшая оптимизация? Никаких своих флагов в .pro файл я не добавлял. Подлиннее: Код
Выхлоп: Цитировать 0.00000000810836997545 -1.00000000000000000000 0.00000044584299985218 -1.00000000000000000000 1.00000000000000000000 1.00000000000000000000 1.00000000000000355271 <--- f, d1 и d2 Проверьте пожалуйста на MSVC 2017 и MSVC 2013 в 32-битной версии. Какие есть гипотезы? :) Название: Re: MSVC 2015 чудит: float -> double Отправлено: ViTech от Июня 27, 2018, 12:55 Мне в винду сейчас лезть далеко, но такие варианты не проверяли:
Код
Цель - повторяемость и стабильность результатов. Посмотреть на ассемблерный код. Посмотреть на d1, d2, d3, d4 в памяти во время отладки, может вывод в поток чудит. И сборка release или debug? Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 14:24 повторяемость 100%, это не рандом. Вывод в поток верен, т.к. в более полном коде из проекта я ещё сравниваю полученное double значение с нужным мне, и первый double проходит проверку, а второй - нет. На release и release+debug symbols работает одинаково неправильно. Я подозреваю, что проблема с оптимизацией RVO и внутренним представлением float. На 64-бит не воспроизводится вероятно потому, что в 64-бит ошибки float меньше.
Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 14:54 GCC в Ubuntu 16.04 работает нормально, d1 и d2 полностью равны
Название: Re: MSVC 2015 чудит: float -> double Отправлено: deMax от Июня 27, 2018, 16:21 В первом случае вы убиваете точность, real(double) -> float -> double, float 24бита на минтиссу 16000000. а у вас 15ый знак
Вопрос, откуда погрешность берется? Попробуйте ручками скалярное произведение посчитать, с типами float, double. Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 16:28 В первом случае вы убиваете точность, real(double) -> float -> double Во втором также. В Qt5 QVector2D принимает и возвращает float. Поэтому и во втором случае идёт преобразование входных double литералов во float, потом dotProduct() считает результат также используя значения float, и возвращает также float! Название: Re: MSVC 2015 чудит: float -> double Отправлено: Igors от Июня 27, 2018, 16:35 А что тут обсуждать? Баг явно, у MSVC они всегда были и будут. Придется отказаться от точного сравнения напр
Код Чисто для спортивного интереса проверить так Код
Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 16:37 deMax Продолжаем мистику! :)
Код
Выхлоп разный! Цитировать 1.00000000000000000000 1.00000000000000355271 Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 16:39 Igors суффикс f не помог. Я проверил - внутри QVector2D данных хранятся правильно и одинаково как в 32-бит, так и в 64-бит версии. Проблема появляется только при вызове функции dotProduct (см. код выше) в 32-бит версии. Когда считаем руками - всё нормально :)
Название: Re: MSVC 2015 чудит: float -> double Отправлено: kuzulis от Июня 27, 2018, 17:50 Запости баг об хреновеньком QVector2D::dotProduct(), если ручками все нормально :)
Название: Re: MSVC 2015 чудит: float -> double Отправлено: Авварон от Июня 27, 2018, 18:25 Igors суффикс f не помог. Я проверил - внутри QVector2D данных хранятся правильно и одинаково как в 32-бит, так и в 64-бит версии. Проблема появляется только при вызове функции dotProduct (см. код выше) в 32-бит версии. Когда считаем руками - всё нормально :) Что дизассемблирование говорит? С мелкомягкого компилятора станется возвращать результат в дабле. Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 19:27 Запости баг об хреновеньком QVector2D::dotProduct(), если ручками все нормально :) Исходники dotProduct() - это копия того что делаю руками: https://code.woboq.org/qt5/qtbase/src/gui/math3d/qvector2d.cpp.html#_ZN9QVector2D10dotProductERKS_S1_ . Проблема явно не в коде как в таковом. Проблема с конпилятором как мне кажется. Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 27, 2018, 19:29 Авварон дизассемблирование пока не смотрел
Название: Re: MSVC 2015 чудит: float -> double Отправлено: ViTech от Июня 28, 2018, 00:18 Цитировать Оптимизирующий компилятор Microsoft (R) C/C++ версии 19.14.26430 для x86 тот же вывод:(C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены. Цитировать 0.00000000810836997545 -1.00000000000000000000 0.00000044584299985218 -1.00000000000000000000 1.00000000000000000000 1.00000000000000000000 1.00000000000000355271 Кусок асма (без оптимизации): Цитировать ; 12 : float f1 = QVector2D::dotProduct(v1, v2); lea edx, DWORD PTR _v2$[ebp] push edx lea eax, DWORD PTR _v1$[ebp] push eax call DWORD PTR __imp_?dotProduct@QVector2D@@SAMABV1@0@Z add esp, 8 fstp DWORD PTR _f1$[ebp] ; 13 : double d1 = f1; cvtss2sd xmm0, DWORD PTR _f1$[ebp] movsd QWORD PTR _d1$[ebp], xmm0 ; 14 : double d2 = QVector2D::dotProduct(v1, v2); lea ecx, DWORD PTR _v2$[ebp] push ecx lea edx, DWORD PTR _v1$[ebp] push edx call DWORD PTR __imp_?dotProduct@QVector2D@@SAMABV1@0@Z add esp, 8 fstp QWORD PTR _d2$[ebp] Я не спец в ассемблере, но настораживают fstp: Цитировать fstp DWORD PTR _f1$[ebp] ... fstp QWORD PTR _d2$[ebp] Похоже в случае с float он снимает со стека float и потом его переводит в double, а в случае с double сразу double и снимает, хотя dotProduct() float возвращает. Может тут собака порылась :). Название: Re: MSVC 2015 чудит: float -> double Отправлено: ViTech от Июня 28, 2018, 00:29 Костыль:
Код
Вывод (без оптимизации): Код: 0.00000000810836997545 -1.00000000000000000000 0.00000044584299985218 -1.00000000000000000000 :) Если включить оптимизацию, то всё возвращается на круги своя. Название: Re: MSVC 2015 чудит: float -> double Отправлено: Авварон от Июня 28, 2018, 01:05 Похоже в случае с float он снимает со стека float и потом его переводит в double, а в случае с double сразу double и снимает, хотя dotProduct() float возвращает. Может тут собака порылась :). Да, так и есть. А получится войти в dotProduct и посмотреть, что он возвращает реально? Мб кутешники криво собрали? (хотя qreal уже давно везде double, а тут явно указан float). То есть версии на 5.2 я бы поставил на косяк версий, а тут даже не знаю... Название: Re: MSVC 2015 чудит: float -> double Отправлено: Igors от Июня 28, 2018, 10:01 Как охотно постится предмет по существу бесполезный :) Что баг компилятора - очевидно по первым строкам стартового поста. Тогда что мы хотим? Найти точно ту (неправильную) команду? Ну допустим даже нашли, проблему это не решит, компилятор не изменить. Найти кукую-то опцию компилятора? Шансов мало и это решается "методом втыка"
Использовать точное сравнение для double можно, но случай это довольно редкий, практически любой код пестрит чем-то типа NEAR_ONE, NEAR_ZERO и.т.п. А конкретно в случае скалярного произведения требование точного совпадения вообще ничем не оправдано. Так может просто найти все вызовы dotProduct и вставить проверки с каким-то epsilon ? Название: Re: MSVC 2015 чудит: float -> double Отправлено: Пантер от Июня 28, 2018, 10:11 Как охотно постится предмет по существу бесполезный :) Что баг компилятора - очевидно по первым строкам стартового поста. Тогда что мы хотим? Найти точно ту (неправильную) команду? Ну допустим даже нашли, проблему это не решит, компилятор не изменить. Найти кукую-то опцию компилятора? Шансов мало и это решается "методом втыка" Если это баг компилятора, то нужно майкрософтовцам об этом сообщить. Но возможно это баг сборки Кьюта. И тема намного полезнее твоих тем по решению твоих проблем.Использовать точное сравнение для double можно, но случай это довольно редкий, практически любой код пестрит чем-то типа NEAR_ONE, NEAR_ZERO и.т.п. А конкретно в случае скалярного произведения требование точного совпадения вообще ничем не оправдано. Так может просто найти все вызовы dotProduct и вставить проверки с каким-то epsilon ? Название: Re: MSVC 2015 чудит: float -> double Отправлено: Alex Custov от Июня 28, 2018, 10:56 В MinGW 5.3.0 на Windows и GCC 5.3.1 на Linux бага нет. И в MinGW и в GCC получается строго 1.00000.... безо всяких хвостов-сюрпризов в мантиссе.
Название: Re: MSVC 2015 чудит: float -> double Отправлено: Igors от Июня 28, 2018, 11:14 В MinGW 5.3.0 на Windows и GCC 5.3.1 на Linux бага нет. И в MinGW и в GCC получается строго 1.00000.... безо всяких хвостов-сюрпризов в мантиссе. Спокойнее к этому относитесь, не тратьте время на всякие проверки. Ну да, это в такой-о версии MSVC не работает, у меня подобных ситуевин было с десяток (если не 2). Это ж чудесный компилятор, там возможно мноогое (что и не снилось стандарту :)). Как говорится "умный гору обойдет". Название: Re: MSVC 2015 чудит: float -> double Отправлено: ViTech от Июня 28, 2018, 13:02 Да, так и есть. А получится войти в dotProduct и посмотреть, что он возвращает реально? Мб кутешники криво собрали? (хотя qreal уже давно везде double, а тут явно указан float). То есть версии на 5.2 я бы поставил на косяк версий, а тут даже не знаю... В debug сборке вычисляется нормально (чистая 1.00000000000000000000). Если упростить пример до: Код
То для него release сборка с оптимизацией выглядит так (если я всё правильно сделал): Код: 4 { Исходник QVector2D::dotProduct (Qt 5.10.0): Код
Асм (Qt 5.10.0 MSVC 2015 32-bit): Код: Qt5Gui!QVector2D::dotProduct [c:\users\qt\work\qt\qtbase\src\gui\math3d\qvector2d.cpp @ 346]: Так что, кто понимает тонкости в этих закорючках, можете расшифровывать :). PS. Для сравнения асм debug сборки: Код: 4 { Код: Qt5Guid!QVector2D::dotProduct [c:\users\qt\work\qt\qtbase\src\gui\math3d\qvector2d.cpp @ 346]: |