Last active
January 27, 2016 23:12
-
-
Save mvw/f165e01d77d1730a4ebe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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