Jump to content
  • Advertisement
Sign in to follow this  
yahastu

which is larger?

This topic is 3377 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have two integral variables "a" and "b" having types "A" and "B", respectively. The types may differ in sign and/or storage size. What is the simplest way in C++ to determine if "a > b" that will never fail?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by SiCrane
Define "never fail".


Give the logically correct result regardless of the sign and storage size of the types.

example:

If they are both signed or both unsigned, then casting the smaller type to the larger type before making the comparison should work.

If one of them is signed and the other unsigned, and the signed variable is positive, and the signed variable is not larger than what fits in the unsigned type, then it can be cast to the unsigned type for comparison. Similarly, if its negative, it can be multiplied by -1 before casting and the result can be inverted.

Another case is if one variable is signed and the other unsigned, but the signed value is too large to fit in the unsigned value...in which case the unsigned value can be cast to the signed value.

So, there seem to be a lot of special cases...

Share this post


Link to post
Share on other sites
Quote:
Original post by yahastu
I have two integral variables "a" and "b" having types "A" and "B", respectively. The types may differ in sign and/or storage size. What is the simplest way in C++ to determine if "a > b" that will never fail?


In theory, I believe this should work:

template <typename typea, typename typeb>
bool Is_A_GT_B(typea a, typeb b)
{
if(sizeof(typea) >= sizeof(typeb))
return a > (typea)b;
return (typeb)a > b;
}



Let's consider the cases

A = unsigned __int64
B = char
sizeof A > sizeof B, B is typecast into A's type, comparison of like values

B = unsigned __int64
A = char
sizeof A < sizeof B, A is typecast into B's type, comparison of like values

A = char
B = char
sizeof A >= sizeof B, B is typecast into A's type (irrelevant), comparison of like values

Anyone see any problems?

Share this post


Link to post
Share on other sites
I believe the problem is illustrated by the following test program:
#include <iostream>

int main() {
std::cout << (-7>3000000000u) << '\n'; // This is true! (in my compiler, anyway)
}


Share this post


Link to post
Share on other sites
Here's a comparison of a naive approach and a somewhat better approach (except to eliminate warnings one should use a type trait like make_unsigned on a signed that is greater than or equal to 0.

Also note how the naive approach fails on types that should be the same size (unsinged long/signed long) but differ in signedness (an implicit cast to the larger type should happen anyway if the sizes differ):


#include <iostream>
#include <limits>

template <class A, class B>
bool bad_greater(A a, B b)
{
return a > b;
}

template <class A, class B, bool ASigned, bool BSigned>
struct safe_greater
{
static bool compare(A a, B b) { return a > b; }
};

template <class A, class B>
struct safe_greater<A, B, true, false>
{
static bool compare(A a, B b) {
return !a < 0 && a > b;
}
};

template <class A, class B>
struct safe_greater<A, B, false, true>
{
static bool compare(A a, B b)
{
return b < 0 || a > b;
}
};

template <class A, class B>
bool better_greater(A a, B b)
{
return safe_greater<A, B, std::numeric_limits<A>::is_signed, std::numeric_limits<B>::is_signed>::compare(a, b);
}

#define COMPARE(a, b) std::cout << (a) << " > " << (b) << ": " << bad_greater((a), (b)) << ' ' << better_greater((a), (b))<< '\n'
int main()
{
long l = -1L;
unsigned long ul = std::numeric_limits<unsigned long>::max() - 1UL;
unsigned long other_ul = 437682;
std::cout << std::boolalpha;
COMPARE(l, ul);
COMPARE(ul, l);
COMPARE(other_ul, ul);
COMPARE(ul, other_ul);
}




Share this post


Link to post
Share on other sites
Quote:
Original post by Drew_Benton
Anyone see any problems?


If typea = signed int, typeb = unsigned int, then this would cast the unsigned int to int before comparison, which could result in incorrect result because the unsigned type may be larger than INT_MAX

EDIT: visitor, your "better_greater" function also has this problem.

[Edited by - yahastu on September 14, 2009 3:02:21 PM]

Share this post


Link to post
Share on other sites
Quote:

EDIT: visitor, your "better_greater" function also has this problem.


Can you post a concrete example where this fails. As far as I see no unsafe casts should happen, because types with mixed signness are handled separately. (I may be mistaken, but in case of mixed signness, isn't the signed implicitly cast to unsigned, not the other way round.)

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
Quote:

EDIT: visitor, your "better_greater" function also has this problem.


Can you post a concrete example where this fails. As far as I see no unsafe casts should happen, because types with mixed signness are handled separately. (I may be mistaken, but in case of mixed signness, isn't the signed implicitly cast to unsigned, not the other way round.)


In the following specialized code A is signed and B is unsigned, assume b is greater than MAX_INT, so b will be cast to signed int in order to make the comparison, causing it to wraparound and then "a>b" will evaluate to true, even though b > a.


template <class A, class B>
struct safe_greater<A, B, true, false>
{
static bool compare(A a, B b) {
return !a < 0 && a > b;
}
};




this should fix that problem


template <class A, class B>
struct safe_greater<A, B, true, false>
{
static bool compare(A a, B b) {
if( a < 0 ) return false;
if( b > (B)std::numeric_limits<A>::max() ) return false;
return a > b;
}
};




but this still assumes that the unsigned B type is large enough to hold the largest positive signed value of the A type...which might not be the case

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!