Converting a unique seed string into a random, yet deterministic, float value in Ruby

前端 未结 3 1460
悲哀的现实
悲哀的现实 2020-12-18 20:44

I\'m having a hard time with this, conceptually.

Basically, I need to accept some arbitrary unique string, and be able to convert that to a normalized float value.

3条回答
  •  青春惊慌失措
    2020-12-18 21:13

    Yes, you are describing a hashing algorithm. You could use a MD5 or SHA1 digest (since they just produce random bits) to generate a floating point number simply by using the String#unpack method with an argument of "G" (double-precision float, network byte order) from a digest:

    require 'digest/sha1'
    
    def string_to_float(str)
      Digest::SHA1.digest(str).unpack("G")[0]
    end
    
    string_to_float("abc-123") # => -2.86011943713676e-154
    string_to_float("def-456") # => -1.13232994606094e+214
    string_to_float("abc-123") # => -2.86011943713676e-154 OK!
    string_to_float("def-456") # => -1.13232994606094e+214 OK!
    

    Note that if you want the resulting floats to be in a particular range then you'll need to do some massaging.

    Also note that the unpacked number doesn't use all of the bits from the digest so you might want to combine into the number of bytes for a double floating point number (although you'll have to be careful not to decrease the entropy of the hash function, if you care about that sort of thing), e.g.:

    def str2float(s)
      d = Digest::SHA1.digest(s)
      x, y = d[0..9], d[10..19]
       # XOR the 1st (x) and 2nd (y) halves to use all bits.
      (0..9).map {|i| x[i] ^ y[i]}.pack("c*").unpack("G")[0]
    end
    

提交回复
热议问题