Странное поведение компилятора

stm7583298

Есть вот такой код:

float F( float x ){
long i = * (long *) &x;
float z = * (float *) &i;
return z;

}

float F1( float x ){
long i = * (long* ) &x;
cout << " x = " << x << endl;
float z = * (float*) &i;
cout << " i = " << i << endl;
return z;
}

int main(int argc, char * argv[]) {
float xx = 9.0F;
cout << "F(9) = " << F(xx) << endl;
cout << "F1(9) = " << F1(xx) << endl;
return 0;
}

При компиляции с опцией -O3 первая функция возвращает 0, вторая работает нормально. Если отключить оптимизацию, первая функция тоже работает правильно. Как ее заставить работать со включенной оптимизацией?
Компилятор g++ 4.0.1

Maurog

долго я искал отличия этих двух функций ;
написал бы, что они отличаются только наличием cout =)
вот мой ответ чемберлену:
 
float F_Super( float x ) {
return x;
}

stm7583298

Они действительно отличаются только наличием cout.
Такой ответ Чемберлену не катит

tamusyav

Попробуй поразглядывать асм-листинг... Кстати, результат таких развлечений зависит от компилятора и платформы. Может получиться, что и исключение схлопочешь

Maurog

поподробнее
какие могут быть тут исключения? если даже sizeof(long) == sizeof(float то кто бросит исключение?:)
в данном случае, я так понимаю, sizeof совпадает. а нельзя ли повпихивать куда ни попадя волшебное слово volatile ?

stm7583298

Листинг уже поразглядывал. При включенной оптимизации такое ощущение, что тело первой функции зохавал сотона

vall

почитай что gcc пишет при -Wall, и используй например
union {
long l;
float f;
};

tamusyav

если даже sizeof(long) == sizeof(float то кто бросит исключение?
В этом случае, пожалуй, никто не бросит. Только вот нет гарантии, что sizeof(long) == sizeof(float).

banderon

У меня например
sizeof(int) = 4
sizeof(long int) = 8
sizeof(long long int) = 8
sizeof(float) = 4
sizeof(double) = 8
sizeof(long double) = 16
sizeof(void *) = 8

Так что далеко не всегда совпадает

Maurog

а даже, если разные sizeof, то кто кинет ?:)
я думаю, просто сигнал будет типа сегфолта

tamusyav

А сегфолт не может быть в виде исключения?

banderon

Исключения не кидаются, но результаты странные:
[-O1]
F(9) = 9
x = 9
i = 7109200272258236416
F1(9) = 9
[-O2]
F(9) = 5.88128e-39
x = 9
i = 7109200272258236416
F1(9) = 9
[-O3]
F(9) = 0
x = 9
i = 7109200272258236416
F1(9) = 9

Maurog

у тебя sizeof совпадает ?

stm7583298

Компилятор не ругается при -Wall.
Union делу помогает Спасибо

tamusyav

Читай выше. Но это к делу не относится. Просто от таких финтов оптимизатору башню сносит

Maurog

у тебя sizeof совпадает ?

упс
это я у автора треда спросил

vall

4.1 ругается
лучше обходится более простыми и наглядными средствами.
кстати long лучше заменить на uint32_t так хоть на x86_64 будет работать.

banderon

Порадовало:
 * QA Notice: Package has poor programming practices which may compile
* fine but exhibit random runtime failures.
* q.cpp:6: warning: dereferencing type-punned pointer will break strict-aliasing rules
q.cpp:7: warning: dereferencing type-punned pointer will break strict-aliasing rules
q.cpp:13: warning: dereferencing type-punned pointer will break strict-aliasing rules
q.cpp:15: warning: dereferencing type-punned pointer will break strict-aliasing rules

stm7583298

Да, sizeof у меня совпадает

Realist

Скорей всего дело в выравнивании. При преобразовании указателей друг другу само значение адреса может поменяться. Попробуй печатать значния адреса после приведений.
Вообще такие приведения — опасная штука. Тем более приведение к указателю на такой тип, значения которого вовсе по данному указателю не храняться. Так что просто не надо писать так.
Union`ы спасают положение, но тоже не сильно. Это небезлпасно с точки зрения типов. Мб напишешь, зачем тебе такое нужно, а потом подумаешь над более изящным решением?

stm7583298

Более изящное решение придумать трудновато будет
Тыкие вывеорты с указателями нужны в алгоритме быстрого вычисления обратного квадратного корня

float Q_rsqrt( float x ){
float xhalf = 0.5f*x;
long i = * (long* ) &x;
cerr << i << endl;
i = 0x5f375a86 - (i >> 1);
cerr << i << endl;
x = * (float*) &i;
cerr << i << endl;
x = x * (1.5f - xhalf*x*x);
x = x * (1.5f - xhalf*x*x);
return x;

}

Realist

1. Проверь, что действительно меняется адрес указателя. Напиши результаты.
2. Правильная программа лучше быстрой программы. Сформулируй, а лучше сверься со стандартом, какие предположения и допущения ты делаешь. Вставь assert(sizeof(long)==sizeof(fload и тому подобное.
3. Перейди от Сишного приведения типов к С++: тебе, похоже, нужен reinterpret_cast. Решение с Union в твоем случае — обман системы типов, а не вариативная запись.

tamusyav

Более изящно это делается одной асмовской инструкцией

Maurog

<режим любопытства>
какая инструкция выполняет вычисление обратного квадратного корня ?
</режим любопытства>

tamusyav

Если есть поддержка SSE, то RSQRTSS и RSQRTPS.
Если есть поддержка 3DNow!, то PFRSQRT и PFRSQRT1+PFRCPIT2.

xronik111

+1. Причина — нарушение strict aliasing rules. Поведение такого кода — undefined. Если хочется, чтобы работало, надо либо использовать union, либо -fno-strict-aliasing.
Upd: http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Optimize-Options... -> grep for strict-aliasing

banderon

А кусок кода из Quake III не подойдет?
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
union {
float f;
int i;
} t;
float x2, y;
const float threehalfs = 1.5F;

x2 = number * 0.5F;
t.f = number;
t.i = 0x5f3759df - ( t.i >> 1 ); // what the fuck?
y = t.f;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

//assert( !isnan(y) ); // bk010122 - FPE?
return y;
}

У меня и компилится, и работает одинаково. Вот только результат не очень точный: Q_rsqrt(9) = 0.332953

stm7583298

Это как раз и был кусок кода из Q3, чуть переделанный

evgen5555

в оригинале там не long, а int

stm7583298

А не подскажешь, как подружить GCC с inline assembly SSE?

juliuzz

t.i = 0x5f3759df - ( t.i >> 1 ); // what the fuck?
реально

tokuchu

реально
В смысле не понятно что происходит?
Уже была, кажется, здесь тема про этот алгоритм.

tamusyav

Не-а, извиняйте. Пользуюсь только интеловским и мелкософтовским.
Оставить комментарий
Имя или ник:
Комментарий: