summaryrefslogtreecommitdiff
path: root/projects/12/Math.jack
blob: 01bce8f17de6cde38e5c23b791cbc4c5d5b4a7db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// 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.
 * Note: Jack compilers implement multiplication and division using OS method calls.
 */
class Math {
    static Array twoToThe;

    /** Initializes the library. */
    function void init() {
        var int i, x;
        let x = 1;
        let i = 0;
        let twoToThe = Array.new(16);
        while (i < 16){
            let twoToThe[i] = x;
            let x = x + x;
            let i = i + 1;
        }
        return;
    }

    function boolean bit(int x, int i) {
        return ~(x & twoToThe[i] = 0);
    }

    function int sign(int x) {
        if (x > 0) {
            return 1;
        } else {
            if (x < 0) {
                return -1;
            } else {
                return 0;
            }
        }
    }

    /** Returns the absolute value of x. */
    function int abs(int x) {
        if (x > 0){
            return x;
        } else {
            return -x;
        }
    }

    /** Returns the product of x and y. 
     *  When a Jack compiler detects the multiplication operator '*' in the 
     *  program's code, it handles it by invoking this method. In other words,
     *  the Jack expressions x*y and multiply(x,y) return the same value.
     */
    function int multiply(int x, int y) {
        var int res, shiftedX, i;
        let shiftedX = x;
        let i = 0;
        let res = 0;
        //while ((~(twoToThe[i] > y)) & (i < 16)) {
        while (i < 16) {
            if (Math.bit(y, i)){
                let res = res + shiftedX;
            }
            let shiftedX = shiftedX + shiftedX;
            let i = i + 1;
        }
        return res;
    }

    /** Returns the integer part of x/y.
     *  When a Jack compiler detects the multiplication operator '/' in the 
     *  program's code, it handles it by invoking this method. In other words,
     *  the Jack expressions x/y and divide(x,y) return the same value.
     */
    function int divide(int x, int y) {
        var int ax, ay;
        if (x > 0) {
            if (y > 0) {
                return Math.divide1(x, y);
            } else {
                return -Math.divide1(x, -y);
            }
        } else {
            if (y > 0) {
                return -Math.divide1(-x, y);
            } else {
                return Math.divide1(-x, -y);
            }
        }
    }

    function int divide1(int x, int y) {
        var int q;
        if (y = 0) {
            do Output.printString("Error: division by zero.");
            do Sys.error(0);
        }
        if ((y > x) | (y < 0)) {
            return 0;
        }
        let q = Math.divide1(x, y * 2);
        if (x - (2 * q * y) < y) {
            return 2 * q;
        } else {
            return 2 * q + 1;
        }
    }

    function int length(int x){
        var int n;
        let n = 14;
        while (twoToThe[n] > x){
            let n = n - 1;
        }
        return n;
    }

    /** Returns the integer part of the square root of x. */
    function int sqrt(int x) {
        var int y, k, z, w;
        if (x < 0) {
            do Output.printString("Error: square rooting a negative number.");
            do Sys.error(0);
        }
        let k = Math.length(x) / 2;
        let y = 0;
        while (~(k < 0)) {
            let z = y + twoToThe[k];
            let w = z * z;
            if ((~(w > x)) & (w > 0)) {
                let y = z;
            }
            let k = k - 1;
        }
        return y;
    }

    /** Returns the greater number. */
    function int max(int a, int b) {
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }

    /** Returns the smaller number. */
    function int min(int a, int b) {
        if (a < b) {
            return a;
        } else {
            return b;
        }
    }
}