( *(uint32_t*)&a < *(uint32_t*)&b ) ^ ( ( *(uint32_t*)&a & *(uint32_t*)&b ) >> 31 )
요렇게하면 ㅅㅅㅅ 보다 간단하긴 한데, 둘 다의 문제는 음수이면서 두 값이 같을때 결과가 뒤집어 진다는거지.
( *(uint32_t*)&a < *(uint32_t*)&b ) ^ ( ( ( *(uint32_t*)&a & *(uint32_t*)&b ) >> 31 ) ^ ( *(uint32_t*)&a == *(uint32_t*)&b ) );
그래서 귀찮지만 이렇게 해봤는데, 이렇게 해도 a < b 하는 것 보다 2배 빠름 = _ =
근데 rebuild 안하면 조건 변화에 따라 결과값이 웃기게 나오더라. VC++ 멍청한듯. ㅋㅋ
정수 트릭은 2클럭 정도, 부동소수점(float) 비교은 4클럭 정도 쓰는걸로 보여짐.
코드 가독성 보소
얌마 저걸 그냥 쓰냐? 최소 #define 으로 가공해서 쓰지.
더 간단한 방법~ register int32_t k = ( ( *(int32_t*)&a & *(int32_t*)&b ) >> 31 ); if( (*(int32_t*)&a ^ k) < (*(int32_t*)&b ^ k) ) { ... }
signed int는 shift right를 하면 MSB가 끌려내려가는 성질을 이용~ 낄낄
저보다 VC++이 똑똑해요!
그건 간단한게 아니라 data hazard
register 너무 남발하는듯. 그러면 망해유.
이건요? float arr[2]; *(int64_t *)arr ^= (int64_t)((*(int32_t*)arr & *(int32_t*)(arr + 1)) >> 31); if(*(int32_t *)&a < *(int32_t *)&b) { ... }
근데 뭔가 중요한거 잊고 있는거 아님? 부동소수점을 비교하는게 둘 다 "초기화로서 대입된 값"이라면 관계없는데, 이게 "계산된 값"이면 안되지 않음? 부동소수점은 계산했을때 "정확도"를 보증할 수가 없음. 계산된 값이면 무조건 추가 계산해야될건데? if(a==b) 라면, if((a-b)<0.000001) 이런식으로. if(a<b) 같은건 아예 케바케가 되어놔서, if(a<(b-케바케값)) 하거나, 정해진 자릿수 있으면 아예 정수로 *100 *1000 이렇게 계산하고 if문 돌려야할텐데?
그런데 부동소수점을 계산도 없이 하는일은 드물지 않음? 소숫점 자체가 뭔가 계산하고 싶다는 강력한 의지(?) 같은데.
아, 쓰고보니 조금 잘못됐다. if(a==b) 라면, if(절대값(a-b)<0.000001) 이런식.
codesafer//보여짐->보임
그건 동일성(equality, ==) 비교일 때나 그런 거고. 대소일 때는 그냥 해도 돼. 동일성일 때도 정수로 할 수 있어. abs(*(int32_t*)&a - *(int32_t*)&b) < 0x100 이런 식으로 비교하면 되지~
ㄴ 동일성이 안되는거 부터가 문제라니까. 동일성이 안되는데 <,> 이런게 어떻게 되는데? if(3.0 < 3.000000000000001) => true 이런식의 결과가 됨.
근데 뒤늦게 껴들어서 사실 다 이해 못했다. abs(*(int32_t*)&a - *(int32_t*)&b) < 0x100 이게 된다고? 좀 생각해봐야겠다. 읭.
부동 소수점 구조를 살펴보면 정수 표현의 '부호와 절대치(Sign and Magnitude)'랑 최대한 호환되게 만들어놨다는 걸 깨달을 수 있음. 부호 비트를 최상위 비트로 놓고 음수를 1로 표현하는 것도 그렇고, 지수부를 가수부보다 높은 자리에 놓은 것도 그렇고. 따라서 계산 오차를 고려하지 않는다면 걍 정수 비교하듯이 비교해도 된다는 말. 다만 인텔에서는 2의 보수법을 쓰기 때문에 그에 대한 보정은 좀 해줘야 겠지. 왜 부동 소수점 연산을 바로 안하냐면 부동 소수점 연산은 기본적으로
x87 레지스터 스택에서 이루어지고 내부적으로 80비트 부동 소수점 표현으로 고쳐서 연산하기 때문에 비용이 꽤 비쌈. 연산을 수행하기 위해 메모리에서 4바이트 float 값을 읽어들여서 x87 레지스터에 로딩하는 것 자체부터가 느림.
근데 부동 소수점에서 말하는 계산 오차라는 건 결국 가수부의 낮은 비트에서 근사값을 표현하려다 생기는 비트 차 때문에 생기는 건데 (지수부가 다르다면 걍 다른 값이 맞는 거고 ㅇㅇ) 고로 if(abs(*(int32_t *)&a - *(int32_t *)&b) < 0x100) { ... } 식으로 해도 무방하다는 거야.
ㅇㅇㅇ // 동일성이 제대로 안되므로 <, >도 문제가 있을 수 있다는 너의 말도 일리는 있는데, 동일성이야 엄격하게 같은 것을 요구하는 거기 때문에 정확성을 담보로 하는 거라 절대값 취하고 별 생쇼를 다 하지만 실수에서의 대소 비교(<, >)는 원래 대강대강 한다. 애초에 계산 결과가 경계점에 걸려서 대소 관계가 이상해지는 확률 자체도 낮고(동일성 비교일 땐 같은 값도 같은 걸로 못 보는 경우가 생기니 얘기가 달라지지만). 정확한 대소 비교를 하고 싶다면 정수 scale로 가져와서 비교해야지.
맞는말 같은데 뭔가 빠뜨린거 같아 계속 걸리네... 사실 부동소수점 형식에 대해서 정확하게 이해를 하고 있는건 아니라서. 지수부에 정말 문제가 없나? 생각해보면 애시당초 실수를 비교문에 올린다는거부터가 문제같기는 한데...
참, 확률이 낮은건 결코 아님. 그리고 낮다고 해도 무시는 못함. 위에 말했듯이 수학적으로 똑같은 3.0인데, 계산하고 3.0000000001 이런 결과 나오는 건 널리고 널렸음.
그런데 막상 오류 만들려니까 잘 안나오네. 자주 안해서 그런가 읭...
저장소만 갖고 있으면 포인터 트릭을 쓰는데 아무 문제가 없쥐.
입실론 문제는 비트값 자체 비교와 아무 상관이 없어유.
float 의 값 자체가 mutable 한건 아니잖아. 비동질성 문제는 float 간에도 발생하는거고.
배열로 인접정렬 비용이 너무 비싸. 배열로의 가공은 자제하는게 좋앙.
여러번 쓸거면 상관없음. : )
그리고 비트 쉬프트할때 unsigned 랑 singed 랑 은근 차이난다? 테스트 해 보렴 : )