Sunday, September 30, 2012

Two ways to find the max of 5 numbers


It started as an experiment to find out which of the two ways (I could think of) how to find the max of 5 numbers. I wanted to make this language agnostic, in other words, no library functions or language specific features.

I used Java for this. Here is the program:

//LargestIn5.java
//Accept 5 numbers and find the largest of the 5 numbers

import java.util.Scanner;

public class LargestIn5
{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);

int a, b, c, d, e; // The five numbers
int nCount = 0;

System.out.print("Enter the first number: ");
a = input.nextInt();

System.out.print("Enter the second number: ");
b = input.nextInt();

System.out.print("Enter the third number: ");
c = input.nextInt();

System.out.print("Enter the fourth number: ");
d = input.nextInt();

System.out.print("Enter the fifth number: ");
e = input.nextInt();

if ((a > b) && (a > c) && (a > d) && (a > e))
{
System.out.println(a + " is the largest");
System.out.println("nCount = 4");
}
else if ((b > a) && (b > c) && (b > d) && (b > e))
{
System.out.println(b + " is the largest");
System.out.println("nCount = 4");
}
else if ((c > a) && (c > b) && (c > d) && (c > e))
{
System.out.println(c + " is the largest");
System.out.println("nCount = 4");
}
else if ((d > a) && (d > b) && (d > c) && (d > e))
{
System.out.println(d + " is the largest");
System.out.println("nCount = 4");
}
else if ((e > a) && (e > b) && (e > c) && (e > d))
{
System.out.println(e + " is the largest");
System.out.println("nCount = 4");
}
else
{
System.out.println("There is something wrong...");
System.out.println("nCount = 0");
}

if (a > b)
{
nCount++;
if (a > c)
{ //a > b & c
nCount++;
if (a > d)
{ // a > b & c & d
nCount++;
if (a > e)
{ // a > b & c & d & e
nCount++;
System.out.println(a + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > a > b & c & d
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
else
{ // d > a > b & c
nCount++;
if (d > e)
{ // d > e & a > b & c
nCount++;
System.out.println(d + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > d > a > b & c
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
}
else
{ // c > a > b
nCount++;
if (c > d)
{ // c > d & a > b
nCount++;
if (c > e)
{ // c > d & e & a > b
nCount++;
System.out.println(c + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > c > d & a > b
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
else
{ // d > c > a > b
nCount++;
if (d > e)
{ // d > e & c > a > b
nCount++;
System.out.println(d + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > d > c > a > b
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
}
}
else
{ // b > a
nCount++;
if (b > c)
{ // b > a & c
nCount++;
if (b > d)
{ // b > a & c & d
nCount++;
if (b > e)
{ // b > a & c & d & e
nCount++;
System.out.println(b + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > b > a & c & d
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
else
{ // d > b > c
nCount++;
if (d > a)
{ // d > a & b > c
nCount++;
if (d > e)
{ // d > e & a & b > c
nCount++;
System.out.println(d + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > d > a & b > c
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
else
{ // a > d > b > c
nCount++;
if (a > e)
{ // a > e & d > b > c
nCount++;
System.out.println(a + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > a > d > b > c
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
}
}
else
{ // c > b > a
nCount++;
if (c > d)
{ // c > d & b > a
nCount++;
if (c > e)
{
nCount++;
System.out.println(c + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
else
{ // d > c > b > a
nCount++;
if (d > e)
{ // d > e & c > b > a
nCount++;
System.out.println(d + " is the largest");
System.out.println("nCount = " + nCount);
}
else
{ // e > d > c > b > a
nCount++;
System.out.println(e + " is the largest");
System.out.println("nCount = " + nCount);
}
}
}
}
}
}


The variable nCount was to find out how many conditions are being executed. Method 2 seems more complex. But is it better in terms of number of conditions executed to find the answer.

Output from few runs:

$ java LargestIn5
Enter the first number: 1
Enter the second number: 2
Enter the third number: 3
Enter the fourth number: 4
Enter the fifth number: 5
5 is the largest
nCount = 4 
5 is the largest
nCount = 4 
$ java LargestIn5
Enter the first number: 2
Enter the second number: 3
Enter the third number: 4
Enter the fourth number: 5
Enter the fifth number: 1
5 is the largest
nCount = 4 
5 is the largest
nCount = 4 
$ java LargestIn5
Enter the first number: 3
Enter the second number: 4
Enter the third number: 5
Enter the fourth number: 1
Enter the fifth number: 2
5 is the largest
nCount = 4 
5 is the largest
nCount = 4 
$ java LargestIn5
Enter the first number: 4
Enter the second number: 5
Enter the third number: 1
Enter the fourth number: 2
Enter the fifth number: 3
5 is the largest
nCount = 4 
5 is the largest
nCount = 4 
$ java LargestIn5
Enter the first number: 5
Enter the second number: 1
Enter the third number: 2
Enter the fourth number: 3
Enter the fifth number: 4
5 is the largest
nCount = 4 
5 is the largest
nCount = 4 


Sometimes, the more complex looking code is not necessarily the more optimal one.

Saturday, March 31, 2012

Handling Return Values

Recently, I was discussing Defensive Programming with a relative newcomer to the industry. I mentioned that the concept was not dependent on languages and more logical in nature. In other words, though a language does not have specific language facilities for Defensive Programming.

To give an example, I used the following:

Consider a function is_data_found() which returns one of the following values:

#define SUCCESS 0
#define FAILURE 1
#define NO_DATA_FOUND 2

int fun1()
{
    //search for data in DB
    //If data not found return NO_DATA_FOUND
    //else if operation failed, then return FAILURE
    //Return SUCCESS
}

Now, one of the common (wrong) ways for a caller fun2() to handle the return values from the call to fun1() is:

void fun2()
{
    //Call fun1
    //if return value is not SUCCESS, continue process
    //else, throw exception
}

Based on code review feedback or testing, they might realize that NO_DATA_FOUND might be a valid scenario. In other words, fun2() might need to do create_if_not_found operation.

To accommodate this, they might change the caller to:

void fun3()
{
    //Call fun1
    //if return value is NO_DATA_FOUND, then create row
    //else if return value is SUCCESS, then continue process
    //else, throw exception
}

This would be fine in the current scenario. But what if a new return value is added to fun1(), say WARNING_POTENTIAL_STALE_DATA:

#define SUCCESS 0
#define FAILURE 1
#define NO_DATA_FOUND 2
#define WARNING_POTENTIAL_STALE_DATA 3

int fun1()
{
    //search for data in DB
    //If data not found return NO_DATA_FOUND
    //else if operation failed but previously fetched data available, then return WARNING_POTENTIAL_STALE_DATA
    //else if operation failed and no previously fetched data available, then return FAILURE
    //Return SUCCESS
}

Now, fun2() would not provide the complete functionality since it does not know about the new functionality. However, no one would notice this, since fun2() does not have the right code for handling such scenarios.

A better way to write the caller is:

void fun4()
{
    //Call fun1
    //if return value is NO_DATA_FOUND, then create row
    //else if return value is SUCCESS, then continue process
    //else if return value is FAILURE, then throw DATA_FETCH_FAILED_EXCEPTION
    //else, return UNKNOWN_RETURN_VALUE_EXCEPTION
}

Now, fun4() will throw an exception when WARNING_POTENTIAL_STALE_DATA is thrown.

Cheers!
Karthick S.