which is larger?

Started by
21 comments, last by Sneftel 14 years, 7 months ago
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?
Advertisement
Define "never fail".
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...
I would use
bool A::operator>( const B &obj )
{
return valueA > obj.valueB
}

or something along those lines
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?
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)}
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);}
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]
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.)
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

This topic is closed to new replies.

Advertisement