modelica / ModelicaSpecification

Specification of the Modelica Language
https://specification.modelica.org
Creative Commons Attribution Share Alike 4.0 International
101 stars 41 forks source link

Stricter definition of numerics #3591

Open HansOlsson opened 1 week ago

HansOlsson commented 1 week ago

There has been a background discussion regarding floating point semantics, especially for the weird cases and I thought it would be best to get some agreement.

For the weird cases I mean:

My thinking is that we use IEEE-754 (alternatively any similar floating point numbers system) with the following extras:

To me it would be good to have this now, and the possible extension for infinity is to allow:

At least for evaluable parameters allow:

And possibly even for other parameters, and even discrete variables.

Background - the critical points for not "just using IEEE-754" are:

Specifically it could be that the simplification p*0*x is sufficiently rare for evaluable parameters that we can delay it until evaluating the evaluable parameters, and in case it is actually infinity view this expression as an error (should be rare, right?).

However, even if this might make perfect sense and have very little impact for models in practice, it could still be complicated to implement in tools. That's one reason I think we should do this later.

Note that for NaN a special case would be something like:

algorithm
   x:=sqrt(y);
   if y<0 then
     x:=0;
   end if;

To me this model has an error when y<0, but a tool does not necessarily have to detect it (if using NaN for negative sqrt it will be overwritten); and even with our current rules, https://specification.modelica.org/master/operators-and-expressions.html#evaluation-order , a tool could simplify this to:

algorithm
   if y<0 then
     x:=0;
   else
     x:=sqrt(y);
   end if;

(avoiding the issue).

casella commented 1 week ago

(Reporting and adapting my argument from #4479, since it is relevant for this discussion.)

Note that expressions in the Modelica code are not always interpreted literally.

A Modelica tool is free to apply transformations to expressions and equations that are equivalent from a mathematical point of view, but not from a numerical point of view. For example, it can

Adding NaN, Inf and the associated semantics to Modelica means that every time a tool applies any such transformation, it will need to take care of that as well.

As Aesop wrote in his fables, be careful what you wish for, lest it comes true! 😃

HansOlsson commented 6 days ago

Numerical routines should be written to avoid overflow. If you look at something simple like the 2-norm in the BLAS-routine dnrm2 you can see that this is something that people actually do.

For scaling it is both important and normally a non-issue. The reason is that scaling is intended to get values closer to 1 and if scaling introduces an overflow it indicates that not only is the scaling not doing what it is supposed to do, but actually making the problem worse.

If you look at the scaling defined in the Modelica specification it uses |x.nominal|+|x| as scale factor for x. You don't have to divide by it, but if you do - dividing x by this scale factor is by definition guaranteed to produce a value <=1 in absolute terms, and thus not overflow (it may underflow if x was close to the smallest number and the nominal value larger than 1, but underflow is less of an issue - especially as this case indicates that the modeler don't care about such a small value).

The only issue is if |x.nominal| is close to the maximum floating point number (DBL_MAX), and the variable also has a value of similar magnitude. Adding a restriction that |nominal| should be less than something like DBL_MAX*DBL_EPSILON avoids that case, and I don't see any existing models violating that. Alternatively we could recommend max(|x.nominal|, |x|) instead, - which avoids the issue without any restriction, or some other alternative.