问题描述
我建立了一个简单的模型来理解“离散表达式”的概念,下面是代码:
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;
但是在检查模型时,出现错误,表明“ time == 0.5”不是离散表达式。
如果我将time==0.5
更改为time>=0.5
,则模型将通过检查。
如果我使用if-clause
到when-clause
,则该模型可以正常工作,但是会显示警告消息,“无法比较Real类型的变量是否相等”。
我的问题是:
- 为什么
time==0.5
不是离散表达式? - 为什么不能比较Real类型的变量是否相等?比较两个Real类型的变量时,这似乎很常见。
解决方法
第一个问题并不重要,因为不允许使用time==0.5
。
第二个问题很重要: 在其他语言中,比较实数是否相等是常见的问题,也是常见的错误来源-除非特别注意。
仅在某些处理器(例如Intel)上混合使用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处触发。