From c6c3d81731acb51c499b94d250287e02bea3d2b8 Mon Sep 17 00:00:00 2001 From: yeom Date: Mon, 3 Oct 2011 00:28:34 +0000 Subject: [PATCH] annotated version. --- .../SSJava/JavaNator/MotorControl.java | 292 +++++++++++++ .../SSJava/JavaNator/MotorController.java | 4 - .../SSJava/JavaNator/PWMManager.java | 63 +-- .../Benchmarks/SSJava/JavaNator/RCBridge.java | 13 +- .../SSJava/JavaNator/RobotMain.java | 105 +++-- .../SSJava/JavaNator/StrategyMgr.java | 88 ++-- .../SSJava/JavaNator/TestSensorInput.java | 2 + Robust/src/ClassLibrary/SSJava/Random.java | 406 ++++++++++++++++++ 8 files changed, 853 insertions(+), 120 deletions(-) create mode 100644 Robust/src/Benchmarks/SSJava/JavaNator/MotorControl.java delete mode 100644 Robust/src/Benchmarks/SSJava/JavaNator/MotorController.java create mode 100644 Robust/src/ClassLibrary/SSJava/Random.java diff --git a/Robust/src/Benchmarks/SSJava/JavaNator/MotorControl.java b/Robust/src/Benchmarks/SSJava/JavaNator/MotorControl.java new file mode 100644 index 00000000..0a879fa1 --- /dev/null +++ b/Robust/src/Benchmarks/SSJava/JavaNator/MotorControl.java @@ -0,0 +1,292 @@ +/* + * PWMRtsj.java + * + * Copyright (c) 1993-2002 Sun Microsystems, Inc. All Rights Reserved. + * + * This software is the confidential and proprietary information of Sun + * Microsystems, Inc. ("Confidential Information"). You shall not + * disclose such Confidential Information and shall use it only in + * accordance with the terms of the license agreement you entered into + * with Sun. + * + * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + */ + +/** + * This class is a wrapper for a PWMControl introduced by porting to SSJava. It + * maintains two key fields motorLeftUpTime and motorRightUpTime and expects + * that the control thread who is running from the other side gets the current + * settings. + */ + +@LATTICE("UP= 44)) { + return 45; + } + return timePosition; + } + + /** + * setSpeedSpin - Set speed for the spin case motor 1. + * + * @param uptime + * pulse width (time position) + */ + public void setSpeedSpinLeft(@LOC("IN") int timePosition) { + /* Speed comes in as a number between 0 - 100 */ + /* It represents values between 1 to 2 ms */ + /* 100-input to get reverse polarity for this motor */ + /* since it's mounted in reverse direction to the other motor */ + if (DEBUG) { + System.out.println("setSpeedSpinLeft: input-> " + Integer.toString(timePosition)); + } + @LOC("THIS,MotorControl.V") int timePos = normalizeTime(timePosition); + + @LOC("THIS,MotorControl.V") int motorUpTime = (int) (timePos * agilityFactor * speedFactor); + // System.out.println("Left Motor UpTime1: " + + // Integer.toString(motorUpTime)); + // Since the right motor is hanging in reverse position + // the direction should be opposit + // Bug in wait. Can't take 0 nanoseconds + if (motorUpTime == 0) { + motorUpTime = 1; + // System.out.println("returning...."); + // return; // ndr + } else if (motorUpTime == 1000000) { + motorUpTime--; + } + + if (DEBUG) { + System.out.println("setSpeedSpinLeft: output-> = " + Integer.toString(motorUpTime)); + } + // synchronized (this) { + /* Factor in the speed and agility factors */ + motorLeftUpTime = motorUpTime; + // } + } + + /** + * setSpeedSpinRight - Set speed for the spin case right motor. + * + * @param uptime + * pulse width (time position) + */ + public void setSpeedSpinRight(@LOC("IN") int timePosition) { + /* Speed comes in as a number between 0 - 100 */ + /* It represents values between 1 to 2 ms */ + /* An input of 50 should result in 0 speed. */ + /* 100 should result in full speed forward */ + /* while 0 should result in full speed backwords */ + if (DEBUG) { + System.out.println("setSpeedSpinRight: input-> " + Integer.toString(timePosition)); + } + @LOC("THIS,MotorControl.V") int timePos = normalizeTime(timePosition); + @LOC("THIS,MotorControl.V") int motorUpTime = (int) ((timePos) * agilityFactor * speedFactor); + // Bug in wait. Cant take 0 nanoseconds + if (motorUpTime == 0) { + motorUpTime = 1; + // System.out.println("returning...."); + // return; // ndr + } else if (motorUpTime == 1000000) { + motorUpTime--; + } + + if (DEBUG) { + System.out.println("setSpeedSpinRight: output-> = " + Integer.toString(motorUpTime)); + } + // synchronized (this) { + /* Factor in the speed and agility factors */ + motorRightUpTime = motorUpTime; + // } + } + + /** + * setSpeedTurnM1 - set speed considering agility factor for motor 1 + * + * @param uptime + * pulse width (time position) + */ + public void setSpeedTurnLeft(@LOC("IN") int timePosition) { + /* Speed comes in as a number between 0 - 100 */ + /* It represents values between 1 to 2 ms */ + /* 100-input to get reverse polarity for this motor */ + /* since it's mounted in reverse direction to the other motor */ + if (DEBUG) { + System.out.println("setSpeedTurnLeft: input-> " + Integer.toString(timePosition)); + } + @LOC("THIS,MotorControl.V") int timePosLocal = normalizeTime(timePosition); + @LOC("THIS,MotorControl.V") int motorUpTime = + (timePosLocal * 100 + ((100 - timePosLocal) * (100 - agilityFactor))) * speedFactor; + if (motorUpTime == 0) { + motorUpTime = 1; + // System.out.println("returning...."); + // return; // ndr + } else if (motorUpTime == 1000000) { + motorUpTime--; + } + if (DEBUG) { + System.out.println("setSpeedTurnLeft: output-> = " + Integer.toString(motorUpTime)); + } + // synchronized (this) { + /* Factor in the speed and agility factors */ + motorLeftUpTime = motorUpTime; + // } + } + + /** + * setSpeedTurnM1 - set speed considering agility factor for motor 2 + * + * @param uptime + * pulse width (time position) + */ + public void setSpeedTurnRight(@LOC("IN") int timePosition) { + /* Speed comes in as a number between 0 - 100 */ + /* It represents values between 1 to 2 ms */ + if (DEBUG) { + System.out.println("setSpeedTurnRight: input-> " + Integer.toString(timePosition)); + } + @LOC("THIS,MotorControl.V") int timePos = normalizeTime(timePosition); + @LOC("THIS,MotorControl.V") int motorUpTime = + ((timePos * 100) + ((100 - timePos) * (100 - agilityFactor))) * speedFactor; + if (motorUpTime == 0) { + motorUpTime = 1; + // System.out.println("returning...."); + // return; // ndr + } else if (motorUpTime == 1000000) { + motorUpTime--; + } + + if (DEBUG) { + System.out.println("setSpeedTurnRight: output-> " + Integer.toString(motorUpTime)); + } + // synchronized (this) { + /* Factor in the speed and agility factors */ + motorRightUpTime = motorUpTime; + // } + } + + /** + * setSpeedLeft - speed control for motor 1. + * + * @param uptime + * pulse width (time position) + */ + public void setSpeedLeft(@LOC("IN") int timePosition) { + /* Speed comes in as a number between 0 - 100 */ + /* It represents values between 1 to 2 ms */ + /* 100-input to get reverse polarity for this motor */ + /* since it's mounted in reverse direction to the other motor */ + if (DEBUG) { + System.out.println("setSpeedLeft: input-> " + Integer.toString(timePosition)); + } + @LOC("THIS,MotorControl.V") int timePos = normalizeTime(timePosition); + @LOC("THIS,MotorControl.V") int motorUpTime = (int) (timePos * 100) * speedFactor; + /* + * System.out.println("motorUpTime = " + Integer.toStri@LOC("IN") + * ng(motorUpTime) + " timePos = " + Integer.toString((int)timePos) + + * " timePosition = " + Integer.toString((int)timePosition) + + * " speedFactor = " + Integer.toString(speedFactor)); + */ + if (motorUpTime == 0) { + motorUpTime = 1; + // System.out.println("returning...."); + // return; // ndr + } else if (motorUpTime == 1000000) { + motorUpTime--; + } + if (DEBUG) { + System.out.println("setSpeedLeft: output-> " + Integer.toString(motorUpTime)); + } + // synchronized (this) { + /* Factor in speedFactor */ + motorLeftUpTime = motorUpTime; + // } + } + + /** + * setSpeedRight - speed control for motor 1. + * + * @param uptime + * pulse width (time position) + */ + public void setSpeedRight(@LOC("IN") int timePosition) { + if (DEBUG) { + System.out.println("setSpeedRight: input-> " + Integer.toString(timePosition)); + } + /* Speed comes in as a number between 0 - 100 */ + /* It represents values between 1 to 2 ms */ + @LOC("THIS,MotorControl.V") int timePos = normalizeTime(timePosition); + @LOC("THIS,MotorControl.V") int motorUpTime = (int) (timePos * 100) * speedFactor; + if (motorUpTime == 0) { + motorUpTime = 1; + // System.out.println("returning...."); + // return; // ndr + } else if (motorUpTime == 1000000) { + motorUpTime--; + } + if (DEBUG) { + System.out.println("setSpeedRight: output-> " + Integer.toString(motorUpTime)); + } + // synchronized (this) { + /* Factor in speedFactor */ + motorRightUpTime = motorUpTime; + // } + } + + public void setUrgentReverse() { + // synchronized (this) { + motorLeftUpTime = 1; + motorRightUpTime = 1; + // } + } + + public void setUrgentStraight() { + // synchronized (this) { + motorLeftUpTime = 99; + motorRightUpTime = 99; + // } + } + + public void justSync() { + // synchronized (this) { + motorLeftUpTime = motorLeftUpTime; + motorRightUpTime = motorRightUpTime; + // } + } + + /** + * Control debug messageing. true - Activate debug messages false - deactivate + * debug messages + */ + public void setDebug(boolean debug) { + DEBUG = debug; + } + +} diff --git a/Robust/src/Benchmarks/SSJava/JavaNator/MotorController.java b/Robust/src/Benchmarks/SSJava/JavaNator/MotorController.java deleted file mode 100644 index 31603843..00000000 --- a/Robust/src/Benchmarks/SSJava/JavaNator/MotorController.java +++ /dev/null @@ -1,4 +0,0 @@ - -public class MotorController { - -} diff --git a/Robust/src/Benchmarks/SSJava/JavaNator/PWMManager.java b/Robust/src/Benchmarks/SSJava/JavaNator/PWMManager.java index 95dcad5a..d1944702 100644 --- a/Robust/src/Benchmarks/SSJava/JavaNator/PWMManager.java +++ b/Robust/src/Benchmarks/SSJava/JavaNator/PWMManager.java @@ -28,25 +28,28 @@ * @version 1.0 */ +@LATTICE("V") +@METHODDEFAULT("OUT 100000) { + break; + } - while (active && count < 100000) { - try { - // if (DEBUG) { - // System.out.println("Main: Waiting for remote commands"); - // } - // try { - // obj.wait(); - // } catch (IllegalMonitorStateException ie) { - // System.out.println("IllegalMonitorStateException caught in main loop"); - // } - currentCommand = TestSensorInput.getCommand(); - if (currentCommand == -1) { - break; - } - System.out.println("currentCommand="+currentCommand); - processIOCommand(); - // Nothing to do - } catch (Exception e) { + // if (DEBUG) { + // System.out.println("Main: Waiting for remote commands"); + // } + // try { + // obj.wait(); + // } catch (IllegalMonitorStateException ie) { + // System.out.println("IllegalMonitorStateException caught in main loop"); + // } + currentCommand = TestSensorInput.getCommand(); + if (currentCommand == -1) { + break; } + System.out.println("currentCommand=" + currentCommand); + processIOCommand(); count++; } System.exit(0); diff --git a/Robust/src/Benchmarks/SSJava/JavaNator/StrategyMgr.java b/Robust/src/Benchmarks/SSJava/JavaNator/StrategyMgr.java index 94df925a..b18dc070 100644 --- a/Robust/src/Benchmarks/SSJava/JavaNator/StrategyMgr.java +++ b/Robust/src/Benchmarks/SSJava/JavaNator/StrategyMgr.java @@ -24,26 +24,32 @@ * @author Michael Gesundheit * @version 1.0 */ +@LATTICE("C 100) { + // if the robot fail to get out of weird condition wihtin 100 steps, + // terminate while loop for stabilizing behavior. + stop(); + break; + } + count++; + if ((lineSensorsMask & RobotMain.LS_ALL) == RobotMain.LS_ALL) { if (DEBUGL) System.out.println("Line Sensors - ALL"); @@ -154,98 +172,98 @@ public class StrategyMgr { public void stop() { if (DEBUG) System.out.println("StrageyMgr: stop...."); - pwmControl.setSpeedLeft(zeroSpeed); - pwmControl.setSpeedRight(zeroSpeed); + mc.setSpeedLeft(zeroSpeed); + mc.setSpeedRight(zeroSpeed); } public void search() { if (DEBUG) System.out.println("StrategyMgr: search...."); - pwmControl.setSpeedLeft(70); - pwmControl.setSpeedRight(50); + mc.setSpeedLeft(70); + mc.setSpeedRight(50); } public void straight() { if (DEBUG) System.out.println("StrategyMgr: strait...."); - pwmControl.setSpeedLeft(100); - pwmControl.setSpeedRight(100); + mc.setSpeedLeft(100); + mc.setSpeedRight(100); } public void spinRight() { if (DEBUG) System.out.println("StrategyMgr: spinRight...."); - pwmControl.setSpeedSpinLeft(100); - pwmControl.setSpeedSpinRight(0); + mc.setSpeedSpinLeft(100); + mc.setSpeedSpinRight(0); } public void spinLeft() { if (DEBUG) System.out.println("StrategyMgr: spinLeft...."); - pwmControl.setSpeedSpinLeft(0); - pwmControl.setSpeedSpinRight(100); + mc.setSpeedSpinLeft(0); + mc.setSpeedSpinRight(100); } public void spin180() { - int mod = (rand.nextInt() % 2); + @LOC("THIS,StrategyMgr.V") int mod = (rand.nextInt() % 2); if (DEBUG) System.out.println("StrategyMgr: spin180...."); if (mod == 1) { - pwmControl.setSpeedSpinLeft(0); - pwmControl.setSpeedSpinRight(100); + mc.setSpeedSpinLeft(0); + mc.setSpeedSpinRight(100); } else { - pwmControl.setSpeedSpinLeft(100); - pwmControl.setSpeedSpinRight(0); + mc.setSpeedSpinLeft(100); + mc.setSpeedSpinRight(0); } } public void right() { if (DEBUG) System.out.println("StrategyMgr: right...."); - pwmControl.setSpeedTurnLeft(100); - pwmControl.setSpeedRight(zeroSpeed); + mc.setSpeedTurnLeft(100); + mc.setSpeedRight(zeroSpeed); } public void left() { if (DEBUG) System.out.println("StrategyMgr: left...."); - pwmControl.setSpeedLeft(zeroSpeed); - pwmControl.setSpeedTurnRight(100); + mc.setSpeedLeft(zeroSpeed); + mc.setSpeedTurnRight(100); } public void bearRight() { if (DEBUG) System.out.println("StrategyMgr: bearRight...."); - pwmControl.setSpeedTurnLeft(100); - pwmControl.setSpeedTurnRight(60); + mc.setSpeedTurnLeft(100); + mc.setSpeedTurnRight(60); } public void bearLeft() { if (DEBUG) System.out.println("StrategyMgr: bearLeft...."); - pwmControl.setSpeedTurnLeft(60); - pwmControl.setSpeedTurnRight(100); + mc.setSpeedTurnLeft(60); + mc.setSpeedTurnRight(100); } public void back() { if (DEBUG) System.out.println("StrategyMgr: back...."); - pwmControl.setSpeedLeft(0); - pwmControl.setSpeedRight(0); + mc.setSpeedLeft(0); + mc.setSpeedRight(0); } public void backBearLeft() { if (DEBUG) System.out.println("StrategyMgr: backBearLeft...."); - pwmControl.setSpeedLeft(30); - pwmControl.setSpeedRight(0); + mc.setSpeedLeft(30); + mc.setSpeedRight(0); } public void backBearRight() { if (DEBUG) System.out.println("StrategyMgr: backBearRight...."); - pwmControl.setSpeedLeft(0); - pwmControl.setSpeedRight(30); + mc.setSpeedLeft(0); + mc.setSpeedRight(30); } } diff --git a/Robust/src/Benchmarks/SSJava/JavaNator/TestSensorInput.java b/Robust/src/Benchmarks/SSJava/JavaNator/TestSensorInput.java index 2f9319c3..046a700b 100644 --- a/Robust/src/Benchmarks/SSJava/JavaNator/TestSensorInput.java +++ b/Robust/src/Benchmarks/SSJava/JavaNator/TestSensorInput.java @@ -2,10 +2,12 @@ public class TestSensorInput { private static FileInputStream inputFile; + @TRUST public static void init() { inputFile = new FileInputStream("input.dat"); } + @TRUST public static byte getCommand() { String in = inputFile.readLine(); if (in == null) { diff --git a/Robust/src/ClassLibrary/SSJava/Random.java b/Robust/src/ClassLibrary/SSJava/Random.java new file mode 100644 index 00000000..f77bf542 --- /dev/null +++ b/Robust/src/ClassLibrary/SSJava/Random.java @@ -0,0 +1,406 @@ +/* Random.java -- a pseudo-random number generator + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + +/** + * This class generates pseudorandom numbers. It uses the same algorithm as the + * original JDK-class, so that your programs behave exactly the same way, if + * started with the same seed. + * + * The algorithm is described in The Art of Computer Programming, + * Volume 2 by Donald Knuth in Section 3.2.1. It is a 48-bit seed, linear + * congruential formula. + * + * If two instances of this class are created with the same seed and the same + * calls to these classes are made, they behave exactly the same way. This + * should be even true for foreign implementations (like this), so every port + * must use the same algorithm as described here. + * + * If you want to implement your own pseudorandom algorithm, you should extend + * this class and overload the next() and + * setSeed(long) method. In that case the above paragraph doesn't + * apply to you. + * + * This class shouldn't be used for security sensitive purposes (like generating + * passwords or encryption keys. See SecureRandom in package + * java.security for this purpose. + * + * For simple random doubles between 0.0 and 1.0, you may consider using + * Math.random instead. + * + * @see java.security.SecureRandom + * @see Math#random() + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +@LATTICE("V,S,S*") +@METHODDEFAULT("OUTsetSeed(System.currentTimeMillis());. + * + * @see System#currentTimeMillis() + */ + public Random() { + setSeed(System.currentTimeMillis()); + } + + /** + * Creates a new pseudorandom number generator, starting with the specified + * seed, using setSeed(seed);. + * + * @param seed + * the initial seed + */ + public Random(long seed) { + setSeed(seed); + } + + /** + * Sets the seed for this pseudorandom number generator. As described above, + * two instances of the same random class, starting with the same seed, should + * produce the same results, if the same methods are called. The + * implementation for java.util.Random is: + * + *
+   * public synchronized void setSeed(long seed) {
+   *   this.seed = (seed ˆ 0x5DEECE66DL) & ((1L << 48) - 1);
+   *   haveNextNextGaussian = false;
+   * }
+   * 
+ * + * @param seed + * the new seed + */ + public synchronized void setSeed(long seed) { + this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); + haveNextNextGaussian = false; + } + + /** + * Generates the next pseudorandom number. This returns an int value whose + * bits low order bits are independent chosen random bits (0 and + * 1 are equally likely). The implementation for java.util.Random is: + * + *
+   * protected synchronized int next(int bits) {
+   *   seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
+   *   return (int) (seed >>> (48 - bits));
+   * }
+   * 
+ * + * @param bits + * the number of random bits to generate, in the range 1..32 + * @return the next pseudorandom value + * @since 1.1 + */ + protected synchronized int next(@LOC("IN") int bits) { + seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); + return (int) (seed >>> (48 - bits)); + } + + /** + * Fills an array of bytes with random numbers. All possible values are + * (approximately) equally likely. The JDK documentation gives no + * implementation, but it seems to be: + * + *
+   * public void nextBytes(byte[] bytes)
+   *      {
+   *      for (int i = 0; i < bytes.length; i += 4)
+   *      {
+   *      int random = next(32);
+   *      for (int j = 0; i + j < bytes.length && j < 4; j++)
+   *      {
+   *       bytes[i+j] = (byte) (random & 0xff)
+   *       random >>= 8;
+   *      }
+   *      }
+   *      }
+   * 
+ * + * @param bytes + * the byte array that should be filled + * @throws NullPointerException + * if bytes is null + * @since 1.1 + */ + public void nextBytes(byte[] bytes) { + int random; + // Do a little bit unrolling of the above algorithm. + int max = bytes.length & ~0x3; + for (int i = 0; i < max; i += 4) { + random = next(32); + bytes[i] = (byte) random; + bytes[i + 1] = (byte) (random >> 8); + bytes[i + 2] = (byte) (random >> 16); + bytes[i + 3] = (byte) (random >> 24); + } + if (max < bytes.length) { + random = next(32); + for (int j = max; j < bytes.length; j++) { + bytes[j] = (byte) random; + random >>= 8; + } + } + } + + /** + * Generates the next pseudorandom number. This returns an int value whose 32 + * bits are independent chosen random bits (0 and 1 are equally likely). The + * implementation for java.util.Random is: + * + *
+   * public int nextInt() {
+   *   return next(32);
+   * }
+   * 
+ * + * @return the next pseudorandom value + */ + public int nextInt() { + return next(32); + } + + /** + * Generates the next pseudorandom number. This returns a value between + * 0(inclusive) and n(exclusive), and each value has the same + * likelihodd (1/n). (0 and 1 are equally likely). The + * implementation for java.util.Random is: + * + *
+   * public int nextInt(int n) {
+   *   if (n <= 0)
+   *     throw new IllegalArgumentException("n must be positive");
+   * 
+   *   if ((n & -n) == n) // i.e., n is a power of 2
+   *     return (int) ((n * (long) next(31)) >> 31);
+   * 
+   *   int bits, val;
+   *   do {
+   *     bits = next(31);
+   *     val = bits % n;
+   *   } while (bits - val + (n - 1) < 0);
+   * 
+   *   return val;
+   * }
+   * 
+ * + *

+ * This algorithm would return every value with exactly the same probability, + * if the next()-method would be a perfect random number generator. + * + * The loop at the bottom only accepts a value, if the random number was + * between 0 and the highest number less then 1<<31, which is divisible by n. + * The probability for this is high for small n, and the worst case is 1/2 + * (for n=(1<<30)+1). + * + * The special treatment for n = power of 2, selects the high bits of the + * random number (the loop at the bottom would select the low order bits). + * This is done, because the low order bits of linear congruential number + * generators (like the one used in this class) are known to be ``less + * random'' than the high order bits. + * + * @param n + * the upper bound + * @throws IllegalArgumentException + * if the given upper bound is negative + * @return the next pseudorandom value + * @since 1.2 + */ + public int nextInt(int n) { + if (n <= 0) + System.printString("ERROR: n must be positive\n"); + if ((n & -n) == n) // i.e., n is a power of 2 + return (int) ((n * (long) next(31)) >> 31); + int bits, val; + do { + bits = next(31); + val = bits % n; + } while (bits - val + (n - 1) < 0); + return val; + } + + /** + * Generates the next pseudorandom long number. All bits of this long are + * independently chosen and 0 and 1 have equal likelihood. The implementation + * for java.util.Random is: + * + *

+   * public long nextLong() {
+   *   return ((long) next(32) << 32) + next(32);
+   * }
+   * 
+ * + * @return the next pseudorandom value + */ + public long nextLong() { + return ((long) next(32) << 32) + next(32); + } + + /** + * Generates the next pseudorandom boolean. True and false have the same + * probability. The implementation is: + * + *
+   * public boolean nextBoolean() {
+   *   return next(1) != 0;
+   * }
+   * 
+ * + * @return the next pseudorandom boolean + * @since 1.2 + */ + public boolean nextBoolean() { + return next(1) != 0; + } + + /** + * Generates the next pseudorandom float uniformly distributed between 0.0f + * (inclusive) and 1.0f (exclusive). The implementation is as follows. + * + *
+   * public float nextFloat() {
+   *   return next(24) / ((float) (1 << 24));
+   * }
+   * 
+ * + * @return the next pseudorandom float + */ + public float nextFloat() { + return next(24) / (float) (1 << 24); + } + + /** + * Generates the next pseudorandom double uniformly distributed between 0.0 + * (inclusive) and 1.0 (exclusive). The implementation is as follows. + * + *
+   * public double nextDouble() {
+   *   return (((long) next(26) << 27) + next(27)) / (double) (1L << 53);
+   * }
+   * 
+ * + * @return the next pseudorandom double + */ + public double nextDouble() { + return (((long) next(26) << 27) + next(27)) / (double) (1L << 53); + } + + /** + * Generates the next pseudorandom, Gaussian (normally) distributed double + * value, with mean 0.0 and standard deviation 1.0. The algorithm is as + * follows. + * + *
+   * public synchronized double nextGaussian() {
+   *   if (haveNextNextGaussian) {
+   *     haveNextNextGaussian = false;
+   *     return nextNextGaussian;
+   *   } else {
+   *     double v1, v2, s;
+   *     do {
+   *       v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
+   *       v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
+   *       s = v1 * v1 + v2 * v2;
+   *     } while (s >= 1);
+   * 
+   *     double norm = Math.sqrt(-2 * Math.log(s) / s);
+   *     nextNextGaussian = v2 * norm;
+   *     haveNextNextGaussian = true;
+   *     return v1 * norm;
+   *   }
+   * }
+   * 
+ * + *

+ * This is described in section 3.4.1 of The Art of Computer + * Programming, Volume 2 by Donald Knuth. + * + * @return the next pseudorandom Gaussian distributed double + */ + public synchronized double nextGaussian() { + if (haveNextNextGaussian) { + haveNextNextGaussian = false; + return nextNextGaussian; + } + double v1, v2, s; + do { + v1 = 2 * nextDouble() - 1; // Between -1.0 and 1.0. + v2 = 2 * nextDouble() - 1; // Between -1.0 and 1.0. + s = v1 * v1 + v2 * v2; + } while (s >= 1); + double norm = Math.sqrt(-2 * Math.log(s) / s); + nextNextGaussian = v2 * norm; + haveNextNextGaussian = true; + return v1 * norm; + } +} -- 2.34.1