|
#!/usr/bin/env ruby
|
|
#==========================================================================
|
|
|
|
def x_apply_binary_operator_t1(x_identity_element,ar_in,
|
|
func_operator_that_might_be_noncommutative)
|
|
# This code is is a slightly edited version of the
|
|
# kibuvits_s_concat_array_of_strings(...) core.
|
|
# The comments and explanations are mostly there.
|
|
#
|
|
# May be the following link works:
|
|
# https://github.com/martinvahi/mmmv_devel_tools/blob/master/src/bonnet/lib/kibuvits_ruby_library/src/include/kibuvits_str_concat_array_of_strings.rb
|
|
#
|
|
# If the next link works properly, then there
|
|
# might be some demos for string concatenation at
|
|
# https://github.com/martinvahi/mmmv_notes/tree/master/mmmv_notes/phenomenon_scrutinization/string_concatenation
|
|
#
|
|
# The general idea is that from memory
|
|
# allocation point of view multiplication
|
|
# is similar to string concatenation. An example:
|
|
#
|
|
# new_string="100"+"000" # == "100000"
|
|
# new_number= 100 *1000 # == 100000
|
|
#
|
|
#------------------------------
|
|
cl=ar_in.class
|
|
if cl!=Array
|
|
raise(Exception.new("ar_in.class=="+cl.to_s+
|
|
", but it is expected to be Array.\n"))
|
|
end # if
|
|
cl=func_operator_that_might_be_noncommutative.class
|
|
if cl!=Proc
|
|
raise(Exception.new("func_operator_that_might_be_noncommutative.class=="+cl.to_s+
|
|
", but it is expected to be Proc.\n"))
|
|
end # if
|
|
#------------------------------
|
|
func_oper=func_operator_that_might_be_noncommutative
|
|
i_n=ar_in.size
|
|
if i_n<3
|
|
if i_n==2
|
|
x_out=func_oper.call(ar_in[0],ar_in[1])
|
|
return x_out
|
|
else
|
|
if i_n==1
|
|
# For the sake of consistency one
|
|
# wants to make sure that the returned
|
|
# string instance always differs from those
|
|
# that are within the ar_in.
|
|
x_out=func_oper.call(x_identity_element,ar_in[0])
|
|
return x_out
|
|
else # i_n==0
|
|
x_out=x_identity_element
|
|
return x_out
|
|
end # if
|
|
end # if
|
|
end # if
|
|
x_out=x_identity_element # needs to be inited to the x_identity_element
|
|
ar_1=ar_in
|
|
b_ar_1_equals_ar_in=true # to avoid modifying the received Array
|
|
ar_2=Array.new
|
|
b_take_from_ar_1=true
|
|
b_not_ready=true
|
|
i_reminder=nil
|
|
i_loop=nil
|
|
i_ar_in_len=nil
|
|
i_ar_out_len=0 # code after the while loop needs a number
|
|
x_1=nil
|
|
x_2=nil
|
|
x_3=nil
|
|
i_2=nil
|
|
while b_not_ready
|
|
# The next if-statement is to avoid copying temporary
|
|
# strings between the ar_1 and the ar_2.
|
|
if b_take_from_ar_1
|
|
i_ar_in_len=ar_1.size
|
|
i_reminder=i_ar_in_len%2
|
|
i_loop=(i_ar_in_len-i_reminder)/2
|
|
i_loop.times do |i|
|
|
i_2=i*2
|
|
x_1=ar_1[i_2]
|
|
x_2=ar_1[i_2+1]
|
|
x_3=func_oper.call(x_1,x_2)
|
|
ar_2<<x_3
|
|
end # loop
|
|
if i_reminder==1
|
|
x_3=ar_1[i_ar_in_len-1]
|
|
ar_2<<x_3
|
|
end # if
|
|
i_ar_out_len=ar_2.size
|
|
if 1<i_ar_out_len
|
|
if b_ar_1_equals_ar_in
|
|
ar_1=Array.new
|
|
b_ar_1_equals_ar_in=false
|
|
else
|
|
ar_1.clear
|
|
end # if
|
|
else
|
|
b_not_ready=false
|
|
end # if
|
|
else # b_take_from_ar_1==false
|
|
i_ar_in_len=ar_2.size
|
|
i_reminder=i_ar_in_len%2
|
|
i_loop=(i_ar_in_len-i_reminder)/2
|
|
i_loop.times do |i|
|
|
i_2=i*2
|
|
x_1=ar_2[i_2]
|
|
x_2=ar_2[i_2+1]
|
|
x_3=func_oper.call(x_1,x_2)
|
|
ar_1<<x_3
|
|
end # loop
|
|
if i_reminder==1
|
|
x_3=ar_2[i_ar_in_len-1]
|
|
ar_1<<x_3
|
|
end # if
|
|
i_ar_out_len=ar_1.size
|
|
if 1<i_ar_out_len
|
|
ar_2.clear
|
|
else
|
|
b_not_ready=false
|
|
end # if
|
|
end # if
|
|
b_take_from_ar_1=!b_take_from_ar_1
|
|
end # loop
|
|
if i_ar_out_len==1
|
|
if b_take_from_ar_1
|
|
x_out=ar_1[0]
|
|
else
|
|
x_out=ar_2[0]
|
|
end # if
|
|
else
|
|
# The x_out has been inited to "".
|
|
if 0<i_ar_out_len
|
|
raise Exception.new("This function is flawed."+
|
|
"\n GUID='1e84a702-39cb-458b-8728-f24371c06ed7'\n\n")
|
|
end # if
|
|
end # if
|
|
return x_out
|
|
end # x_apply_binary_operator_t1
|
|
|
|
|
|
def i_factorial_t1(i_n)
|
|
if defined? KIBUVITS_b_DEBUG
|
|
if KIBUVITS_b_DEBUG
|
|
bn=binding()
|
|
# Allowing the i_n to be a Bignum is a bit crazy in 2014,
|
|
# but may be in the future that might not be that crazy.
|
|
kibuvits_typecheck bn, [Fixnum,Bignum], i_n
|
|
kibuvits_assert_is_smaller_than_or_equal_to(bn,0,i_n,
|
|
"\n GUID='4289c481-1793-4f01-b3e5-e2700090bed7'\n\n")
|
|
end # if
|
|
else
|
|
# It's up to the final implementers to figure out,
|
|
# what, if any, input verification must take place here,
|
|
# but, for the time being:
|
|
cl=i_n.class
|
|
if cl!=Fixnum
|
|
if cl!=Bignum
|
|
raise(Exception.new("i_n.class=="+cl.to_s+
|
|
", but it is expected to be of some whole number type."))
|
|
end # if
|
|
end # if
|
|
if i_n<0
|
|
raise(Exception.new("i_n=="+i_n.to_s+" < 0 ,"+
|
|
"but factorials are defined for positive numbers."))
|
|
end # if
|
|
end # if
|
|
i_out=1 # factorial(0)==1
|
|
return i_out if i_n==0
|
|
func_star=lambda do |x_a,x_b|
|
|
x_out=x_a*x_b
|
|
return x_out
|
|
end # func_star
|
|
ar_n=Array.new
|
|
# For i_n==2, the ar_n==[0,1,2], ar_n.size==3 .
|
|
# To avoid multiplication with 0, ar_n[0]==1 .
|
|
# Therefore, for i_n==2, ar_n==[1,2] .
|
|
i_n.times{|i| ar_n<<(i+1)} # i starts from 0
|
|
x_identity_element=1
|
|
i_out=x_apply_binary_operator_t1(
|
|
x_identity_element,ar_n,func_star)
|
|
return i_out
|
|
end # i_factorial_t1
|
|
|
|
class Fixnum
|
|
def factorial
|
|
i_out=i_factorial_t1(self)
|
|
return i_out
|
|
end # factorial
|
|
end # class Fixnum
|
|
|
|
class Bignum
|
|
def factorial
|
|
i_out=i_factorial_t1(self)
|
|
return i_out
|
|
end # factorial
|
|
end # class Bignum
|
|
|
|
#--------------------------------------------------------------------------
|
|
|
|
def i_factorial_old_style(i_n)
|
|
i_factorial=1
|
|
return i_factorial if (i_n==0)||(i_n==1)
|
|
i_n.times do |i|
|
|
i_factorial=i_factorial*(i+1)
|
|
end # loop
|
|
return i_factorial
|
|
end # i_factorial_old_style
|
|
|
|
if ARGV.size==0
|
|
puts "\n\nFirst console argument must be a whole number.\n\n"
|
|
exit
|
|
end # if
|
|
i_n=ARGV[0].to_i
|
|
b_both=false
|
|
b_old=true
|
|
b_old=false if 1<ARGV.size
|
|
b_both=true if ARGV.size==3
|
|
|
|
if b_old
|
|
i_factorial=i_factorial_old_style(i_n)
|
|
s_result=i_factorial.to_s
|
|
if s_result.length<10
|
|
puts "\n\n Factorial of "+i_n.to_s+" by the simplistic algorithm is:\n"+
|
|
s_result+"\n\n"
|
|
else
|
|
puts "\n\n Factorial of "+i_n.to_s+" by the simplistic algorithm \n"+
|
|
"has a length of "+s_result.length.to_s+"\n\n"
|
|
end # if
|
|
else
|
|
if b_both
|
|
i_factorial_old=i_factorial_old_style(i_n)
|
|
i_factorial_new=i_n.factorial
|
|
if i_factorial_old!=i_factorial_new
|
|
puts "\n\nThere's a flaw somewhere.\n\n"
|
|
else
|
|
puts "\n\nThe results of the proposed algorithm and the \n"+
|
|
"simplistic algorithm match.\n\n"
|
|
end # if
|
|
else
|
|
i_factorial=i_n.factorial
|
|
s_result=i_factorial.to_s
|
|
if s_result.length<10
|
|
puts "\n\n Factorial of "+i_n.to_s+" by the proposed algorithm is:\n"+
|
|
i_factorial.to_s+"\n\n"
|
|
else
|
|
puts "\n\n Factorial of "+i_n.to_s+" by the proposed algorithm \n"+
|
|
"has a length of "+s_result.length.to_s+"\n\n"
|
|
end # if
|
|
end # if
|
|
end # if
|
|
|
|
|
|
#==========================================================================
|