001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.core.util;
020
021public class MathMan {
022
023    private static final int ATAN2_BITS = 7;
024    private static final int ATAN2_BITS2 = ATAN2_BITS << 1;
025    private static final int ATAN2_MASK = ~(-1 << ATAN2_BITS2);
026    private static final int ATAN2_COUNT = ATAN2_MASK + 1;
027    private static final int ATAN2_DIM = (int) Math.sqrt(ATAN2_COUNT);
028    private static final float INV_ATAN2_DIM_MINUS_1 = 1.0f / (ATAN2_DIM - 1);
029    private static final float[] atan2 = new float[ATAN2_COUNT];
030    private static final int[] table =
031            {0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, 64, 65, 67, 69, 71, 73, 75,
032                    76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104,
033                    106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123,
034                    124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
035                    141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155,
036                    155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
037                    169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, 181,
038                    181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 192, 192,
039                    193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203,
040                    204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214,
041                    214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223, 224,
042                    224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
043                    234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242,
044                    243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251,
045                    251, 252, 252, 253, 253, 254, 254, 255};
046
047    static {
048        for (int i = 0; i < ATAN2_DIM; i++) {
049            for (int j = 0; j < ATAN2_DIM; j++) {
050                float x0 = (float) i / ATAN2_DIM;
051                float y0 = (float) j / ATAN2_DIM;
052
053                atan2[(j * ATAN2_DIM) + i] = (float) Math.atan2(y0, x0);
054            }
055        }
056    }
057
058    public static final int gcd(int a, int b) {
059        if (b == 0) {
060            return a;
061        }
062        return gcd(b, a % b);
063    }
064
065    public static final int gcd(int[] a) {
066        int result = a[0];
067        for (int i = 1; i < a.length; i++) {
068            result = gcd(result, a[i]);
069        }
070        return result;
071    }
072
073    public static long pairInt(int x, int y) {
074        return (((long) x) << 32) | (y & 0xffffffffL);
075    }
076
077    public static int unpairIntX(long pair) {
078        return (int) (pair >> 32);
079    }
080
081    public static int unpairIntY(long pair) {
082        return (int) pair;
083    }
084
085    public static byte pair16(byte x, byte y) {
086        return (byte) (x + (y << 4));
087    }
088
089    public static byte unpair16x(byte value) {
090        return (byte) (value & 0xF);
091    }
092
093    public static byte unpair16y(byte value) {
094        return (byte) ((value >> 4) & 0xF);
095    }
096
097    public static long inverseRound(double val) {
098        long round = Math.round(val);
099        return (long) (round + Math.signum(val - round));
100    }
101
102    public static int sqrt(int x) {
103        int xn;
104
105        if (x >= 0x10000) {
106            if (x >= 0x1000000) {
107                if (x >= 0x10000000) {
108                    if (x >= 0x40000000) {
109                        xn = table[x >> 24] << 8;
110                    } else {
111                        xn = table[x >> 22] << 7;
112                    }
113                } else {
114                    if (x >= 0x4000000) {
115                        xn = table[x >> 20] << 6;
116                    } else {
117                        xn = table[x >> 18] << 5;
118                    }
119                }
120
121                xn = (xn + 1 + (x / xn)) >> 1;
122                xn = (xn + 1 + (x / xn)) >> 1;
123                return ((xn * xn) > x) ? --xn : xn;
124            } else {
125                if (x >= 0x100000) {
126                    if (x >= 0x400000) {
127                        xn = table[x >> 16] << 4;
128                    } else {
129                        xn = table[x >> 14] << 3;
130                    }
131                } else {
132                    if (x >= 0x40000) {
133                        xn = table[x >> 12] << 2;
134                    } else {
135                        xn = table[x >> 10] << 1;
136                    }
137                }
138
139                xn = (xn + 1 + (x / xn)) >> 1;
140
141                return ((xn * xn) > x) ? --xn : xn;
142            }
143        } else {
144            if (x >= 0x100) {
145                if (x >= 0x1000) {
146                    if (x >= 0x4000) {
147                        xn = (table[x >> 8]) + 1;
148                    } else {
149                        xn = (table[x >> 6] >> 1) + 1;
150                    }
151                } else {
152                    if (x >= 0x400) {
153                        xn = (table[x >> 4] >> 2) + 1;
154                    } else {
155                        xn = (table[x >> 2] >> 3) + 1;
156                    }
157                }
158
159                return ((xn * xn) > x) ? --xn : xn;
160            } else {
161                if (x >= 0) {
162                    return table[x] >> 4;
163                }
164            }
165        }
166        throw new IllegalArgumentException("Invalid number:" + x);
167    }
168
169
170    public static double getMean(int[] array) {
171        double count = 0;
172        for (int i : array) {
173            count += i;
174        }
175        return count / array.length;
176    }
177
178    public static double getMean(double[] array) {
179        double count = 0;
180        for (double i : array) {
181            count += i;
182        }
183        return count / array.length;
184    }
185
186    public static int pair(short x, short y) {
187        return (x << 16) | (y & 0xFFFF);
188    }
189
190    public static final int average(int a, int b) {
191        return (a & b) + (a ^ b) / 2;
192    }
193
194    public static short unpairX(int hash) {
195        return (short) (hash >> 16);
196    }
197
198    public static short unpairY(int hash) {
199        return (short) (hash & 0xFFFF);
200    }
201
202    /**
203     * get the x,y,z unit vector from pitch and yaw specified
204     *
205     * @param yaw   yaw
206     * @param pitch pitch
207     * @return x, y, z unit vector
208     */
209    public static float[] getDirection(float yaw, float pitch) {
210        double pitch_sin = Math.sin(pitch);
211        return new float[]{(float) (pitch_sin * Math.cos(yaw)),
212                (float) (pitch_sin * Math.sin(yaw)), (float) Math.cos(pitch)};
213    }
214
215    public static int floorMod(int x, int y) {
216        int i = x % y;
217        if (i < 0) {
218            i += y;
219        }
220        return i;
221    }
222
223    public static int roundInt(double value) {
224        return (int) (value < 0 ? (value == (int) value) ? value : value - 1 : value);
225    }
226
227    /**
228     * Returns [ pitch, yaw ]
229     *
230     * @param x x
231     * @param y y
232     * @param z z
233     * @return pitch and yaw of x,y,z from 0,0,0
234     */
235    public static float[] getPitchAndYaw(float x, float y, float z) {
236        float distance = sqrtApprox((z * z) + (x * x));
237        return new float[]{atan2(y, distance), atan2(x, z)};
238    }
239
240    public static final float atan2(float y, float x) {
241        float add;
242        float mul;
243
244        if (x < 0.0f) {
245            if (y < 0.0f) {
246                x = -x;
247                y = -y;
248
249                mul = 1.0f;
250            } else {
251                x = -x;
252                mul = -1.0f;
253            }
254
255            add = -3.141592653f;
256        } else {
257            if (y < 0.0f) {
258                y = -y;
259                mul = -1.0f;
260            } else {
261                mul = 1.0f;
262            }
263
264            add = 0.0f;
265        }
266
267        float invDiv = 1.0f / (((x < y) ? y : x) * INV_ATAN2_DIM_MINUS_1);
268
269        int xi = (int) (x * invDiv);
270        int yi = (int) (y * invDiv);
271
272        return (atan2[(yi * ATAN2_DIM) + xi] + add) * mul;
273    }
274
275    public static float sqrtApprox(float f) {
276        return f * Float.intBitsToFloat(0x5f375a86 - (Float.floatToIntBits(f) >> 1));
277    }
278
279    public static double sqrtApprox(double d) {
280        return Double
281                .longBitsToDouble(((Double.doubleToLongBits(d) - (1L << 52)) >> 1) + (1L << 61));
282    }
283
284    public static float invSqrt(float x) {
285        float xhalf = 0.5f * x;
286        int i = Float.floatToIntBits(x);
287        i = 0x5f3759df - (i >> 1);
288        x = Float.intBitsToFloat(i);
289        x = x * (1.5f - (xhalf * x * x));
290        return x;
291    }
292
293    public static int getPositiveId(int i) {
294        if (i < 0) {
295            return (-i * 2) - 1;
296        }
297        return i * 2;
298    }
299
300    public static boolean isInteger(String str) {
301        if (str == null) {
302            return false;
303        }
304        int length = str.length();
305        if (length == 0) {
306            return false;
307        }
308        int i = 0;
309        if (str.charAt(0) == '-') {
310            if (length == 1) {
311                return false;
312            }
313            i = 1;
314        }
315        for (; i < length; i++) {
316            char c = str.charAt(i);
317            if ((c <= '/') || (c >= ':')) {
318                return false;
319            }
320        }
321        return true;
322    }
323
324    public static double getSD(double[] array, double av) {
325        double sd = 0;
326        for (double element : array) {
327            sd += Math.pow(Math.abs(element - av), 2);
328        }
329        return Math.sqrt(sd / array.length);
330    }
331
332    public static double getSD(int[] array, double av) {
333        double sd = 0;
334        for (int element : array) {
335            sd += Math.pow(Math.abs(element - av), 2);
336        }
337        return Math.sqrt(sd / array.length);
338    }
339
340    public static int mod(int x, int y) {
341        if (isPowerOfTwo(y)) {
342            return x & (y - 1);
343        }
344        return x % y;
345    }
346
347    public static int unsignedmod(int x, int y) {
348        if (isPowerOfTwo(y)) {
349            return x & (y - 1);
350        }
351        return x % y;
352    }
353
354    public static boolean isPowerOfTwo(int number) {
355        return (number & (number - 1)) == 0;
356    }
357
358}