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.

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 on other sites
Define "never fail".

Share on other sites
Quote:
 Original post by SiCraneDefine "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 on other sites
I would use
bool A::operator>( const B &obj )
{
return valueA > obj.valueB
}

or something along those lines

Share on other sites
Quote:
 Original post by yahastuI 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 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 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 on other sites
Quote:
 Original post by Drew_BentonAnyone 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 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 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

1. 1
2. 2
3. 3
Rutin
13
4. 4
5. 5

• 26
• 11
• 9
• 9
• 11
• Forum Statistics

• Total Topics
633699
• Total Posts
3013416
×