Skip to content

Instantly share code, notes, and snippets.

@mvw
Last active January 27, 2016 23:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mvw/f165e01d77d1730a4ebe to your computer and use it in GitHub Desktop.
Save mvw/f165e01d77d1730a4ebe to your computer and use it in GitHub Desktop.
# digit_wise_average.rb
# the usual average of two numbers
def average(a, b)
(a + b) / 2.0
end
# convert "n" into array of digits regarding "base"
# lowest power stored first
def to_a(n, base)
a = [ ]
x = n
begin
r = x % base
a << r
x = (x - r) / base
end while x > 0
a
end
# here we act on the digits of the two
# argument numbers, to come up with the
# digits of the average
def dwa(a, b, base=10)
base_half = base / 2
a_a = to_a(a, base)
b_a = to_a(b, base)
m_a = a_a.length
m_b = b_a.length
if m_a > m_b
# switch variables (we assumed m_a < m_b)
a, b, a_a, b_a, m_a, m_b = b, a, b_a, a_a, m_b, m_a
end
#print "a: #{a_a.reverse}_#{base} (#{a}), "
#puts "b: #{b_a.reverse}_#{base} (#{b})"
# set up digits and remainder arrays
d_a = [ ]
d_b = [ ]
r = [ ]
(0..m_b).each do |k|
d_a[k] = (k < m_a) ? a_a[k] : 0
d_b[k] = (k < m_b) ? b_a[k] : 0
r[k] = (d_a[k] + d_b[k]) % 2
end
r[m_b + 1] = 0
# calculate average digits
d_c = [ ]
o = [ ]
# d[-1]
d_cm = base_half * r[0]
# d[0]
x0 = base_half * r[1] + (d_a[0] + d_b[0]) / 2 # intentional truncate
d_c[0] = x0 % base
o[0] = x0 / base # intentional truncate
# d[1] .. d[m_b]
(1..m_b).each do |k|
xk = base_half * r[k+1] + (d_a[k] + d_b[k]) / 2 + o[k-1] # intentional truncate
d_c[k] = xk % base
o[k] = xk / base
# test testing
#if rand() > 0.99999
# o[k] += 1
#end
if o[k] > 1
puts "x[#{k}] = #{xk} d_c[#{k}] = #{d_c[k]} o[#{k}] = #{o[k]}"
end
end
# convert digits to float
c = 0
p = 1
(0..m_b).each do |k|
c += d_c[k] * p
p *= base
end
c += d_cm * (1.0 / base)
c
end
# calculate the average by both methods,
# compare the result
def test(a, b, base=10)
c1 = average(a, b)
c2 = dwa(a, b, base)
equal = (c1 == c2)
if not equal
print "a: #{a}, "
print "b: #{b} "
puts "ERROR #{c1} vs. #{c2} base: #{base}"
end
equal
end
# print statistics
def stats(succeeded, failed)
success_rate = (100.0 * succeeded) / (succeeded + failed)
puts " succeeded: #{succeeded}"
puts " failed: #{failed}"
puts " success rate: #{success_rate} %"
end
N1 = 1000
# test all pairs from [0, .., N1]^2 using base 10
def test1
puts "#{__method__}:"
succeeded = 0
failed = 0
(N1+1).times do |i|
(N1+1).times do |j|
if test(i, j)
succeeded += 1
else
failed += 1
end
end
end
stats(succeeded, failed)
end
N2 = 1_000_000
# peform N2 tests, with random arguments and random even base
def test2
puts "#{__method__}:"
n = 1000 * N2
succeeded = 0
failed = 0
N2.times do |k|
a = rand(n)
b = rand(n)
base = 2 * (1 + rand(500))
if test(a, b, base)
succeeded += 1
else
failed += 1
end
end
stats(succeeded, failed)
end
test1
test2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment