6

I'm trying to generate meaningless words without using any Random() functions. I figured out that i can use current clock or mouse coordinate. And i picked to use current clock. Here is the code i wrote.

private final char[] charray = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};

private char getRandomCharacter(){
    return charray[random(charray.length)];
}

private int random(int value){
    value =(int) System.nanoTime()% 52;
    return value;
}

protected Randomizer(){
    boolean running = true;
    int count = 0;
    int max = 5;
    while(running){
        StringBuilder sb = new StringBuilder();
        int size = random(25) + random(25);
        for (int i = 0; i < size; i++) {
            sb.append(getRandomCharacter());
        }
        System.out.println("Random Line : " + sb.toString());

        if (count++ == max) {
            running = false;
            System.out.println("All of them are random.");
        }
    }
}

public static void main(String[] args) {
    new Randomizer();
}

I was expecting the out put like:

axdlMkjiIfjcmqQopv etc..

but i get something like this:

ZNNrrrUUUUxxxxbbbhhhLLLLoooRRRRRvvvYYYYBBBBfffI or JmmmPPKKKKnnnnRRBeeHHHHlllllOOOOrrrVVVVV

Why there are too much continuous. Is nanoTime too slow for that or what?I used currentTimeMillis before that and it was much worser. I couldn't figured out and couldn't find any source about how to random with current clock.

c0der
  • 18,467
  • 6
  • 33
  • 65
Jarnsida
  • 63
  • 7
  • *I was expecting the out put like : axdlMkjiIfjcmqQopv etc..* -- Why exactly? – Nicholas K Mar 09 '19 at 12:55
  • 3
    Is this a homework question? (Fair enough if it is, you've shown a decent effort so far.) If it's not for homework then I'd strongly suggest you stick with using the built-in Java `Random` class. Pseudo-random number generation is hard to get right (even the original random method in Java did not do a great job) so you'll be torturing yourself if you try to reinvent this wheel. – Bobulous Mar 09 '19 at 12:57
  • 2
    why do you pass `int value` to random only to assign new value and return? what's the point of the input arg? – Sharon Ben Asher Mar 09 '19 at 13:05
  • 2
    Also, I would not exepect that System.nanoTime() % 52 is evenly stributed. This basically boils down to the [jiffy](https://en.wikipedia.org/wiki/Jiffy_(time)) of each CPU being different and thus not every CPU having the same granularity wrt. time precision. – Turing85 Mar 09 '19 at 13:15
  • @NicholasK i dont know actually. i thought my code's output will be accurately random. – Jarnsida Mar 09 '19 at 13:18
  • @Bobulous Appreciated for your informative comment. i have almost read everything about pseudo random generator but i dont think i get it. It is a small homework project actually and i have been trying for 3 days, i have 4 more days to go.. i guess our assistants want us to reinvent this wheel in 7 days. thanks again, i will work harder about pseudo random generators :) – Jarnsida Mar 09 '19 at 13:18
  • @Turing85 thanks for your informative comment. i thought if i use my array's lenght it would work right. and actually it works only 52 otherwise it crashes and get boundary error in some lines. – Jarnsida Mar 09 '19 at 13:28
  • 1
    It is likely platform dependent. On Mac OS, I get for example "OaWoVbYVNHxqeWMICACBzxlhYPHAtjkYPKveTWUWUXRTrmZVNDqAttjgaWMDAzWGEvpgcYLjSPHIENAs". What operating system do you use? – Thomas Mueller Mar 09 '19 at 13:29
  • 1
    @Eren. I did some tests. The `52` is not the problem, even with `% 10`, you get not uniformly distributed values between 0 and 9. The problem is that `System.nanoTime()` is not evenly distributed. – Turing85 Mar 09 '19 at 13:30
  • @ThomasMueller i didn't know that, thanks. I'm using W10 and don't have a chance to try different OS – Jarnsida Mar 09 '19 at 13:31
  • The main problem I see is that the measured time between two method calls is very likely similar each time (less random that what you would expect). So, this has low entropy. But yes, you can use timing data to seed a random number generator - just don't _only_ use timing data, that's insufficient. – Thomas Mueller Mar 09 '19 at 13:32
  • It is not related to the main problem but I think you wanted `private int random(int value){ return (int) System.nanoTime()% value; }` – c0der Mar 09 '19 at 13:32
  • 3
    Why are you avoiding using the built-in `Random` class? – Mureinik Mar 09 '19 at 13:35
  • 1
    @Eren, I suggest you to print System.nanoTime() value, in my win 10 pc, all value end with xxxxxxxx00, which greatly affect the randomness. – samabcde Mar 09 '19 at 13:43
  • @c0der thank you its much efficient i guess. :) – Jarnsida Mar 09 '19 at 13:49
  • @samabcde i get something like these, xxxxxxxx73 xxxxxxxx20 xxxxxxxx04 etc. – Jarnsida Mar 09 '19 at 13:50
  • @Mureinik it is just a school project that "i have to reinvent randomness i guess." :) – Jarnsida Mar 09 '19 at 13:51
  • nano() times indeed are not evenly disterbuted, I didn't take much time or effort to get into it, but you can dive into uArchitecture and cpu uops to understand what's happening and write a blog post or two on this topic (I'd consider dev.to), people strive for quality posts like this today. – Vitali Pom Mar 09 '19 at 13:58
  • Did the assignment explicitly say to not use `Random`, or is that something you decided to do on your own? My advice is to not try to invent your own - it's very hard, and even luminaries such as [John von Neumann](https://en.wikipedia.org/wiki/John_von_Neumann), widely regarded as the most brilliant mathematician of his generation, have managed to royally screw up on this. – pjs Mar 09 '19 at 18:24
  • 1
    If you're not allowed to use `Random`, but not prohibited from implementing known algorithms independently, [these](https://en.wikipedia.org/wiki/Xorshift) are relatively easy to code up. – pjs Mar 09 '19 at 18:31

3 Answers3

2

You can use timing data (besides other data) to seed a random number generator, but only using timing data for randomness is not easy. It is possible, but can be very slow. See for example the code I wrote here on how to use other data to seed a secure random instance (H2 database, MathUtils.generateAlternativeSeed). It uses:

  • System.currentTimeMillis()
  • System.nanoTime()
  • new Object().hashCode()
  • Runtime.freeMemory(), maxMemory(), totalMemory()
  • System.getProperties().toString()
  • InetAddress
  • more timing data

This is to seed a secure pseudo-random number generator. This ensures you get enough entropy even on systems that don't have anything else running, don't know the current time, and have no UI.

But only relying on timing data, as you see yourself, is hard, as it depends on the operating system, time between method calls, the compiler, the hardware.

Thomas Mueller
  • 48,905
  • 14
  • 116
  • 132
  • I really appreciated for your comment it will help me more than i think when i research all of them. Thanks again. – Jarnsida Mar 09 '19 at 13:55
2

You could get somewhat better results by defining charray as Character[] charray and make it a list: List<Character> chars = Arrays.asList(charray);
Use this list in getRandomCharacter() method:

 private char getRandomCharacter(){
     Collections.shuffle(chars); // shuffle before each use 
     return chars.get(random(chars.size()));
 }

And of course fix random:

private int random(int value){
    return (int) System.nanoTime()% value;
}

Output:

Random Line : tjnBUxTDeTulHfLqnEJBRBLXFqqikUYyrREzzwPwG
Random Line : MZpzJbOyCaqraRPsQPSK
Random Line : cEzKcsNHTmoVmT
Random Line : CmGXpDHGOsUufSxxStDVQruR
Random Line : XtFKmOAIisnXEdPikhAIcfzD
Random Line : GVxdnwgWLKZvQIGuofCIhiiUbKsEbmAyzVfNNPM

c0der
  • 18,467
  • 6
  • 33
  • 65
  • How it this the accepted answer while the question is asking for a solution "without using any Random() functions"? And also why are you using a random index after shuffling? It's already shuffled, why not char.get(0)? – Rad Mar 09 '19 at 14:37
  • @Rad - the `random` isn't an inbuilt method which is presumably what the OP wanted to avoid - not specifically a method called `random`. It could be renamed to `ghyusssqqq` and the functionality would still remain. – Wai Ha Lee Mar 09 '19 at 14:41
  • 1
    I'm not following. If I understand it correctly, the homework is to reinvent the random functionality. But this solution is using Java random built-in functionality. – Rad Mar 09 '19 at 14:44
  • @Rad you are right about `get(0)`. It should work as well. The benefit of using `get(random)` needs to be tested. As for does it answer the OP needs or not, I leave it to him / her. – c0der Mar 09 '19 at 14:46
1

Using only time is problematic as it limits the frequency you can ask for a random number and is also very implementation dependent.

A better approach would be to use the time as the seed and then use a pseudorandom generator, for example a linear congruential generator. You have more info in this answer. Take into account that this random number generator algorithm is not secure, and that as Thomas pointed out using only time as a seed might not be enough if you want a secure RNG in all systems.

So your code might look like this:

    private final char[] charray = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

private long seed;

private char getRandomCharacter() {
    return charray[random(charray.length)];
}

private int random(int value) {
    seed = (1103515245L * seed + 12345L) % 2147483648L;
    return (int)seed%value;
}

protected Randomizer() {
    boolean running = true;
    int count = 0;
    int max = 5;
    seed = System.nanoTime();
    while (running) {
        StringBuilder sb = new StringBuilder();
        int size = random(25) + random(25);
        for (int i = 0; i < size; i++) {
            sb.append(getRandomCharacter());
        }
        System.out.println("Random Line : " + sb.toString());

        if (count++ == max) {
            running = false;
            System.out.println("All of them are random.");
        }
    }
}

public static void main(String[] args) {
    new Randomizer();
}
Sergio B
  • 105
  • 1
  • 1
  • 10