-
Notifications
You must be signed in to change notification settings - Fork 142
/
Math.java
334 lines (264 loc) · 10.3 KB
/
Math.java
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package java.lang;
import static javaemul.internal.InternalPreconditions.checkCriticalArithmetic;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
/**
* Math utility methods and constants.
*/
public final class Math {
// The following methods are not implemented because JS doesn't provide the
// necessary pieces:
// public static double ulp (double x)
// public static float ulp (float x)
// public static int getExponent (double d)
// public static int getExponent (float f)
// public static double IEEEremainder(double f1, double f2)
// public static double nextAfter(double start, double direction)
// public static float nextAfter(float start, float direction)
// public static double nextUp(double start) {
// return nextAfter(start, 1.0d);
// }
// public static float nextUp(float start) {
// return nextAfter(start,1.0f);
// }
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
private static final double PI_OVER_180 = PI / 180.0;
private static final double PI_UNDER_180 = 180.0 / PI;
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.abs")
public static native double abs(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.abs")
public static native float abs(float x);
public static int abs(int x) {
// This relies on J2cl's 32-bit integer coercion so that
// abs(Integer.MIN_VALUE) correctly equals Integer.MIN_VALUE.
return x < 0 ? -x : x;
}
public static long abs(long x) {
return x < 0 ? -x : x;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.acos")
public static native double acos(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.asin")
public static native double asin(double x);
public static int addExact(int x, int y) {
double r = (double) x + (double) y;
checkCriticalArithmetic(isSafeIntegerRange(r));
return (int) r;
}
public static long addExact(long x, long y) {
long r = x + y;
// "Hacker's Delight" 2-12 Overflow if both arguments have the opposite sign of the result
checkCriticalArithmetic(((x ^ r) & (y ^ r)) >= 0);
return r;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.atan")
public static native double atan(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.atan2")
public static native double atan2(double y, double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.cbrt")
public static native double cbrt(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.ceil")
public static native double ceil(double x);
public static double copySign(double magnitude, double sign) {
return isNegative(sign) ? -abs(magnitude) : abs(magnitude);
}
private static boolean isNegative(double d) {
return d < 0 || 1 / d < 0;
}
public static float copySign(float magnitude, float sign) {
return (float) copySign((double) magnitude, (double) sign);
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.cos")
public static native double cos(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.cosh")
public static native double cosh(double x);
public static int decrementExact(int x) {
checkCriticalArithmetic(x != Integer.MIN_VALUE);
return x - 1;
}
public static long decrementExact(long x) {
checkCriticalArithmetic(x != Long.MIN_VALUE);
return x - 1;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.exp")
public static native double exp(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.expm1")
public static native double expm1(double d);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.floor")
public static native double floor(double x);
public static int floorDiv(int dividend, int divisor) {
checkCriticalArithmetic(divisor != 0);
// round down division if the signs are different and modulo not zero
return ((dividend ^ divisor) >= 0 ? dividend / divisor : ((dividend + 1) / divisor) - 1);
}
public static long floorDiv(long dividend, long divisor) {
checkCriticalArithmetic(divisor != 0);
// round down division if the signs are different and modulo not zero
return ((dividend ^ divisor) >= 0 ? dividend / divisor : ((dividend + 1) / divisor) - 1);
}
public static int floorMod(int dividend, int divisor) {
checkCriticalArithmetic(divisor != 0);
return ((dividend % divisor) + divisor) % divisor;
}
public static long floorMod(long dividend, long divisor) {
checkCriticalArithmetic(divisor != 0);
return ((dividend % divisor) + divisor) % divisor;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.hypot")
public static native double hypot(double x, double y);
public static int incrementExact(int x) {
checkCriticalArithmetic(x != Integer.MAX_VALUE);
return x + 1;
}
public static long incrementExact(long x) {
checkCriticalArithmetic(x != Long.MAX_VALUE);
return x + 1;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.log")
public static native double log(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.log10")
public static native double log10(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.log1p")
public static native double log1p(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.max")
public static native double max(double x, double y);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.max")
public static native float max(float x, float y);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.max")
public static native int max(int x, int y);
public static long max(long x, long y) {
return x > y ? x : y;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.min")
public static native double min(double x, double y);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.min")
public static native float min(float x, float y);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.min")
public static native int min(int x, int y);
public static long min(long x, long y) {
return x < y ? x : y;
}
public static int multiplyExact(int x, int y) {
double r = (double) x * (double) y;
checkCriticalArithmetic(isSafeIntegerRange(r));
return (int) r;
}
public static long multiplyExact(long x, long y) {
if (y == -1) {
return negateExact(x);
}
if (y == 0) {
return 0;
}
long r = x * y;
checkCriticalArithmetic(r / y == x);
return r;
}
public static int negateExact(int x) {
checkCriticalArithmetic(x != Integer.MIN_VALUE);
return -x;
}
public static long negateExact(long x) {
checkCriticalArithmetic(x != Long.MIN_VALUE);
return -x;
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.pow")
public static native double pow(double x, double exp);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.random")
public static native double random();
public static double rint(double x) {
// Floating point has a mantissa with an accuracy of 52 bits so
// any number bigger than 2^52 is effectively a finite integer value.
// This case also filters out NaN and infinite values.
if (abs(x) < (double) (1L << 52)) {
double mod2 = x % 2;
if ((mod2 == -1.5) || (mod2 == 0.5)) {
x = floor(x);
} else {
x = round(x);
}
}
return x;
}
public static long round(double x) {
return (long) NativeMath.round(x);
}
public static int round(float x) {
return (int) NativeMath.round(x);
}
public static int subtractExact(int x, int y) {
double r = (double) x - (double) y;
checkCriticalArithmetic(isSafeIntegerRange(r));
return (int) r;
}
public static long subtractExact(long x, long y) {
long r = x - y;
// "Hacker's Delight" Overflow if the arguments have different signs and
// the sign of the result is different than the sign of x
checkCriticalArithmetic(((x ^ y) & (x ^ r)) >= 0);
return r;
}
public static double scalb(double d, int scaleFactor) {
if (scaleFactor >= 31 || scaleFactor <= -31) {
return d * pow(2, scaleFactor);
} else if (scaleFactor > 0) {
return d * (1 << scaleFactor);
} else if (scaleFactor == 0) {
return d;
} else {
return d / (1 << -scaleFactor);
}
}
public static float scalb(float f, int scaleFactor) {
return (float) scalb((double) f, scaleFactor);
}
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.sign")
public static native double signum(double d);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.sign")
public static native float signum(float f);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.sin")
public static native double sin(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.sinh")
public static native double sinh(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.sqrt")
public static native double sqrt(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.tan")
public static native double tan(double x);
@JsMethod(namespace = JsPackage.GLOBAL, name = "Math.tanh")
public static native double tanh(double x);
public static double toDegrees(double x) {
return x * PI_UNDER_180;
}
public static int toIntExact(long x) {
int ix = (int) x;
checkCriticalArithmetic(ix == x);
return ix;
}
public static double toRadians(double x) {
return x * PI_OVER_180;
}
private static boolean isSafeIntegerRange(double value) {
return Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE;
}
@JsType(isNative = true, name = "Math", namespace = JsPackage.GLOBAL)
private static class NativeMath {
public static native double round(double x);
}
}