LINUX.ORG.RU

Отключить оптимизации для функции

 ,


1

4

Всем привет, при компиляции с флагом -O0 программа работает идеально, стоит добавить -O1 функция проверки пересечения 2х прямых перестает работать, можно ли отключить оптимизации для этой функции? Код функции:

#define EPS 0.00001f

bool Intersect (glm::vec2 A, glm::vec2 B) {
		glm::vec2 p1 = v1->Pos;
		glm::vec2 p2 = v2->Pos;
		//
		float rTop = (A.y-p1.y)*(p2.x-p1.x)-(A.x-p1.x)*(p2.y-p1.y);
		float sTop = (A.y-p1.y)*(B.x-A.x)-(A.x-p1.x)*(B.y-A.y);
		float rBot = (B.x-A.x)*(p2.y-p1.y)-(B.y-A.y)*(p2.x-p1.x);
		float sBot = (B.x-A.x)*(p2.y-p1.y)-(B.y-A.y)*(p2.x-p1.x);
		//
		if (rBot == 0 || sBot == 0)
			return false;
		//
		float r = rTop/rBot;
		float s = sTop/sBot;

		if (r > EPS && r < 1.0f-EPS && s > EPS && s < 1.0f-EPS)
			return true;

		return false;
	}

есть еще другая функция, через скалярное произведение векторов, но для моей задачи она иногда работает не точно, а эта функция всегда хорошо определяла, есть ли пересечение, или нету.

★★★

стоит добавить -O1 функция проверки пересечения 2х прямых перестает работать

Может таки саму функцию пофиксить?

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

А что с ней не так? вроде все правильно, и работает нормально, оптимизатор что-то не так оптимизирует и все ломает )

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

Ну так сравни значения всех переменных (их тут не так много) для -O0 и -O3, и увидишь, что не так

yoghurt ★★★★★
()

К тому же не понятно, как у тебя v1 и v2 инициализируются из твоего клда

esandmann
()

свалить вину на компилятор всегда успеешь, проверь свой код ещё пять раз, прежде чем отключать оптимизацию.

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

В С++11 есть

[[gnu::optimize("-O0")]]
void foo() {
    ...
}

что стандартно в [[...]], хотя содержание всё ещё implementation-defined.

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

Ещё один горе-разработчик, утверждающий, что компилятор портит его совершенный код. Откуда же вы лезете?

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

«is a non-standard but widely supported preprocessor directive». Но ударение всё таки на non-standard.

Помню, искал список где оно работает/неработает, так вот работает во всех меинстримных компиляторах.

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

Ололо, покажи коНпилер, неподерживающий щит с прагма онс сначала.

nanoolinux ★★★★
()

rBot == 0

А ты я смотрю шютник.

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

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

uber_cat
()

за == с дробными надо делать вон из профессии

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

что все же никак не гарантирует его работу в недалеком далеком будущем

Это будущее наступит сразу после захвата Земли марсианами. А проблемы из-за header guards прут изо всех щелей здесь и сейчас. Комитет давно бы уже стандартизировал какой-нить #once в новом C++, но что у них за борщ в голове пойди догадайся. Спасибо хоть разработчикам компиляторов, которые давно поняли, что проверка на повторный #include решается запоминанием пути к заголовочнику или простым подсчётом его хеш-суммы.

Так что только #pragma once. А если нужно будет поддержка экзотического компилятора, то мои пра-пра-пра-пра-правнуки напишут однострочный скрипт, который повставляет header guards в мои проекты.

Dendy ★★★★★
()
		float rTop = (A.y-p1.y)*(p2.x-p1.x)-(A.x-p1.x)*(p2.y-p1.y);
		float sTop = (A.y-p1.y)*(B.x-A.x)-(A.x-p1.x)*(B.y-A.y);
		float rBot = (B.x-A.x)*(p2.y-p1.y)-(B.y-A.y)*(p2.x-p1.x);
		float sBot = (B.x-A.x)*(p2.y-p1.y)-(B.y-A.y)*(p2.x-p1.x);

сделай отдельные переменные A.y-p1.y и всё остальное. Ну и проверяй их близость.

И вообще формулы должны быть в двух вариантах, либо считаешь y=k0*x+y0, либо x=k1*y+x0, иначе у тебя ерунда получается.

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

проблемы из-за header guards прут изо всех щелей здесь и сейчас

А какие проблемы могут быть от header guards, кроме коллизий имен дефайнов, которые решаются использованием достаточно сложных уникальных имен?

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

мой код работает правильно с любым -On. Т.ч. мне ваши прагмы не нужны.

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

volatile

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

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

А какие проблемы могут быть от header guards, кроме коллизий имен дефайнов, которые решаются использованием достаточно сложных уникальных имен?

Все проблемы из-за того, что программист берёт на себя задачу, которую компилятор умеет решить на 100% безошибочно и к тому же быстрее.

  • Простые макросы, типа CONFIG_H, порождают коллизию.
  • Сложные макросы путём конкатенации цепочки подпроектов: PROJECT_SUBPROJECT_MODULE_SUBMODULE_SHMODULE_H заставляют мозг напрягаться, больше простор для ошибок.
  • Перенос/переименование заголовочника должно сопровождаться переименованием макроса, о чём часто забывают.
  • Несовпадение #ifndef и #define из-за опечаток, тоже достаточно типично.
  • Никакой защиты от копирования заголовочников.
  • Потенциальная возможность нарушить семантику путём вставки кода до #ifndef и после #endif.
  • Ну и конечно же раздутие текста программы лишними буквами, несущими ровно ноль информации для человека, а значит затрудняющими чтение.

У header guards нет области применения, в других языках основанных на единицах трансляции уже давно от этого избавились: Java, JavaScript, Python, Objective-C, D, etc.

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

Да, извиняюсь за офтоп, если есть желание обсудить, то лучше продолжить в отдельной теме.

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

В принципе, согласен. Но если уж избавляться от header guards, то тогда нужно выкидывать вместе с ними и весь препроцессор, и заменять чем-то менее универсальным и более продвинутым.

kravich ★★★★
()

Эта функция ничего хорошо не определяет, можно сделать абсолютно точно. Пусть прямая задается вектором и точкой. Возьмем вектора, (x1, y1) и (x2, y2), и попробуем определить их параллельность. Для этого один повернем на 90 градусов( (x2, y2) -> (-y2, x2) ) и сравним скалярное произведение с нулем.

bool collinear_d(vector a, vector b) {
   double l = a.y * b.x;
   double r = a.x * b.y;
   double threshold = std::numeric_limits<double>::epsilon() * 3.0 * (fabs(l) + fabs(r));
   if (l - r > threshold || l - r < -threshold) {
      return false;
   } else {
      return true;
   }
}

Если эта штука вернула false, то вектора точно не коллинеарны, true означает ответ «не знаю», в этом случае нужно перейти к рациональной арифметике и посчитать точный ответ в ней.

Как посчитать значение порога? Примерно так

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

на счет if (rBot == 0 || sBot == 0) это реализация не моя, я ее взял у чувака, который реализовывал алгоритм, который мне нужен, я делаю вообще через скалярное произведение векторов, но моя функция иногда не правильно работает, попробовал эту функцию, все работает норм. Вот реализация моей функции:

	bool Intersect (Edge *e, float &t) {
		glm::vec2 a = v1->Pos;
		glm::vec2 b = v2->Pos;
		glm::vec2 c = e->v1->Pos;
		glm::vec2 d = e->v2->Pos;
		glm::vec2 n = glm::vec2((d-c).y, (c-d).x);

		float denom = glm::dot(n, b-a);

		if (denom == 0.0f)
			return false;

		float num = glm::dot(n, a-c);
		t = -num/denom;
		return true;
	}
Int64 ★★★
() автор топика
Последнее исправление: Int64 (всего исправлений: 1)
Ответ на: комментарий от Int64

Как тебе уже говорили, делать такое

if (denom == 0.0f)
нельзя, так как ты сравниваешь float значения, и из-за особенностей представления чисел с плавающей точкой твоя проверка может фейлится даже если значение denom по сути нулевое.

Делай проверки с необходимой точностью:

if( fabs(0.0f - denom) < 0.00001f )
    return false;

В общем, читай до просветления, особенно пункт 4.5

kravich ★★★★
()
Последнее исправление: kravich (всего исправлений: 2)
Ответ на: комментарий от anonymous

Ещё один горе-разработчик, утверждающий, что компилятор портит его совершенный код. Откуда же вы лезете?

Из багзиллы GCC, в которой баги висят десятилетиями. очевидно.

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

Ты забыл ссылку на баг, соответствующий данному топику.

Данному топику соответствует баг в ДНК ТС. Но это не отменяет того факта, что в gcc багов хоть жопой жуй.

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

так, уважаемый, программирование ≠ математика. В том смысле, что float это НЕ ℝ. Float нельзя сравнивать на (не)равенство.

float denom = glm::dot(n, b-a);

t = -num/denom;

ну а что внутри dot()?

Ответь на вопрос: Какой геометрический смысл ситуации, когда denom находится в малой окрестности нуля?

Очевидно, это особый случай, и его надо обработать отдельно. И выясни, КАКАЯ окрестность, в компьютере нет бесконечно малых, есть просто малые числа. Но они имеют конкретное значение, и если их считать равными нулю, программа будет работать неправильно(т.к. бесконечно малых нет).

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

сделал так:

template <typename T>
inline bool feq (T a, T b) {
	return  a >= b-numeric_limits<T>::epsilon() &&
		a <= b+numeric_limits<T>::epsilon();
}

...
if (fcmp<float>(denom, 0.0f)) return false;

когда denom = 0, то векторы либо параллельны либо коллинеарны.
Функция dot - это скалярное произведение векторов. Уравнение прямой использую это: P(t) = a+t(b-a), поэтому ищу параметр t по этой функции, и уже потом можно найти точку пересечения.
Не понимаю зачем оскорблять людей, что у меня ошибка в ДНК, и что мне нужно идти вон из профессии, я давно программирую, и для меня это хобби, по специальности я инженер связи, и учился я сам, поэтому некоторых элементарных вещей, которые преподают в университете по программированию не знаю (как работает float например, сейчас разбираюсь с этим). Как будто вы сразу начали в этом всем хорошо разбираться.

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

ну в двух словах, float это не число в обычном смысле этого слова. Это вроде комплексного числа, f=x+σy, здесь σ=numeric_limits, у тебя FLT_EPSILON = 1/10⁵. А вот значение y НЕИЗВЕСТНО, и может быть ЛЮБЫМ, от 0, до 1. Т.о. вычитая из одного float другой(такой же) float, ты получаешь ЛЮБОЙ результат. Ситуация эквивалентна делению нуля на ноль, за той разницей, что при делении на ноль возникает исключение, а тут — не возникает. Получается НЕ ИМЕЮЩИЙ СМЫСЛА результат.

И ничего ты тут своим EPSILON не исправишь.

Сам же видишь, что результат зависит от флагов компиляции, погоды на Марсе, и чёрт его знает чего.

Ошибка как обычно в преждевременной оптимизации. Ты точно хотел найти пересечение двух прямых? Нет, уверен, речь про отрезки. Которые могут пересекаться где-то в Over9000 километров от интересующей тебя области пространства. Есть два решения:

1. считать со сверхвысокой точностью, что-бы выяснить, что пересекаются в Over9000 км, и не считать это пересечением.

2. считать с нормальной точностью, но перед вычислением точки пересечения сначала выяснить пересечение с границами области. Возможно твои _отрезки_ если и пересекаются, то _за_ границей.

Ну и нужно помнить, что при вычитании _близких_ чисел результат недостоверен. Как и при сложении/вычитании _разных_ чисел(число с малым модулем поглощается без следа большим). При умножении любых двух чисел бесследно исчезает ровно половина значащих битов, т.к. разрядность мантиссы результата такая же, а у произведения бит должно быть вдвое больше.

С делением всё совсем печально, не работают даже простые выражения вроде 5*0.2≠1. Правильно работают только целые числа, и числа со знаменателем вида 2ⁿ (вроде ¾, если они не очень отличаются величиной).

PS: FLT_EPSILON обычно спасает, но надо помнить, что это погрешность ОДНОЙ операции над примерно равными числами.

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

в стандарте MSVC

Емулек, ты дебил.

тег «сарказм» в дефолте. Почитай описание этих «багов», ссылку я дал. То, что я видел — по нормальному стандарту — UB. А «баг» это только для тех, у кого MSVC головного мозга.

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