diff --git a/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEff.java b/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEff.java
new file mode 100644
index 000000000..2fcd386bc
--- /dev/null
+++ b/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEff.java
@@ -0,0 +1,306 @@
+package Q16_09_Operations;
+
+import CtCILibrary.AssortedMethods;
+import java.util.function.IntBinaryOperator;
+
+public class QuestionEff {
+ /* a constant = -1 (hexadecimal notation is needed to avoid "-" operation) */
+ private static final int NEGATIVE_ONE = 0xffffffff;
+ /* bit shift operations (<<, >>, >>>) use only first 5 bits of right-side argument
+ * e.g., 5 >> 43 is the same as 5 >> 11 because 43 % 32 == 43 & 31 == 11 */
+ private static final int SHIFT_MASK = 31;
+ /* BITS[i] is an integer with i'th bit set to 1 (and other bits are 0) */
+ private static final int[] BITS = new int[32];
+
+ /* fill BITS array
+ * one-time preparation, O(WORD_SIZE) */
+ static {
+ int bit = 1;
+ for (int i = 0; i < 32; i = inc(i)) {
+ BITS[i] = bit;
+ bit = shiftLeft(bit, 1);
+ }
+ }
+
+ /* operator ++
+ * O(1) */
+ public static int inc(int a) {
+ return a + 1;
+ }
+
+ /* operator --
+ * O(1) */
+ public static int dec(int a) {
+ return a + NEGATIVE_ONE;
+ }
+
+ /* operator +
+ * O(1) */
+ public static int add(int a, int b) {
+ return a + b;
+ }
+
+ /* operator - (binary subtraction)
+ * O(WORD_SIZE) */
+ public static int subtract(int a, int b) {
+ return a + negate(b);
+ }
+
+ /* operator - (unary minus)
+ * O(WORD_SIZE) */
+ public static int negate(int n) {
+ return bitNot(n) + 1;
+ }
+
+ /* absolute value
+ * O(WORD_SIZE) */
+ public static int abs(int n) {
+ return n < 0 ? negate(n) : n;
+ }
+
+ /* operator ~ (inverse bits)
+ * O(WORD_SIZE) */
+ public static int bitNot(int n) {
+ return traverseBits(n, 0, (bit, zero)->bit == 0 ? 1 : 0);
+ }
+
+ /* operator &
+ * O(WORD_SIZE) */
+ public static int bitAnd(int a, int b) {
+ return traverseBits(a, b, (aBit, bBit)->aBit == 1 && bBit == 1 ? 1 : 0);
+ }
+
+ /* operator |
+ * O(WORD_SIZE) */
+ public static int bitOr(int a, int b) {
+ return traverseBits(a, b, (aBit, bBit)->aBit == 1 || bBit == 1 ? 1 : 0);
+ }
+
+ /* operator ^
+ * O(WORD_SIZE) */
+ public static int bitXor(int a, int b) {
+ return traverseBits(a, b, (aBit, bBit)->aBit == bBit ? 0 : 1);
+ }
+
+ /* loop over 2 integers, bit by bit, and construct a new integer according to bits returned by a callback function
+ * O(WORD_SIZE) */
+ private static int traverseBits(int a, int b, IntBinaryOperator callback) {
+ int result = 0;
+ for (int i = 31; i >= 0; i = dec(i)) {
+ int aBit = getBit(a, 31);
+ int bBit = getBit(b, 31);
+ int newBit = callback.applyAsInt(aBit, bBit);
+ if (newBit == 1) {
+ result = result + BITS[i];
+ }
+ a = shiftLeft(a, 1);
+ b = shiftLeft(b, 1);
+ }
+ return result;
+ }
+
+ /* get requested bit of an integer
+ * example: getBit(3, 0) == getBit(3, 1) == 1, other positions return 0
+ * O(WORD_SIZE) in worst case, O(1) if position==31 */
+ public static int getBit(int n, int position) {
+ if (position < 0) {
+ throw new ArithmeticException("Negative bit address");
+ }
+ if (position > 31) {
+ throw new IndexOutOfBoundsException(position);
+ }
+ for (int p = position; p < 31; p = inc(p)) {
+ n = shiftLeft(n, 1);
+ }
+ return n < 0 ? 1 : 0;
+ }
+
+ /* return a new integer with requested bit set to a given value
+ * O(WORD_SIZE) */
+ public static int setBit(int n, int position, int newBit) {
+ if (newBit<0 || newBit>1) {
+ throw new IllegalArgumentException("Bit value must be 0 or 1");
+ }
+ int oldBit = getBit(n, position);
+ if (oldBit == newBit) {
+ return n;
+ }
+ if (oldBit == 0) {
+ return n + BITS[position];
+ }
+ return subtract(n, BITS[position]);
+ }
+
+ /* check if given integer is even (0, 2, -2, 4, -4, etc.)
+ * O(WORD_SIZE) */
+ public static boolean isEven(int n) {
+ return getBit(n, 0) == 0;
+ }
+
+ /* check if given integer is odd (1, -1, 3, -3, etc.)
+ * O(WORD_SIZE) */
+ public static boolean isOdd(int n) {
+ return getBit(n, 0) == 1;
+ }
+
+ /* operator <<
+ * O(WORD_SIZE) in worst case, O(1) if shift==1 */
+ public static int shiftLeft(int n, int shift) {
+ if (shift < 0 || shift > 31) {
+ shift = bitAnd(shift, SHIFT_MASK);
+ }
+ for (int s = 0; s < shift; s = inc(s)) {
+ n = n + n;
+ }
+ return n;
+ }
+
+ /* generic implementation for >> and >>> operators
+ * O(WORD_SIZE) */
+ private static int shiftRightGeneric(int n, int shift, boolean unsigned) {
+ if (shift < 0 || shift > 31) {
+ shift = bitAnd(shift, SHIFT_MASK);
+ }
+ if (shift == 0) {
+ return n;
+ }
+ boolean negative = !unsigned && n < 0;
+ int result = 0;
+ int position = 31;
+ for (int i = 31 + shift; i >= 0; i = dec(i)) {
+ int bit;
+ if (i > 31) {
+ bit = negative ? 1 : 0;
+ } else {
+ bit = getBit(n, 31);
+ }
+ if (bit == 1) {
+ result = result + BITS[position];
+ }
+ position = dec(position);
+ if (position < 0) {
+ break;
+ }
+ if (i <= 31) {
+ n = shiftLeft(n, 1);
+ }
+ }
+ return result;
+ }
+
+ /* operator >>
+ * O(WORD_SIZE) */
+ public static int shiftRight(int n, int shift) {
+ return shiftRightGeneric(n, shift, false);
+ }
+
+ /* operator >>>
+ * O(WORD_SIZE) */
+ public static int shiftRightUnsigned(int n, int shift) {
+ return shiftRightGeneric(n, shift, true);
+ }
+
+ /* operator *
+ * O(WORD_SIZE) */
+ public static int multiply(int a, int b) {
+ int result = 0;
+ for (int i = 0; i < 32; i = inc(i)) {
+ result = shiftLeft(result, 1);
+ int bit = getBit(b, 31);
+ if (bit == 1) {
+ result = result + a;
+ }
+ b = shiftLeft(b, 1);
+ }
+ return result;
+ }
+
+ /* operator /
+ * O(WORD_SIZE**2) */
+ public static int divide(int a, int b) {
+ if (b == 0) {
+ throw new ArithmeticException("/ by zero");
+ }
+ if (a == 0) {
+ return 0;
+ }
+ if (b == Integer.MIN_VALUE) {
+ return a == Integer.MIN_VALUE ? 1 : 0;
+ }
+ if (b < 0) {
+ return negate(divide(a, negate(b)));
+ }
+ if (a == Integer.MIN_VALUE) {
+ return dec(divide(a + b, b));
+ }
+ if (a < 0) {
+ return negate(divide(negate(a), b));
+ }
+ int result = 0;
+ while (a >= b) {
+ int candidate = b;
+ for (int i = 0; i < 32; i = inc(i)) {
+ int shifted = shiftLeft(candidate, 1);
+ if (shifted < 0 || shifted > a) {
+ result = result + BITS[i];
+ break;
+ }
+ candidate = shifted;
+ }
+ a = subtract(a, candidate);
+ }
+ return result;
+ }
+
+ /* operator % (see BigInteger.remainder)
+ * O(WORD_SIZE**2) */
+ public static int remainder(int a, int b) {
+ return subtract(a, multiply(divide(a, b), b));
+ }
+
+ /* always non-negative remainder (see BigInteger.mod)
+ * O(WORD_SIZE**2) */
+ public static int mod(int a, int b) {
+ a = remainder(a, b);
+ if (a < 0) {
+ a = a + abs(b);
+ }
+ return a;
+ }
+
+ 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 = subtract(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);
+ }
+ }
+
+}
diff --git a/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEff.md b/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEff.md
new file mode 100644
index 000000000..d75a9705f
--- /dev/null
+++ b/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEff.md
@@ -0,0 +1,204 @@
+16.9 - Operations
+---
+> Write methods to implement the multiply, subtract, and divide operations for integers.
+> The results of all of these are integers. Use only the add operator.
+
+In [the first solution](https://github.com/careercup/CtCI-6th-Edition/blob/master/Java/Ch%2016.%20Moderate/Q16_09_Operations/Question.java), we managed to implement requested methods: `subtract`, `multiply` and `divide`. Let's assess their time complexity:
+- `subtract(a, b)` takes O((log b)2) (see the book for thorough explanation)
+- `multiply(a, b)` takes O(b) because we add `a` to itself `b` times
+- `divide(a, b)` takes O(a / b) because we add up `b` (until it becomes equal to `a`) `a / b` times
+
+Now, we'll try to improve the asymptotics of our functions. In order to do this, we'll apply some bit level manipulations keeping in mind that only `+` operator is allowed. Let's start from the `negate` function.
+
+---
+
+### negate (unary `-`)
+
+On bit level, negation is performed as inversion of each bit and addition of 1. For example, 1210 = 000011002. After inversing every bit, we get 11110011. Add 1 to this: 111101002 = -1210. To verify that the result is correct, we need to add 12: 11110100 + 00001100 = 00000000 - zero, as expected. So, our implementation becomes:
+```java
+int subtract(int a, int b) { return a + negate(b); } // same as before
+int negate(int n) { return bitNot(n) + 1; } // different
+```
+where `bitNot` is a bit inversion operator (`~`) that needs to be implemented.
+
+---
+
+### bitNot (`~`)
+
+If we had a function that allowed us to morph one number to another one bit by bit then we could implement `bitNot` like this, using functional approach:
+```java
+int bitNot(int n) { return traverseBits(n, bit -> bit == 0 ? 1 : 0); }
+```
+So, we simply map every bit to the opposite value.
+
+If you aren't familiar with lambda notation then here's the equivalent code using a class:
+```java
+interface BitMapper {
+ int map(int bit);
+}
+final BitMapper BIT_NOT = new BitMapper() {
+ @Override
+ int map(int bit) {
+ return bit == 0 ? 1 : 0;
+ }
+}
+int bitNot(int n) {
+ return traverseBits(n, BIT_NOT);
+}
+int traverseBits(int n, BitMapper mapper) {
+ <...>
+ int newBit = mapper.map(oldBit);
+ <...>
+}
+```
+Thus, now we have to find a way to implement `traverseBits`. Sometimes, it's useful to solve a high level task first, and then to find missing pieces of the puzzle.
+
+---
+
+### dec (`--`) and inc (`++`)
+
+Apparently, we will require loops in this task. And to make simple loops, we need decrement and increment operators. Let's be purists here: if we're only allowed to use `+` then `++` is also prohibited! :stuck_out_tongue_winking_eye:
+
+While increment is trivial, decrement requires a constant `-1`. But how can we define it if unary minus (`-`) is prohibited? We can use hexadecimal notation: -110 = 1111...11112 (a number with all bits set to 1) = FFFFFFFF16. Easy to remember: adding 1 to it will turn it into 0, so that's what we need.
+```java
+final int NEGATIVE_ONE = 0xFFFFFFFF;
+int dec(int n){ return n + NEGATIVE_ONE; }
+int inc(int n){ return n + 1; }
+```
+
+---
+
+### traverseBits
+
+The pseudocode of `traverseBits` function:
+```java
+int traverseBits(int n, BitMapper mapper) {
+ int result = 0;
+ for (int i = 31; i >= 0; i--) {
+ int oldBit = extract the last bit of n
+ int newBit = mapper.map(oldBit);
+ result[i] = newBit; // set newBit in position "i"
+ n <<= 1;
+ }
+ return result;
+}
+```
+It's only left to fill the gaps:
+- the last bit is the sign bit. If a number is less than 0 then this bit is set (and vice versa). That's how we get it: `oldBit = n < 0 ? 1 : 0`.
+- setting a bit at some position is just the addition of 2i because "result" is zero initially, and indicies never overlap
+- to quickly get 2i, we can pre-compute 32 integers each having 1 bit set in all possible slots (using left shift - `<<`)
+- shifting a number to the left by one bit is literally multiplying by 2, i.e. adding the number to itself
+
+The time complexity of our method is O(W) where W is the machine word size (32 for int). Since we traverse all the bits of a number, it's rather closer to O(log n) than to O(1). But it's definitely better than O((log n)2) we had before. The new implementation will outperform on large numbers (such as billion).
+
+---
+
+### left shift (`<<`)
+
+Of course, a general implementation of left shift accepts an argument "number of bits to shift by" (and therefore requires a loop), but for our needs, it's enough to shift by 1 bit:
+```java
+int leftShift(int n) { return n + n; }
+```
+
+---
+
+### multiply (`*`)
+
+We will use a classic multiplication algorithm taught to everyone in school. But we'll do it for binary representation. See example:
+```text
+ 1101 = a = 13
+ * 110 = b = 6
+----------|- a -
+ 110 | 1
+ | 0
+ + 110 | 1
++ 110 | 1
+----------|-----
+ 1001110 = 78
+```
+Pseudocode:
+```java
+int multiply(int a, int b) {
+ int result = 0;
+ for (repeat 32 times) {
+ result <<= 1;
+ if (last bit of a == 1) {
+ result += b;
+ }
+ a <<= 1;
+ }
+ return result;
+}
+```
+Note that there are no exceptional situations: this algorithm works correctly for negative numbers and in case of overflow, no adjustments are needed.
+
+Complexity is O(W), and it's a significant improvement comparing to prior O(n) = O(2W) approach.
+
+---
+
+### divide (`/`)
+
+The division algorithm also comes from school lessons. Take a look at the example:
+```text
+Step 1: find multiplier (align divisor with dividend but don't overflow)
+
+ 10011 | 110
+---------|----
+ 110 | 1 is not enough => shift
+ 1100 | 10 is still small => try to shift again
+ 11000 | 100 is too much => keep 10
+
+Step 2: subtract
+
+ 10011 | 110
+---------|----
+ - 1100 | 10
+ 111 |
+
+Step 3: repeat on remainder
+
+ 111 | 110
+---------|----
+ 110 | 1 doesn't overflow => shift
+ 1100 | 10 is too much => keep 1
+
+Step 4: subtract
+
+ 111 - 110 = 1 => remainder is less than divisor => finish the loop
+
+Step 5: sum up the result
+
+ 10 + 1 = 11 => done
+```
+
+Pseudocode:
+```java
+int divide(int a, int b) {
+ int result = 0;
+ while (a >= b) {
+ int shift = -1;
+ int shifted = b;
+ int previous = b;
+ while (shifted <= a) {
+ previous = shifted;
+ shifted <<= 1;
+ shift++;
+ }
+ a -= previous;
+ result[shift] = 1; // set bit at position "shift"
+ }
+ return result;
+}
+```
+
+On each iteration of the outer loop, at least one bit of `a` is erased. The inner loop takes O(W). Subtraction is also O(W). Total time is O(W2). It's slower than for `subtract` and `multiply` but faster than O(a / b) = O(2W) of our previous solution.
+
+Please be careful with division - it's very tricky:
+- first of all, the value of `shifted` may overflow. To avoid this, we can ensure that the last bit is free. It means that we need to get rid of negative numbers and work only with positive ones.
+- secondly, if `a` is large, and `shifted` is doubled to occupy the last bit then `shifted` becomes negative. So, the condition `shifted <= a` should actually be `shifted >= 0 && shifted <= a`.
+- getting rid of negative numbers seems to be easy, right? `if (a < 0) return negate(divide(negate(a), b))` - and the same for `b`. Yes, almost. However, there's one important special case - it's `Integer.MIN_VALUE` = -231. This is a negative number which doesn't have its positive counterpart. If you try to negate it, you'll get the same number. Therefore, it has to be carefully handled. If divisor is `MIN_VALUE` then the result is 0 because `MIN_VALUE` is a big number (despite that it's negative) - its absolute value is greater than any other int32. Except itself. If both `a` and `b` are `MIN_VALUE` then the result is 1. Things get interesting when `a` is `MIN_VALUE` (and `b` is positive at this point). Result has to be really calculated, we can't just hardcode it as in case of `b = MIN_VALUE`. The following formula helps: `a / b = (a + b) / b - 1`. Since `b` is positive, adding it to negative `a` will decrease the absolute value of `a`, and we'll be able to negate it in a regular manner.
+- finally, the most obvious exception related to division is division by zero. Standard Java division throws an error, so it could be reasonable to do the same. Other languages may behave differently. Anyway, it's always worth discussing such exceptional cases with your interviewer.
+
+---
+
+The full code listing for this solution also contains an implementation of all other standard operators (such as `%`, `>>>` and `^`) just for reference. It's highly unlikely though that you'll be asked to add all of them during an interview.
diff --git a/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEffTester.java b/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEffTester.java
new file mode 100644
index 000000000..ce0eff6ab
--- /dev/null
+++ b/Java/Ch 16. Moderate/Q16_09_Operations/QuestionEffTester.java
@@ -0,0 +1,140 @@
+package Q16_09_Operations;
+
+import java.math.BigInteger;
+import java.util.stream.IntStream;
+import java.lang.reflect.Method;
+import static Q16_09_Operations.QuestionEff.*;
+
+public class QuestionEffTester {
+ private static final int[] TEST_NUMBERS = {
+ Integer.MIN_VALUE, -Integer.MAX_VALUE, -Integer.MAX_VALUE + 1,
+ Integer.MIN_VALUE / 2 - 1, Integer.MIN_VALUE / 2, Integer.MIN_VALUE + 1,
+ -1000, -300, -200, -100, -90, -85, -84, -83,
+ -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 83, 84, 85, 90, 100, 200, 300, 1000,
+ Integer.MAX_VALUE / 2 - 3, Integer.MAX_VALUE / 2 - 2, Integer.MAX_VALUE / 2 - 1,
+ Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2 + 1, Integer.MAX_VALUE / 2 + 2,
+ Integer.MAX_VALUE / 2 + 3, Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
+ };
+
+ private static void assertEquals(int expected, int actual) {
+ if (expected == actual) {
+ return;
+ }
+ String message = String.format("expected: <%d> but was: <%d>", expected, actual);
+ throw new AssertionError(message);
+ }
+
+ private static void assertThrows(Class expectedType, Runnable runnable) {
+ try {
+ runnable.run();
+ } catch (Exception e) {
+ if (expectedType.isInstance(e)) {
+ return;
+ }
+ throw new AssertionError("unexpected exception type thrown");
+ }
+ throw new AssertionError("nothing was thrown");
+ }
+
+ public void testBitNot() {
+ for (int n : TEST_NUMBERS) {
+ assertEquals(~n, bitNot(n));
+ }
+ }
+
+ public void testGetBit() {
+ for (int n : TEST_NUMBERS) {
+ for (final int shift : IntStream.rangeClosed(-100, 200).toArray()) {
+ if (shift < 0) {
+ assertThrows(ArithmeticException.class, ()->getBit(n, shift));
+ } else if (shift > 31) {
+ assertThrows(IndexOutOfBoundsException.class, ()->getBit(n, shift));
+ } else {
+ assertEquals((n >>> shift) & 1, getBit(n, shift));
+ }
+ }
+ }
+ }
+
+ public void testShiftLeft() {
+ for (int n : TEST_NUMBERS) {
+ for (final int shift : IntStream.rangeClosed(-100, 200).toArray()) {
+ assertEquals(n << shift, shiftLeft(n, shift));
+ }
+ }
+ }
+
+ public void testShiftRight() {
+ for (int n : TEST_NUMBERS) {
+ for (final int shift : IntStream.rangeClosed(-100, 200).toArray()) {
+ assertEquals(n >> shift, shiftRight(n, shift));
+ }
+ }
+ }
+
+ public void testShiftRightUnsigned() {
+ for (int n : TEST_NUMBERS) {
+ for (final int shift : IntStream.rangeClosed(-100, 200).toArray()) {
+ assertEquals(n >>> shift, shiftRightUnsigned(n, shift));
+ }
+ }
+ }
+
+ public void testMultiply() {
+ for (int a : TEST_NUMBERS) {
+ for (int b : TEST_NUMBERS) {
+ assertEquals(a * b, multiply(a, b));
+ }
+ }
+ }
+
+ public void testDivide() {
+ for (int a : TEST_NUMBERS) {
+ for (int b : TEST_NUMBERS) {
+ if (b == 0) {
+ assertThrows(ArithmeticException.class, ()->divide(a, b));
+ } else {
+ assertEquals(a / b, divide(a, b));
+ }
+ }
+ }
+ }
+
+ public void testRemainder() {
+ for (int a : TEST_NUMBERS) {
+ for (int b : TEST_NUMBERS) {
+ if (b == 0) {
+ assertThrows(ArithmeticException.class, ()->remainder(a, b));
+ } else {
+ assertEquals(a % b, remainder(a, b));
+ }
+ }
+ }
+ }
+
+ public void testMod() {
+ for (int a : TEST_NUMBERS) {
+ for (int b : TEST_NUMBERS) {
+ if (b == 0) {
+ assertThrows(ArithmeticException.class, ()->mod(a, b));
+ } else {
+ assertEquals(BigInteger.valueOf(a).mod(BigInteger.valueOf(b).abs()).intValue(), mod(a, b));
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ QuestionEffTester tester = new QuestionEffTester();
+ Method[] methods = QuestionEffTester.class.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("test")) {
+ continue;
+ }
+ System.out.println(method.getName());
+ method.invoke(tester);
+ }
+ }
+}
\ No newline at end of file