Forum: Ruby Help with leap year programing

Posted by HB (Guest)
on 2007-09-01 16:36
(Received via mailing list)
Hi, All,

I am a beginner on programming now reading books by Chris Pine: Learn
to Program.
On chapter 6, I got same assignment. I guess that is a classic one.

I have tried to use what I have learned so far: The loop.

My code is as below. i have run several test without finding any
problem.

Can you help to have a look and throw some light on any possible
improvement? Thanks.

____________________

puts 'starting year:'
s = gets.chop
puts 'ending year:'
e = gets.chop

if s.to_i > e.to_i
  puts 'ending year should be bigger than staring year'
  else
    puts 'leap year between ' + s + ' and '+ e + ' as below:'
end

while s.to_i  < e.to_i

  while ( (s.to_i % 4 == 0 and s.to_i % 100 != 0) or (s.to_i % 100 ==
0 and s.to_i % 400 == 0 ))
      puts s
      s = s.to_i + 1
      end
s = s.to_i + 1
end
puts 'all done'


On Nov 7, 2006, at 12:15 PM, Shiloh Madsen wrote:


> into the "true" group that I am having trouble with...or maybe I am
> just not wrapping my mind around the problem well
> enough...suggestions?


The key point of all the methods proposed in this thread is: deal
with the years divisible by 400 first, the years divisible by 100
second, and the years divisible by 4 last of all.

Regards, Morton
Posted by Robert Klemme (Guest)
on 2007-09-01 17:01
(Received via mailing list)
On 01.09.2007 16:33, HB wrote:
> improvement? Thanks.
The fist thing I'd change is to remove all the #to_i's.  You should
convert to integer just once, namely after reading user input.  If you
use Integer() for the conversion, then you also get automatic error
checking, i.e., if the user enters "foo" no calculations will be done
but he will see an error message instead.

Next, I am not sure what you are trying to achieve.  As far as I can see
there is no condition on the "puts s" but your print statement seems to
indicate that you are interested in leap years only.  If you want to
print leap years only then you need to somehow put a condition around
that output statement.

Normally you would need just a single loop as far as I understand the
problem and what you are trying to do.  So you could get rid of one of 
them.

I would also move the leap year output code inside the if-else.  The
code will likely work the way it is as well because if s>e the body of
the while loop will never be executed.  But from a control flow point of
view the code becomes clearer when you nest the "activity" (leap year
calculation and output in this case) in the proper branch of the
conditional statement.

>     puts 'leap year between ' + s + ' and '+ e + ' as below:'
> end
> puts 'all done'

Kind regards

  robert
Posted by Josef 'Jupp' Schugt (Guest)
on 2007-09-01 18:54
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

* HB:

> On chapter 6, I got same assignment. I guess that is a classic one.

So here is a nonclassic solution to this classic problem :)

If s % 4 differs from 0 we start with a year that cannot be a leap year.
If this occurs add 4 - (s % 4) to skip to the next year that is a leap
year unless century rules happen to apply. Now only every fourth year
needs to be considered. A year that can be divided by four is a leap
year under the condition that it can be divided by 400 or cannot be
divided by 100.

puts 'starting year:'
s = gets.chomp.to_i
puts 'ending year:'
e = gets.chomp.to_i

if s > e
    puts 'ending year should be bigger than staring year'
else
    puts "leap year between #{s} and #{e} as below:"
end

s += 4 - (s % 4) if s % 4 != 0

while s  <= e
    puts s if (s % 400 == 0 or s % 100 != 0)
    s += 4
end
puts 'all done'

Josef 'Jupp' Schugt
- --
Blog available at http://www.mynetcologne.de/~nc-schugtjo/blog/
PGP key with id 6CC6574F available at http://wwwkeys.de.pgp.net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iD8DBQFG2ZkSrhv7B2zGV08RAmuVAJ4xCwywVTVlXg2S3kUvtibQcynnmgCg2hHD
Mpa+a5kp4DdFSqLqMa+FDQQ=
=T/yP
-----END PGP SIGNATURE-----
Posted by Hu Yoi (kgo_yoi)
on 2007-09-02 18:24
HB wrote:
> Hi, All,
> 
> I am a beginner on programming now reading books by Chris Pine: Learn
> to Program.
> On chapter 6, I got same assignment. I guess that is a classic one.
> 
> I have tried to use what I have learned so far: The loop.
> 
> My code is as below. i have run several test without finding any
> problem.
> 
> Can you help to have a look and throw some light on any possible
> improvement? Thanks.
> 

I think it's easier to use Date#leap? for this question.

puts 'Starting year:'
start = gets.chop
puts 'Ending year:'
ending = gets.chop
if start.to_i > ending.to_i
  puts 'Ending year should be bigger than staring year'
else
   puts 'Leap year between ' + start + ' and '+ ending + ' as below:'
   while start.to_i <= ending.to_i
    if Date.new(start.to_i).leap?
      puts start
    end
    start = start.to_i + 1
  end
end
puts 'all done'


Yoi
Posted by HB (Guest)
on 2007-09-08 15:37
(Received via mailing list)
On Sep 3, 12:24 am, Hu Yoi <kgo_...@hotmail.com> wrote:
> > problem.
> if start.to_i > ending.to_i
> puts 'all done'
>
> Yoi
> --
> Posted viahttp://www.ruby-forum.com/.

Thanks to all!
I have a lot to learn and it is fun!
Posted by 7stud -- (7stud)
on 2007-09-09 04:26
HB wrote:
> Hi, All,
> 
> I am a beginner on programming now reading books by Chris Pine: Learn
> to Program.
>
> ...
>
>     while ( (s.to_i % 4 == 0 and s.to_i % 100 != 0) or (s.to_i % 100 ==
>           0 and s.to_i % 400 == 0 ))
>
> The key point of all the methods proposed in this thread is: deal
> with the years divisible by 400 first, the years divisible by 100
> second, and the years divisible by 4 last of all.
> 
> Regards, Morton


Your complex conditional can be expressed more clearly with a series of 
if statements:

start = 2000
finish = 2200

year = start

while year <= finish

    is_leap =
        if year % 400 == 0
            true
        elsif year % 100 == 0
            false
        else
            year % 4 == 0
        end

    if is_leap: puts year
    end

    year += 1
end



Or you can use each() on a Range for your loop, and a case statement 
inside the loop:

start = 2000
finish = 2200

user_range = start..finish

user_range.each do |year|

    is_leap =
        case
        when year % 400 == 0
            true
        when year % 100 == 0
            false
        else
            year % 4 == 0
        end

    if is_leap: puts year
    end

    year += 1
end
Posted by Bernie Loriaga (bernie_loriaga)
on 2008-10-16 09:15
I have a little modification, I included the minutes in a year.


#!/usr/bin/ruby

puts "please enter starting year:"
STDOUT.flush
starting = gets

puts "please enter end_year:"
STDOUT.flush
end_year = gets

year = starting.to_i

while year <= end_year.to_i

  leapyear =
        if year % 400 == 0
            true
        elsif year % 100 == 0
            false
        else
            year % 4 == 0
        end


 if leapyear: puts "#{year}-> This year is a leapyear and #{366*60*24} 
minutes"
 else
  puts "#{year}-> Not a leapyear #{365*60*24} minutes"
 end
  year += 1
end


Good day,
Bernie Loriaga
Posted by Victor Goff (kotp)
on 2008-10-16 09:25
(Received via mailing list)
:) That is what I am talking about... I just ran it from my e-mail... 
much
better for the assignment.  You are greatly improving, by the way!
Warmest Regards,

Victor H. Goff III
Voice (218) 206-2470
Posted by Bernie Loriaga (bernie_loriaga)
on 2008-10-16 09:29
Thanks Vic,
  I just copy the code and modify it a little,is it mean that I'm 
improving?
Right now,I'm reading some ruby book.I want to improve my ruby skill.

Take care & Good day,
Bernie Loriaga
Posted by Hh Rg (auderesemper)
on 2010-06-23 22:19
The problem comes from a beginner´s tutorial. Using methods like .leap? 
of course work just fine. However, a beginner is not familiar with them. 
This a way to do it using the tools showed in the same tutorial up to 
that level:


puts "Give me the two years"
 year1 = gets.chomp.to_i
 year2 = gets.chomp.to_i
 puts "This is the list of years:"

 if year1 > year2
   puts "The second year has to be bigger than the first"
 else
   while (year1 <= year2)
     if
       (((year1 % 4 == 0) and (year1 %100 !=0)) or (year1 % 400 == 0))
       puts year1.to_s

     end
     (year1 = year1.to_i + 1)
   end
puts "Finished"
end
Posted by Chris K. (chris_k10)
on 2011-06-21 18:36
I'm a complete programming noob and just starting to learn Ruby. I'm
going through the same book and got stumped on this one.

Now that I see how it's done, I get everything but the last line (in
Pine's solution) which is

year = year + 1


What's the function of this line? I've experimented with
changing/eliminating it and I see that it's necessary, but I still don't
understand why.



(If it would be best to create a new topic, let me know. Not sure what 
the etiquette is here, but I figured it was such a small piece of the 
program that I should just add to an existing thread.)
Posted by Chris K. (chris_k10)
on 2011-06-22 08:55
Chris K. wrote in post #1006695:
> I'm a complete programming noob and just starting to learn Ruby. I'm
> going through the same book and got stumped on this one.
>
> Now that I see how it's done, I get everything but the last line (in
> Pine's solution) which is
>
> year = year + 1
>
>
> What's the function of this line? I've experimented with
> changing/eliminating it and I see that it's necessary, but I still don't
> understand why.
>
>
>
> (If it would be best to create a new topic, let me know. Not sure what
> the etiquette is here, but I figured it was such a small piece of the
> program that I should just add to an existing thread.)


Feel like kind of a goof now. It just hit me.  In case anyone else has 
the same mental block - for the program to run through the years one at 
a time, it has to be told to do that, which is what the +1 accomplishes. 
Seems terribly obvious now.
Posted by Hieu Le (hieulh89)
on 2012-12-11 09:50
This is my function:



puts 'Begin year:'
beginyear = gets.chomp
puts 'End year:'
endyear = gets.chomp
puts 'The leap years between ' + beginyear + ' and ' + endyear + ':'

beginyear = beginyear.to_i
endyear = endyear.to_i
if endyear < beginyear
        puts 'Note: Begin year < End year'
else
        while (beginyear <= endyear)
                if
                (((beginyear % 4 == 0) and (beginyear %100 !=0)) or 
(beginyear % 400 == 0))
       puts beginyear.to_s

     end
     (beginyear = beginyear.to_i + 1)
   end
end
Posted by Robert Klemme (robert_k78)
on 2012-12-11 13:27
(Received via mailing list)
On Tue, Dec 11, 2012 at 9:50 AM, Hieu Le <lists@ruby-forum.com> wrote:
> beginyear = beginyear.to_i
>      end
>      (beginyear = beginyear.to_i + 1)
>    end
> end

Here's mine

require 'date'

puts 'Begin year:'
beginyear = Integer(gets)

puts 'End year:'
endyear = Integer(gets)

puts "Leap years between #{beginyear} and #{endyear}:"

for y in beginyear..endyear
  puts y if Date.new(y, 1, 1).leap?
end

Cheers

robert
Posted by tamouse mailing lists (Guest)
on 2012-12-12 07:10
(Received via mailing list)
On Tue, Dec 11, 2012 at 6:22 AM, Robert Klemme
<shortcutter@googlemail.com> wrote:
>>
>>
> beginyear = Integer(gets)
>
> puts 'End year:'
> endyear = Integer(gets)
>

One minor tweak:

   beginyear, endyear = endyear, beginyear if endyear < beginyear
Posted by Kristine Lai (screamingmunch)
on 2013-01-23 05:32
Hi, I'm also a newbie trying the Leap Year problem using while loops..
Can anyone advice why the following code doesn't work?  Much thanks!

puts "Enter starting year:"
      starting_year = gets.chomp.to_i
puts "Enter ending year:"
      ending_year = gets.chomp.to_i
while true
      year = starting_year
      if (year%4==0)&& (year%100!=0)
          puts year.to_s + ' is a Leap Year'
      end
    year = year +1
      break if year >= ending_year
end
Posted by Eduardo B. (eduardo_b)
on 2013-01-23 05:45
Kristine Lai wrote in post #1093222:
> Hi, I'm also a newbie trying the Leap Year problem using while loops..
> Can anyone advice why the following code doesn't work?  Much thanks!
>
> puts "Enter starting year:"
>       starting_year = gets.chomp.to_i
> puts "Enter ending year:"
>       ending_year = gets.chomp.to_i
> while true
>       year = starting_year
>       if (year%4==0)&& (year%100!=0)
>           puts year.to_s + ' is a Leap Year'
>       end
>     year = year +1
>       break if year >= ending_year
> end

You are resetting the variable "year" to "starting_year" every time to 
loop runs.  Set the variable "year" outside of the while loop.  Also, 
there is a leap year every 400 years.
Posted by Eduardo Bautista (Guest)
on 2013-01-23 05:45
(Received via mailing list)
You are resetting year to starting_year every time the loop runs.  Set 
that variable outside of the loop.  Also, every 400 years, there is a 
leap year.
Posted by Kristine Lai (screamingmunch)
on 2013-01-24 02:01
Thanks for the pointers Eduardo!

The new code here works.
---------------------------------------

puts "Enter starting year:"
        starting_year = gets.chomp.to_i
puts "Enter ending year:"
      ending_year = gets.chomp.to_i
year = starting_year
while true
      if year%4==0
          if year%100!=0 || year%400 ==0
              puts year.to_s + ' is a Leap Year'
          end
      end
    year = year +1
      break if year >= ending_year
end
Posted by Heesob Park (phasis)
on 2013-01-24 02:36
(Received via mailing list)
Hi,

2013/1/24 Kristine Lai <lists@ruby-forum.com>

> while true
>       if year%4==0
>           if year%100!=0 || year%400 ==0
>               puts year.to_s + ' is a Leap Year'
>           end
>       end
>     year = year +1
>       break if year >= ending_year
> end
>

You can also use date standard library for detecting leap year like 
this:

require 'date'
Date.leap?(1900) #=> false
Date.leap?(2000) #=> true

Regards,
Park Heesob
Posted by unknown (Guest)
on 2013-01-24 21:04
(Received via mailing list)
Am 24.01.2013 02:01, schrieb Kristine Lai:
> while true
>        if year%4==0
>            if year%100!=0 || year%400 ==0
>                puts year.to_s + ' is a Leap Year'
>            end
>        end
>      year = year +1
>        break if year >= ending_year
> end

Usually you would not use a while loop for tasks like this,
try for example:

   print "Enter starting year: "
   starting_year = gets.chomp.to_i
   print "Enter ending year: "
   ending_year = gets.chomp.to_i

   starting_year.upto(ending_year) do |year|
     if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
       puts "#{year} is a leap year"
     end
   end

which saves 3 lines of code and some possibilities for typos/bugs.

BTW, for an infinite loop there exists `loop do ... end'.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.