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 )
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 }
related commits:
https://github.com/OpenModelica/OMCompiler/commit/63d57dd2ca84c3e72641edba77fde0494bc56b73
https://github.com/OpenModelica/OMCompiler/commit/cb732fc280ac2d8940713d8a104c18952a0634da
Change History (7)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
Description: | modified (diff) |
---|
comment:4 by , 7 years ago
Maybe a function like OMC_POW will produce less code line in the generic case
comment:5 by , 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
comment:6 by , 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 , 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.
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
or
or
so that
p
can be constant evaluated andtime^p
replaced withtime
.Have you tried those out?