0

我想通过分段函数的处理程序扩展 Maple CodeGeneration[C](不知道为什么不包含它)。为此我做了:

with(CodeGeneration):
with(LanguageDefinition):

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            local i;
            Printer:-Print("if(",_passed[1],"){",_passed[2],"}");
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print("else if(",_passed[i],"){",_passed[i+1],"}");
            end do;
            Printer:-Print("else{",_passed[_npassed],"}");
        end proc,
    numeric=double)
);

请注意,我使用 if else 语句来支持 case 语句。这是要翻译的示例代码:

myp:=proc(x::numeric)
    piecewise(x>1,1*x,x>2,2*x,x>3,3*x,0);
end proc:
Translate(myp, language="NewC");

输出是

void myp (double x)
{
    if(0.1e1 < x){x}else if(0.2e1 < x){0.2e1 * x}else if(0.3e1 < x){0.3e1 * x}else{0};
    ;
}

对于有效的 C 例程,我显然需要替换大括号,例如

{x}

通过类似的东西

{result=x;}

和其他类似的。我可以通过修改上述 AddFunction 语句中的字符串来手动完成此操作。但是随后代码生成器不知道变量名 result,因此不会有任何声明,也不会根据需要返回 result 的值以匹配例程 myp 或更复杂的过程,其中可能会分配分段的结果到一些其他变量或用于计算。那么如何在 CodeGeneration 例程中正确处理这个问题呢?即我怎样才能得到一个有效的变量名等。

4

1 回答 1

1

这样的事情怎么样?

restart:

with(CodeGeneration):
with(LanguageDefinition):

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            local i;
            Printer:-Print("( (",_passed[1],") ? ",_passed[2]);
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print(" : (",_passed[i],") ? ",_passed[i+1]);
            end do;
            Printer:-Print(" : ",_passed[_npassed]," ) ");
        end proc,
    numeric=double)
);

myp:=proc(x::numeric) local result::numeric;
    result := piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0);
end proc:

Translate(myp, language="NewC");

double myp (double x)
{
  double result;
  result = ( (0.3e1 < x) ? 0.3e1 * x : (0.2e1 < x) ? 0.2e1 * x : (0.1e1 < x) ? x : 0 ) ;
  return(result);
}

[编辑,添加以下材料]

事实证明 CodeGeneration[C] 确实处理piecewise,但前提optimize是提供了该选项。(我将提交一个错误报告,它应该默认处理。)

restart:

with(CodeGeneration):
with(LanguageDefinition):
myp:=proc(x::numeric) local result::numeric;
     result:=piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0);
end proc;

         myp := proc(x::numeric)
         local result::numeric;
           result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
         end proc;

Translate(myp, language="C", optimize);

double myp (double x)
{
  double result;
  double s1;
  if (0.3e1 < x)
    s1 = 0.3e1 * x;
  else if (0.2e1 < x)
    s1 = 0.2e1 * x;
  else if (0.1e1 < x)
    s1 = x;
  else
    s1 = 0.0e0;
  result = s1;
  return(result);
}

如您所见,piecewise上面通过转换到单独的if(){..}块来处理,并分配给引入的临时变量。该临时文件随后piecewise在 Maple 过程中存在调用的任何地方使用。并且临时声明。漂亮和自动。因此,这可能足以满足您使用piecewise.

您还询问了如何在自己的扩展中引入和声明此类临时变量(如果我理解正确的话)。从上面继续在同一个 Maple 会话中,这里有一些沿着这些思路的想法。生成一个未分配的全局名称。该myp过程被放入惰性形式,其中添加了新的局部变量。然后,改变后的惰性形式又变成了实际的程序。作为说明,我使用了您原始扩展的修改版本来处理piecewise. 这一切都产生了接近可接受的东西。唯一的障碍是赋值语句,

result = temporary_variable;

不合适!它位于piecewise翻译块之前。我还没有看到如何在该方法中修复它。

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            global T;
            local i, t;
            t:=convert(T,string);
            Printer:-Print(t,";\n");
            Printer:-Print("  if (",_passed[1],
                           ")\n    { ",t," = ",_passed[2],"; }\n");
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print("  else if (",_passed[i],")\n    { ",
                               t," = ",_passed[i+1],"; }\n");
            end do;
            Printer:-Print("  else { ",t," = ",_passed[_npassed],"; }");
        end proc,
    numeric=double)
):

T:=`tools/genglobal`('s'):

newmyp := FromInert(subsindets(ToInert(eval(myp)),'specfunc(anything,_Inert_LOCALSEQ)',
           z->_Inert_LOCALSEQ(op(z),
                              _Inert_DCOLON(_Inert_NAME(convert(T,string)),
                                            _Inert_NAME("numeric",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected")
          ))))))));

             newmyp := proc(x::numeric)
             local result::numeric, s::numeric;
               result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
             end proc;

Translate(newmyp, language="NewC");

double newmyp (double x)
{
  double result;
  double s;
  result = s;
  if (0.3e1 < x)
    { s = 0.3e1 * x; }
  else if (0.2e1 < x)
    { s = 0.2e1 * x; }
  else if (0.1e1 < x)
    { s = x; }
  else { s = 0; };
  return(result);
}

如果您重新运行上面的最后三个语句(从对 的赋值T,到Translate调用),那么您应该会看到使用了一个新的临时变量,例如 s0。然后 s1 如果再次重复。等等。

也许这会给你更多的想法。干杯。

于 2012-04-10T05:41:09.330 回答