Ruby: What is the speed difference between While and Until loops?
There would not be a speed difference between while
and until
as they mirror each other.
We'll compare a while
loop with an until
loop:
n = 0
puts n += 1 while n != 3
n = 0
puts n += 1 until n == 3
These will both print 1 through 3.
Here's a diff between the two disassembled human-readable instruction sequences from the Ruby VM:
@@ -13,7 +13,7 @@
0021 pop
0022 getlocal_OP__WC__0 2
0024 putobject 3
-0026 opt_neq <callinfo!mid:!=, argc:1, ARGS_SIMPLE>, <callcache>, <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
-0031 branchif 8
-0033 putnil
-0034 leave
+0026 opt_eq <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
+0029 branchunless 8
+0031 putnil
+0032 leave
A while
loop uses a branchif
for its jump, whereas the until
loop used a branchunless
. So, these loops simply differ in the comparison being made, which you can see by looking at how branchif
and branchunless
are defined:
DEFINE_INSN
branchif
(OFFSET dst)
(VALUE val)
()
{
if (RTEST(val)) {
RUBY_VM_CHECK_INTS(th);
JUMP(dst);
}
}
DEFINE_INSN
branchunless
(OFFSET dst)
(VALUE val)
()
{
if (!RTEST(val)) {
RUBY_VM_CHECK_INTS(th);
JUMP(dst);
}
}
Performance between while
and until
should be nearly identical. Usage should be determined by readability.
Is each slower than while in Ruby?
When you do range=range.reject {..}
, you don't modify the parent range (which you shouldn't do, because it would mess up the iteration--you need reject!
to do that) but rather construct a temporary array which only gets assigned to the parent range variable at the end of the iteration.
The each
iteration in prime2
runs over the whole original range, not the shortened which, before the loop ends, only exist in the block.
The while version modifies the original array and is therefore quicker (BTW, you realize that i remains zero and it's the range.count
that changes (decreases) in that while condition and that reject iterates over the WHOLE array again--even the beginning where there couldn't possibly be any more nonprimes to reject).
You'll get a much faster result if you improve the logic of your code. That array manipulation is costly and for this, you don't even need an array:
def prime3?(prime_candidate)
return false if prime_candidate==1
return true if prime_candidate==2
range = 2..(Math.sqrt(prime_candidate).ceil)
range.all? {|x| prime_candidate % x !=0 }
end #about 300× times as fast for your example as prime1? on my PC
Ruby - I have code that I like but I would like it to loop until one of the conditions is true
Put an infinite loop around the code using loop
operator. Put next
after the "bad" condition to go back to the beginning of the loop. In all other cases, the code falls through to the final break
operator before the end
of the infinite loop, which causes the loop to exit. If you do not need to reuse math
variable, you can get rid of it altogether. Here it is used only once, so I remove it, and instead gets.chomp.downcase
is directly evaluated in the case
statement without the need of a temporary variable.
#!/usr/bin/env ruby
puts "Welcome to math.rb!"
puts "Enter a number!"
user = gets.to_i
puts "Enter another number!"
user2 = gets.to_i
puts "What would you like to do with your number?"
loop do
case gets.chomp.downcase
when "add"
puts user + user2
when "subtract"
puts user - user2
when "multiply"
puts user * user2
else
puts "I don't understand! Type a command like:
-add
-subtract
-multiply"
next
end
break
end
SEE ALSO:
loop
is the most accepted and common way to create infinite loops in Ruby : Creating an Infinite Looploop
is a kernel method which takes a block
, which introduces a new local variable scope in the infinite loop. This is unlike while true
infinite loop, which does not introduce a new scope. Thus, while true
may leak variables outside of the loop, which may be unexpected and lead to subtle bugs later: https://stackoverflow.com/a/45070639/967621
Ruby while loop with sleep
The console output is buffered and nobody promised to IO#flush
it for you:
$i = 0
$num = 3
while $i < $num do
$stdout.puts "My loop just executed"
$stdout.flush
sleep 10
$i +=1
end
Why do people say that Ruby is slow?
Why is Ruby considered slow?
Because if you run typical benchmarks between Ruby and other languages, Ruby loses.
I do not find Ruby to be slow but then
again, I'm just using it to make
simple CRUD apps and company blogs.
What sort of projects would I need to
be doing before I find Ruby becoming
slow? Or is this slowness just
something that affects all programming
languages?
Ruby probably wouldn't serve you well in writing a real-time digital signal processing application, or any kind of real-time control system. Ruby (with today's VMs) would probably choke on a resource-constrained computer such as smartphones.
Remember that a lot of the processing on your web applications is actually done by software developed in C. e.g. Apache, Thin, Nginx, SQLite, MySQL, PostgreSQL, many parsing libraries, RMagick, TCP/IP, etc are C programs used by Ruby. Ruby provides the glue and the business logic.
What are your options as a Ruby
programmer if you want to deal with
this "slowness"?
Switch to a faster language. But that carries a cost. It is a cost that may be worth it. But for most web applications, language choice is not a relevant factor because there is just not enough traffic justify using a faster language that costs much more to develop for.
Which version of Ruby would best suit
an application like Stack Overflow
where speed is critical and traffic is
intense?
Other folks have answered this - JRuby, IronRuby, REE will make the Ruby part of your application run faster on platforms that can afford the VMs. And since it is often not Ruby that causes slowness, but your computer system architecture and application architecture, you can do stuff like database replication, multiple application servers, loadbalancing with reverse proxies, HTTP caching, memcache, Ajax, client-side caching, etc. None of this stuff is Ruby.
Finally, I can't find much news on
Ruby 2.0 - I take it we're a good few
years away from that then?
Most folks are waiting for Ruby 1.9.1. I myself am waiting for Rails 3.1 on Ruby 1.9.1 on JRuby.
Finally, please remember that a lot of developers choose Ruby because it makes programming a more joyful experience compared to other languages, and because Ruby with Rails enables skilled web developers to develop applications very quickly.
How come this algorithm in Ruby runs faster than in Parallel'd C#?
Actually, the bug is quite subtle, and has nothing to do with threading. The reason that your C# version takes so long is that the intermediate values computed by the collatz
method eventually start to overflow the int
type, resulting in negative numbers which may then take ages to converge.
This first happens when i
is 134,379, for which the 129th term (assuming one-based counting) is 2,482,111,348. This exceeds the maximum value of 2,147,483,647 and therefore gets stored as -1,812,855,948.
To get good performance (and correct results) on the C# version, just change:
int current = i;
…to:
long current = i;
…and:
static int collatz(int num)
…to:
static long collatz(long num)
That will bring down your performance to a respectable 1.5 seconds.
Edit: CodesInChaos raises a very valid point about enabling overflow checking when debugging math-oriented applications. Doing so would have allowed the bug to be immediately identified, since the runtime would throw an OverflowException
.
When implementing an infinite loop, is there a difference in using while(1) vs for(;;) vs goto (in C)?
They are equivalent, even if you turn the optimizer off.
Example:
#include <stdio.h>
extern void f(void) {
while(1) {
putchar(' ');
}
}
extern void g(void) {
for(;;){
putchar(' ');
}
}
extern void h(void) {
z:
putchar(' ');
goto z;
}
Compile with gcc -O0
gives equivalent assembly for all 3 functions:
f:
; [ EXTERNAL ]
;
+00000 00000fb4 80402DE9 stmdb sp!,{r7,lr}
+00004 00000fb8 00708DE2 add r7,sp,#0x0
+00008 00000fbc 2000A0E3 loc_000008: mov r0,#0x20
+0000c 00000fc0 0A0000EB bl putchar (stub)
+00010 00000fc4 FCFFFFEA b loc_000008
;
;
g:
; [ EXTERNAL ]
;
+00000 00000fc8 80402DE9 stmdb sp!,{r7,lr}
+00004 00000fcc 00708DE2 add r7,sp,#0x0
+00008 00000fd0 2000A0E3 loc_000008: mov r0,#0x20
+0000c 00000fd4 050000EB bl putchar (stub)
+00010 00000fd8 FCFFFFEA b loc_000008
;
;
h:
; [ EXTERNAL ]
;
+00000 00000fdc 80402DE9 stmdb sp!,{r7,lr}
+00004 00000fe0 00708DE2 add r7,sp,#0x0
+00008 00000fe4 2000A0E3 loc_000008: mov r0,#0x20
+0000c 00000fe8 000000EB bl putchar (stub)
+00010 00000fec FCFFFFEA b loc_000008
Related Topics
Gmaps4Rails:Setting Map Width and Height
Why Should You Avoid the Then Keyword in Ruby
How to Effectively Force Minitest to Run My Tests in Order
Spring Doesn't Work. [ Uninitialized Constant Spring::Sid::Dl ]
Watir: Get Sometimes a Net::Readtimeout Error by Launching Chrome Browser
Why Are Parenthesis Sometimes Required in Ruby
Rails Object Based Permission/Authorization Engine
-Bash: /Usr/Local/Bin/Heroku: /Usr/Local/Bin/Ruby: Bad Interpreter: No Such File or Directory
Dangerousattributeerror in Omniauth Railscast Tutorial: Create Is Defined by Activerecord
System New Line Separator in Ruby
Why Does My Recursive Method from Helper Not Return Every Value
Failing to Enable User-Env-Compile on Heroku
Regex "Punct" Character Class Matches Different Characters Depending on Ruby Version