Can you get truly random numbers from Dynamics NAV?

josephdeweyjosephdewey Member Posts: 87
I use random numbers for testing a lot, and I'm used to Excel, where you can get a lot of precision from '=RAND()'

It seems like the easiest way to replicate the Excel RAND function in Navision is with this code:
RANDOMIZE;
x :=  RANDOM(2147483647)/2147483647)
And, then this really isn't a true random number, but it's based on an algorithm that wouldn't pass really advanced randomness tests.

Is there something better in Navision than RANDOM? Or, do you know if future versions of Navision will support random numbers that are more random?
Joseph Dewey
Microsoft Dynamics NAV User

Comments

  • manjusreemanjusree Member Posts: 79
    Hope this helps :D :-

    RandomDigit := CREATEGUID;
    RandomDigit := DELCHR(RandomDigit,'=','{}-01');
    RandomDigit := COPYSTR(RandomDigit,1,10);
  • krikikriki Member, Moderator Posts: 9,112
    Well, also GUID is not really random, but it probably is more random than RANDOM.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • SogSog Member Posts: 1,023
    take the last digit of currentdatetime, (the ones after the decimal seperator).
    Guaranteed to be random.
    |Pressing F1 is so much faster than opening your browser|
    |To-Increase|
  • krikikriki Member, Moderator Posts: 9,112
    or also with TIME.

    I tried this code:
    for i := 1 to 1000000 do begin
      tim := time;
      tim2 := 000000T;
      int := (tim - tim2) MOD 1000;
    
      tmpInteger.Number := int;
      if tmpInteger.insert then ;
    end;
    
    message('%1',tmpInteger.count);
    
    With this I wanted to see if the last 2 digits (the milliseconds) can have all values and the count is always close to 1000. So this is not a bad system.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • josephdeweyjosephdewey Member Posts: 87
    Using the last digit of the thousands in TIME (the milliseconds count) to generate a random number is definitely a unique approach. The biggest problem with this, though, is that Navision does many calculations per millisecond, so even though this would probably generate a random enough number between 0 and 9, then it kind of falls apart when you need something outside of the 0 to 9 range, or if you need multiple numbers.

    But, I did make a working prototype that gives pretty random numbers. It's pretty slow, and I would guess that it wouldn't pass too many heavy-duty randomness tests. Also, about half of the time this gives a number with far fewer decimal places than the max. I don't understand why my code does that.

    But the numbers it generates do look random.
    FOR j := 1 TO 10 DO BEGIN
      rand_string := '0.';
      FOR i := 1 TO 20 DO BEGIN
        rand_string := rand_string + COPYSTR(FORMAT(TIME,0,'<Thousands>'),3,1);
        SLEEP(1); //try removing this to see what happens
      END;
      EVALUATE(rand_dec, rand_string);
      MESSAGE('%1',rand_dec);
    END;
    
    Thanks for your ideas!
    Joseph Dewey
    Microsoft Dynamics NAV User
  • kapamaroukapamarou Member Posts: 1,152
    Were do you need to use such a generator?

    I guess you could use some dll file that does only than, or even use Excel automation to generate a random number...
  • josephdeweyjosephdewey Member Posts: 87
    Here's my code for using the CREATEGUID to get a random number between 0 and 1.
    FOR j := 1 TO 10 DO BEGIN
      rand_string := '0.';
      WHILE STRLEN(rand_string) < 20 DO
        rand_string := rand_string + DELCHR(CREATEGUID,'=','{}-ABCDEF');
      EVALUATE(rand_dec, rand_string);
      MESSAGE('%1',rand_dec);
    END;
    
    I think this is going to be the best method, if I want a true random number, but I think I'll probably mostly just use Navision's RANDOM function. It did pass a few randomness tests that I threw at it.

    I use random numbers for testing, mostly. But random numbers are very helpful in a lot of situations. How would I learn how to hook Navision up to a DLL or Excel's automation?
    Joseph Dewey
    Microsoft Dynamics NAV User
  • kapamaroukapamarou Member Posts: 1,152
    It depends on the version you are using.

    You can look at the Excel Buffer Table to see how to Interact with excel. Otherwise you could create a .NET dll or COM interface depending on the version.
  • krikikriki Member, Moderator Posts: 9,112
    kapamarou wrote:
    You can look at the Excel Buffer Table to see how to Interact with excel. Otherwise you could create a .NET dll or COM interface depending on the version.
    I would advice against it because:
    -you need Excel installed (and probably it must be the correct version)
    -It is probably slower than RANDOM because you have to connect to .NET or COM.

    After all, why do you need a random no. in NAV. Only to do some tests and for that the C/AL RANDOM is good enough.
    If you need random numbers in a scientific way, you
    1) need some black box (don't remember the name) that generates really random numbers using quantum fluctuations (some companies have created such a thing)
    2) you're really using the wrong language/development environment for that.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • SogSog Member Posts: 1,023
    All in all, I think the topic is answered.
    However, I am very curious in what business process a random number is needed.
    Is it like a random discount? If you're lucky you'll receive a 100% discount?
    |Pressing F1 is so much faster than opening your browser|
    |To-Increase|
  • Luc_VanDyckLuc_VanDyck Member, Moderator, Administrator Posts: 3,633
    If you want to delve into the science of randomness, then look at this site: http://www.random.org/randomness/
    No support using PM or e-mail - Please use this forum. BC TechDays 2024: 13 & 14 June 2024, Antwerp (Belgium)
  • David_SingletonDavid_Singleton Member Posts: 5,479
    Schrodinger's cat is long dead anyway, so why does it matter. :mrgreen:

    Get a dog instead. 8)
    David Singleton
  • SogSog Member Posts: 1,023
    edited 2012-05-11
    Schrodinger's cat is long dead anyway, so why does it matter. :mrgreen:
    David, you can't state that as a fact if you havn't looked under the box :mrgreen:
    (And how is this ontopic? I seem to have missed the link between Shrodingers cat and randomness)
    |Pressing F1 is so much faster than opening your browser|
    |To-Increase|
  • David_SingletonDavid_Singleton Member Posts: 5,479
    But if I open the box then the randomness is gone. My gut feeling is that after all these decades trapped in the box that the kitten has by now starved or suffocated :cry:
    David Singleton
  • josephdeweyjosephdewey Member Posts: 87
    Sog wrote:
    However, I am very curious in what business process a random number is needed.
    Is it like a random discount? If you're lucky you'll receive a 100% discount?
    Here are a few that I've used in conjunction with ERP systems:
    • Quality testing/random sample
    • Pick a random customer for something like a survey
    • Randomly pick items for inventory counts
    • Unique identifier generation

    And, I agree, RANDOM is usually good enough. But, NAV is an extensible ERP system after all. And NAV's a top tier product, also.

    From the NAV documentation, RANDOM returns "A pseudo-random number." I guess the thing that bugs me most about it, is that this is a reminder than Dynamics NAV is built on top of a super old, creaky programming language. Pretty much all modern programming languages have the ability to generate real random numbers, and have gotten rid of the pseudo-random algorithms.
    Joseph Dewey
    Microsoft Dynamics NAV User
  • babbab Member Posts: 65
    Pretty much all modern programming languages have the ability to generate real random numbers, and have gotten rid of the pseudo-random algorithms.
    Which modern programming language are you talking about, which has built-in true random number generator? Just curious.
  • josephdeweyjosephdewey Member Posts: 87
    Well, after doing some research, it looks like I was wrong. Most modern programming languages all use similar algorithms behind the scenes.

    There are only two differences, as far as I can see:

    #1: Most modern programming languages have the RANDOMIZE command built in. For example, Java uses as a seed the number of milliseconds since January 1, 1970. So, you don't have to initialize random numbers with a RANDOMIZE command in other languages.

    #2: In Navision, you get a random number in only 4% of the total possible set of random numbers 1 and 2,147,483,647, for your first random number. Here's the math. There are 24*60*60*1000 (86,400,000) milliseconds in a day, so this is the maximum number of possible seed values for the random number. So the most unique random numbers that will be returned are 86,400,000/2,147,483,647, or 4.02%.

    Or, in other words, the following code will never return 96% of all possible numbers between 1 and 2147483647:
    RANDOMIZE();
    MESSAGE('%1',RANDOM(2147483647));
    
    But, the second time you run the second line, it should give equal chances of getting every number.

    So, are Navision random numbers really random? I guess the answer really is: they're random enough.
    Joseph Dewey
    Microsoft Dynamics NAV User
  • winfywinfy Member Posts: 8
    So, are Navision random numbers really random? I guess the answer really is: they're random enough.
    I don't think so and I can tell you why.

    Try to implement a simple Dice.
    randomize(); //with a seed it's the same problem
    message('The number is: %1 <- odd ?', random(6));
    
    The first number is always an odd value (1, 3 or 5). :bug: :bug: :bug: :bug: :bug:

    BTW: It's the same with all even values in the random function.
    random(<even value>) returns an <odd value> at the first try.

    Kind regards,
    winfy
  • josephdeweyjosephdewey Member Posts: 87
    Hi winfy,

    Thanks very much! This is great, simple sample code. I tested it a bunch of times and I never got an even number. I'm curious how you found this random deficiency in NAV.
    Joseph Dewey
    Microsoft Dynamics NAV User
  • winfywinfy Member Posts: 8
    When trust is lost:
    Park and Millers Minimal Standard Random Number Generator is simple, fast and in my opinion good enough for the most simulations in Navision.

    Random2(VAR Seed : Integer;Number : Integer) : Integer
    //......................................................................................................
    //Name: Minimal Standard Random Number Generator (linear congruential generator)
    //Source: Steve K. Park and Keith W. Miller "Random Number Generators: Good ones are hard to find", 1988
    //Language: Navision C/AL (modified by winfy)
    //Limits: only 32 Bit signed Integer. Generates Numbers from 1 to Parameter "Number"
    //......................................................................................................
    
    //Definitions
    //a,m,q,r (Type Integer) 
    //test, hi, lo (Type Integer)
    //Seed (Typ Integer)
    
    //Initialize the "good" Values
    //the other Values are good alternatives too
    a:= 16807;  //a:= 48271; //a:= 39373;
    m:= 2147483647;
    q:= 127773; //q:= 44488; //q:= 54542;
    r:= 2836;   //r:= 3399   //r:= 1481;
    
    //Generate the Random Number
    hi := Seed DIV q;
    lo := Seed MOD q;  
    test := a * lo - r * hi; 
    
    //Change to a positive range
    IF test > 0 THEN Seed := test
      ELSE Seed := test + m;
    
    //Result between 1 and the Parameter Number 
    IF (Number > 0) THEN EXIT((Seed MOD Number) + 1)
      ELSE EXIT(1); //alternative EXIT(0) or Errormessage
    

    Someone post it here before.
    I think it's good enough to generate a Startseed with it.

    Randomize2(VAR Seed : Integer)
    //Generate a Seed with GUID values between 1 und 2.147.483.646.
    //bigseed (Type BigInteger)
    EVALUATE(bigseed, COPYSTR(DELCHR(CREATEGUID(),'=','{}-ABCDEF'),1,10));
    Seed:= (bigseed MOD 2147483646) +1;
    

    Maybe useful?

    Literature: (Link)

    Kind regards,
    winfy
  • MattMCompuTECHMattMCompuTECH Member Posts: 4
    edited 2018-01-25
    Forgive me as this thread is ancient, but nobody seemed to mention anything about parallel execution. If a SOAP enabled codeunit function were to seed the Navision random generator and multiple (simultaneous enough) requests could generate the same seed since internally it's based on the millisecond counter and a millisecond is actually a HUGE unit of time. For an application like password reset this could be disastrous. A higher precision timer needs to be evaluated at instantiation, or ideally like kriki said a truly random source.

    Nonetheless, here's my seeding solution, which is probably slow, but hopefully there's always enough schedule changes between multiple simultaneous calls to ensure different last loop times. I assume CREATEGUID uses a higher precision timer. I'll do testing with parallelism and post my findings.
    j, integer
    rand_string, text
    FOR j := 1 TO 100 DO BEGIN
        rand_string := rand_string + FORMAT(CREATEGUID);
    END;
    seed := ComputeHash(rand_string);
    
    public static int ComputeHash(string subject)
    {
    	using (var ha = new MD5CryptoServiceProvider())
    	{
    		using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(subject)))
    		{
    			return BitConverter.ToInt32(ha.ComputeHash(ms), 0);
    		}
    	}
    }
    
  • RockWithNAVRockWithNAV Member Posts: 1,139
    Yep, I did ti 3 years before to generate tracking no and till now no issue.
    What I wrote was something like that.

    WHILE NOT UniqueValue DO BEGIN
    "Tracking No":=GenerateTrackingNo;
    IF NOT CheckDuplicateTracking("Tracking No") THEN
    UniqueValue := TRUE;
    END;

    Where GenerateTrackingNo was the function which was generating unique number with Random NAV Keyword and CheckDuplicateTracking was the function where I was just cross validating that the generated tracking number doesn't exist in the Database.

    P.S - Till 6 month it was OK but after then what I experienced was system had started generating duplicate tracking numbers hence added to cross verify with the existing one in the DB.
  • MattMCompuTECHMattMCompuTECH Member Posts: 4
    edited 2018-01-26
    The default method of seeding the PRNG is based on time so if several instances are all synchronized (they all began execution at the same exact moment) they will all have the same seed, and thus the same PRNG output (very bad). The CREATEGUID function and .NET's Guid.NewGuid might be doing something different or tap into a more precise timer, which shrinks that "exact moment" window, since people here are saying "it's probably more random"
  • MattMCompuTECHMattMCompuTECH Member Posts: 4
    My test passed when exposing a codeunit that returns a CREATEGUID generated value via SOAP web service and running 1000 rounds of 8 simultaneous requests to the web service. every round had 8 distinct values. either there's some kind of blocking going on in the way Navision handles SOAP web requests or the time window CREATEGUID uses is small enough that it's safe to use CREATEGUID like this. I imagine we wouldn't have people suggesting its use if it weren't. If anyone has more insight into how Navision handles web requests it would be interesting to me. I'm going to run it overnight with 2 threads per round and I'm confident it will pass. Thanks!
            static long y = 0; // threads finished count
            static long x = Environment.ProcessorCount * 1; // number of simultanious requests
            static ManualResetEvent done = new ManualResetEvent(false); // detect round finish
            static ManualResetEvent go = new ManualResetEvent(false); // synchronize request start times
            static ConcurrentBag<int> results = new ConcurrentBag<int>();
            static Test2.test2 p = new Test2.test2(); // navision codeunit via SOAP web service
            private static void work(object r)
            {
                var ready = (ManualResetEvent)r;
                ready.Set();
                go.WaitOne();
                results.Add(p.GetRand2());
                if (Interlocked.Increment(ref y) == x)
                    done.Set();
            }
            static void Main(string[] args)
            {
                p.Credentials = new NetworkCredential("***********", "**********");
                for (int round = 0; round < 1000; round++) {
                    for (int i = 0; i < x; i++)
                    {
                        ManualResetEvent ready = new ManualResetEvent(false);
                        Thread g = new Thread(new ParameterizedThreadStart(work));
                        g.Start(ready);
                        ready.WaitOne();
                    }
                    go.Set();
                    done.WaitOne();
                    var p = results.Distinct();
                    if (p.Count() != results.Count) throw new Exception("Test: FAIL");
                    Console.Write('.');
                    go.Reset();
                    done.Reset();
                    y = 0;
                    results = new ConcurrentBag<int>();
                }
                Console.WriteLine("Test: PASS");
                Console.ReadKey();
            }
    
  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    edited 2018-02-08
    I think that you cannot physically have 8 sessions running concurrently. The requests come through a network card so requests are serialized one way or antoher - if not by your code then by the OS and by the hardware along the way. The time difference migh be quite significant - if your card works at 1Gbps sending single TCP packet takes time measured probably in microseconds.

    If you run within the same machine while there is still a time required do copy the data between one process and another.
    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
  • MattMCompuTECHMattMCompuTECH Member Posts: 4
    edited 2018-02-09
    Even serialized, if the requests all construct instances of a run-of-the-mill PRNG within the same window of time they will generate the same PRN sets. This depends on the granularity of the clock being used to seed the PRNG. .NET Random default constructor seeds itself with a 1 millisecond window, which is offensively huge and broken.

    CREATEGUID is probably calling .NET Guid.NewGuid so I looked up Microsoft's explanation of what's happening under that hood.

    Remarks
    This is a convenient static method that you can call to get a new Guid. The method wraps a call to the Windows CoCreateGuid function. The returned Guid is guaranteed to not equal Guid.Empty.

    Remarks
    The CoCreateGuid function calls the RPC function UuidCreate, which creates a GUID, a globally unique 128-bit integer. Use CoCreateGuid when you need an absolutely unique number that you will use as a persistent identifier in a distributed environment.To a very high degree of certainty, this function returns a unique value – no other invocation, on the same or any other system (networked or not), should return the same value.

    CREATEGUID is practically immune if it's using this, which is very good.
  • krikikriki Member, Moderator Posts: 9,112
    A GUID is not perfectly unique. If you try to create a few 10^9 GUID's, you will hit some doubles.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


Sign In or Register to comment.