_4afc_ 25 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба Есть исходник в котором переменные double и int64 - компилирую его при помощи DevCpp При этом получаю разный результат при компиляции под x86 и x64. Также замечал, что int64 работал криво в x86. Ещё есть код выдающий один результат, если компилирую только его и совершенно другой результат, когда компилирую в составе проекта (при одинаковых входных данных). Никаких спец библиотек не использую, использую calloc. от версии DevCpp тоже была зависимость На что грешить: стек, выход за массив, оптимизация? PS: Который день туплю... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба Вначале обновить gcc и написать версии. Покрыть вычислительный код юнит-тестами и выяснить где конкретно расхождение. Помедитировать над асемблерным листингом этого участка. Если не помогло выложить результаты двух предыдущих шагов сюда. Ну или найти телепата. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mikl74 0 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба А можно глянуть на Ваш код? Если в разную работу double на разных компиляторах и настройках я еще верю, то в int64 - врядли Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба 5 hours ago, mikl74 said: А можно глянуть на Ваш код? Если в разную работу double на разных компиляторах и настройках я еще верю, то в int64 - врядли int64 пока не нашёл в каком проекте, а вот double - пожалуйста: Quote x32: Test1 Float (x32 = 114, x64=114) 114 Test2 Float (x32 = 114, x64=115) 114 - original source Test3 Double (x32 = 114, x64=115) 114 Test4 Double (x32 = 114, x64=115) 114 x64: Test1 Float (x32 = 114, x64=114) 114 Test2 Float (x32 = 114, x64=115) 115 - original source Test3 Double (x32 = 114, x64=115) 115 Test4 Double (x32 = 114, x64=115) 115 Компилятор Dev-Cpp 5.11 TDM-GCC 4.9.2 Setup (48МБ) TestDouble1.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба #include <stdio.h> #include <stdlib.h> //-------------------------- #define u08 unsigned char #define u32 unsigned int #define f32 float #define f64 double //-------------------------- u32 DD[16]={112,111,110,109,115,115,115,115,115,116,117,118,114,115,117,118}; //-------------------------- //-------------------------- u08 test1(void) { f32 T[4]; u32 i; u32 N=0; for (i = 0,N=0; i < 4; i++) { T = 0; T += DD[N++] * 0.15; T += DD[N++] * 0.35; T += DD[N++] * 0.35; T += DD[N++] * 0.15; } return (u08)(T[0]*0.15+T[1]*0.35+T[2]*0.35+T[3]*0.15); } //-------------------------- u08 test2(void) { f32 K[4] = {0.15, 0.35, 0.35, 0.15}; f32 T[4]; u32 i; u32 N=0; for (i=0; i < 4; i++) { T = 0; T += DD[N++]*K[0]; T += DD[N++]*K[1]; T += DD[N++]*K[2]; T += DD[N++]*K[3]; } return (u08)( T[0]*K[0]+ T[1]*K[1]+ T[2]*K[2]+ T[3]*K[3]); } u08 test3(void) { f64 T[4]; u32 i; u32 N=0; for (i = 0,N=0; i < 4; i++) { T = 0; T += DD[N++] * 0.15; T += DD[N++] * 0.35; T += DD[N++] * 0.35; T += DD[N++] * 0.15; } return (u08)(T[0]*0.15+T[1]*0.35+T[2]*0.35+T[3]*0.15); } //-------------------------- u08 test4(void) { f32 K[4] = {0.15, 0.35, 0.35, 0.15}; f64 T[4]; u32 i; u32 N=0; for (i=0; i < 4; i++) { T = 0; T += DD[N++]*K[0]; T += DD[N++]*K[1]; T += DD[N++]*K[2]; T += DD[N++]*K[3]; } return (u08)( T[0]*K[0]+ T[1]*K[1]+ T[2]*K[2]+ T[3]*K[3]); } //-------------------------- int main(int argc, char *argv[]) { u08 F1 = test1(); printf("Test1 Float (x32 = 114, x64=114) %8d \n",F1 ); u08 F2 = test2(); printf("Test2 Float (x32 = 114, x64=115) %8d - original source\n",F2 ); u08 D3 = test3(); printf("Test3 Double (x32 = 114, x64=115) %8d \n",D3 ); u08 D4 = test4(); printf("Test4 Double (x32 = 114, x64=115) %8d \n",D4 ); //---- printf("\n\n\n\n",D4 ); system("pause"); return 0; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба Matlab считает, что правильный ответ 115 clc clear DD=single([112,111,110,109,115,115,115,115,115,116,117,118,114,115,117,118]); K=single([0.15, 0.35, 0.35, 0.15]); T=single([0,0,0, 0]); N=1; for i = 1:4 T(i)=0; T(i)=T(i)+DD(N)*K(1);N=N+1; T(i)=T(i)+DD(N)*K(2);N=N+1; T(i)=T(i)+DD(N)*K(3);N=N+1; T(i)=T(i)+DD(N)*K(4);N=N+1; end D=uint8( T(1)*K(1)+ T(2)*K(2)+T(3)*K(3)+T(4)*K(4) ) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба Поставил Code::Blocks 17.12 выдаёт 114, но он только 32 разрядный. А вот Exel как и matlab считает, что ответ 115 TD.xls Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 9 октября, 2018 Опубликовано 9 октября, 2018 · Жалоба Посчитал с фиксированной точкой - там ровно 115.0000, хоть х32 хоть х64... u08 test5(void) { u32 K[4] = {15, 35, 35, 15}; u32 T[4]; u32 i; u32 N=0; for (i=0; i < 4; i++) { T[i] = 0; T[i] += DD[N++]*K[0]; T[i] += DD[N++]*K[1]; T[i] += DD[N++]*K[2]; T[i] += DD[N++]*K[3]; } return (u08)(( T[0]*K[0]+ T[1]*K[1]+ T[2]*K[2]+ T[3]*K[3]+5000)/10000); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба Результат вполне ожидаемый. При приведении типа от любого плавающего к целому происходит отбрасывание дробной части (а не округление). Из за того, что точность плавучки не бесконечная, а десятичные дроби точно не представимы в двоичном внутреннем представлении как float так и double, при вычислениях неизбежно накапливаются ошибки округления. Достаточно ошибки в 1 бит в мантисе и результат будет тот, что вы и получили. Самое простое решение - добавить 0.5 перед приведением к u08 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 203 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 9 часов назад, _4afc_ сказал: Скрыть контент u08 test1(void) { f32 T[4]; u32 i; u32 N=0; for (i = 0,N=0; i < 4; i++) { T = 0; T += DD[N++] * 0.15; T += DD[N++] * 0.35; T += DD[N++] * 0.35; T += DD[N++] * 0.15; } return (u08)(T[0]*0.15+T[1]*0.35+T[2]*0.35+T[3]*0.15);} И как вообще какой-то компилятор переваривает подобную галиматью??? Хотя-бы потрудитесь читать то, что постите... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 9 minutes ago, xvr said: Результат вполне ожидаемый. При приведении типа от любого плавающего к целому происходит отбрасывание дробной части (а не округление). Из за того, что точность плавучки не бесконечная, а десятичные дроби точно не представимы в двоичном внутреннем представлении как float так и double, при вычислениях неизбежно накапливаются ошибки округления. Достаточно ошибки в 1 бит в мантисе и результат будет тот, что вы и получили. Самое простое решение - добавить 0.5 перед приведением к u08 Да,при этих данных, добавление 0.5 даёт правильный ответ 115. Остаётся вопрос - почему на точность влияет компиляция под х86 / х64 ? Меняется порядок обработки данных? Почему ошибки подругому накапливаются? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 3 minutes ago, jcxz said: И как вообще какой-то компилятор переваривает подобную галиматью??? Какой компилятор позволяет использовать массив (T) как указатель (T+=)? И ещё при этом присваивать ему значение (T=0)? Такое вообще не должно скомпилиться. Не надо сказки рассказывать. Мда, П Р О С Р А Л И Х О Р О Ш И Й Ф О Р У М ! ! ! я постил u08 test2(void) { f32 K[4] = {0.15, 0.35, 0.35, 0.15}; f32 T[4]; u32 i; u32 N=0; for (i=0; i < 4; i++) { T[i] = 0; T[i] += DD[N++]*K[0]; T[i] += DD[N++]*K[1]; T[i] += DD[N++]*K[2]; T[i] += DD[N++]*K[3]; } return (u08)( T[0]*K[0]+ T[1]*K[1]+ T[2]*K[2]+ T[3]*K[3]+0.5); } [ i ] поел движок форума !!! посмотрите аттач выше Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 203 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 17 минут назад, _4afc_ сказал: Меняется порядок обработки данных? Конечно. Каждый компилятор (оптимизатор) волен выбирать такой порядок обработки и команды, который он считает нужным. Один сделает: x0 * 0.15 + x1 * 0.15 А другой сделает: (x0 + x1) * 0.15 И результат получится чуть-чуть разный. Хоть с double хоть с int64 - без разницы. И результат ещё будет зависеть и от уровня оптимизации например. PS: А самый умный компилятор соптимизирует все подобные "тесты", оставив от них только printf() с константой в качестве аргумента. Подумайте почему. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба У вас там ключик -ffast-math случаем не завалялся в аргументах к компилятору? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба дел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться