Search code examples
javaalgorithmrandomlogarithmexponential

Random Even Logarithmic Distribution Between Two Doubles


Maybe I'm over thinking this, but I'm trying to find a nice way to obtain random numbers between two points that are uniformly logarithmically distributed. Let's say I have two bounds 0.001 and 1000 and I want to find 6 random numbers that are logarithmically evenly distributed. So numbers such as these: 0.002, 0.033, 0.543, 1.634, 34.673, 765.234... now say I'm looking for 7 random numbers instead, they would be ordered approximately evenly in this range as well... I'm using Java


Solution

  • Is this what you want? I took numbers uniformly distributed over the range formed by the logs of the limits, then used Math.exp to convert back to the actual range. I sorted the result array because your examples showed sorted data. Delete the Arrays.sort call if you don't want that.

    For simplicity, I skipped the bounds checking. Presumably, 0 < lowerLimit < upperLimit.

    The checks for the limits are because rounding error could, at least in theory, lead to results just outside the required range.

    import java.util.Arrays;
    import java.util.Random;
    
    public class Test {
      public static void main(String[] args) {
        Random rand = new Random(3);
        System.out.println(Arrays.toString(logRandom(rand, 0.001, 1000, 7)));
        System.out.println(Arrays.toString(logRandom(rand, 0.001, 1000, 7)));
        System.out.println(Arrays.toString(logRandom(rand, 0.001, 1000, 7)));
        System.out.println(Arrays.toString(logRandom(rand, 0.001, 1000, 7)));
      }
    
      public static double[] logRandom(Random rand, double lowerLimit,
          double upperLimit, int count) {
        double[] result = new double[count];
        double logLower = Math.log(lowerLimit);
        double logUpper = Math.log(upperLimit);
        for (int i = 0; i < count; i++) {
          double raw = rand.nextDouble();
          result[i] = Math.exp(raw * (logUpper - logLower) + logLower);
          if (result[i] < lowerLimit) {
            result[i] = lowerLimit;
          } else if (result[i] > upperLimit) {
            result[i] = upperLimit;
          }
        }
        Arrays.sort(result);
        return result;
      }
    
    }