5

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
Joe
  • 14,513
  • 28
  • 82
  • 144
  • 1
    What should the range be of the divisors and the dividends? – ypercubeᵀᴹ May 13 '11 at 13:47
  • 4
    Not an answer, so I'm posting it as a comment, but make sure you understand this paper as it could have an affect on your solution: http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html – JasCav May 13 '11 at 13:47
  • 1
    Which numbers are the random ones here - the divisors or the dividends? If you need exactly 1 or 2 decimal places why can't you just work with integers, and divide by 100 later? – Matt Ball May 13 '11 at 13:50
  • 2
    what about generating the result and the devidor, and generate the 3rd from them? it's a bit cheating but it might solve the problem :\ – amit May 13 '11 at 13:50
  • 1
    @Matt: I guess: If you divide 1 by 3, you get 0,3333... - If you divide 100/3, you get 33.3333... . You suggest taking integer division (100/3=33) and then divide by 100=> (0.33) But you always end with rounding problems. .33 * 3 is .99. 33/100 is 0.33. He isn't looking for a rounding technique, but for proper divisors for (the number, multiplied by 100). – user unknown May 13 '11 at 14:05
  • @Matt - As my sample states its a whole number divided by a decimal which produces an answer with max of 2 decimal places after the decimal point. 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. – Joe May 14 '11 at 05:14
  • @Kalpana: Can you elaborate, what you think, what the question is, and why you're not satisfied with the accepted answer or mine? – user unknown Jun 08 '11 at 22:00

4 Answers4

4
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)
user unknown
  • 35,537
  • 11
  • 75
  • 121
3

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.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • How should the code be invoked? What's the solution? I only see whole numbers (randNum := long) and nearly whole numbers (randNum*factor) yielding. `14600.000000000002, 38000.0, 31300.000000000004, 25500.0, 11300.0, 37900.0, ...` maybe I'm invoking/initialising it wrong? – user unknown May 13 '11 at 15:42
  • My guess is you are not managing your rounding error. If you have operations which produce rounding error you need to format them when you print them. – Peter Lawrey May 13 '11 at 16:09
  • So you just produce .0, .25, .5 and .75? I understood the questsion, that every fraction like .01, .02, ... .89, .99 should be produced, not just whole quarters. – user unknown May 13 '11 at 16:59
  • My understanding is that the number should be an integer and after division it should be a multiple of 0.01. For some divisors, you can only get certain fractions. – Peter Lawrey May 13 '11 at 17:05
  • 2
    Well, @Joe doesn't clarify questions. I started to downvote him, therefore. We are working here for hours and hours, days and days, year after year, and he already lost interest? – user unknown May 13 '11 at 17:39
  • @user unknown - Apologize, but I live in a different timezone and just logged in to see the progress. – Joe May 14 '11 at 05:10
1

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
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • As my sample states its a whole number divided by a decimal which produces an answer with max of 2 decimal places after the decimal point. Your samples show it with whole number division which is incorrect. – Joe May 14 '11 at 05:13
  • 2
    @Joe: you said 'e.g.' meaning, this is one of the possible ways to do it, not the only way to do it. have to be clearer. – Claudiu May 14 '11 at 14:04
0

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216