Перейти к содержанию
    

DevCpp разный результат вычислений double от x86 x64 и размера проекта

Есть исходник в котором переменные double и int64 - компилирую его при помощи DevCpp

При этом получаю разный результат при компиляции под x86 и x64.

Также замечал, что int64 работал криво в x86.

Ещё есть код выдающий один результат, если компилирую только его

и совершенно другой результат, когда компилирую в составе проекта (при одинаковых входных данных).

Никаких спец библиотек не использую, использую calloc.

от версии DevCpp тоже была зависимость

 

На что грешить: стек, выход за массив, оптимизация?

 

PS: Который день туплю...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вначале обновить gcc и написать версии.

Покрыть вычислительный код юнит-тестами и выяснить где конкретно расхождение.

Помедитировать над асемблерным листингом этого участка.

Если не помогло выложить результаты двух предыдущих шагов сюда.

 

Ну или найти телепата. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А можно глянуть на Ваш код? Если в разную работу double на разных компиляторах и настройках я еще верю, то в int64 - врядли

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#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;
}


Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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) )

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поставил  Code::Blocks 17.12

выдаёт 114, но он только 32 разрядный.

 

А вот Exel как и matlab считает, что ответ 115

TD.xls

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посчитал с фиксированной точкой - там ровно 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);
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Результат вполне ожидаемый. При приведении типа от любого плавающего к целому происходит отбрасывание дробной части (а не округление). Из за того, что точность плавучки не бесконечная, а десятичные дроби точно не представимы в двоичном внутреннем представлении как float так и double, при вычислениях неизбежно накапливаются ошибки округления. Достаточно ошибки в 1 бит в мантисе и результат будет тот, что вы и получили.

 

Самое простое решение - добавить 0.5 перед приведением к u08

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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);
}

И как вообще какой-то компилятор переваривает подобную галиматью??? Хотя-бы потрудитесь читать то, что постите...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 minutes ago, xvr said:

Результат вполне ожидаемый. При приведении типа от любого плавающего к целому происходит отбрасывание дробной части (а не округление). Из за того, что точность плавучки не бесконечная, а десятичные дроби точно не представимы в двоичном внутреннем представлении как float так и double, при вычислениях неизбежно накапливаются ошибки округления. Достаточно ошибки в 1 бит в мантисе и результат будет тот, что вы и получили.

 

Самое простое решение - добавить 0.5 перед приведением к u08

 

Да,при этих данных,  добавление 0.5 даёт правильный ответ 115.

 

Остаётся вопрос - почему на точность влияет компиляция под х86 / х64 ?

Меняется порядок обработки данных?

Почему ошибки подругому накапливаются?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 ] поел движок форума !!!

посмотрите аттач выше

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 минут назад, _4afc_ сказал:

Меняется порядок обработки данных?

Конечно. Каждый компилятор (оптимизатор) волен выбирать такой порядок обработки и команды, который он считает нужным.

Один сделает: x0 * 0.15 + x1 * 0.15

А другой сделает: (x0 + x1) * 0.15

И результат получится чуть-чуть разный. Хоть с double хоть с int64 - без разницы.

И результат ещё будет зависеть и от уровня оптимизации например.

 

PS: А самый умный компилятор соптимизирует все подобные "тесты", оставив от них только printf() с константой в качестве аргумента.

Подумайте почему.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У вас там ключик -ffast-math  случаем не завалялся в аргументах к компилятору?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...