Беда с комбинированной логикой в ​​рубине - PullRequest
1 голос
/ 30 ноября 2010

написание простой модели Монте-Карло нейтронного пучка. Возникли проблемы с геометрией логики (находится ли что-то в той или иной среде). Моя проблема в том, что Ruby, кажется, обрабатывает условия последовательно и сохраняет первое значение, к которому он приходит.

Код ниже очень хорошо иллюстрирует это:

def checkPosition(*args)

  polyCylRad = 2.5
  polyCylFr = 15
  polyCylB = -2.0
  borPolyBoxL = 9.0 / 2
  pbCylRad = 3.0
  pbBoxL = 10.0 / 2
  cdBoxL = 9.5 / 2

  position = Array.new
  material = String.new

  args.each do |item|
    position << item.inspect.to_f
  end
  xSquared = position.at(0) ** 2
  ySquared = position.at(1) ** 2
  zSquared = position.at(2) ** 2
  modX = Math.sqrt(xSquared)
  modY = Math.sqrt(ySquared)
  modZ = Math.sqrt(zSquared)

  puts xSquared
  puts Math.sqrt(ySquared + zSquared) <= polyCylRad
  puts (position.at(0) >= polyCylB)
  puts (position.at(0) <= polyCylFr)
  puts (position.at(0) >= polyCylB)and(position.at(0) <= polyCylFr)
  puts (position.at(0) <= polyCylFr)and(position.at(0) >= polyCylB)

  puts zSquared


  polyCylinder = (Math.sqrt(ySquared + zSquared) <= polyCylRad)and((position.at(0) >= polyCylB)and(position.at(0) <= polyCylFr) )
  puts polyCylinder
  borPolyBox = ((modX <= borPolyBoxL)or(modY < borPolyBoxL)or(modZ <= borPolyBoxL)) and not((modX >= cdBoxL)or(modY >= cdBoxL)or(modZ >= cdBoxL)) and not(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  puts borPolyBox
  cadmiumShield = ((modX <= cdBoxL)or(modY < cdBoxL)or(modZ <= cdBoxL)) and not((modX >= pbBoxL)or(modY >= pbBoxL)or(modZ >= pbBoxL)) and not(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  puts cadmiumShield
  leadShield = ( ((modX <= pbBoxL)or(modY <= pbBoxL)or(modZ <= pbBoxL)) or ((position.at(0) <= ployCylFr)and(Math.sqrt(ySquared + zSquared) <= pbCylRad)) ) and not(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  puts leadShield

  if (polyCylinder) : material = "poly"
  elsif(borPolyBox) : material = "borPoly"
  elsif(cadmiumSheild) : material = "cd"
  elsif(leadSheild) : material = "pb"
  elsif(material == nil) : position = Array.new
  end

  thisEnvironment = Array.new
  thisEnvironment << position << material
  puts thisEnvironment.at(0)
  puts thisEnvironment.at(1)
end

checkPosition(40, 0, 0)

вызывайте код как хотите, но дайте ему * аргументы в качестве аргумента (я ленив и могу захотеть добавить больше аргументов в будущем), затем вызовите его с 3 числами с плавающей запятой, с геометрией, установленной в логике, и вы посмотрим, что я имею в виду.

Мой вопрос: как мне заставить его работать так, как должно (т.е. правильно оценивать логику) без целой связки вложенных if? (это то, что я собираюсь переделать, однако читать это кошмар, а память дешева.)

Ответы [ 4 ]

3 голосов
/ 01 декабря 2010

Вы несколько раз набрали «Шилд», где вы, вероятно, имели в виду «Щит»

В контексте их использования вы должны использовать && вместо and, || вместо or и ! вместо not. Причина в том, что or и and имеют такой низкий приоритет, что заставят ваши операторы присваивания работать не так, как вы хотите. Например,

a = b and c

оценивается как

(a = b) and c

Так, что a всегда присваивается значение b, а затем в результате получается истина, c оценивается (и отбрасывается). С другой стороны,

a = b && c

оценивается как

a = (b && c)

Что вам нужно в этом коде.

Кроме того, я бы переместил весь этот код в класс, чтобы я мог создать множество маленьких методов для вещей:

class PositionChecker

  def initialize(*args)
    @x, @y, @z = *args
  end

  def checkPosition
    ...
  end

end

Ищите возможности заменить локальные переменные в checkPosition вызовами методов. Например, вы можете переместить borPolyBox в его собственный метод (как только все значения, которые он использует, являются их собственными методами):

class PositionChecker
  ...
  def borPolyBox
    ((modX <= borPolyBoxL)||(modY < borPolyBoxL)||(modZ <= borPolyBoxL)) && !((modX >= cdBoxL)||(modY >= cdBoxL)||(modZ >= cdBoxL)) && !(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  end
  ...
end

Как только вы получите все эти предикаты в качестве собственного метода, вы можете создать метод для определения материала, например:

def material
  [
    [:polyCylinder, 'poly'],
    [:borPolyBox, 'borPoly'],
    [:cadmiumShield, 'cd'],
    [:leadShield, 'pb'],
  ].each do |method, name|
    return name if send(method)
  end
  nil
end

И еще один на должность:

def position
  [@x, @y, @z] if material
end

Продолжайте в том же духе, пока не останется ничего, кроме мешка маленьких, сфокусированных методов.

1 голос
/ 01 декабря 2010

Измените все and и or на && и ||.

Никогда раньше никто не видел, чтобы на самом деле использовалось array.at(index) вместо array[index].

Я такжерекомендовать против *args в пользу параметра Hash в качестве вида именованных параметров

def test(params)
  x = params[:x] || raise("You have to provide x!")
  y = params[:y] || raise("You have to provide y!")
  z = params[:z] || raise("You have to provide z!")
  puts x, y, z
end

и вызывать его с (синтаксис Ruby 1.9+)

test({x: 42, y: 4711, z: 93})

42
4711
93

0 голосов
/ 01 декабря 2010

Глядя на свой код, вы настраиваете его так, чтобы четыре "материальные" переменные были булевыми.Затем вы вводите эти bools в блок if-elsif-else.

Проблема в том, что самое первое, если оно возвращает true, будет выходить из блока if-elsif-else.Если это то, что вы имеете в виду, сохраняя первое значение, к которому это приходит, то это чрезвычайно предсказуемый результат.

0 голосов
/ 01 декабря 2010

Попробуйте использовать && вместо and, || вместо or и ! вместо not.

Ваша проблема, вероятно, приоритетная - для получения дополнительной информации прочитайте эту статью .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...