티스토리 툴바


Programming/Bugs2009/03/19 17:20


코딩을 할때는 언제나 냉정함을 유지하려 했는데...

2009년 3월 16일날 발생한 한 버그가 나를 완젼히 '조져' 버렸다.

세상에 그렇게 짜증이 날수가 없었다!


이 버그는 사원수로 회전을 구현했을때, 처음 회전은 잘 가다가 회전축이 바뀌는 순간 이상한 축으로 돌아버리는 버그였다.

그래서 나도 같이 돌아버렸다. 한 2시간이면 해결할줄 알았던 버그를 3일이나 끌고간 것이다.





 for( size_t j=1; j<jLimit; ++j )
    D3DXQuaternionMultiply( &( sampleRot[j] ), &( sampleRot[j-1] ), &( sampleRot[j] ) );

이 코드가 정상코드이다.

그럼 버그 코드를 보자.


 for( size_t j=1; j<jLimit; ++j )
    D3DXQuaternionMultiply( &( sampleRot[j] ), &( sampleRot[j] ), &( sampleRot[j-1] ) );



실수의 곱셈은 교환법칙이 성립한다. 하지만 사원수의 곱셈은 좀 다르다. 곱하는 순서가 바뀌면 좀 곤란해진다.

q1 * q2 와 q2 * q1은 엄연히 다르단 말이다!

저렇게 사원수의 회전값을 누적할때 누적순서가 꼬여버리면, 회전이 엿되는것은 물론이고
프로그래머의 마음까지 늘어난 엿가락 마냥 고통으로 흐믈거리게 된다.

Posted by EXXA : Google Docs로 이사 EXXA
Programming/Bugs2009/03/10 20:13

//────────────────────────────────────
// DATE : 2009 03 10 화
// DESC : 지역객체 사용시 주의점
//────────────────────────────────────
struct GeomObject
{
 GeomObject( char* p, char* n, int data = 0 ) : data_(0)
 {
  parent_ = p;
  name_ = n;
  data_ = data;
 }
 GeomObject(){}

 std::string     parent_;
 std::string     name_;

 std::vector< GeomObject* > pChild_;

 int data_;
};


struct GeomObjectManager
{
 void Insert( GeomObject& AAA );
 void Print();

 std::map< std::string, GeomObject > mapGO;
};


void GeomObjectManager::Insert( GeomObject& AAA )
{
 std::map< std::string, GeomObject >::iterator itr;

 itr = mapGO.find( AAA.name_ );
 if( itr == mapGO.end() )  // 없는 인덱스일때
 {
  mapGO[ AAA.name_ ] = AAA; // 인덱스 생성
 }
 else       // 이미 있다면 자신의 이름과 부모이름만 등록
 {
  // 그런데 이름마저 등록되어 있다면! skip. 그렇지 않다면 실행
  if( strcmp( mapGO[ AAA.name_ ].name_.c_str(), AAA.name_.c_str() ) != 0 )
  {
   mapGO[ AAA.name_ ].name_ = AAA.name_;
   mapGO[ AAA.name_ ].parent_ = AAA.parent_;
  }
 }

 // 부모의 차일드 포인터에 자신을 등록
 mapGO[ AAA.parent_ ].pChild_.push_back( &AAA );


}

//────────────────────────────────────
// 문제의 코드
//────────────────────────────────────
manager.Insert ( GeomObject ( "EEE", "AAA" ) );
manager.Insert ( GeomObject ( "EEE", "BBB" ) );
manager.Insert ( GeomObject ( "EEE", "CCC" ) );
manager.Insert ( GeomObject ( "EEE", "DDD" ) );
manager.Insert ( GeomObject ( "root", "EEE" ) );

이 상황에서 Insert는 전혀 기대한 대로 동작을 하지 않는다. 임시객체는 자신의 라인을 벗어나면
사라지는데, Insert에서 그 포인터를 가지고 있게 되기 때문이다.

역시 기본이 중요하다.

Posted by EXXA : Google Docs로 이사 EXXA
Programming/Think2009/03/10 14:45

"거의 사용하지 않는 이상한 기능을 잘도 알고 있다든지, 대다수의 기능을 치장하듯이 써 본다든지 하는 것은 현업 프로그래밍에서는 실속 없는 것들이다." - 2.8절 100페이지.


 어느날 문득 코드를 살펴보면, 무언가 덕지덕지 붙어있다는 느낌을 지울수가 없다. 그럴때마다 떠올릴만한 한 마디인것 같다.
Posted by EXXA : Google Docs로 이사 EXXA