View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math.util;
19  
20  import java.io.File;
21  import java.io.DataOutputStream;
22  import java.io.InputStream;
23  import java.io.DataInputStream;
24  import java.io.BufferedOutputStream;
25  import java.io.BufferedInputStream;
26  import java.io.FileOutputStream;
27  import java.io.FileNotFoundException;
28  import java.io.IOException;
29  import java.nio.ByteBuffer;
30  import java.nio.DoubleBuffer;
31  import org.apache.commons.math.exception.MathInternalError;
32  
33  /**
34   * Utility class for saving and loading tabulated data used by
35   * {@link FastMath}.
36   *
37   * @version $Id$
38   */
39  class FastMathResources {
40      /**
41       * Resource directory. Assuming that this class and the resource files
42       * are located in the same package as "FastMath".
43       */
44      private static final String RES_DIR = "data/" +
45          FastMath.class.getPackage().getName().replace('.', '/') + "/";
46      /** File resource prefix. */
47      private static final String RES_PREFIX = RES_DIR + "FastMath__";
48      /** Resource basename for "EXP_INT_TABLE_A" and "EXP_INT_TABLE_B". */
49      private static final String EXP_INT = "exp_int";
50      /** Resource basename for "EXP_FRAC_TABLE_A" and "EXP_FRAC_TABLE_B". */
51      private static final String EXP_FRAC = "exp_frac";
52      /** Resource basename for "LN_MANT". */
53      private static final String LN_MANT = "ln_mant";
54      /** Number of bytes in a "double". */
55      private static final int BYTES_IN_DOUBLE = Double.SIZE / Byte.SIZE;
56  
57      /**
58       * Class contains only static methods.
59       */
60      private FastMathResources() {}
61  
62      /**
63       * Compute and save all the resources.
64       */
65      static void createAll() {
66          // Create resource directory.
67          final File resDir = new File(RES_DIR);
68          if (resDir.exists()) {
69              if (!resDir.isDirectory()) {
70                  throw new MathInternalError();
71              }
72          } else {
73              try {
74                  resDir.mkdirs();
75              } catch (SecurityException e) {
76                  throw new MathInternalError(e);
77              }
78          }
79  
80          // "EXP_INT" tables.
81          final double[] expIntA = new double[FastMath.EXP_INT_TABLE_LEN];
82          final double[] expIntB = new double[FastMath.EXP_INT_TABLE_LEN];
83  
84          final double tmp[] = new double[2];
85          final double recip[] = new double[2];
86  
87          for (int i = 0; i < FastMath.EXP_INT_TABLE_MAX_INDEX; i++) {
88              FastMathCalc.expint(i, tmp);
89              expIntA[i + FastMath.EXP_INT_TABLE_MAX_INDEX] = tmp[0];
90              expIntB[i + FastMath.EXP_INT_TABLE_MAX_INDEX] = tmp[1];
91  
92              if (i != 0) {
93                  // Negative integer powers.
94                  FastMathCalc.splitReciprocal(tmp, recip);
95                  expIntA[FastMath.EXP_INT_TABLE_MAX_INDEX - i] = recip[0];
96                  expIntB[FastMath.EXP_INT_TABLE_MAX_INDEX - i] = recip[1];
97              }
98          }
99  
100         saveTable2d(EXP_INT, new double[][] { expIntA, expIntB });
101 
102         // "EXP_FRAC" tables.
103         final double[] expFracA = new double[FastMath.EXP_FRAC_TABLE_LEN];
104         final double[] expFracB = new double[FastMath.EXP_FRAC_TABLE_LEN];
105 
106         for (int i = 0; i < FastMath.EXP_FRAC_TABLE_LEN; i++) {
107             FastMathCalc.slowexp(i / 1024d, tmp); // TWO_POWER_10
108             expFracA[i] = tmp[0];
109             expFracB[i] = tmp[1];
110         }
111 
112         saveTable2d(EXP_FRAC, new double[][] { expFracA, expFracB });
113 
114         // "LN_MANT" table.
115         final double[][] lnMant = new double[FastMath.LN_MANT_LEN][];
116 
117         for (int i = 0; i < FastMath.LN_MANT_LEN; i++) {
118             final double d = Double.longBitsToDouble((((long) i) << 42) |
119                                                      0x3ff0000000000000L);
120             lnMant[i] = FastMathCalc.slowLog(d);
121         }
122 
123         saveTable2d(LN_MANT, transpose(lnMant));
124     }
125 
126     /**
127      * Load "EXP_INT" tables.
128      * "EXP_INT_TABLE_A" is at index 0.
129      * "EXP_INT_TABLE_B" is at index 1.
130      *
131      * @return the retrieved data.
132      */
133     static double[][] loadExpInt() {
134         return loadTable2d(EXP_INT, 2, FastMath.EXP_INT_TABLE_LEN);
135     }
136 
137     /**
138      * Load "EXP_FRAC" tables.
139      * "EXP_FRAC_TABLE_A" is at index 0.
140      * "EXP_FRAC_TABLE_B" is at index 1.
141      *
142      * @return the retrieved data.
143      */
144     static double[][] loadExpFrac() {
145         return loadTable2d(EXP_FRAC, 2, FastMath.EXP_FRAC_TABLE_LEN);
146     }
147 
148     /**
149      * Load "LN_MANT".
150      *
151      * @return the retrieved data.
152      */
153     static double[][] loadLnMant() {
154         return transpose(loadTable2d(LN_MANT, 2, FastMath.LN_MANT_LEN));
155     }
156 
157     /**
158      * @param name Basename of the resource.
159      * @return an output stream.
160      * @throws FileNotFoundException if the file cannot be opened.
161      */
162     private static DataOutputStream out(String name)
163         throws FileNotFoundException {
164         final String fullName = RES_PREFIX + name;
165         return new DataOutputStream(new BufferedOutputStream(new FileOutputStream(fullName)));
166     }
167 
168     /**
169      * @param name Basename of the resource.
170      * @param data Data to be stored.
171      */
172     private static void saveTable1d(String name,
173                                     double[] data) {
174         final int len = data.length;
175 
176         try {
177             final DataOutputStream out = out(name);
178 
179             for (int i = 0; i < len; i++) {
180                 out.writeDouble(data[i]);
181             }
182 
183             out.close();
184         } catch (IOException e) {
185             throw new MathInternalError(e);
186         }
187     }
188 
189     /**
190      * @param name Basename of the resource.
191      * @param data Data to be stored.
192      */
193     private static void saveTable2d(String name,
194                                     double[][] data) {
195         final int len = data.length;
196         final int rowLen = data[0].length;
197 
198         try {
199             final DataOutputStream out = out(name);
200 
201             for (int i = 0; i < len; i++) {
202                 for (int j = 0; j < rowLen; j++) {
203                     out.writeDouble(data[i][j]);
204                 }
205             }
206 
207             out.close();
208         } catch (IOException e) {
209             throw new MathInternalError(e);
210         }
211     }
212 
213     /**
214      * @param name Basename of the resource.
215      * @return an input stream.
216      * @throws FileNotFoundException if the resource cannot be accessed.
217      */
218     private static DataInputStream in(String name)
219         throws FileNotFoundException {
220         final String fullName = "/" + RES_PREFIX + name;
221         final InputStream in = FastMathResources.class.getResourceAsStream(fullName);
222         return new DataInputStream(new BufferedInputStream(in));
223     }
224 
225     /**
226      * @param name Basename of the resource.
227      * @param len Size of the data.
228      * @return the retrieved data.
229      */
230     private static double[] loadTable1d(String name,
231                                         int len) {
232         try {
233             final DataInputStream in = in(name);
234 
235             final double[] data = new double[len];
236             for (int i = 0; i < len; i++) {
237                 data[i] = in.readDouble();
238             }
239 
240             in.close();
241             return data;
242         } catch (IOException e) {
243             throw new MathInternalError(e);
244         }
245     }
246 
247     /**
248      * @param name Basename of the resource.
249      * @param len Size of the table.
250      * @param rowLen Size of each row of the table.
251      * @return the retrieved data.
252      */
253     private static double[][] loadTable2d(String name,
254                                           int len,
255                                           int rowLen) {
256         try {
257             final DataInputStream in = in(name);
258             final byte[] b = new byte[BYTES_IN_DOUBLE * rowLen];
259             final double[][] data = new double[len][rowLen];
260             final ByteBuffer bBuf = ByteBuffer.wrap(b);
261 
262             for (int i = 0; i < len; i++) {
263                 in.readFully(b);
264                 final DoubleBuffer dBuf = bBuf.asDoubleBuffer();
265                 for (int j = 0; j < rowLen; j++) {
266                     data[i][j] = dBuf.get();
267                 }
268             }
269 
270             in.close();
271             return data;
272         } catch (IOException e) {
273             throw new MathInternalError(e);
274         }
275     }
276 
277     /**
278      * Transposes a two-dimensional array: The number of rows becomes the
279      * number of columns and vice-versa.
280      * The array must be rectangular (same number of colums in each row).
281      *
282      * @param data Array to be transposed.
283      * @return the transposed array.
284      */
285     private static double[][] transpose(double[][] data) {
286         final int rowLen = data.length;
287         final int len = data[0].length;
288         final double[][] tData = new double[len][rowLen];
289 
290         for (int i = 0; i < len; i++) {
291             for (int j = 0; j < rowLen; j++) {
292                 tData[i][j] = data[j][i];
293             }
294         }
295 
296         return tData;
297     }
298 }