Skip to content

Instantly share code, notes, and snippets.

@AgentAntelope
Created September 7, 2021 11:31
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 AgentAntelope/c3f7aa6acdf7bf8f14da0f0cdcdcc1af to your computer and use it in GitHub Desktop.
Save AgentAntelope/c3f7aa6acdf7bf8f14da0f0cdcdcc1af to your computer and use it in GitHub Desktop.
A quick hack to calculate rational frations where digits can be cancelled to correctly reduce the fraction
class Array
# Subtract each passed value once:
# %w(1 2 3 1).subtract_once %w(1 1 2) # => ["3"]
# [ 1, 1, 2, 2, 3, 3, 4, 5 ].subtract_once([ 1, 2, 4 ]) => [1, 2, 3, 3, 5]
# Time complexity of O(n + m)
def subtract_once(values)
counts = values.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
reject { |e| counts[e] -= 1 unless counts[e].zero? }
end
end
class Fractionator
attr_reader :max_denominator, :digits
def initialize(max_denominator = 10000)
@max_denominator = max_denominator
end
def leftover_digits(num_1, num_2)
num_1_digits = num_1.to_s.chars
num_2_digits = num_2.to_s.chars
digit_diff = num_1_digits.subtract_once(num_2_digits)
end
def share_some_digits?(numerator, denominator)
digit_diff = leftover_digits(numerator, denominator)
digit_diff.count > 0 && digit_diff.count < numerator.to_s.chars.count
end
def same_value?(numerator:, denominator:, reduced_fraction:)
Rational(numerator, denominator) == reduced_fraction
end
def calculate
denominator = 0
while denominator < max_denominator
denominator += 1
possible_numerators(denominator).each do |numerator|
possible_bad_reductions(denominator, numerator).each do |bad_denominator|
possible_bad_reductions(numerator, denominator).filter{|bn| bn < bad_denominator}.each do |bad_numerator|
# These are less impressive in base 10
next if (numerator/bad_numerator % 10) == 0 && (denominator/bad_denominator % 10) == 0
next if (bad_numerator % 11) == 0 || (bad_denominator % 11) == 0
# puts "trying #{numerator}/#{denominator} => #{bad_numerator}/#{bad_denominator}"
next unless same_value?(numerator: numerator, denominator: denominator, reduced_fraction: Rational(bad_numerator, bad_denominator))
next unless bad_numerator == leftover_digits(numerator, denominator).join.to_i
next unless bad_denominator == leftover_digits(denominator, numerator).join.to_i
puts "#{numerator}/#{denominator} cancels to #{bad_numerator}/#{bad_denominator}"
end
end
end
end
end
def possible_numerators(denominator)
(1..(denominator - 1)).filter do |numerator|
share_some_digits?(numerator, denominator)
end
end
def possible_bad_reductions(num_1, num_2)
[leftover_digits(num_1, num_2).join.to_i].reject(&:zero?)
end
end
Fractionator.new.calculate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment