为什么“time==0.5”不是 Modelica 语言中的离散表达式?

Mar*_*vel 0 modelica openmodelica dymola

我构建了一个简单的模型来理解“离散表达式”的概念,代码如下:

model Trywhen
  parameter Real B[ :] =   {1.0, 2.0, 3.0};
algorithm 
    when time>=0.5 then
      Modelica.Utilities.Streams.print("message");
    end when;
  annotation (uses(Modelica(version="3.2.3")));
end Trywhen;
Run Code Online (Sandbox Code Playgroud)

但是在检查模型时,我收到一条错误消息,表明“time==0.5”不是离散表达式。 在此处输入图片说明

在此处输入图片说明

如果我更改time==0.5time>=0.5,模型将通过检查。

在此处输入图片说明

如果我使用if-clauseto when-clause,该模型工作正常,但警告显示“不能比较 Real 类型的变量是否相等。”

在此处输入图片说明

我的问题是:

  1. 为什么time==0.5不是离散表达式?
  2. 为什么不能比较 Real 类型的变量是否相等?比较两个 Real 类型的变量时,这似乎很常见。

Han*_*son 5

第一个问题不重要,因为time==0.5不允许。

第二个问题很重要:比较实数是否相等在其他语言中很常见,也是常见的错误来源 - 除非特别小心。

仅使用处理器的浮点比较对于某些混合了 80 位和 64 位浮点数(或带有性能损失)的处理器(如英特尔)的想法来说是一个非常糟糕的主意,并且在其他情况下它可能无法按预期工作。在这种情况下,0.5 可以表示为浮点数,但 0.1 和 0.2 不能。

通常abs(x-y)<eps是一个不错的选择,但它取决于预期用途,eps 取决于其他因素;不仅是机器精度,还有用于计算 x 和 y 及其误差传播的算法。

在 Modelica 中,问题比在许多其他语言中更严重,因为允许工具更多地优化表达式(包括符号操作)——这使得找出 eps 的好值变得更加困难。

所有这些问题意味着决定不允许比较平等 - 并且需要更合适的东西。

特别是如果你知道你只会从一个方向接近平等,你就可以避免许多问题。在这种情况下time是递增的,所以如果它已经>0.5在一个事件中它不会<=0.5在以后的事件中,并且when只会在表达式第一次变为真时触发。

因此when time>=0.5只会触发一次,并且会在time==0.5左右触发,所以是一个不错的选择。但是,可能会有一些数值不准确,因此它可能会在 0.500000000000001 处触发。