Converting a Unique Seed String into a Random, Yet Deterministic, Float Value in Ruby

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

The key part that you want is a way of converting a SHA1 or MD5 hash output into a float that is both deterministic and 1-1. Here's a simple solution based on md5. This could be used as integers too.

require 'digest/md5'

class String
def float_hash
(Digest::MD5.hexdigest(self).to_i(16)).to_f
end
end

puts "example_string".float_hash # returns 1.3084281619666243e+38

This generates a hexadecimal hash, then converts it to an integer, then converts that to a float. Each step is deterministic.

Note: as pointed out by @emboss, this reduces collision resistance because a double is 8 bytes and the hash is 16 bytes. It shouldn't be a big deal though by the sounds of your application.

Use a string as seed generator for random number generation in ruby on rails

What about

srand "a3989f5a-1c4b-11e3-8573-0025906a9230".tr('-', '').to_i(16)

It will seed Ruby rng from UUID as hex number after we strip dashes

Is any data lost when converting a Ruby float in scientific notation to an integer?

On the contrary, (deterministic but meaningless) data is added (as you demonstrated in your code sample). You're not losing any information. But it's not the same value.

Your float has a precision of about 17 decimal digits, your int suddenly has a precision of 51 digits. This has to do with Floating Point Arithmetic: Issues and Limitations. That "precision" arises as the result of the binary representation of a decimal floating point value, which leads to the "invention" of a series of digits in your integer.

Consider the following (in Python, which follows the same rules, as will probably all programming languages that feature arbitrarily long integers):

>>> a = int(1.5815450433041317e+51)
>>> a
1581545043304131697954259018410479150921451567054848
>>> b = a + 10000000000000000
>>> a == b
False
>>> float(a) == float(b)
True
>>> a == 1.5815450433041317e+51
True

In Python, the decimal module would be quite a good compromise:

>>> from decimal import Decimal, getcontext
>>> a = str(29873409852730498572309485723**3) # just an arbitrary number
>>> getcontext().prec = 100
>>> cube = Decimal(a)
>>> cube ** Decimal("0.333333333333333333333333333333333333333333333333333333333
33333333333333333333")
Decimal('29873409852730498572309485722.99999999999999999999999999999999999999999
999998041297117811390088120595')

(which still has a slight rounding error due to the problem of representing 1/3 as a decimal float, but the result is obvious, isn't it?)

How to get a random number in Ruby

Use rand(range)

From Ruby Random Numbers:

If you needed a random integer to simulate a roll of a six-sided die, you'd use: 1 + rand(6). A roll in craps could be simulated with 2 + rand(6) + rand(6).

Finally, if you just need a random float, just call rand with no arguments.


As Marc-André Lafortune mentions in his answer below (go upvote it), Ruby 1.9.2 has its own Random class (that Marc-André himself helped to debug, hence the 1.9.2 target for that feature).

For instance, in this game where you need to guess 10 numbers, you can initialize them with:

10.times.map{ 20 + Random.rand(11) } 
#=> [26, 26, 22, 20, 30, 26, 23, 23, 25, 22]

Note:

  • Using Random.new.rand(20..30) (using Random.new) generally would not be a good idea, as explained in detail (again) by Marc-André Lafortune, in his answer (again).

  • But if you don't use Random.new, then the class method rand only takes a max value, not a Range, as banister (energetically) points out in the comment (and as documented in the docs for Random). Only the instance method can take a Range, as illustrated by generate a random number with 7 digits.

This is why the equivalent of Random.new.rand(20..30) would be 20 + Random.rand(11), since Random.rand(int) returns “a random integer greater than or equal to zero and less than the argument.” 20..30 includes 30, I need to come up with a random number between 0 and 11, excluding 11.

Float value returns with double quotes from [String: AnyObject] in swift

Replace AnyObject with Any like below:

let appliedLoyalty: Float = 1.05
let appliedWallet: Float = 0.55
let custID = "puma"
let payLoad: [String: Any] = ["custid": custID, "discounts": ["loyalty": appliedLoyalty,"wallet": appliedWallet]] // custid is string value

print(payLoad)

Sample Image

Swift: converting String to Float and back to String again after doing some mathematical operations

Actually floats can not represent numbers accurately, you'll have to use Double.
Here is a very nice answer on that issue:
https://stackoverflow.com/a/3730040/4662531

EDIT:

Sorry, but actually Double should not be use to perform calculations (I'm assuming from the naming of your variables you are working on some banking things). That part of the above linked answer is really giving a great suggestion:

A solution that works in just about any language is to use integers
instead, and count cents. For instance, 1025 would be $10.25. Several
languages also have built-in types to deal with money. Among others,
Java has the BigDecimal class, and C# has the decimal type.

A colleague of mine that used to work in a banking company also confirmed that all calculations were done without using Floats or Double, but with Int as suggested in the link.

Why this repeats the same random number?

By calling the rand.Seed() function, passing it a (random) seed (typically the current unix timestamp). Quoting from math/rand package doc:

Top-level functions, such as Float64 and Int, use a default shared Source that produces a deterministic sequence of values each time a program is run. Use the Seed function to initialize the default Source if different behavior is required for each run.

Example:

rand.Seed(time.Now().UnixNano())

If rand.Seed() is not called, the generator behaves as if seeded by 1:

Seed uses the provided seed value to initialize the default Source to a deterministic state. If Seed is not called, the generator behaves as if seeded by Seed(1).



Related Topics



Leave a reply



Submit