Eu queria animar meu dever de casa EletroMagnetismo na semana passada, o que exigiu que fizéssemos um pouco de MATLAB. Infelizmente, não tenho o MATLAB porque não é o sistema operacional e não queria ir para a escola para usar um computador, então fiz alguns macacos de patch para fazer meu código Ruby parecer o MATLAB. Agora posso apenas copiar o código MATLAB, fazer algumas alterações e executá-lo. Apenas algumas mudanças são necessárias neste ponto para converter o MATLAB para Ruby:
[1 2 3] -> [1, 2, 3] # arrays
x^2 -> x**2 # exponents
% -> # # comments
Atualização: ^
tem menos precedência do **
que o motivo pelo qual eu continuei **
. Comente se você sabe como alterar a precedência do operador. Não consegui encontrar muito.
Aqui está o arquivo que eu exijo:
#matlab_helper.rb
$VERBOSE = nil # surpress constant redefinition warnings
include Math
def norm(vector)
sqrt vector.map{ |x| x**2 }.inject(0, &:+)
end
class Array
def +(op)
self.zip(op).map { |a, b| a + b }
end
def -(op)
self.zip(op).map { |a, b| a - b }
end
def /(op)
self.map { |a| a / op }
end
end
class Float
alias_method :mult, :*
def *(op)
if op.is_a? Array
op.map { |a| self * a }
else
mult op
end
end
end
class Fixnum
alias_method :mult, :*
def *(op)
if op.is_a? Array
op.map { |a| self * a }
else
mult op
end
end
end
def pi
PI
end
E meu dever de casa convertido do MATLAB:
#hw.rb
require './matlab_helper'
# clc #clear the command line
# clear #remove all previous variables
Q1 = 8e-9 #charges on Q1
Q2 = 8e-9 #charges on Q2
pL = 2e-9 #charge density of the line
Epsilon_o = 8.8419e-12 #Permitivity of free space
P = [2, 3, 4] #coordinates of observation point
A = [0, 0, 1] #coordinates of Q1
B = [0, 0, -1] #coordinates of Q2
C = [2, 0, 0] #coordinates of the center of the line charge
Number_of_L_Steps = 100000 #the steps of L
##the following routine calculates the electric fields at the
##observation point generated by the point charges
R1 = P - A #the vector pointing from Q1 to the observation point
R2 = P - B #the vector pointing from Q2 to the observation point
R1Mag = norm(R1) #the magnitude of R1
R2Mag = norm(R2) #the magnitude of R1
E1 = Q1 / (4 * pi * Epsilon_o * R1Mag**3) * R1 #the electric field generated by Q1
E2 = Q2 / (4 * pi * Epsilon_o * R2Mag**3) * R2 #the electric field generated by Q2
##the following routine calculates the electric field at the
##observation point generated by the line charge
d = norm(P - C) #the distance from the observation point to the center of the line
length = 100 * d #the length of the line
dL_V = length / Number_of_L_Steps * [1, 0, 0] #vector of a segment
dL = norm(dL_V) #length of a segment
EL = [0, 0, 0] #initialize the electric field generated by EL
C_segment = C - (Number_of_L_Steps / 2 * dL_V - dL_V / 2) #the center of the first segment
for i in (1..Number_of_L_Steps)
R = P - C_segment #the vector seen from the center of the first segment to the observation point
RMag = norm(R) #the magnitude of the vector R
EL = EL + dL * pL / (4 * pi * Epsilon_o * RMag**3) * R #get contibution from each segment
C_segment = C_segment + dL_V #the center of the i-th segment
end
E = E1 + E2 + EL # the electric field at P
puts "E = #{E}"
# $ ruby hw.rb
# E = [2.010238790127288, 7.334514610377015, 9.388970095358529]
Ele é executado em cerca de 2 segundos com 100.000 passos, mas é Ruby!
Observação: incluí apenas os operadores necessários para concluir meu dever de casa, portanto, algumas combinações foram deixadas de fora.