Here below a little program in JRuby that implements 2 classes. There is the main class, called Fiborial (Fibo(nnacci)+(Facto)rial) that implements the Fibonacci and the Factorial algorithms in two ways, one Recursive (using recursion) and the other Imperative (using loops and states). The second class is just an instance class that does the same thing, but its there just to show the difference between static and instance classes, and finally a main function called as module level code.
You can also find 3 more little examples at the bottom. One prints out the Factorial's Series and Fibonacci's Series, the second one just shows a class that mixes both: static and instance members, and finally the third one that uses different return types for the Factorial method to compare the timing and result.
As with the previous posts, you can copy and paste the code below in your favorite IDE/Editor and start playing and learning with it. This little "working" program will teach you some more basics of the Programming Language.
There are some "comments" on the code added just to tell you what are or how are some features called. In case you want to review the theory, you can read my previous post, where I give a definition of each of the concepts mentioned on the code. You can find it here: http://carlosqt.blogspot.com/2011/01/new-series-factorial-and-fibonacci.html
WARNING: the code that you will see below is not following ruby guidelines/idiomatic coding, I did it in purpose to compare ruby's syntax and features side by side with other programming languages... For instance, instead of using a ruby bignum I imported and used java.math.BigInteger instead. Other examples, naming convention and so on, so bear with me!
I'm using the same Stopwatch java class that I used in the Java version of this post. I just added the .class into a 'target' folder and added it to the classpath. then I java_imported it. http://carlosqt.blogspot.com/2011/05/stopwatch-class-for-java.html
The Fiborial Program
# Factorial and Fibonacci in JRuby require "java" $CLASSPATH << "target" java_import 'Stopwatch' import java.lang.System import java.math.BigInteger module FiborialRb # Static Class # static classes are not supported in Ruby class StaticFiborial # Static Field @@class_name = "" # no builtin static constructor/initializer support # you can initialize field at this point and even add extra code @@class_name = "Static Constructor" puts @@class_name # Static Method - Factorial Recursive def self.factorial_r(n) if n < 2 BigInteger.new('1') else BigInteger.new(n.to_s).multiply(self.factorial_r(n-1)) end end # Static Method - Factorial Imperative def self.factorial_i(n) res = BigInteger.new('1') while n > 1 res = BigInteger.new(res.multiply(n).to_s) n -= 1 end res end # Static Method - Fibonacci Recursive def self.fibonacci_r(n) if n < 2 1 else self.fibonacci_r(n - 1) + self.fibonacci_r(n - 2) end end # Static Method - Fibonacci Imperative def self.fibonacci_i(n) pre = 1 cur = 1 tmp = 0 for i in 2..n tmp = cur + pre pre = cur cur = tmp end cur end # Static Method - Benchmarking Algorithms def self.benchmark_algorithm(algorithm, values) timer = Stopwatch.new i = 0 testValue = 0 facTimeResult = BigInteger::ZERO fibTimeResult = 0 # "case/switch" Flow Control Statement case algorithm when 1 puts "\nFactorial Imperative:" # "For in range" Loop Statement for i in 0..values.size - 1 do testValue = values[i] # Taking Time timer.start facTimeResult = self.factorial_i(testValue) timer.stop # Getting Time puts " (#{testValue}) = #{timer.elapsed}" end when 2 puts "\nFactorial Recursive:" # "While" Loop Statement while i < values.size do testValue = values[i] # Taking Time timer.start facTimeResult = self.factorial_r(testValue) timer.stop # Getting Time puts " (#{testValue}) = #{timer.elapsed}" i += 1 end when 3 puts "\nFibonacci Imperative:" # "until" Loop Statement until i == values.size do testValue = values[i] # Taking Time timer.start fibTimeResult = self.fibonacci_i(testValue) timer.stop # Getting Time puts " (#{testValue}) = #{timer.elapsed}" i += 1 end when 4 puts "\nFibonacci Recursive:" # "For each?" Statement values.each do |testValue| # Taking Time timer.start fibTimeResult = self.fibonacci_r(testValue) timer.stop # Getting Time puts " (#{testValue}) = #{timer.elapsed}" end else puts "DONG!" end end end # Instance Class class InstanceFiborial # Instance Field @class_name = "" # Instance Constructor/Initializer def initialize @class_name = "Instance Constructor" puts @class_name end # Instance Method - Factorial Recursive def factorial_r(n) # Calling Static Method StaticFiborial::factorial_r(n) end # Instance Method - Factorial Imperative def factorial_i(n) # Calling Static Method StaticFiborial::factorial_i(n) end # Instance Method - Fibonacci Recursive def fibonacci_r(n) # Calling Static Method StaticFiborial::fibonacci_r(n) end # Instance Method - Fibonacci Imperative def fibonacci_i(n) # Calling Static Method StaticFiborial::fibonacci_i(n) end end # Console Program puts "Static Class" # Calling Static Class and Methods # No instantiation needed. Calling method directly from the class puts "FacImp(5) = #{StaticFiborial::factorial_i(5)}" puts "FacRec(5) = #{StaticFiborial::factorial_r(5)}" puts "FibImp(11)= #{StaticFiborial::fibonacci_i(11)}" puts "FibRec(11)= #{StaticFiborial::fibonacci_r(11)}" puts "\nInstance Class" # Calling Instance Class and Methods # Need to instantiate before using. Calling method from instantiated object ff = InstanceFiborial.new puts "FacImp(5) = #{ff.factorial_i(5)}" puts "FacRec(5) = #{ff.factorial_r(5)}" puts "FibImp(11)= #{ff.fibonacci_i(11)}" puts "FibRec(11)= #{ff.fibonacci_r(11)}" # Create a (Ruby) list of values to test # From 5 to 50 by 5 values = [] for i in (5..50).step(5) values << i end # Benchmarking Fibonacci # 1 = Factorial Imperative StaticFiborial::benchmark_algorithm(1,values) # 2 = Factorial Recursive StaticFiborial::benchmark_algorithm(2,values) # Benchmarking Factorial # 3 = Fibonacci Imperative StaticFiborial::benchmark_algorithm(3,values) # 4 = Fibonacci Recursive StaticFiborial::benchmark_algorithm(4,values) # Stop and exit puts "Press any key to exit..." gets end
And the Output is:
Printing the Factorial and Fibonacci Series
require 'java' import java.lang.StringBuffer import java.math.BigInteger module FiborialSeriesRb class Fiborial # Using a StringBuffer as a list of string elements def self.get_factorial_series(n) # Create the String to hold the list series = StringBuffer.new # We begin by concatenating the number you want to calculate # in the following format: "!# =" series.append("!") series.append(n) series.append(" = ") # We iterate backwards through the elements of the series i = n while i >= 1 # and append it to the list series.append(i) if i > 1 series.append(" * ") else series.append(" = ") end i -= 1 end # Get the result from the Factorial Method # and append it to the end of the list series.append(self.factorial(n).to_s) # return the list as a string series.to_s end # Using a StringBuffer as a list of string elements def self.get_fibonnaci_series(n) # Create the String that will hold the list series = StringBuffer.new # We begin by concatenating the first 3 values which # are always constant series.append("0, 1, 1") # Then we calculate the Fibonacci of each element # and add append it to the list for i in 2..n if i < n series.append(", ") else series.append(" = ") end series.append(self.fibonacci(i)) end # return the list as a string series.to_s end def self.factorial(n) if n < 2 BigInteger.new('1') else BigInteger.new(n.to_s).multiply(self.factorial(n-1)) end end def self.fibonacci(n) if n < 2 1 else self.fibonacci(n - 1) + self.fibonacci(n - 2) end end end # Printing Factorial Series puts "" puts Fiborial::get_factorial_series(5) puts Fiborial::get_factorial_series(7) puts Fiborial::get_factorial_series(9) puts Fiborial::get_factorial_series(11) puts Fiborial::get_factorial_series(40) # Printing Fibonacci Series puts "" puts Fiborial::get_fibonnaci_series(5) puts Fiborial::get_fibonnaci_series(7) puts Fiborial::get_fibonnaci_series(9) puts Fiborial::get_fibonnaci_series(11) puts Fiborial::get_fibonnaci_series(40) # Stop and exit puts "Press any key to exit..." gets end
And the Output is:
Mixing Instance and Static Members in the same Class
Instance classes can contain both, instance and static members such as: fields, properties, constructors, methods, etc.
require 'java' # Instance Class class Fiborial # Instance Field @instance_count = 0 # Static Field @@static_count = 0 # Instance Read-Only Getter def get_instance_count() @instance_count end # Static Read-Only Getter def self.get_static_count() @@static_count end # Instance Constructor/Initializer def initialize() @instance_count = 0 puts "\nInstance Constructor #{@instance_count}" end # No Static Constructor/Initializer # You can do a self.initialize() static method, but it will not be called #def self.initialize() # @@static_count = 0 # puts "\nStatic Constructor #{@@static_count}" # Instance Method def factorial(n) @instance_count += 1 puts "\nFactorial(#{n.to_s})" end # Static Method def self.fibonacci(n) @@static_count += 1 puts "\nFibonacci(#{n.to_s})" end # Calling Static Constructor and Methods # No need to instantiate Fiborial::fibonacci(5) # Calling Instance Constructor and Methods # Instance required fib = Fiborial.new fib.factorial(5) Fiborial::fibonacci(15) fib.factorial(5) # Calling Instance Constructor and Methods # for a second object fib2 = Fiborial.new fib2.factorial(5) puts "" # Calling Static Getter puts "Static Count = #{Fiborial::get_static_count}" # Calling Instance Property of object 1 and 2 puts "Instance 1 Count = #{fib.get_instance_count}" puts "Instance 2 Count = #{fib2.get_instance_count}" gets end
And the Output is:
Factorial using int, float, System.Numerics.BigInteger
So, it looks like integers in ruby can hold big integers (they are handled as bignum), so using JRuby int/long or java.math.BigInteger is the same so not much to say here.
require 'java' $CLASSPATH << "target" java_import 'Stopwatch' import java.math.BigInteger # Int/Long Factorial def factorial_int(n) if n == 1 1.to_i else (n * factorial_int(n - 1)).to_i end end # double/float Factorial def factorial_float(n) if n == 1 1.0 else (n * factorial_float(n - 1)).to_f end end # BigInteger Factorial def factorial_bigint(n) if n == 1 BigInteger.new('1') else BigInteger.new(n.to_s).multiply(factorial_bigint(n-1)) end end timer = Stopwatch.new facIntResult = 0 facDblResult = 0.0 facBigResult = BigInteger.new('0') i = 0 puts "\nFactorial using Int/Long" # Benchmark Factorial using Int64 for i in (5..50).step(5) timer.start facIntResult = factorial_int(i) timer.stop puts " (#{i.to_s}) = #{timer.elapsed} : #{facIntResult}" end puts "\nFactorial using Float/Double" # Benchmark Factorial using Double for i in (5..50).step(5) timer.start facDblResult = factorial_float(i) timer.stop puts " (#{i.to_s}) = #{timer.elapsed.to_s} : #{facDblResult.to_s}" end puts "\nFactorial using BigInteger" # Benchmark Factorial using BigInteger for i in (5..50).step(5) timer.start facBigResult = factorial_bigint(i) timer.stop puts " (#{i.to_s}) = #{timer.elapsed.to_s} : #{facBigResult.to_s}" end gets
And the Output is: