// This file is part of www.nand2tetris.org // and the book "The Elements of Computing Systems" // by Nisan and Schocken, MIT Press. // File name: projects/12/Math.jack /** * A library of commonly used mathematical functions. * All functions runs in O(n), where n is the number of bits used * for representing a two's complement integer value (16 in the Hack computer). * Note: Jack compilers implement multiplication and division * using calls to OS functions in this class. */ class Math { static int n; // Number of bits used for representing a two's complement integer static Array powersOfTwo; // Stores 2^0, 2^1, 2^2,..., 2^(n-1) // Initializes the Math library. function void init() { var int i, val; let n = 16; let powersOfTwo = Array.new(n); let i = 0; let val = 1; while (i < n) { let powersOfTwo[i] = val; let val = val + val; let i = i + 1; } return; } /** Returns the product of x and y. * When a Jack compiler detects the multiplication operator '*' * in an expression, it handles it by invoking this method. * Thus, in Jack, x * y and Math.multiply(x,y) return the same value. */ function int multiply(int x, int y) { var int sum, shiftedX, i; let sum = 0; let shiftedX = x; let i = 0; while (i < n) { if (Math.bit(y, i)) { let sum = sum + shiftedX; } let shiftedX = shiftedX + shiftedX; let i = i + 1; } return sum; } /** Returns true if the i-th bit of x is 1, false otherwise */ function boolean bit(int x, int i) { return ~((x & powersOfTwo[i]) = 0); } /** Returns the integer part of x / y. * When a Jack compiler detects the division operator '/' * an an expression, it handles it by invoking this method. * Thus, x/y and Math.divide(x,y) return the same value. */ function int divide(int x, int y) { var int q; var int absX, absY; var int result; var boolean neg; let neg = (x < 0) = (y > 0); // true if signs differ let absX = Math.abs(x); let absY = Math.abs(y); if (absY > absX) { return 0; } // Handle overflow for 2*y if ((absY + absY) < 0) { let q = 0; } else { let q = Math.divide(absX, absY + absY); } if ((absX - (2 * q * absY)) < absY) { let result = q + q; } else { let result = q + q + 1; } if (neg) { return -result; } return result; } /** Returns the integer part of the square root of x. */ function int sqrt(int x) { var int y, j, approx, approxSq; let y = 0; let j = 7; // n/2 - 1 for n=16 while (j > -1) { let approx = y + powersOfTwo[j]; let approxSq = approx * approx; // Checks if approxSq > 0 (overflow check) and approxSq <= x if (((approxSq > 0) | (approxSq = 0)) & ((approxSq < x) | (approxSq = x))) { let y = approx; } let j = j - 1; } return y; } /** Returns the greater value. */ function int max(int a, int b) { if (a > b) { return a; } return b; } /** Returns the smaller value. */ function int min(int a, int b) { if (a < b) { return a; } return b; } /** Returns the absolute value of x. */ function int abs(int x) { if (x < 0) { return -x; } return x; } }