Skip to content

Commit

Permalink
Merge b5cb927 into 1850b03
Browse files Browse the repository at this point in the history
  • Loading branch information
HcPlu committed May 8, 2020
2 parents 1850b03 + b5cb927 commit 02df636
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 28 deletions.
56 changes: 35 additions & 21 deletions src/main/java/com/github/javafaker/Number.java
Expand Up @@ -24,30 +24,45 @@ public int randomDigitNotZero() {
}

/**
* @see Number#numberBetween(long, long)
* Generate random number between min and max.
* Notice min is the smaller one, max is larger one
* @param min Usually the smaller number, also the inclusive lower bound of generated number
* @param max Usually the larger number, also the exclusive(inclusive only min=max) upper bound of generated number
* @return A generated number between min and max
*/
public int numberBetween(int min, int max) {
if (min>max){
int tmp=max;
max=min;
min=tmp;
}
if (min == max) return min;

int value = decimalBetween(min,max).setScale(0, BigDecimal.ROUND_HALF_DOWN).intValue();
return value == max ? value - 1 : value;
else{
int value = decimalBetween(min,max).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
return value >= max ? max - 1 : value;
}
}

/**
* Return a number between <em>min</em> and <em>max</em>. If
* min == max, then min is returned. So numberBetween(2,2) will yield 2 even though
* it doesn't make sense.
*
* @param min inclusive
* @param max exclusive (unless min == max)
* Generate random number between min and max.
* Notice min is the smaller one, max is larger one
* @param min Usually the smaller number, also the inclusive lower bound of generated number
* @param max Usually the larger number, also the exclusive(inclusive only min=max) upper bound of generated number
* @return A generated number between min and max
*/
public long numberBetween(long min, long max) {
if (min>max){
long tmp=max;
max=min;
min=tmp;
}
if (min == max) return min;

long value = decimalBetween(min, max).setScale(0, BigDecimal.ROUND_HALF_DOWN).longValue();
return value == max ? value - 1 : value;
else{
long value = decimalBetween(min,max).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
return value >= max ? max - 1 : value;
}
}

/**
* @param numberOfDigits the number of digits the generated value should have
* @param strict whether or not the generated value should have exactly <code>numberOfDigits</code>
Expand Down Expand Up @@ -99,14 +114,13 @@ private BigDecimal decimalBetween(long min, long max) {
final long trueMax = Math.max(min, max);

final double range = (double) trueMax - (double) trueMin;

final double chunkCount = Math.sqrt(Math.abs(range));
final double chunkSize = chunkCount;
final long randomChunk = faker.random().nextLong((long) chunkCount);

final double chunkStart = trueMin + randomChunk * chunkSize;
final double adj = chunkSize * faker.random().nextDouble();
return new BigDecimal(chunkStart + adj);
final double chunkCount = Math.sqrt(Math.abs(range));
final long decimalOfChunkCount=(long)Math.ceil(chunkCount);
final long randomChunk = faker.random().nextLong(decimalOfChunkCount);
final double chunkStart = trueMin + randomChunk * chunkCount;
final double adj = chunkCount * faker.random().nextDouble();
return chunkStart + adj >= trueMax ? new BigDecimal(trueMax -1) :new BigDecimal(chunkStart + adj);
}

public String digits(int count) {
Expand Down
133 changes: 126 additions & 7 deletions src/test/java/com/github/javafaker/NumberTest.java
Expand Up @@ -5,6 +5,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -185,7 +186,7 @@ public void numberBetweenLongLongZeroMinMax() {
assertThat("Calling numberBetween with min==max yields min, with 0",
faker.number().numberBetween(0L, 0L),
is(0L));
assertThat("Calling numberBetween with min==max yields min",
assertThat("Calling numberBetween with min==max yields min",
faker.number().numberBetween(2L, 2L),
is(2L));
}
Expand Down Expand Up @@ -233,7 +234,7 @@ public Double call() throws Exception {
* calculate the uniqueness for that given min/max range.
* For all 'uniqueness' values
* verify the percentage of 'uniqueness' ratios over 80% is 90%.
*
*
* This isn't perfect but it ensures a pretty good degree of uniqueness in the random number generation.
*/
@Test
Expand Down Expand Up @@ -290,7 +291,7 @@ public Long call() throws Exception {
});
}
};

final double percentGreaterThan80Percent = randomizationQualityTest(individualRunGtPercentUnique, minMaxRangeToUniquePercentageFunction);
assertThat("Percentage of runs > 80% unique is gte 90%",
percentGreaterThan80Percent, greaterThanOrEqualTo(percentRunsGtUniquePercentage));
Expand Down Expand Up @@ -329,14 +330,14 @@ public void testDigits() {
* Over the series of numbers identified from RANDOMIZATION_QUALITY_RANGE_START to
* RANDOMIZATION_QUALITY_RANGE_END, create a min/max range of -value/value and
* with of those min/max values, call <em>percentUniqueRunner</em>.
*
*
* Collect the number of calls to <em>percentUniqueRunner</em> that were
* above the threshold and finally return that number divided by the total number of calls to
* <em>percentUniqueRunner</em>.
*
*
* @return percent of percentUniqueRunner's results greater than the threshold
*/
private double randomizationQualityTest(final double threshold,
private double randomizationQualityTest(final double threshold,
final Function<Pair<Long,Long>,Double> percentUniqueRunner) {
final int rangeEnd = RANDOMIZATION_QUALITY_RANGE_END;
final int rangeStep = RANDOMIZATION_QUALITY_RANGE_STEP;
Expand All @@ -357,7 +358,7 @@ private double randomizationQualityTest(final double threshold,
return (double) greaterThanThreshold.get() / (double) total.get();
}


/**
* Given a number of iterations, calls <em>callable</em> 'iterations' times and collects the results,
* then calculates the number of results that were unique and returns the percentage that where unique.
Expand All @@ -384,4 +385,122 @@ private long calculateNumbersToGet(long min, long max) {
if (numbersToGet == 0) numbersToGet = RANDOMIZATION_TESTS_MAX_NUMBERS_TO_GET;
return numbersToGet;
}
@Test
public void satisfyIssueForIntTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
outer: for (int i = 1; i <= 1000; i++) {
for (int j = 0; j < 100000; j++) {
int r = fake.number().numberBetween(0, i);
if (r == i-1) {
continue outer;
}
}
isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberAboveZeroForIntTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
for(int i=0;i<1000;i++){
int r = fake.number().numberBetween(0, 10);
if(r<0||r>=10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberAboveOrBelowZeroForIntTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
for(int i=0;i<1000;i++){
int r = fake.number().numberBetween(-10, 10);
if(r<-10||r>=10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberBelowZeroForIntTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
for(int i=0;i<1000;i++){
int r = fake.number().numberBetween(-20, -10);
if(r<-20||r>=-10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberBetweenMaxMinForIntTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
for(int i=0;i<1000;i++){
int r = fake.number().numberBetween(10, 0);
if(r<0||r>=10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}



@Test
public void satisfyIssueForLongTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
outer: for (int i = 1; i <= 1000; i++) {
for (int j = 0; j < 100000; j++) {
long r = fake.number().numberBetween(0, i);
if (r == i-1) {
continue outer;
}
}
isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberAboveZeroForLongTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
for(int i=0;i<1000;i++){
long min=0;long max=10;
long r = fake.number().numberBetween(min, max);
if(r<0||r>=10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberAboveOrBelowZeroForLongTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
long min=-10;long max=10;
for(int i=0;i<1000;i++){
long r = fake.number().numberBetween(min, max);
if(r<-10||r>=10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberBelowZeroForLongTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
long min=-20;long max=-10;
for(int i=0;i<1000;i++){
long r = fake.number().numberBetween(min, max);
if(r<-20||r>=-10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}
@Test
public void generateNumberBetweenMaxMinForLongTest(){
Faker fake = new Faker();
boolean isSatisfied =true;
long min=10;long max=0;
for(int i=0;i<1000;i++){
long r = fake.number().numberBetween(min, max);
if(r<0||r>=10)isSatisfied=false;
}
Assert.assertTrue(isSatisfied);
}

}

0 comments on commit 02df636

Please sign in to comment.