//
// file: OverUnder.java
// Demonstrate overflow and underflow with integer types
//
public class OverUnder { 
	//members
	int a = 12345, b = 234567, c, d; 
	long e,f; 
	
	public static void main(String[] args) { 
		//create and instance of class OverUnder
		OverUnder ou = new OverUnder(); 
		
		// Mult first will overflow, divide first will lose precision
		// Expected result: c =  12345 * 234567 =  2895729615
		//  2895729615/234567 = 12345
		ou.c = ou.a * ou.b / ou.b; 
		ou.d = ou.a / ou.b * ou.b;
		System.out.println("a is :"+ ou.a +
			"\nb is :"+ ou.b +
			"\nc is :"+ ou.c +
			"\nd is :"+ ou.d ); 
			
		// Try it with long. The cast forces result of ou.a * ou.b to 64 bits
		// In this case, multiply first, then divide works perfectly
		// However. divide first, then multiply still loses precision 
		// and results in a nonsense answer
		ou.e = (long)ou.a * ou.b /ou.b; 
		ou.f = (long)ou.a /ou.b * ou.b; 
		System.out.println("e is :"+ ou.e +
			"\nf is :"+ ou.f); 
			
		// Another example with type byte
		// In this case, the expected result is 4 * 64 = 256
		// The binary representation of 256 is: 
		// 0000 0001 0000 0000
		// When we attempt to shove this pattern into type 
		// byte, the top 8 bits are discarded. The result is 0
		// Q: Why is the cast to byte required ? 
		byte g = 4, h = 64, i; 
		i = (byte)(g * h); 
		System.out.println("i is :"+i); 
		
			
		
	}
}