From eb21d847e1e3d72633ea0b37fb78ab11754485b0 Mon Sep 17 00:00:00 2001 From: evan hemsley Date: Thu, 22 Feb 2018 20:53:01 -0800 Subject: [PATCH] more solutions in crystal --- crystal/euler.cr | 58 ++++++++++++++++++++++++++++++-------- crystal/euler003.cr | 28 ++----------------- crystal/euler005.cr | 19 +++++++++++++ crystal/euler006.cr | 1 + crystal/euler007.cr | 3 ++ crystal/euler008.cr | 27 ++++++++++++++++++ crystal/euler009.cr | 14 ++++++++++ crystal/euler010.cr | 4 +++ crystal/prime.cr | 68 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 185 insertions(+), 37 deletions(-) create mode 100644 crystal/euler005.cr create mode 100644 crystal/euler006.cr create mode 100644 crystal/euler007.cr create mode 100644 crystal/euler008.cr create mode 100644 crystal/euler009.cr create mode 100644 crystal/euler010.cr create mode 100644 crystal/prime.cr diff --git a/crystal/euler.cr b/crystal/euler.cr index 17dcdce..b07b147 100644 --- a/crystal/euler.cr +++ b/crystal/euler.cr @@ -1,23 +1,59 @@ # miscellaneous stuff -module Euler - def self.eratosthenes_sieve(n) - sieve = Array.new(n + 1, true) - sieve[0] = false - sieve[1] = false +require "big" - 2.step(to: Math.sqrt(n)) do |i| - if sieve[i] - (i * i).step(to: n, by: i) do |j| - sieve[j] = false - end +module Euler + alias NumType = Int32 | Int64 | UInt32 | UInt64 | BigInt + + def self.trial_division(n : NumType) + factors = [] of NumType + check = ->(p: NumType) { + q, r = n.divmod(p) + while r.zero? + factors << p + n = q + q, r = n.divmod(p) + end + } + + check.call(2) + check.call(3) + p = 5 + while p * p <= n + check.call(p) + p += 2 + check.call(p) + p += 4 + end + factors << n if n > 1 + factors + end + + def self.prime_factorization(n : NumType) + result = {} of NumType => NumType + factors = self.trial_division(n) + + factors.each do |f| + result[f] = 0 + num = n + while num % f == 0 + result[f] += 1 + num /= f end end - result = sieve.map_with_index { |b, i| b ? i : nil }.compact + result end def self.palindrome?(x) x.to_s.reverse == x.to_s end + + def self.to_digit_list(n : NumType) + n.to_s.chars.map { |d| d.to_i } + end + + def self.to_big_ints(num_list : Array(NumType)) + num_list.map { |n| BigInt.new(n) } + end end diff --git a/crystal/euler003.cr b/crystal/euler003.cr index cd5ab03..f4e64c9 100644 --- a/crystal/euler003.cr +++ b/crystal/euler003.cr @@ -1,27 +1,3 @@ -alias NumType = Int32 | Int64 | UInt32 | UInt64 +require "./euler" -def trial_division(n : NumType) - factors = [] of NumType - check = ->(p: NumType) { - q, r = n.divmod(p) - while r.zero? - factors << p - n = q - q, r = n.divmod(p) - end - } - - check.call(2) - check.call(3) - p = 5 - while p * p <= n - check.call(p) - p += 2 - check.call(p) - p += 4 - end - factors << n if n > 1 - factors -end - -puts trial_division(600851475143).max +puts Euler.trial_division(600851475143).max diff --git a/crystal/euler005.cr b/crystal/euler005.cr new file mode 100644 index 0000000..8ad35bd --- /dev/null +++ b/crystal/euler005.cr @@ -0,0 +1,19 @@ +require "./euler" + +def integer_factorization_divisible_by_all_up_to(n) + result = {} of Euler::NumType => Euler::NumType + (2..n).map do |i| + Euler.prime_factorization(i).each do |prime, exponent| + if !result.has_key?(prime) || (exponent > result[prime]) + result[prime] = exponent + end + end + end + result +end + +def factors_to_int(factorization : Hash(Euler::NumType, Euler::NumType)) + factorization.map { |prime, exponent| prime ** exponent }.product +end + +puts factors_to_int(integer_factorization_divisible_by_all_up_to(20)) diff --git a/crystal/euler006.cr b/crystal/euler006.cr new file mode 100644 index 0000000..8c172e6 --- /dev/null +++ b/crystal/euler006.cr @@ -0,0 +1 @@ +puts (1..100).sum ** 2 - (1..100).map { |n| n * n }.sum diff --git a/crystal/euler007.cr b/crystal/euler007.cr new file mode 100644 index 0000000..b338dbc --- /dev/null +++ b/crystal/euler007.cr @@ -0,0 +1,3 @@ +require "./euler" + +puts Euler.eratosthenes_sieve(1000000)[10000] diff --git a/crystal/euler008.cr b/crystal/euler008.cr new file mode 100644 index 0000000..88c9cbe --- /dev/null +++ b/crystal/euler008.cr @@ -0,0 +1,27 @@ +require "./euler" + +def largest_consecutive_product(n, adjacent) + Euler.to_big_ints(Euler.to_digit_list(n)).each_cons(adjacent).map { |x| x.product }.max +end + +puts largest_consecutive_product( +BigInt.new("73167176531330624919225119674426574742355349194934 +96983520312774506326239578318016984801869478851843 +85861560789112949495459501737958331952853208805511 +12540698747158523863050715693290963295227443043557 +66896648950445244523161731856403098711121722383113 +62229893423380308135336276614282806444486645238749 +30358907296290491560440772390713810515859307960866 +70172427121883998797908792274921901699720888093776 +65727333001053367881220235421809751254540594752243 +52584907711670556013604839586446706324415722155397 +53697817977846174064955149290862569321978468622482 +83972241375657056057490261407972968652414535100474 +82166370484403199890008895243450658541227588666881 +16427171479924442928230863465674813919123162824586 +17866458359124566529476545682848912883142607690042 +24219022671055626321111109370544217506941658960408 +07198403850962455444362981230987879927244284909188 +84580156166097919133875499200524063689912560717606 +05886116467109405077541002256983155200055935729725 +71636269561882670428252483600823257530420752963450"), 13) diff --git a/crystal/euler009.cr b/crystal/euler009.cr new file mode 100644 index 0000000..76e045d --- /dev/null +++ b/crystal/euler009.cr @@ -0,0 +1,14 @@ +require "./euler" + +def generate_pythagorean_triples(upper_bound) + ([] of Array(Euler::NumType)).tap do |triples| + (2..upper_bound).each do |a| + (a..upper_bound).each do |b| + c = Math.sqrt(a**2 + b**2) + triples << [a, b, c.to_i] if c % 1 == 0 + end + end + end +end + +puts generate_pythagorean_triples(500).find([-1]) { |x| x.sum == 1000 }.product diff --git a/crystal/euler010.cr b/crystal/euler010.cr new file mode 100644 index 0000000..2425db8 --- /dev/null +++ b/crystal/euler010.cr @@ -0,0 +1,4 @@ +require "./prime" + +prime = Euler::Prime.new +puts prime.take_while { |x| x < 2000000 }.sum diff --git a/crystal/prime.cr b/crystal/prime.cr new file mode 100644 index 0000000..08151db --- /dev/null +++ b/crystal/prime.cr @@ -0,0 +1,68 @@ +require "./euler" + +module Euler + class Prime + include Iterator(NumType) + + def initialize() + @sieve_size = 16 + @sieved_up_to = 0 + + @primes = Array(Bool).new(@sieve_size, true) + @primes[0] = false + @primes[1] = false + + @index = 0 + iterative_eratosthenes_sieve + end + + private def check_and_increase_sieve + if @index > @primes.size - 1 + @sieve_size *= 2 + until @primes.size == @sieve_size + @primes << true + end + end + + iterative_eratosthenes_sieve + end + + private def iterative_eratosthenes_sieve + 2.step(to: Math.sqrt(@sieve_size)) do |i| + if @primes[i] + (i * i >= @sieved_up_to ? i * i : @sieved_up_to + i - (@sieved_up_to % i)).step(to: @sieve_size-1, by: i) do |j| + @primes[j] = false + end + end + end + @sieved_up_to = @sieve_size-1 + end + + def next + @index += 1 + check_and_increase_sieve + + until @primes[@index] + @index += 1 + check_and_increase_sieve + end + @index + end + + def self.eratosthenes_sieve(n) + sieve = Array.new(n + 1, true) + sieve[0] = false + sieve[1] = false + + 2.step(to: Math.sqrt(n)) do |i| + if sieve[i] + (i * i).step(to: n, by: i) do |j| + sieve[j] = false + end + end + end + + result = sieve.map_with_index { |b, i| b ? i : nil }.compact + end + end +end