5

I am trying to generate a random enough number quickly.

Right Now I am using the following:

uniqueID() ->   C = random:uniform(9999) ,   %%%DO SPEED TEST
    random:seed(C,random:uniform(99),random:uniform(99)),
    {_, {H, Min, S}}  = calendar:universal_time(),
    {A, B} = statistics(wall_clock),
    (A*B) +((H + C + Min) * S).

It takes too long compared to something like make_ref().

6> make_ref().
#Ref<0.0.0.74>

How can I take the unique ref and parse it to become an integer?

such as 00074

Thanks for the help.

BAR
  • 15,909
  • 27
  • 97
  • 185

3 Answers3

8

Are you really sure you want to use erlang:make_ref/0 for unique numbers? Refs are only unique for one launch of one erlang vm - they are repeatable, predictable, and make lousy unique identifiers if you plan to use them for anything other than tags in erlang messages to match up requests and replies.

You could do it by formatting the ref as a string (erlang:ref_to_list/1) and then parsing that.

However, I think the best idea would be to use crypto:rand_bytes/1 to get yourself an N byte binary of random bytes, or crypto:rand_uniform/2 if you need a random integer in some range. This method at least gives you some guarantees as to the quality of the random integers you produce (see the openssl rand_bytes documentation).

archaelus
  • 7,109
  • 26
  • 37
  • Is crypto faster than the original that I am using right now? I also do not need it to be unique across nodes it is going to be used for message passing, however it does need to be an integer. – BAR Feb 10 '11 at 21:49
  • I don't know - I'd guess slower, but you'd want to benchmark to be sure. "Do not guess when you can know" in the words of the OTP manual. My next question would be how much does speed really matter? Is the performance of your system really dominated by generating message tags? If the number just needs to be unique per a single process why not just keep an integer counter in the processes state? – archaelus Feb 10 '11 at 22:55
1

{A,B,C} = now(), A * 1000000000000 + B * 1000000 + C.

probsolver
  • 916
  • 7
  • 4
  • If the @user417896 really does want just integers good enough for tagging messages to match requests and responses, then this is a pretty good method. It requires an emulator-wide lock for `now`, but this is a negligable cost in 99% of cases. – archaelus Feb 10 '11 at 22:53
  • I tried using this but sometimes numbers are generated within the same few hundred nano seconds. My experience with this has been now() gives the same number and I end up with the same "random" number. The same applies to using random:uniform(), it is not unique at all and I believe it is based off of the time in itself. – BAR Feb 11 '11 at 00:30
  • `now()` is guaranteed give unique numbers all the time. See the [erlang:now() man page](http://erldocs.com/R14B01/erts/erlang.html?i=0&search=erlang:now#now/0). If you're using `random:uniform()` you'd have to initialize the seed with [random:seed/3](http://erldocs.com/R14B01/stdlib/random.html?i=1&search=random:seed#seed/3). – Adam Lindberg Feb 11 '11 at 10:19
0

From Erlang/OTP release 18.0 this is supported out of the box using erlang:unique_integer/{0,1}.

Called without options it returns unique values and with modifiers it produces strictly monotonic results albeit these calls are more expensive.

erlang:unique_integer() -> integer()
erlang:unique_integer(ModList) -> integer()     Modlist = [Modifier]
    Modifier = positive | monotonic

Generates and returns an integer unique on current runtime system instance. The integer is unique in the sense that this BIF, using the same set of modifiers, will not return the same integer more than once on the current runtime system instance. Each integer value can of course be constructed by other means.

Currently valid Modifiers:

positive
    Return only positive integers.

monotonic
    Return strictly monotonically increasing integers corresponding to creation time.

As erlang:now/0 became deprecated, a few things are suggested to be implemented with erlang:unique_integer/{0,1}.

toraritte
  • 6,300
  • 3
  • 46
  • 67