Skip to content

Commit 982a9d1

Browse files
committed
Refactor mandelbrot, seems to run quicker
1 parent be3e804 commit 982a9d1

File tree

2 files changed

+36
-51
lines changed

2 files changed

+36
-51
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require 'forwardable'
2+
3+
# A simpler complex class
4+
class SimpleComplex
5+
extend Forwardable
6+
attr_reader :complex
7+
def_delegator :@complex, :to_s
8+
def_delegators :@complex, :abs, :+, :*
9+
10+
def initialize(real, complex)
11+
@complex = Complex(real, complex)
12+
end
13+
14+
def add!(other)
15+
@complex += other.complex
16+
end
17+
18+
def square!
19+
@complex *= complex
20+
end
21+
end

contributed/mandelbrot.rb

Lines changed: 15 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Mandelbrot Set example
2-
# by Jordan Scales (http://jordanscales.com)
3-
# Modified to use map1d (instead of map), and somewhat
4-
# optimized (update_pixels instead of set, and hypot for abs)
5-
# no need to loop
2+
# after an original by Jordan Scales (http://jordanscales.com)
3+
# Modified to use simple_complex library, instead of a custom Complex also uses
4+
# map1d (instead of map), and a somewhat optimized (update_pixels instead of
5+
# set), and using grid, rather than nested loops
6+
7+
load_library :simple_complex
68

79
def setup
810
sketch_title 'Mandelbrot'
@@ -12,69 +14,31 @@ def setup
1214

1315
# main drawing method
1416
def draw
15-
(0...900).each do |x|
16-
(0...600).each do |y|
17-
c = Complex.new(map1d(x, (0...900), (-3..1.5)), map1d(y, (0...600), (-1.5..1.5)))
18-
# mandel will return 0 to 20 (20 is strong)
19-
# map this to 0, 255 (and flip it)
20-
pixels[x + y * 900] = color(255 - map1d(mandel(c, 20), (0..20), (0..255)).to_i)
21-
end
17+
grid(900, 600) do |x, y|
18+
c = SimpleComplex.new(
19+
map1d(x, (0...900), (-3..1.5)), map1d(y, (0...600), (-1.5..1.5))
20+
)
21+
# mandel will return 0..20 (20 is strong) map this to 255..0 (NB: reverse)
22+
pixels[x + y * 900] = color(map1d(mandel(c, 20), (0..20), (255..0)).to_i)
2223
end
2324
update_pixels
2425
end
2526

2627
# calculates the "accuracy" of a given point in the mandelbrot set
27-
# : how many iterations the number survives without becoming chaotic
28+
# how many iterations the number survives without becoming chaotic
2829
def mandel(z, max = 10)
2930
score = 0
3031
c = z.clone
3132
while score < max
3233
# z = z^2 + c
33-
z.square
34-
z.add c
34+
z.square!
35+
z.add! c
3536
break if z.abs > 2
3637
score += 1
3738
end
3839
score
3940
end
4041

41-
# rolled my own Complex class
42-
# including only the functionality I need (abs, square, add, to_s)
43-
#
44-
# Using this class, runs in ~12.5s on my MacBook Air
45-
# compared to ~22s using ruby's Complex struct
46-
class Complex
47-
attr_accessor :real, :imag
48-
49-
def initialize(real, imag)
50-
@real = real
51-
@imag = imag
52-
end
53-
54-
# squares a complex number - overwriting it
55-
def square
56-
r = real * real - imag * imag
57-
i = 2 * real * imag
58-
@real = r
59-
@imag = i
60-
end
61-
62-
# adds a given complex number
63-
def add(c)
64-
@real += c.real
65-
@imag += c.imag
66-
end
67-
68-
# computes the magnitude (HelperMethods dist is a safer version of Math.hypot)
69-
def abs
70-
dist(0, 0, real, imag)
71-
end
72-
73-
def to_s
74-
format('(%f+%fi)', real, imag)
75-
end
76-
end
77-
7842
def settings
7943
size 900, 600
8044
end

0 commit comments

Comments
 (0)