How to generate random numbers which will provide proper results on division
How to generate random numbers which will provide proper results on division (i.e the results should round to exactly 1 or 2 places after the decimal开发者_开发知识库 point).
(e.g a whole number by a decimal number providing decimal results - I have given a set of sample inputs below)
2827 by 2.5 = 1130.8
1747 by 0.8 = 2183.75
425 by 0.4 = 1062.5
935 by 0.8 = 1168.75
res = input * random.nextInt (100) / 100.0;
Explanation:
You take a whole number n, and multiply it with something. If this something is a number like 34.56, we call the part before the decimal digit w (whole part) and the part behind .xy.
If you multiply this with n, you end with (n*w)+(n*(x/10))+n*(y/100). There will never be an fractional part 3 ciphers behind the dot - do you agree?
We can combine x and y to a single part, and say (n*w) + (n*(xy/100)), and xy is just the name for something from 0 to 100.
Since the part before the decimal dot can be arbitrary large, you can calculate it seperately, if you need something else than 0. But you have to define a range somehow. If you take an random Integer R for that part:
res = input * R * random.nextInt (100) / 100.0;
Do you need the divisor explicityl?
div = 100.0 / (R * random.nextInt (100));
Scala is always handy, when testing code fragmenst:
val r = util.Random
r: util.Random.type = scala.util.Random$@ce2f12
scala> def res (input: Int) = input * r.nextInt (100) / 100.0;
res: (input: Int)Double
scala> (1 to 20).map (res)
res338: scala.collection.immutable.IndexedSeq[Double] =
Vector(0.48, 1.58, 0.48, 2.8, 0.15, 1.98, 5.67, 3.36, 6.93, 6.0, 9.02, 0.48, 7.41, 6.44, 9.6, 1.92, 16.66, 5.94, 7.98, 18.4)
It is worth noting that all integers can be divided by 0.4, 0.8 or 2.5 and be represented to two decimal places. This is because it is the same as multiplying by 2.5, 1.25, and 0.4
However, if you have a divisor for which this is not true, you can do this in a loop.
double divisor = 2.4;
double factor = 100/divisor;
Random rand = new Random();
int maxValue = 1000;
double ERROR = 1e-14*maxValue;
for(int i=0;i<100;i++) {
long randNum;
do {
randNum = rand.nextInt(maxValue+1);
if (Math.abs(randNum * factor - (long) (randNum * factor)) > ERROR)
System.out.println("reject "+randNum + " => "+randNum/divisor);
} while(Math.abs(randNum * factor - (long) (randNum * factor)) > ERROR);
System.out.println(randNum + " => "+randNum/divisor);
prints
729 => 303.75
285 => 118.75
84 => 35.0
123 => 51.25
999 => 416.25
75 => 31.25
reject 727 => 302.9166666666667
reject 842 => 350.83333333333337
504 => 210.0
reject 368 => 153.33333333333334
441 => 183.75
579 => 241.25
165 => 68.75
This will generate random numbers until you have a number which is a multiple of 0.01.
If you want the result to 'round' to 2 decimal places (it's not really rounding, it's just a finite decimal representation with two decimal points), then just generate the divisor, and have the dividend always be 100, e.g.:
106250 / 100 = 1062.5
116875 / 100 = 1168.75
If you want more interesting dividends then divide the divisor and dividend. e.g. the first one could be any one of:
(/1): 106250 / 100 = 1062.5
(/2): 53125 / 50 = 1062.5
(/10): 10625 / 10 = 1062.5
(/4): 26562.5 / 25 = 1062.5
(/125): 850 / 0.8 = 1062.5
For me the dividend and divisor are both random numbers. I have to produce an answer which doesn't require rounding decimals beyond 2 decimal places.
If that is the case, the answer might be "there is no such number". Here's a little Java program I wrote to test this hypothesis:
import java.text.DecimalFormat;
public class Test {
public static void main(String[] args) {
double num = Math.PI;
DecimalFormat format = new DecimalFormat(
"####################################0." +
"00##############################");
while (true) {
for (int i = 1; i < Integer.MAX_VALUE; i++) {
double tmp = (i / num) * 100;
if (tmp == (long) tmp) {
System.err.println("Solution - " + i + " - " +
format.format(tmp) + " - " + format.format(num));
break;
}
}
pi = Math.nextAfter(num, 1);
}
System.err.println("No solution for " + format.format(num));
}
}
I ran this for 10 minutes (starting at PI), and didn't find any values of num
that had no solution i
. But I did observe that solutions can be very sparse. For instance:
Gotcha! - 179453441 - 5712180438.00 - 3.1415926535897714
It took 179 million attempts to find the solution for that divisor.
精彩评论