Suppose I call srand(1234), then call rand() repeatedly. Am I guaranteed to get the same sequence of random numbers regardless of my environment?
For instance,
Ruby 1.8.7 vs 1.9.3 vs 2.0
MRI vs JRuby
Windows vs Mac vs Linux
The answer in my experience is "yes"
I do this exact same thing when testing a new gem. The gem is not ready for real-world use, but relies heavily on random numbers, and most of the tests involve running Ruby's srand() beforehand so I get predictable numbers for assertions. All in all I probably test a few hundred small integers generated by rand() every time I run the test suite.
So far I have tested:
On Windows: MRI 1.9.3
On Mac: MRI 1.8.7, MRI 1.9.3 and MRI 2.0.0
On Travis (see build https://travis-ci.org/neilslater/games_dice), I test all these:
"1.8.7"
"1.9.3"
"2.0.0"
jruby-18mode # JRuby in 1.8 mode
jruby-19mode # JRuby in 1.9 mode
rbx-18mode
rbx-19mode
The last two of which I don't even know what they are :-)
The test suite has never failed due to an unexpected number from Ruby's rand method.
The underlying mechanism in Ruby is called the Mersenne Twister http://en.wikipedia.org/wiki/Mersenne_twister and this will generate same values from the same seeds, even across different languages, where it has been implemented. As far as I know, this algorithm is the one used by Ruby's rand() (and srand()) in all the standard implementations.
Well, this is what I get inside my irb - does it match what you get in yours? If so, then I think you can safely say "yes".
BTW, this is the whole point of seeding, so I expect the answer will definitely be "yes", and if not I'll be surprised.
ruby 1.9.3p327 (2012-11-10) [x86_64-darwin12.2.0]
irb(main):001:0> srand(1234)
=> 312936473923896776645464224839555650313
irb(main):002:0> rand
=> 0.1915194503788923
irb(main):003:0> rand
=> 0.6221087710398319
irb(main):004:0> rand
=> 0.4377277390071145
irb(main):006:0> rand
=> 0.7853585837137692
irb(main):007:0> rand
=> 0.7799758081188035
Related
I get this for a nil object in Ruby (irb):
nil.object_id # => 4
But for a string, I get negative results:
"abc".object_id # => -570954278
"abc".object_id # => -570956148
I am confused about the negative part. Is this proper or have I done something strange?
My ruby is:
ruby 2.3.0p0 (2015-12-25 revision 53290) [i686-linux]
The number effectively is a signed integer, with one bit used for sign and the rest used for data. See here for a discussion on some finer points of its implementation, mentioning the positive and negative storage.
But to be short, no, there isn't anything to worry about.
Here was the behavior that somewhat surprised me:
1.9.3-p392 :001 > n = 1
=> 1
1.9.3-p392 :002 > n.frozen?
=> false
1.9.3-p392 :003 > 1.freeze
=> 1
1.9.3-p392 :004 > n.frozen?
=> true
I tried grepping through the RubySpec source code for frozen and I didn't see anything about Fixnums at all.
Is this behavior the same as what would be expected on non-MRI Ruby implementations? If I run n = 1; 1.freeze; n.frozen?, will the final result always be true on any Ruby implementation? Why or why not?
It looks like it is an intended feature. In Ruby Forum, a question is raised:
Isn't technically all Fixnums "frozen" (because you can't modify the state)?
to which matz answers:
Not really, since fixnums could have instance variables.
Thus, theoretically, there's room for freezing fixnums. I don't think it's worth the cost though.
There seems to have been unintended inconsistency between different MRI Ruby versions, but as far as MRI is concerned, they look like they were identified as bugs, and were fixed. The specification you observed seems to be the intended one.
Since everything in Ruby is an object, it perhaps shouldn't be surprising that you can freeze 1. Symbol has the same behavior. As mentioned in the comments, this behavior changed from 1.8.7 (freezing didn't do anything) to 1.9+ (freezing works).
What might be more surprising is that freezing 1 also freezes n. According to the documentation for Fixnum,
There is effectively only one Fixnum object instance for any given
integer value
This means that n and 1 are references to the same object, and modifying one will modify the other.
You can check this for yourself by looking at the object_id.
1.object_id
=> 3
n=1
n.object_id
=> 3
n.equal? 1
=> true
I tried this code in MRI 1.8.7, MRI 2.0.0, JRuby, and Rubinius and got the same result.
Long story short, I was writing a method that included an options argument, that will do certain stuff if the value for the key :if, evaluated to true. When I trying the hash in IRB using the new syntax I got a syntax error in IRB, the prompt stays open:
1.9.3p374 :010 > {if: true}
1.9.3p374 :011?>
Using the old syntax, works just fine:
1.9.3p374 :011 > {:if => true}
=> {:if=>true}
All keywords that start a statement, exhibit the same behavior. E.g. def, do, module, case
Other reserved words that occur in the middle and class work just fine: else, end
My question is: Is this expected behavior, a bug or a limitation?
It's challenging to reliably and unambiguously parse things in any language. This is especially true when you start using reserved words. And irb has to go beyond that and provide an interactive model on top of the parser, which is even harder. I personally don't think there's too much value in worrying about cases like this, either as a user of the language or as a maintainer. In my mind, it's better to simply figure out what works and avoid getting into these situations if possible.
You can see some similar behaviors in plain Ruby, outside irb. For example:
puts({if: true}) # no problem, behaves as expected in Ruby 1.9.3.
puts {if: true} # raises a syntax error in Ruby 1.9.3
To answer your question, is it "expected behavior, a bug or a limitation", I'd say you should ignore irb and compare it to plain Ruby, and if you do this, it works fine. That means it has to be an irb bug.
But is it possible or worthwhile to solve? #coreyward makes a good point in his comment that irb has to delay execution in most cases when it encounters an if. You'd have to look further to know for sure, but you may not be able to unambiguously interpret all cases like this.
My advice: avoid this construct altogether if you can, and don't use reserved words for labels if you can avoid it!
Here's a file you can run with plain Ruby (eg MRI). You should see {:if=>true} in the output to confirm it works.
{if: true}
foo = {if: true}
# if MRI is working, should be able to execute this file without trouble.
p foo
I'm looking for a way to parse ordinal numbers (first, second, third, etc) in Ruby and convert them to integers. Do you know of any libraries that do this?
I was half-way through asking this question when I realized that the chronic gem does this as part of the process of parsing dates. After installing the gem, you can convert ordinal numbers to integers pretty easily:
irb(main):001:0> require 'chronic'
=> true
irb(main):002:0> Chronic::Numerizer.numerize("eighty-fifth").to_i
=> 85
Edit: Unfortunately, it seems that chronic doesn't correctly parse the ordinal "second":
irb(main):003:0> Chronic::Numerizer.numerize("twenty-second").to_i
=> 20
The reason for this is that chronic is designed to parse dates and times, and "second" could be either an ordinal number or a unit of time in that context. To solve this problem, you can monkey patch chronic's Numerizer class with this line:
Chronic::Numerizer::ORDINALS.insert(1, ['second', '2'])
Now it works:
irb(main):005:0> Chronic::Numerizer.numerize("eighty-second").to_i
=> 82
If you are actually using chronic for its intended purpose though, you probably won't want to screw with its internals. In that case, you can copy the source code from Chronic::Numerizer into a new class and use that one instead. Don't forget to add ['second', '2'] to the ORDINALS constant in the new class.
There's a gem called numerouno which seems to be specifically targeted at this, if Chronic doesn't fit your use case.
I've been using a gem called deordinalize (https://rubygems.org/gems/deordinalize) which seems to do the trick nicely - just make sure you downcase before calling;
>> require 'deordinalize'
>> 'Forty-Second'.downcase.deordinalize
=> 42
To correctly parse the ordinal "second":
you have now to monkey patch Numerizer class with this line
SINGLE_ORDINALS.insert(1, ['second', 2])
I've only seen something like rand(1..5) work in MRI ruby 1.9.3 (haven't tried 1.9.2). Jruby doesn't support it, even in 1.9 mode - it raises a TypeError.
Even ruby-doc doesn't mention that Ranges are supported. What's the official behavior?
UPDATE
Well as the answers and comments point out, only 1.9.3 supports it. Jruby is only at 1.9.2.
The docs do say that it is supported
If max is Range, returns a pseudorandom number where range.member(number) == true.
It's also in the 1.9.3 changelog
Verbatim Copy-paste from docs
If max is Range, returns a pseudorandom number where range.member(number) == true.
Or else converts max to an integer using max1 = max.to_i.abs.
so, yes. it is supported from ruby 1.9.3