Mathematica模块没有返回值

时间:2011-11-15 16:42:10

标签: module wolfram-mathematica mathematical-optimization

我是Mathematica的新手,并使用Module执行一个过程,然后返回一个值。但是,Mathematica似乎正在评估和返回符号值而不是我想要的数值。

我的问题是:你什么时候不用分号?什么时候使用Return [value]而不是只写“value”?

DumpVar[x_] := Print[ToString[HoldForm[x]], ":", x];
SetAttributes[DumpVar, {Listable, HoldAll}]

width = 1;
interval = width/2;

panelCoeff = 2;
lightAngle = Pi/3;

(*Panel and light equations*)

panel[x_] = Abs[panelCoeff x];(*panelCoeff ((x)^2);*)

light[x_] = Tan[lightAngle]*x;

getAngleAttack[offset_] := 
  Module[{bounce1x, l1a, lightSlope, panelSlope},
   light[x_] = light'[x] (x - offset) + panel[interval];
   DumpVar[offset];

   lightSlope = N[light'[offset]];
   u1S = light'[offset];
   u1[x_] = (u1S (x - offset)) + panel[interval]; 

   bounce1x = 
    x /. N[NSolve[u1[x] == panel[x] && x < interval && x > -interval, 
       x]];

   u1r[x_] = panel'[bounce1x] (x - bounce1x) + panel[bounce1x];

   If[Length[bounce1x] > 0,
     bounce1x = bounce1x[[1]];,
     bounce1x = offset;
     ]

    If[bounce1x > -interval && bounce1x < interval,

     lightSlope = N[u1'[bounce1x]];

     If[x <= 0,
      panelSlope := N[panelCoeff],
      panelSlope := -N[panelCoeff]];

     DumpVar[lightSlope];
     DumpVar[panelSlope];
     l1a = 
      N[ArcTan[(lightSlope - 
           panelSlope)/(1 + (panelSlope lightSlope))]];

     DumpVar[l1a];

     l1a
      Return[l1a]
     ]

    Return[l1a];
   ];


myint = getAngleAttack[0];
(*myint = N[f[10]];*)
DumpVar[myint];

Plot[{panel[x], light[x]}, {x, -.6, .6}]

myint = getAngleAttack[.5];
DumpVar[myint];

我的目标是能够绘制和集成此功能。

2 个答案:

答案 0 :(得分:10)

在你的街区中间你有:

If[Length[bounce1x] > 0,
  bounce1x = bounce1x[[1]];,
  bounce1x = offset;
  ]

If的格式如下:If[Condition, ValueIfTrue, ValueIfFalse]

因此If[True, 3, 2]返回3,If[False, 3, 2]返回2.此处的分号是不必要的,但在if语句的末尾确实需要一个分号:

If[Length[bounce1x] > 0,
  bounce1x = bounce1x[[1]],
  bounce1x = offset
  ];

否则,Mathematica会将其解释为该语句的乘法次数,无论下一次出现的是什么。在这种情况下,您将从null语句返回If,并将其乘以出现的下一个If语句的返回值。

对于Module,语法为:Module[{localvars}, ReturnValue]

这意味着返回没有分号的最后一个语句是ReturnValue。例如,以下模块:

Module[{y},
   y = x * x;
   If[x < 0, -y, +y]
]
当x 将返回-y。 0,否则为+ y。唯一的例外是Return出现时。就像在大多数语言中一样,您可以使用Return

从函数中提前返回
Module[{y},
   y = x * x;
   If[x < 0, 
      Return[-y],
      Return[+y]];
 (* We never reach this point to return null *)
 ];

关于你的Module,我认为这可能是你想要实现的目标:

getAngleAttack[offset_] := 
 Module[{bounce1x, l1a, lightSlope, panelSlope}, 
  light[x_] = light'[x] (x - offset) + panel[interval];
  DumpVar[offset];

  lightSlope = N[light'[offset]];
  u1S = light'[offset];
  u1[x_] = (u1S (x - offset)) + panel[interval];

  bounce1x = 
   x /. N[NSolve[u1[x] == panel[x] && x < interval && x > -interval, 
      x]];

  u1r[x_] = panel'[bounce1x] (x - bounce1x) + panel[bounce1x];

  If[Length[bounce1x] > 0,
   bounce1x = bounce1x[[1]],
   bounce1x = offset];

   If[bounce1x > -interval && bounce1x < interval,

   lightSlope = N[u1'[bounce1x]];

   If[x <= 0,
    panelSlope := N[panelCoeff],
    panelSlope := -N[panelCoeff]];

   DumpVar[lightSlope];
   DumpVar[panelSlope];

   l1a = N[
     ArcTan[(lightSlope - panelSlope)/(1 + (panelSlope lightSlope))]];

   DumpVar[l1a];
   Return[l1a]
  ];
  l1a]

您应该注意的另一件事是您在Module内使用的任何变量。如果您运行以下代码,您将获得4, -113/5, 32作为输出值:

d = 4 (* d was 4 *)
Module[{a, b, c},
   a = 3;
   b = 2;
   c = 5;
   d = 32; (* Uh oh! I just overwrite whatever d was *)
   a^2 + b / c - d]
d (* d is now 32 *)

要避免这种情况,请在Module的开头定义您用作局部变量的所有变量:Module[{a, b, c, d}, ...]

答案 1 :(得分:8)

我想向Mike's excellent answer添加一些内容。

首先,分号是构建compound expressions的方式,正如迈克指出的那样,它们会抑制前一个语句的输出。但是,它们最有用的是允许您将多个表达式链接在一起,只需要一个表达式,就像在Module的正文中一样。但是,它们对于像这个人为的例子这样简单的事情很有用。

a = 5;
b = (Print[a]; a - 3)

请注意括号; ;的优先级低于=,因此

b = Print[a]; a - 3

会将b设置为Print的返回值Null

将Sjoerd在评论中所说的内容纳入表达式

b = (Print[a]; a - 3)

被解释为

Set[b, CompoundExpression[ Print[a], a - 3] ]

而第二个不正确的表单被解释为

CompoundExpression[ Set[b, Print[a]], a - 3]

如果要查看表达式采用何种形式,请使用FullForm[Hold[ expression ]]显示表达式的内部形式。在检查表单之前,如果不希望执行任何操作,则需要使用HoldSet就是这种情况。

其次,当If表达式Set将变量用于不同的值时,可以将其从If语句中拉出,如下所示

 bounce1x = If[Length[bounce1x] > 0, bounce1x[[1]], offset];

由于If将返回bounce1x[[1]]offset。这可以大大简化您的表达。这也适用于SetDelayed:=),就像panelSlope

一样
panelSlope := If[x <= 0, N[panelCoeff], -N[panelCoeff]];

但是,我不会在这里使用SetDelayed,因为每次使用时都不需要重新计算panelSlope。此外,您可以使用UnitStep

简化一点
panelSlope = (1 - 2 UnitStep[x]) N[panelCoeff];

或者,甚至

panelSlope = If[x<=0, 1, -1] N[panelCoeff];

Sign在这里不合适,因为当参数为0时它将返回零。)

最后,您的代码中存在与l1a有关的错误。您的Module会将其返回,但如果未满足bounce1x > -interval && bounce1x < interval条件,则不会输入设置它的If语句。因此,它会返回l1a$###形式的内容,其中###是数字。另外,我完全摆脱了Return[ l1a ]语句中的If,因为没有必要,l1a语句中设置了If