File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\util\MathUtils.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.util;
8
9 import java.io.ByteArrayOutputStream;
10 import java.io.DataOutputStream;
11 import java.io.IOException;
12 import java.lang.reflect.Method;
13 import java.math.BigDecimal;
14 import java.security.SecureRandom;
15 import java.util.Random;
16 import org.h2.message.DbException;
17
18 /**
19 * This is a utility class with mathematical helper functions.
20 */
21 public class MathUtils {
22
23 /**
24 * The secure random object.
25 */
26 static SecureRandom cachedSecureRandom;
27
28 /**
29 * True if the secure random object is seeded.
30 */
31 static volatile boolean seeded;
32
33 private static final Random RANDOM = new Random();
34
35 /**
36 * The maximum scale of a BigDecimal value.
37 */
38 private static final int BIG_DECIMAL_SCALE_MAX = 100000;
39
40
41 private MathUtils() {
42 // utility class
43 }
44
45 private static synchronized SecureRandom getSecureRandom() {
46 if (cachedSecureRandom != null) {
47 return cachedSecureRandom;
48 }
49 // Workaround for SecureRandom problem as described in
50 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6202721
51 // Can not do that in a static initializer block, because
52 // threads are not started until after the initializer block exits
53 try {
54 cachedSecureRandom = SecureRandom.getInstance("SHA1PRNG");
55 // On some systems, secureRandom.generateSeed() is very slow.
56 // In this case it is initialized using our own seed implementation
57 // and afterwards (in the thread) using the regular algorithm.
58 Runnable runnable = new Runnable() {
59 public void run() {
60 try {
61 SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
62 byte[] seed = sr.generateSeed(20);
63 synchronized (cachedSecureRandom) {
64 cachedSecureRandom.setSeed(seed);
65 seeded = true;
66 }
67 } catch (Exception e) {
68 // NoSuchAlgorithmException
69 warn("SecureRandom", e);
70 }
71 }
72 };
73
74 try {
75 Thread t = new Thread(runnable, "Generate Seed");
76 // let the process terminate even if generating the seed is really slow
77 t.setDaemon(true);
78 t.start();
79 Thread.yield();
80 try {
81 // normally, generateSeed takes less than 200 ms
82 t.join(400);
83 } catch (InterruptedException e) {
84 warn("InterruptedException", e);
85 }
86 if (!seeded) {
87 byte[] seed = generateAlternativeSeed();
88 // this never reduces randomness
89 synchronized (cachedSecureRandom) {
90 cachedSecureRandom.setSeed(seed);
91 }
92 }
93 } catch (SecurityException e) {
94 // workaround for the Google App Engine: don't use a thread
95 runnable.run();
96 generateAlternativeSeed();
97 }
98
99 } catch (Exception e) {
100 // NoSuchAlgorithmException
101 warn("SecureRandom", e);
102 cachedSecureRandom = new SecureRandom();
103 }
104 return cachedSecureRandom;
105 }
106
107 private static byte[] generateAlternativeSeed() {
108 try {
109 ByteArrayOutputStream bout = new ByteArrayOutputStream();
110 DataOutputStream out = new DataOutputStream(bout);
111
112 // milliseconds
113 out.writeLong(System.currentTimeMillis());
114
115 // nanoseconds if available
116 try {
117 Method m = System.class.getMethod("nanoTime");
118 if (m != null) {
119 Object o = m.invoke(null);
120 out.writeUTF(o.toString());
121 }
122 } catch (Exception e) {
123 // nanoTime not found, this is ok (only exists for JDK 1.5 and higher)
124 out.writeUTF(e.toString());
125 }
126
127 // memory
128 out.writeInt(new Object().hashCode());
129 Runtime runtime = Runtime.getRuntime();
130 out.writeLong(runtime.freeMemory());
131 out.writeLong(runtime.maxMemory());
132 out.writeLong(runtime.totalMemory());
133
134 // environment
135 try {
136 String s = System.getProperties().toString();
137 // can't use writeUTF, as the string
138 // might be larger than 64 KB
139 out.writeInt(s.length());
140 out.write(s.getBytes("UTF-8"));
141 } catch (Exception e) {
142 warn("generateAlternativeSeed", e);
143 }
144
145 // host name and ip addresses (if any)
146 try {
147 // workaround for the Google App Engine: don't use InetAddress
148 Class<?> inetAddressClass = Class.forName("java.net.InetAddress");
149 Object localHost = inetAddressClass.getMethod("getLocalHost").invoke(null);
150 String hostName = inetAddressClass.getMethod("getHostName").invoke(localHost).toString();
151 out.writeUTF(hostName);
152 Object[] list = (Object[]) inetAddressClass.getMethod("getAllByName", String.class).invoke(null, hostName);
153 Method getAddress = inetAddressClass.getMethod("getAddress");
154 for (Object o : list) {
155 out.write((byte[]) getAddress.invoke(o));
156 }
157 } catch (Throwable e) {
158 // on some system, InetAddress is not supported
159 // on some system, InetAddress.getLocalHost() doesn't work
160 // for some reason (incorrect configuration)
161 }
162
163 // timing (a second thread is already running usually)
164 for (int j = 0; j < 16; j++) {
165 int i = 0;
166 long end = System.currentTimeMillis();
167 while (end == System.currentTimeMillis()) {
168 i++;
169 }
170 out.writeInt(i);
171 }
172
173 out.close();
174 return bout.toByteArray();
175 } catch (IOException e) {
176 warn("generateAlternativeSeed", e);
177 return new byte[1];
178 }
179 }
180
181 /**
182 * Print a message to system output if there was a problem initializing the
183 * random number generator.
184 *
185 * @param s the message to print
186 * @param t the stack trace
187 */
188 static void warn(String s, Throwable t) {
189 // not a fatal problem, but maybe reduced security
190 System.out.println("Warning: " + s);
191 if (t != null) {
192 t.printStackTrace();
193 }
194 }
195
196 /**
197 * Round the value up to the next block size. The block size must be a power
198 * of two. As an example, using the block size of 8, the following rounding
199 * operations are done: 0 stays 0; values 1..8 results in 8, 9..16 results
200 * in 16, and so on.
201 *
202 * @param x the value to be rounded
203 * @param blockSizePowerOf2 the block size
204 * @return the rounded value
205 */
206 public static int roundUpInt(int x, int blockSizePowerOf2) {
207 return (x + blockSizePowerOf2 - 1) & (-blockSizePowerOf2);
208 }
209
210 /**
211 * Round the value up to the next block size. The block size must be a power
212 * of two. As an example, using the block size of 8, the following rounding
213 * operations are done: 0 stays 0; values 1..8 results in 8, 9..16 results
214 * in 16, and so on.
215 *
216 * @param x the value to be rounded
217 * @param blockSizePowerOf2 the block size
218 * @return the rounded value
219 */
220 public static long roundUpLong(long x, long blockSizePowerOf2) {
221 return (x + blockSizePowerOf2 - 1) & (-blockSizePowerOf2);
222 }
223
224 /**
225 * Get the value that is equal or higher than this value, and that is a
226 * power of two.
227 *
228 * @param x the original value
229 * @return the next power of two value
230 */
231 public static int nextPowerOf2(int x) {
232 long i = 1;
233 while (i < x && i < (Integer.MAX_VALUE / 2)) {
234 i += i;
235 }
236 return (int) i;
237 }
238
239 /**
240 * Set the scale of a BigDecimal value.
241 *
242 * @param bd the BigDecimal value
243 * @param scale the new scale
244 * @return the scaled value
245 */
246 public static BigDecimal setScale(BigDecimal bd, int scale) {
247 if (scale > BIG_DECIMAL_SCALE_MAX || scale < -BIG_DECIMAL_SCALE_MAX) {
248 throw DbException.getInvalidValueException("scale", scale);
249 }
250 return bd.setScale(scale, BigDecimal.ROUND_HALF_UP);
251 }
252
253 /**
254 * Convert a long value to an int value. Values larger than the biggest int
255 * value is converted to the biggest int value, and values smaller than the
256 * smallest int value are converted to the smallest int value.
257 *
258 * @param l the value to convert
259 * @return the converted int value
260 */
261 public static int convertLongToInt(long l) {
262 if (l <= Integer.MIN_VALUE) {
263 return Integer.MIN_VALUE;
264 } else if (l >= Integer.MAX_VALUE) {
265 return Integer.MAX_VALUE;
266 } else {
267 return (int) l;
268 }
269 }
270
271 /**
272 * Compare two values. Returns -1 if the first value is smaller, 1 if bigger,
273 * and 0 if equal.
274 *
275 * @param a the first value
276 * @param b the second value
277 * @return the result
278 */
279 public static int compareInt(int a, int b) {
280 return a == b ? 0 : a < b ? -1 : 1;
281 }
282
283 /**
284 * Compare two values. Returns -1 if the first value is smaller, 1 if bigger,
285 * and 0 if equal.
286 *
287 * @param a the first value
288 * @param b the second value
289 * @return the result
290 */
291 public static int compareLong(long a, long b) {
292 return a == b ? 0 : a < b ? -1 : 1;
293 }
294
295 /**
296 * Get a cryptographically secure pseudo random long value.
297 *
298 * @return the random long value
299 */
300 public static long secureRandomLong() {
301 SecureRandom sr = getSecureRandom();
302 synchronized (sr) {
303 return sr.nextLong();
304 }
305 }
306
307 /**
308 * Get a number of pseudo random bytes.
309 *
310 * @param bytes the target array
311 */
312 public static void randomBytes(byte[] bytes) {
313 RANDOM.nextBytes(bytes);
314 }
315
316 /**
317 * Get a number of cryptographically secure pseudo random bytes.
318 *
319 * @param len the number of bytes
320 * @return the random bytes
321 */
322 public static byte[] secureRandomBytes(int len) {
323 if (len <= 0) {
324 len = 1;
325 }
326 byte[] buff = new byte[len];
327 SecureRandom sr = getSecureRandom();
328 synchronized (sr) {
329 sr.nextBytes(buff);
330 }
331 return buff;
332 }
333
334 /**
335 * Get a pseudo random int value between 0 (including and the given value
336 * (excluding). The value is not cryptographically secure.
337 *
338 * @param lowerThan the value returned will be lower than this value
339 * @return the random long value
340 */
341 public static int randomInt(int lowerThan) {
342 return RANDOM.nextInt(lowerThan);
343 }
344
345 /**
346 * Get a cryptographically secure pseudo random int value between 0
347 * (including and the given value (excluding).
348 *
349 * @param lowerThan the value returned will be lower than this value
350 * @return the random long value
351 */
352 public static int secureRandomInt(int lowerThan) {
353 SecureRandom sr = getSecureRandom();
354 synchronized (sr) {
355 return sr.nextInt(lowerThan);
356 }
357 }
358
359 }
360