1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.util;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.PrintStream;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.nio.charset.StandardCharsets;
26 import java.util.Arrays;
27
28 import org.junit.Assert;
29 import org.junit.Test;
30
31 public class FastMathCalcTest {
32
33 @Test
34 public void testExpIntTables() {
35
36 final double[] fmTableA = getD1("ExpIntTable", "EXP_INT_TABLE_A");
37 final double[] fmTableB = getD1("ExpIntTable", "EXP_INT_TABLE_B");
38 final int len = getInt("EXP_INT_TABLE_LEN");
39 final int max = getInt("EXP_INT_TABLE_MAX_INDEX");
40 Assert.assertEquals(len, fmTableA.length);
41 Assert.assertEquals(len, fmTableB.length);
42
43 final double[] tmp = new double[2];
44 final double[] recip = new double[2];
45 for (int i = 0; i < max; i++) {
46 FastMathCalc.expint(i, tmp);
47 if (i == 0) {
48 Assert.assertEquals(fmTableA[max], tmp[0], FastMath.ulp(fmTableA[i]));
49 Assert.assertEquals(fmTableB[max], tmp[1], FastMath.ulp(fmTableB[i]));
50 } else {
51 FastMathCalc.splitReciprocal(tmp, recip);
52 Assert.assertEquals(fmTableA[max - i], recip[0], FastMath.ulp(fmTableA[i]));
53 Assert.assertEquals(fmTableB[max - i], recip[1], FastMath.ulp(fmTableB[i]));
54 }
55 }
56
57 }
58
59 @Test
60 public void testExpFracTables() {
61
62 final double[] fmTableA = getD1("ExpFracTable", "EXP_FRAC_TABLE_A");
63 final double[] fmTableB = getD1("ExpFracTable", "EXP_FRAC_TABLE_B");
64 final int len = getInt("EXP_FRAC_TABLE_LEN");
65 Assert.assertEquals(len, fmTableA.length);
66 Assert.assertEquals(len, fmTableB.length);
67
68 final double factor = 1d / (len - 1);
69 final double[] tmp = new double[2];
70 for (int i = 0; i < len; i++) {
71 FastMathCalc.slowexp(i * factor, tmp);
72 Assert.assertEquals(fmTableA[i], tmp[0], FastMath.ulp(fmTableA[i]));
73 Assert.assertEquals(fmTableB[i], tmp[1], FastMath.ulp(fmTableB[i]));
74 }
75
76 }
77
78 @Test
79 public void testLnMantTables() {
80 final double[][] fmTable = getD2("lnMant", "LN_MANT");
81 final int len = getInt("LN_MANT_LEN");
82 Assert.assertEquals(len, fmTable.length);
83
84 for (int i = 0; i < len; i++) {
85 final double d = Double.longBitsToDouble( (((long) i) << 42) | 0x3ff0000000000000L );
86 final double[] tmp = FastMathCalc.slowLog(d);
87 Assert.assertEquals(fmTable[i].length, tmp.length);
88 for (int j = 0; j < fmTable[i].length; ++j) {
89 Assert.assertEquals(fmTable[i][j], tmp[j], FastMath.ulp(fmTable[i][j]));
90 }
91 }
92
93 }
94
95 @Test
96 public void testSplit() {
97 checkSplit(0x3ffe0045dab7321fl, 0x3ffe0045c0000000l, 0x3e7ab7321f000000l);
98 checkSplit(0x3ffe0045fab7321fl, 0x3ffe004600000000l, 0xbe55233784000000l);
99 checkSplit(0x7dfedcba9876543fl, 0x7dfedcba80000000l, 0x7c7876543f000000l);
100 checkSplit(0x7dfedcbaf876543fl, 0x7dfedcbb00000000l, 0xfc5e26af04000000l);
101 checkSplit(0xfdfedcba9876543fl, 0xfdfedcba80000000l, 0xfc7876543f000000l);
102 checkSplit(0xfdfedcbaf876543fl, 0xfdfedcbb00000000l, 0x7c5e26af04000000l);
103 }
104
105 private void checkSplit(final long bits, final long high, final long low) {
106 try {
107 Method split = FastMathCalc.class.getDeclaredMethod("split", Double.TYPE, double[].class);
108 split.setAccessible(true);
109 double d = Double.longBitsToDouble(bits);
110 double[] result = new double[2];
111 split.invoke(null, d, result);
112 Assert.assertEquals(bits, Double.doubleToRawLongBits(result[0] + result[1]));
113 Assert.assertEquals(high, Double.doubleToRawLongBits(result[0]));
114 Assert.assertEquals(low, Double.doubleToRawLongBits(result[1]));
115
116 } catch (NoSuchMethodException | SecurityException | IllegalArgumentException |
117 IllegalAccessException | InvocationTargetException e) {
118 Assert.fail(e.getLocalizedMessage());
119 }
120 }
121
122 @Test
123 public void testSinCosTanTables() {
124 try {
125 final double[] sinA = getFastMathTable("SINE_TABLE_A");
126 final double[] sinB = getFastMathTable("SINE_TABLE_B");
127 final double[] cosA = getFastMathTable("COSINE_TABLE_A");
128 final double[] cosB = getFastMathTable("COSINE_TABLE_B");
129 final double[] tanA = getFastMathTable("TANGENT_TABLE_A");
130 final double[] tanB = getFastMathTable("TANGENT_TABLE_B");
131 Method buildSinCosTables = FastMathCalc.class.getDeclaredMethod("buildSinCosTables",
132 double[].class, double[].class, double[].class, double[].class,
133 Integer.TYPE,
134 double[].class, double[].class);
135 buildSinCosTables.setAccessible(true);
136 final double[] calcSinA = new double[sinA.length];
137 final double[] calcSinB = new double[sinB.length];
138 final double[] calcCosA = new double[cosA.length];
139 final double[] calcCosB = new double[cosB.length];
140 final double[] calcTanA = new double[tanA.length];
141 final double[] calcTanB = new double[tanB.length];
142 buildSinCosTables.invoke(null, calcSinA, calcSinB, calcCosA, calcCosB, sinA.length, calcTanA, calcTanB);
143 checkTable(sinA, calcSinA, 0);
144 checkTable(sinB, calcSinB, 0);
145 checkTable(cosA, calcCosA, 0);
146 checkTable(cosB, calcCosB, 0);
147 checkTable(tanA, calcTanA, 0);
148 checkTable(tanB, calcTanB, 0);
149
150 } catch (NoSuchMethodException | SecurityException | IllegalArgumentException |
151 IllegalAccessException | InvocationTargetException e) {
152 Assert.fail(e.getLocalizedMessage());
153 }
154 }
155
156 private double[] getFastMathTable(final String name) {
157 try {
158 final Field field = FastMath.class.getDeclaredField(name);
159 field.setAccessible(true);
160 return (double[]) field.get(null);
161 } catch (NoSuchFieldException | SecurityException |
162 IllegalArgumentException | IllegalAccessException e) {
163 Assert.fail(e.getLocalizedMessage());
164 return null;
165 }
166 }
167
168 private void checkTable(final double[] reference, final double[] actual, int maxUlps) {
169 Assert.assertEquals(reference.length, actual.length);
170 for (int i = 0; i < reference.length; ++i) {
171 Assert.assertTrue(Precision.equals(reference[i], actual[i], maxUlps));
172 }
173 }
174
175 @Test
176 public void testPrintArray1() {
177 try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
178 PrintStream ps = new PrintStream(bos, true, StandardCharsets.UTF_8.name())) {
179 Method printArray = FastMathCalc.class.getDeclaredMethod("printarray", PrintStream.class,
180 String.class, Integer.TYPE, double[].class);
181 printArray.setAccessible(true);
182 printArray.invoke(null, ps, "name", 2, new double[] { 1.25, -0.5 });
183 Assert.assertEquals(String.format("name=%n" +
184 " {%n" +
185 " +1.25d,%n" +
186 " -0.5d,%n" +
187 " };%n"),
188 bos.toString(StandardCharsets.UTF_8.name()));
189 } catch (IOException | NoSuchMethodException | IllegalAccessException |
190 IllegalArgumentException | InvocationTargetException e) {
191 e.printStackTrace();
192 Assert.fail(e.getLocalizedMessage());
193 }
194 }
195
196 @Test
197 public void testPrintArray2() {
198 try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
199 PrintStream ps = new PrintStream(bos, true, StandardCharsets.UTF_8.name())) {
200 Method printArray = FastMathCalc.class.getDeclaredMethod("printarray", PrintStream.class,
201 String.class, Integer.TYPE, double[][].class);
202 printArray.setAccessible(true);
203 printArray.invoke(null, ps, "name", 2, new double[][] { { 1.25, -0.5 }, { 0.0, 3.0 } });
204 Assert.assertEquals(String.format("name%n" +
205 " { %n" +
206 " {+1.25d, -0.5d, }, // 0%n" +
207 " {+0.0d, +3.0d, }, // 1%n" +
208 " };%n"),
209 bos.toString(StandardCharsets.UTF_8.name()));
210 } catch (IOException | NoSuchMethodException | IllegalAccessException |
211 IllegalArgumentException | InvocationTargetException e) {
212 e.printStackTrace();
213 Assert.fail(e.getLocalizedMessage());
214 }
215 }
216
217 private double[] getD1(final String innerClassName, final String tableName) {
218 try {
219
220 final Class<?> inerClass = Arrays.stream(FastMath.class.getDeclaredClasses()).
221 filter(c -> c.getName().endsWith("$" + innerClassName)).
222 findFirst().
223 get();
224 final Field fmTableField = inerClass.getDeclaredField(tableName);
225 fmTableField.setAccessible(true);
226 return (double[]) fmTableField.get(null);
227
228 } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
229 Assert.fail(e.getLocalizedMessage());
230 return null;
231 }
232 }
233
234 private double[][] getD2(final String innerClassName, final String tableName) {
235 try {
236
237 final Class<?> inerClass = Arrays.stream(FastMath.class.getDeclaredClasses()).
238 filter(c -> c.getName().endsWith("$" + innerClassName)).
239 findFirst().
240 get();
241 final Field fmTableField = inerClass.getDeclaredField(tableName);
242 fmTableField.setAccessible(true);
243 return (double[][]) fmTableField.get(null);
244
245 } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
246 Assert.fail(e.getLocalizedMessage());
247 return null;
248 }
249 }
250
251 private int getInt(String lenName) {
252 try {
253
254 final Field fmLen = FastMath.class.getDeclaredField(lenName);
255 fmLen.setAccessible(true);
256 return ((Integer) fmLen.get(null)).intValue();
257
258 } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
259 Assert.fail(e.getLocalizedMessage());
260 return -1;
261 }
262 }
263
264 }