LINUX.ORG.RU

[GCC/ANSI-C89][НЁХ] Глюки с умножением о_О

 


0

1

Здравствуй, ЛОР. Долго и упорно прогаю одну хрень, мои мозги уже давно поплавились, и похоже, что уже начал плавиться процессор.
Суть: Есть одна переменная (double), в ней лежит значение. К этой переменной домножается значение, возвращённое одной функцией. Значения достаточно адекватные, но если сделать var*=func(); то в неё записывается НЁХ порядка десяти в десятой степени.

fsfgds.c

dvalue=(double)getInt(routes,N,i,j);
dvalue=dvalue*getDouble(tau,N,i,j);
tau_ij+=dvalue;

gdb fsfgds

(gdb) break 132 if k==0 && x==1 && y==5
Breakpoint 1 at 0x8048d26: file fsfgds.c, line 132.
(gdb) run first.map
Starting program: /home/northsoft/fsfgds/fsfgds first.map

Breakpoint 1, main (argc=2, argv=0xbffbdb74, env=0xbffbdb80) at fsfgds.c:132
132                                                             dvalue=dvalue*getDouble(tau,N,i,j);
(gdb) printf "old dvalue=%f (%e), multiplier=%f (%e)\n", dvalue, dvalue, getDouble(tau,N,i,j), getDouble(tau,N,i,j)
old dvalue=192.000000 (1.920000e+02), multiplier=22.062000 (2.206200e+01)
(gdb) next
133                                                             tau_ij+=dvalue;
(gdb) printf "new dvalue=%f (%e)\n", dvalue, dvalue
new dvalue=31246281216.000000 (3.124628e+10)
(gdb) quit
The program is running.  Exit anyway? (y or n) y

dvalue имеет тип double, getDouble — тоже. :)
Приложение однопоточно.
Каждый раз НЁХ разная, хотя исходные данные каждый раз одинаковы, getDouble просто берёт число из матрицы.
Ума не приложу, в чём может быть фишка.

For your consideration:
Linux 2.6.31.13-desktop-1mnb #1 SMP
GNU gdb 6.8-7mdv2010.0 (Mandriva Linux release 2010.0)
gcc версия 4.4.1 (GCC)

Кто-нибудь, пожалуйста, объясните мне, ЧЯДНТ?!?!?!

Вы бы не могли вместо вывода GDB привести результат выполнения такого кода:

double d;

d=(double)getInt(routes,N,i,j);
printf("getInt -> %lf\n", d);
dvalue=d;

d=getDouble(tau,N,i,j);
printf("getDouble -> %lf\n", d);
dvalue=dvalue*d;

printf("old dvalue -> %lf\n", dvalue);
printf("old tau_ij -> %lf\n", tau_ij);

tau_ij+=dvalue;

printf("new dvalue -> %lf\n", dvalue);
printf("new tau_ij -> %lf\n", tau_ij);

anonymous
()

Значение из функции записываю в отдельную переменную, смотрю в отладчике значение функции до и после отладки, каждый раз отладчик выдаёт адекватное значение, а в переменную пишется та самая НЁХ.

dvalue=(double)getInt(routes,N,i,j);
dvalue2=getDouble(tau,N,i,j);
dvalue=dvalue*dvalue2;

gdb fsfgds

(gdb) break 132 if k==0 && x==1 && y==5
Breakpoint 1 at 0x8048d35: file fsfgds.c, line 132.
(gdb) run first.map
Starting program: /home/northsoft/fsfgds/fsfgds first.map

Breakpoint 1, main (argc=2, argv=0xbf979784, env=0xbf979790) at fsfgds.c:132
132                                                             dvalue2=getDouble(tau,N,i,j);
(gdb) printf "%f\n", getDouble(tau,N,i,j)
22.062000
(gdb) next
133                                                             dvalue=dvalue*dvalue2;
(gdb) printf "%f\n", getDouble(tau,N,i,j)
22.062000
(gdb) printf "%f\n", dvalue2
159066936.000000
(gdb)

Northsoft ★★
() автор топика
Ответ на: комментарий от guilder

Да, так как использую exp и log. #include <math.h> в комплекте.

Northsoft ★★
() автор топика
Ответ на: комментарий от anonymous
getInt -> 192.000000
getDouble -> 163744568.000000
old dvalue -> 31438957056.000000
old tau_ij -> 0.000000
new dvalue -> 31438957056.000000
new tau_ij -> 31438957056.000000

Что самое интересное, GDB опять-таки выводит годное значение, каждый раз. А вывод программы каждый раз разный (числа getDouble'ом возвращаются каждый раз разные).

double getDouble(double *array, int dimension, int x, int y){
        double *ret;
        if(array==NULL) return 0;
        ret=array;
        ret+=dimension*x+y;
        return *ret;
}

Northsoft ★★
() автор топика
Ответ на: комментарий от Northsoft

Я не знаю как работает printf в gdb, ибо всегда пользовался просто 'p'. в программе поставь %lf обязательно, иначе мусор будет печататься. Еще прогони через valgrind.

Reset ★★★★★
()
Ответ на: комментарий от Reset

Печаль в том, что программа это не выводит, а использует в расчётах дальше, в итоге получаю кучу NaNов.

Northsoft ★★
() автор топика
Ответ на: комментарий от Northsoft
#include <float.h>

#ifdef WIN32
#include <windows.h>
extern "C" void set_fpe_except()
{
  int cw = _controlfp (0, 0);
  cw &= ~ (EM_OVERFLOW | EM_UNDERFLOW | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID
);
  _controlfp (cw, MCW_EM);
}
#else
extern "C" void set_fpe_except()
{
  unsigned m = 0;
  asm ("fstcw %0" : : "m" (*&m) );
  asm ("fwait");
  m ^= 0x1f; //turn on all exceptions!
  m |= (1 << 8);
  m |= (1 << 9);
  m ^= (1 << 8);
  m ^= (1 << 9);
  m |= (1 << 9); // double precision
  asm ("fldcw %0" : : "m" (*&m) );
  asm ("fwait");

  m = 1 << 12;
  asm ("ldmxcsr %0" : : "m" (*&m) );
}
#endif
Reset ★★★★★
()
Ответ на: комментарий от Northsoft

тут что-то очень не тек. что есть array? почему ты возвращаех поинтер на переменную со стека?

double
getDouble(double *array, int dimension, int x, int y)
{
        return *array + dimension*x+y;
}
beastie ★★★★★
()
Ответ на: комментарий от Reset

Если флаги fpu грохнут прогу на генерации NaNа, то я уже отловил первый из них, экспериментально (k==0 && x==1 && y==5)

Northsoft ★★
() автор топика
Ответ на: комментарий от Northsoft

Это выставляет флаги. При любой нежелательной работе с floating point прога рушится. Проверено на win32/win64, linux x86/x86_64

Reset ★★★★★
()
Ответ на: комментарий от beastie

array - double* tau=malloc(N*N*sizeof(double)), memset(tau,0,N*N*sizeof(double))
Если бы я хотел вернуть указатель на переменную со стека, то я бы писал &(array+dimension*x+y). В Вашем коде, как я понимаю, происходит возврат первого элемента массива, к которому прибавлен dimension*x+y. В моём коде возвращается *(array+dimension*x+y), или, проще говоря, array[dimension*x+y]

Northsoft ★★
() автор топика
Ответ на: комментарий от Reset

Спасибо за исходник, прога рухнула по SIGFPE при обращении к exp(), конец немного предсказуем. :) и всё же, в чём может быть фишка, если GDB'вский printf выдаёт адекватное значение, но в переменную пишется бред?

Northsoft ★★
() автор топика
Ответ на: комментарий от Reset

Ругается только на утечки памяти, я пока не дописал до конца, чтоб можно было спокойно деаллокать память)

Northsoft ★★
() автор топика
Ответ на: комментарий от Reset

Вот в том-то и дело, что нет. Я очень тщательно работаю над данными, прежде чем их использовать. Мемсеты, несколькоэтажные циклы по инициализации матриц, всё как положено. Думаю, тут должна быть другая зацепка - вывод GDB.

Northsoft ★★
() автор топика
Ответ на: комментарий от Northsoft

И в этом выводе проблем тоже нет никаких! Все правильно!

anonymous
()
Ответ на: комментарий от anonymous

> getDouble -> 163744568.000000
Там значение должно быть порядка двадцати (см. вывод GDB)

(gdb) printf «old dvalue=%f (%e), multiplier=%f (%e)\n», dvalue, dvalue, getDouble(tau,N,i,j), getDouble(tau,N,i,j)

old dvalue=192.000000 (1.920000e+02), multiplier=22.062000 (2.206200e+01)


Multiplier - значение от getDouble

Northsoft ★★
() автор топика
Ответ на: комментарий от Northsoft

Ну, теперь вы знаете где ошибка - некорректный метод getDouble! Каким бы он ни казался правильным, все же он неправильный в данном контексте :)

anonymous
()
Ответ на: комментарий от Northsoft

то, что getDouble в отладчике выдает верный ответ - случайность. Где-то что-то не перетерлось просто.

anonymous
()
Ответ на: комментарий от anonymous

Вы это логически обосновать можете? Каждый раз (!) чтобы выдавался верный ответ в отладчике - не слишком ли крутая «случайность»? :)

Northsoft ★★
() автор топика
Ответ на: комментарий от Northsoft

Только что протестировал ваши методы работы с матрицами - у меня все работает правильно. Не могли бы вы запостить сюда весь код?

anonymous
()
Ответ на: комментарий от Northsoft

Просто получается - того, что вы запостили не достаточно для того, чтоб воспроизвести проблему.

anonymous
()
Ответ на: комментарий от Reset

Убей себя об стену - спаси мир: gcc -Wall

Всё оказалось очень тупо и уныло. Исходник состоит из двух файлов, злополучная getDouble объявлена в другом исходнике. По уму должна была быть записана в хеадер, но записана не была, по моей собственной тупости. Первая же компиляция со всеми предупреждениями меня ткнула мордой в то, что функция getDouble объявлена неявно.
Прости, ЛОР...
Reset, ты - сам знаешь кто :) спасибо за помощь,твой исходник схоронил. Добра тебе и удачи во всём. Вива ла Мандрива. :)
anonymous, ты, как всегда, неотразим и бесподобен. Спасибо за посильное участие, да пребудет с тобою Легион.

Northsoft ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.