text: package Q16_09_Operations;
  
  import java.util.Random;
  
  import CtCILibrary.AssortedMethods;
  
  public class Question {
  	/* Flip a positive sign to negative, or a negative sign to pos */
  	public static int negate(int a) {
  		int neg = 0;
  		int newSign = a < 0 ? 1 : -1;
  		while (a != 0) {
  			neg += newSign;
  			a += newSign;
  		}
  	    return neg;
  	}
  	
  	/* Flip a positive sign to negative, or a negative sign to pos */
  	public static int negateOptimized(int a) {
  		int neg = 0;
  		int newSign = a < 0 ? 1 : -1;
  		int delta = newSign;
  		while (a != 0) {
  			boolean differentSigns = (a + delta > 0) != (a > 0);
  			if (a + delta != 0 && differentSigns) { // If delta is too big, reset it.
  				delta = newSign;
  			}
  			neg += delta;
  			a += delta;
  			delta += delta; // Double the delta
  		}
  	    return neg;
  	}	
  
  	/* Subtract two numbers by negating b and adding them */
  	public static int minus(int a, int b) {
  		return a + negate(b);
  	}
  
  	/* Return absolute value */
  	public static int abs(int a) {
  		if (a < 0) {
  			return negateOptimized(a);
  		}
  		else return a;
  	}
  
  	/* Multiply a by b by adding a to itself b times */
  	public static int multiply(int a, int b) {
  		if (a < b) {
  			return multiply(b, a); // algo is faster if b < a
  		}
  		int sum = 0;
  		for (int i = abs(b); i > 0; i = minus(i, 1)) {
  			sum += a;
  		}
  		if (b < 0) {
  			sum = negateOptimized(sum);
  		}
  		return sum;
  	}
  
  	/* Divide a by b by literally counting how many times b can go into
  	 * a. That is, count how many times you can add b to itself until you reach a. */
  	public static int divide(int a, int b) throws java.lang.ArithmeticException {
  		if (b == 0) {
  			throw new java.lang.ArithmeticException("ERROR: Divide by zero.");
  		}
  		int absa = abs(a);
  		int absb = abs(b);
  		
  		int product = 0;
  		int x = 0;
  		while (product + absb <= absa) { /* don't go past a */
  			product += absb;
  			x++;
  		}
  		
  		if ((a < 0 && b < 0) || (a > 0 && b > 0)) {
  			return x;
  		} else {
  			return negateOptimized(x);
  		}
  	}
  	
  	public static void main(String[] args) {
  		int minRange = -100;
  		int maxRange = 100;
  		int cycles = 100;
  		
  		for (int i = 0; i < cycles; i++) {
  			int a = AssortedMethods.randomIntInRange(minRange, maxRange);
  			int b = AssortedMethods.randomIntInRange(minRange, maxRange);
  			int ans = minus(a, b);
  			if (ans != a - b) {
  				System.out.println("ERROR");
  			}
  			System.out.println(a + " - " + b + " = " + ans);
  		}
  		for (int i = 0; i < cycles; i++) {
  			int a = AssortedMethods.randomIntInRange(minRange, maxRange);
  			int b = AssortedMethods.randomIntInRange(minRange, maxRange);
  			int ans = multiply(a, b);
  			if (ans != a * b) {
  				System.out.println("ERROR");
  			}
  			System.out.println(a + " * " + b + " = " + ans);
  		}
  		for (int i = 0; i < cycles; i++) {
  			int a = AssortedMethods.randomIntInRange(minRange, maxRange);
  			int b = AssortedMethods.randomIntInRange(minRange, maxRange);
  			System.out.print(a + " / " + b + " = ");
  			int ans = divide(a, b);
  			if (ans != a / b) {
  				System.out.println("ERROR");
  			}
  			System.out.println(ans);
  		}
  	}
  
  }
  