greatest of two numbers

B

Ben Bacarisse

James Fang said:
How to find the greatest of 2 numbers without using relational
operators ?
Actually there's a simpler solution: you can use an array, and use the
array index istead of the relational operators.

int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[(a-b)&0x80000000];
}

Broken, but it does suggest a better way and does show why these
questions are so daft. Ruling out relational operators rules out a
reasonable branch-less solution (in C99 using compound literals):

((int [2]){a, b})[b > a]
 
J

James Kuyper

James Fang wrote:
....
Actually there's a simpler solution: you can use an array, and use the
array index istead of the relational operators.

int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[(a-b)&0x80000000];
}

There are several problems with that approach. First of all, the mask
that you're using assumes a particular size for 'int' - that makes it
rather unportable. (UINT_MAX/2+1U) would be more portable. However, it
still wouldn't be perfect; it assumes that the sign bit of 'int' is
stored in the same location as the high-order bit of unsigned int, which
is a much more portable assumption, but technically the C standard
allows the corresponding bit of the unsigned type to be a padding bit.
Much more serious is the biggest problem: if a is less than b, your code
subscripts a 2-element array with 0x80000000!

That last item can be fixed, in several different ways. The simplest is:

return array[(a-b)&(UINT_MAX/X+1U) != 0];
also, you can make use of the C system stack to get rid of extra
memory space:

int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
// so integer b is stored in high address.

The C standard imposes no such requirement. That's an
implementation-specific detail.
 
J

James Fang

James Fang wrote, On 08/12/07 04:23:


On Dec 7, 1:33 pm, (e-mail address removed) wrote:
Hi all,
The following question is asked frequently in interviews
How to find the greatest of 2 numbers without using relational
operators ?
the solution i have seen is
( a+b + abs(a-b) ) /2 ;
is there any better solution than this ....?????
In your solution there's an overflow issue.
Actually there's a simpler solution: you can use an array, and use the
array index istead of the relational operators.
int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[(a-b)&0x80000000];
}

Did you actually test this piece of rubbish? When I try it I always get
the value of a. I'm really not sure how it is giving me that since the
code is so broken. Just to show you how bad I've added a bit of
diagnostic and here it is...

markg@brenda:~$ cat t.c
#include<stdio.h>

int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
printf("%d\n",(a-b)&0x80000000);
return array[(a-b)&0x80000000];

}

int main(void)
{
printf("%d\n",max(1,2));
return 0;}

markg@brenda:~$ gcc -ansi -Wall -Wextra -O t.c
markg@brenda:~$ ./a.out
-2147483648
1
markg@brenda:~$

Obviously the index is just a little outside the array.

C does not have a system stack. Your implementation might, but equally
well it might not work as you expect.

Or they are passed in registers (if you take the address then obviously
it has to allocate a memory location), or the stack might not grow in
the direction you expect, or the parameters might be pushed left to right....

int might not be 32 bits. It invokes undefined behaviour if you take a
pointer to a, add 1 to it, and dereference it.


Sorry, I've made a mistake, the second implementation should be:
int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
// so integer b is stored in high address.
return *(&a+((a-b)&0x80000000>>31));
}

No, the second implementation should be erased not corrected, and anyone
who thinks it is valid needs to learn C. The first could be corrected as
an intellectual exercise, but should never be used in real life.

Actually, I just missed one shift operation in the max function
because the code was written in a hurry in the bbs reply, attached
below is the corrected function int max(int,int).

My code is directly written in the bbs reply, the purpose of my code
is to illustrate new idea and algorithm, rather than help sb directly
do copy&paste job. The entire execution code is pasted below, it was
compiled with gcc and had basic functionality test on win32 system.


#include <stdio.h>

int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[((a-b)&0x80000000)>>31];
}

int main()
{
printf("%d\n",max(-1,100));
printf("%d\n",max(10000,100));
printf("%d\n",max(99,99));
getchar();
}
 
J

James Fang

James Fang wrote:

...
Actually there's a simpler solution: you can use an array, and use the
array index istead of the relational operators.
int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[(a-b)&0x80000000];
}

There are several problems with that approach. First of all, the mask
that you're using assumes a particular size for 'int' - that makes it
rather unportable. (UINT_MAX/2+1U) would be more portable. However, it
still wouldn't be perfect; it assumes that the sign bit of 'int' is
stored in the same location as the high-order bit of unsigned int, which
is a much more portable assumption, but technically the C standard
allows the corresponding bit of the unsigned type to be a padding bit.
Much more serious is the biggest problem: if a is less than b, your code
subscripts a 2-element array with 0x80000000!

That last item can be fixed, in several different ways. The simplest is:

return array[(a-b)&(UINT_MAX/X+1U) != 0];
also, you can make use of the C system stack to get rid of extra
memory space:
int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
// so integer b is stored in high address.

The C standard imposes no such requirement. That's an
implementation-specific detail.

Thanks for your correction. It's surely a more portable implementation
to use system defines.

BTW, since "!=" is also in the Relational Operator Set which is also
disatisfied with the question requirement, a better way may be like
below:
int get_max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[( (a-b)& (UINT_MAX/2+1U) ) >>
((sizeof(int)*8)-1)];
}
int main()
{
printf("%d\n",get_max(-190,-100));
printf("%d\n",get_max(10000,100));
printf("%d\n",get_max(99,199));
}

For the sign bit assumption, can we use a serios of macro to control
it?

Anyway, in engineering practice, the best solution for this max impl
is to use the Relational Operators.
 
P

ptkmartin

Thanks for your correction...

int get_max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[( (a-b)& (UINT_MAX/2+1U) ) >>
((sizeof(int)*8)-1)];}

int main()
{
printf("%d\n",get_max(-190,-100));
printf("%d\n",get_max(10000,100));
printf("%d\n",get_max(99,199));

}

Still wrong. With your code,
printf("%d
\n",get_max(2147483647,-1));
will print -1 as the answer.

Your entire attempt is stupid, and the OP's requirement
is stupid. Your whole attempt is pointless,
and encourages stupid programming.
 
C

CBFalconer

James said:
.... snip ...

My code is directly written in the bbs reply, the purpose of my code
is to illustrate new idea and algorithm, rather than help sb directly
do copy&paste job. The entire execution code is pasted below, it was
compiled with gcc and had basic functionality test on win32 system.

#include <stdio.h>

int max(int a,int b) {
int array[2];
array[0]=a;
array[1]=b;
return array[((a-b)&0x80000000)>>31];
}

int main() {
printf("%d\n",max(-1,100));
printf("%d\n",max(10000,100));
printf("%d\n",max(99,99));
getchar();
}

And how does it work on sign magnitude systems, or 16 bit integer
systems, or any non-32 bit integer systems, etc.? What is the
useless 'getchar' for? Are there prizes for deleting blanks?
 
J

James Fang

Thanks for your correction...
int get_max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[( (a-b)& (UINT_MAX/2+1U) ) >>
((sizeof(int)*8)-1)];}
int main()
{
printf("%d\n",get_max(-190,-100));
printf("%d\n",get_max(10000,100));
printf("%d\n",get_max(99,199));

Still wrong. With your code,
printf("%d
\n",get_max(2147483647,-1));
will print -1 as the answer.

Your entire attempt is stupid, and the OP's requirement
is stupid. Your whole attempt is pointless,
and encourages stupid programming.

You are right, I omitted the overflow condition in the code, and it
can be workarounded as follow:
int get_max(int a,int b)
{
long long divisor = (long long)a-(long long)b;
int array[2];
array[0]=a;
array[1]=b;
return array[( divisor & (ULLONG_MAX/2+1U) ) >> ((sizeof(long
long)*8)-1)];
}

As far as I am concerned, this question is rather an excersice than
what will be used in the real engineering environment. It forces the
coder to implement an "if(a<b){....}" expression with high level
programming language C rather than the compiler generated assembly.
In the assembly we can get the value of the status-register, which
will help us know the overflow in the last caculation. but with pure C
it is hard to get this valuable information(if I am wrong please
correct me).So it's impossible to implement a perfect "if(a<b){...}"
without knowing the processor details. And it's impossible for a
program caring the processor details be portable!

If we see the question as an excersice for "if(a<b){....}" and an
interesting puzzle, it is worthwhile to have a try and have some fun.

The "if(a>b){return a;}..." like impl is surely not stupid for the
real-world engineering, but it is surely not a clever answer for a
puzzle, right?

Anyway, I am with this answer just because that I am with this sounds-
interesting-question, not means that I support this kind of coding
standard in the project. I take your point that in engineering
practice, simply is the best.

BTW, is there any perfect solution to implement the "if(a<b){....}"
without any Relational Operator?
 
J

James Fang

Thanks for your correction...
int get_max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[( (a-b)& (UINT_MAX/2+1U) ) >>
((sizeof(int)*8)-1)];}
int main()
{
printf("%d\n",get_max(-190,-100));
printf("%d\n",get_max(10000,100));
printf("%d\n",get_max(99,199));

Still wrong. With your code,
printf("%d
\n",get_max(2147483647,-1));
will print -1 as the answer.

Your entire attempt is stupid, and the OP's requirement
is stupid. Your whole attempt is pointless,
and encourages stupid programming.

You are right, I omitted the overflow condition in the code, and it
can be workarounded as follow:
int get_max(int a,int b)
{
long long divisor = (long long)a-(long long)b;
int array[2];
array[0]=a;
array[1]=b;
return array[( divisor & (ULLONG_MAX/2+1U) ) >> ((sizeof(long
long)*8)-1)];
}

As far as I am concerned, this question is rather an excersice than
what will be used in the real engineering environment. It forces the
coder to implement an "if(a<b){....}" expression with high level
programming language C rather than the compiler generated assembly.
In the assembly we can get the value of the status-register, which
will help us know the overflow in the last caculation. but with pure C
it is hard to get this valuable information(if I am wrong please
correct me).So it's impossible to implement a perfect "if(a<b){...}"
without knowing the processor details. And it's impossible for a
program caring the processor details be portable!

If we see the question as an excersice for "if(a<b){....}" and an
interesting puzzle, it is worthwhile to have a try and have some fun.

The "if(a>b){return a;}..." like impl is surely not stupid for the
real-world engineering, but it is surely not a clever answer for a
puzzle, right?

Anyway, I am with this answer just because that I am with this sounds-
interesting-question, not means that I support this kind of coding
standard in the project. I take your point that in engineering
practice, simply is the best.

BTW, is there any perfect solution to implement the "if(a<b){....}"
without any Relational Operator?
 
J

James Fang

Thanks for your correction...
int get_max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[( (a-b)& (UINT_MAX/2+1U) ) >>
((sizeof(int)*8)-1)];}
int main()
{
printf("%d\n",get_max(-190,-100));
printf("%d\n",get_max(10000,100));
printf("%d\n",get_max(99,199));

Still wrong. With your code,
printf("%d
\n",get_max(2147483647,-1));
will print -1 as the answer.

Your entire attempt is stupid, and the OP's requirement
is stupid. Your whole attempt is pointless,
and encourages stupid programming.

Just omitted the overflow condition in the code, and it can be
workarounded as follow:
int get_max(int a,int b)
{
long long divisor = (long long)a-(long long)b;
int array[2];
array[0]=a;
array[1]=b;
return array[( divisor & (ULLONG_MAX/2+1U) ) >> ((sizeof(long
long)*8)-1)];
}

As far as I am concerned, this question is rather an excersice than
what will be used in the real engineering environment. It forces the
coder to implement an "if(a<b){....}" expression with high level
programming language C rather than the compiler generated assembly.
In the assembly we can get the value of the status-register, which
will help us know the overflow in the last caculation. but with pure C
it is hard to get this valuable information(if I am wrong please
correct me).So it's impossible to implement a perfect "if(a<b){...}"
without knowing the processor details. And it's impossible for a
program caring the processor details be portable!

If we see the question as an excersice for "if(a<b){....}" and an
interesting puzzle, it is worthwhile to have a try and have some fun.

The "if(a>b){return a;}..." like impl is surely not stupid for the
real-world engineering, but it is surely not a clever answer for a
puzzle, right?

Anyway, I am with this answer just because that I am with this sounds-
interesting-question, not means that I support this kind of coding
standard in the project. I take your point that in engineering
practice, simply is the best.

BTW, is there any perfect solution to implement the "if(a<b){....}"
without any Relational Operator?
 
F

Flash Gordon

James Fang wrote, On 08/12/07 13:33:
James Fang wrote, On 08/12/07 04:23:
On Dec 7, 1:33 pm, (e-mail address removed) wrote:
Hi all,
The following question is asked frequently in interviews
How to find the greatest of 2 numbers without using relational
operators ?
the solution i have seen is
( a+b + abs(a-b) ) /2 ;
is there any better solution than this ....?????
In your solution there's an overflow issue.
Actually there's a simpler solution: you can use an array, and use the
array index istead of the relational operators.
int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[(a-b)&0x80000000];
}
Did you actually test this piece of rubbish? When I try it I always get
the value of a. I'm really not sure how it is giving me that since the
code is so broken. Just to show you how bad I've added a bit of
diagnostic and here it is...

markg@brenda:~$ cat t.c
#include<stdio.h>

int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
printf("%d\n",(a-b)&0x80000000);
return array[(a-b)&0x80000000];

}

int main(void)
{
printf("%d\n",max(1,2));
return 0;}

markg@brenda:~$ gcc -ansi -Wall -Wextra -O t.c
markg@brenda:~$ ./a.out
-2147483648
1
markg@brenda:~$

Obviously the index is just a little outside the array.
also, you can make use of the C system stack
C does not have a system stack. Your implementation might, but equally
well it might not work as you expect.
to get rid of extra
memory space:
int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
Or they are passed in registers (if you take the address then obviously
it has to allocate a memory location), or the stack might not grow in
the direction you expect, or the parameters might be pushed left to right...
// so integer b is stored in high address.
return array *(&a+((a-b)&0x80000000>>31));
int might not be 32 bits. It invokes undefined behaviour if you take a
pointer to a, add 1 to it, and dereference it.


}
Sorry, I've made a mistake, the second implementation should be:
int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
// so integer b is stored in high address.
return *(&a+((a-b)&0x80000000>>31));
}
No, the second implementation should be erased not corrected, and anyone
who thinks it is valid needs to learn C. The first could be corrected as
an intellectual exercise, but should never be used in real life.

Actually, I just missed one shift operation in the max function
because the code was written in a hurry in the bbs reply, attached
below is the corrected function int max(int,int).

No, you have several other errors. With assume int is 32 bits as I
already stated, your code will invoke undefined behaviour due to
overflow with some values. It may well have other problems, your second
example certainly does.
My code is directly written in the bbs reply, the purpose of my code

I have no idea what you mean by bbs.
is to illustrate new idea and algorithm, rather than help sb directly
do copy&paste job. The entire execution code is pasted below, it was
compiled with gcc and had basic functionality test on win32 system.

Specific implementations are not relevant.
#include <stdio.h>

int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[((a-b)&0x80000000)>>31];
}

int main()
{
printf("%d\n",max(-1,100));
printf("%d\n",max(10000,100));
printf("%d\n",max(99,99));

#include <limits.h>
printf("%d\n",max(INT_MIN,INT_MAX);

I get the value of INT_MIN printed which is just a little incorrect.
getchar();
}

Basically the only sensible answer is that it is a stupid question.
 
J

James Fang

James Fang wrote:

... snip ...
My code is directly written in the bbs reply, the purpose of my code
is to illustrate new idea and algorithm, rather than help sb directly
do copy&paste job. The entire execution code is pasted below, it was
compiled with gcc and had basic functionality test on win32 system.
#include <stdio.h>
int max(int a,int b) {
int array[2];
array[0]=a;
array[1]=b;
return array[((a-b)&0x80000000)>>31];
}
int main() {
printf("%d\n",max(-1,100));
printf("%d\n",max(10000,100));
printf("%d\n",max(99,99));
getchar();
}

And how does it work on sign magnitude systems, or 16 bit integer
systems, or any non-32 bit integer systems, etc.? What is the
useless 'getchar' for? Are there prizes for deleting blanks?

hi Chuck,
the getchar() is only used to facilitate test in windows command
prompt(as I don't want the command prompt window disapear after
process exits)

This code is absolutely un-portable due to the limitation of the
question itself. It need to be re-considered for each type of
processor(maybe use a macro to control them).
 
J

James Kuyper

James Fang wrote:
....
BTW, since "!=" is also in the Relational Operator Set which is also
disatisfied with the question requirement, a better way may be like

No, the C standard restricts the term "relational operator" to '<', '>',
'<=' and '>=' (6.5.8). '!=' is an equality operator, a category that
also includes '==' (6.5.9).
 
J

Joachim Schmitz

Flash Gordon said:
James Fang wrote, On 08/12/07 13:33:
I have no idea what you mean by bbs.
I presume he means "Bulletin Board System", in the (wrong) assumption that
Usenet is just that.

Bye, Jojo
 
J

James Fang

James Fang wrote, On 08/12/07 13:33:


James Fang wrote, On 08/12/07 04:23:
On Dec 7, 1:33 pm, (e-mail address removed) wrote:
Hi all,
The following question is asked frequently in interviews
How to find the greatest of 2 numbers without using relational
operators ?
the solution i have seen is
( a+b + abs(a-b) ) /2 ;
is there any better solution than this ....?????
In your solution there's an overflow issue.
Actually there's a simpler solution: you can use an array, and use the
array index istead of the relational operators.
int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[(a-b)&0x80000000];
}
Did you actually test this piece of rubbish? When I try it I always get
the value of a. I'm really not sure how it is giving me that since the
code is so broken. Just to show you how bad I've added a bit of
diagnostic and here it is...
markg@brenda:~$ cat t.c
#include<stdio.h>
int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
printf("%d\n",(a-b)&0x80000000);
return array[(a-b)&0x80000000];
}
int main(void)
{
printf("%d\n",max(1,2));
return 0;}
markg@brenda:~$ gcc -ansi -Wall -Wextra -O t.c
markg@brenda:~$ ./a.out
-2147483648
1
markg@brenda:~$
Obviously the index is just a little outside the array.
also, you can make use of the C system stack
C does not have a system stack. Your implementation might, but equally
well it might not work as you expect.
to get rid of extra
memory space:
int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
Or they are passed in registers (if you take the address then obviously
it has to allocate a memory location), or the stack might not grow in
the direction you expect, or the parameters might be pushed left to right...
// so integer b is stored in high address.
return array *(&a+((a-b)&0x80000000>>31));
int might not be 32 bits. It invokes undefined behaviour if you take a
pointer to a, add 1 to it, and dereference it.
}
Sorry, I've made a mistake, the second implementation should be:
int max(int a,int b)
{
// in C standard, the function parameters are pushed from right to
left.
// so integer b is stored in high address.
return *(&a+((a-b)&0x80000000>>31));
}
No, the second implementation should be erased not corrected, and anyone
who thinks it is valid needs to learn C. The first could be corrected as
an intellectual exercise, but should never be used in real life.
Actually, I just missed one shift operation in the max function
because the code was written in a hurry in the bbs reply, attached
below is the corrected function int max(int,int).

No, you have several other errors. With assume int is 32 bits as I
already stated, your code will invoke undefined behaviour due to
overflow with some values. It may well have other problems, your second
example certainly does.
My code is directly written in the bbs reply, the purpose of my code

I have no idea what you mean by bbs.
is to illustrate new idea and algorithm, rather than help sb directly
do copy&paste job. The entire execution code is pasted below, it was
compiled with gcc and had basic functionality test on win32 system.

Specific implementations are not relevant.
#include <stdio.h>
int max(int a,int b)
{
int array[2];
array[0]=a;
array[1]=b;
return array[((a-b)&0x80000000)>>31];
}
int main()
{
printf("%d\n",max(-1,100));
printf("%d\n",max(10000,100));
printf("%d\n",max(99,99));

#include <limits.h>
printf("%d\n",max(INT_MIN,INT_MAX);

I get the value of INT_MIN printed which is just a little incorrect.
getchar();
}

Basically the only sensible answer is that it is a stupid question.

You are right, detection of arithmetical overflow with portable
solution should be a problem.
The following code can handle the arithmetical overflow, but it still
assumes that the sign bit is the high bit, which might be non-portable
on some CPUs.
In fact,these processor specific differences should be concealed by
the C compiler,right?

int get_max(int a,int b)
{
long long divisor = (long long)a-(long long)b;
int array[2];
array[0]=a;
array[1]=b;
return array[( divisor & (ULLONG_MAX/2+1U) ) >> ((sizeof(long
long)*8)-1)];
}


Thanks and Regards,
James
 
P

Peter Nilsson

Depends how you look at it. The irony is that you need to
be reasonably skilled to actually get this done portably.
Of course, it's highly unlikely that people asking the
question in an interview are actually in a position to
grade the attempts.
You are right, I omitted the overflow condition in the
code, and it can be workarounded as follow:
int get_max(int a,int b)
{
long long divisor = (long long)a-(long long)b;

What if the range of int is the same as long long?
int array[2];
array[0]=a;
array[1]=b;
return array[( divisor & (ULLONG_MAX/2+1U) ) >> ((sizeof(long
long)*8)-1)];

}

The version at...

<http://groups.google.com/group/comp.lang.c/msg/5aeee18e55ea156c>

Should be maximally portable, though it's obviously not
maximally readable. :)
 
J

James Dow Allen


I've not been following this discussion, but ...

when a has no side-effects (and is unaffected by
evaluating b), and the net expression's value
is discarded or treated as a boolean,
and missing parentheses are not an issue, then
(a && b || !a && c)
is equivalent to
a ? b : c

I don't know if C's "?" is considered a "relational
operator" but if so, to say that the first expression
above "avoids the relational operator" in the second
seems quite frivolous.

James
 
C

Chris Torek

The question [of branchless min and max] is asked frequently
in interviews ...

I think it is moronic to ask for gag answers in an interview. I
imagine that they were looking for the solutions from this web site:
http://aggregate.org/MAGIC/
[snippage]

Writing weird crap like that when you mean:
maxab = a > b ? a : b;
is just plain stupid. Since 80% of the cost of software is
maintenance, writing code that is hard to maintain is counter
productive.

Indeed. However, questions like that might make sense in interviews
for compiler-writing positions. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top