Opened 7 years ago

Last modified 7 years ago

#4890 new defect

strange power

Reported by: Vitalij Ruge Owned by: somebody
Priority: high Milestone: Future
Component: Backend Version:
Keywords: Cc: Francesco Casella, Willi Braun

Description (last modified by Vitalij Ruge)

the following simple model create for simple power operation

model pow_test
 Real x = time^(1/3);
end pow_test;  

about 60 lines C-Code:

/*
 equation index: 2
 type: SIMPLE_ASSIGN
 x = time ^ 0.3333333333333333
 */
void pow_test_eqFunction_2(DATA *data, threadData_t *threadData)
{
  TRACE_PUSH
  const int equationIndexes[2] = {1,2};
  modelica_real tmp0;
  modelica_real tmp1;
  modelica_real tmp2;
  modelica_real tmp3;
  modelica_real tmp4;
  modelica_real tmp5;
  modelica_real tmp6;
  tmp0 = data->localData[0]->timeValue;
  tmp1 = 0.3333333333333333;
  if(tmp0 < 0.0 && tmp1 != 0.0)
  {
    tmp3 = modf(tmp1, &tmp4);
    
    if(tmp3 > 0.5)
    {
      tmp3 -= 1.0;
      tmp4 += 1.0;
    }
    else if(tmp3 < -0.5)
    {
      tmp3 += 1.0;
      tmp4 -= 1.0;
    }
    
    if(fabs(tmp3) < 1e-10)
      tmp2 = pow(tmp0, tmp4);
    else
    {
      tmp6 = modf(1.0/tmp1, &tmp5);
      if(tmp6 > 0.5)
      {
        tmp6 -= 1.0;
        tmp5 += 1.0;
      }
      else if(tmp6 < -0.5)
      {
        tmp6 += 1.0;
        tmp5 -= 1.0;
      }
      if(fabs(tmp6) < 1e-10 && ((unsigned long)tmp5 & 1))
      {
        tmp2 = -pow(-tmp0, tmp3)*pow(tmp0, tmp4);
      }
      else
      {
        throwStreamPrint(threadData, "%s:%d: Invalid root: (%g)^(%g)", __FILE__, __LINE__, tmp0, tmp1);
      }
    }
  }
  else
  {
    tmp2 = pow(tmp0, tmp1);
  }
  if(isnan(tmp2) || isinf(tmp2))
  {
    throwStreamPrint(threadData, "%s:%d: Invalid root: (%g)^(%g)", __FILE__, __LINE__, tmp0, tmp1);
  }
  data->localData[0]->realVars[0] /* x variable */ = tmp2;
  TRACE_POP
}

Line: https://github.com/OpenModelica/OMCompiler/blob/master/Compiler/Template/CodegenCFunctions.tpl#L4938

related commits:
https://github.com/OpenModelica/OMCompiler/commit/63d57dd2ca84c3e72641edba77fde0494bc56b73

https://github.com/OpenModelica/OMCompiler/commit/cb732fc280ac2d8940713d8a104c18952a0634da

Change History (7)

comment:1 by Francesco Casella, 7 years ago

I guess that is kind of necessary if p is a parameter that is amenable to be changed at runtime. I guess the whole thing should be much leaner if you had either

constant Real p = 1;

or

final Real p = 1;

or

parameter Real p = 1 annotation(Evaluate=true);

so that p can be constant evaluated and time^p replaced with time.

Have you tried those out?

comment:2 by Vitalij Ruge, 7 years ago

Description: modified (diff)

comment:3 by Vitalij Ruge, 7 years ago

@casella updated test.

comment:4 by Vitalij Ruge, 7 years ago

Maybe a function like OMC_POW will produce less code line in the generic case

comment:5 by Vitalij Ruge, 7 years ago

Note:

model pow_test                     
  Real x = (-y)^(1/3);             
  Real y(start = 1, fixed=true);   
equation                           
  der(y) = 0;                      
end pow_test; 

work, solution x = -1

model pow_test                     
  Real x = (-y)^(2/3);             
  Real y(start = 1, fixed=true);   
equation                           
  der(y) = 0;                      
end pow_test; 

failed, solution x = (-1)^2

Last edited 7 years ago by Vitalij Ruge (previous) (diff)

comment:6 by anonymous, 7 years ago

From Modelica specification sect. 6.6:
"For exponentiation and division the type compatible expression is Real (even if both A and B are Integer)"

So, probably, in this case the power should cause domain error (as it does in Dymola).

comment:7 by Martin Sjölund, 7 years ago

We already have some code for example for real_int_pow; real_real_pow (or modelica_pow, whatever) could be similar (the only difference is that you would need to pass it __FILE__ and __LINE__ if you want it to produce the same messages; you could make it an inline function if you want the branch selection to be chosen).

As an alternative you could handle the case where the exponent is a Real literal and perform all the branch selection and checking during code generation resulting in usually simply calling pow.

Note: See TracTickets for help on using tickets.