【问题标题】:Validate math expressions including relational operators [closed]验证数学表达式,包括关系运算符 [关闭]
【发布时间】:2016-02-19 12:32:45
【问题描述】:

我面临一种情况,允许用户定义一些条件如下:

x >= 2
x < 6
y >= 2
y > 2*x

其中 x 和 y 是变量。 Java 或 Python 中是否存在能够计算每个变量的域范围的库(例如 [2,6] 中的 x 和 [2,12] 中的 y),然后验证这些表达式?比如添加语句

x + y <= 2

应该会导致错误。

最好的

【问题讨论】:

  • Java Python?您使用两种语言?
  • 您允许哪些运算符?小心,解析这些表达式会变得很容易。您可能希望使用某种外部程序与(Mathematica 或 Maple)进行交互。使用科学库可能适合您的需求(例如 SciPy for python),但这可能需要您做一些工作。
  • 图书馆推荐离题
  • 当您说“允许用户定义”时,这是否意味着已解析的输入文本?还是您的意思是您的库的用户应该能够在代码中定义这些谓词?
  • @Jonathan 首选 Java

标签: java math expression conditional relational


【解决方案1】:

我想您可以手动执行此操作。 AFAIK,没有内置的方法来处理不平等。

您可以创建一种方法来处理限制,然后根据您的输入不等式手动分配这些限制。

这会造成不平等。您可以操纵多个不等式的极限和方向来组成一个系统,然后使用这些系统来验证方程。

public class Limit {
    public double limit;          // limit number
    public boolean isUpperLimit;  // essentially the direction
    public boolean includes;      // differentiates between <= and <
    public Limit(double limit, boolean isUpperLimit, boolean includes) {
        this.limit = limit;
        this.isUpperLimit = isUpperLimit;
        this.includes = includes;
    }
}
public class Inequality {
    public Limit limit;
    public String variable;
    public Inequality(String inequality) { // if inequality is 
        String variable = inequality.split(" ")[0];
        this.variable = variable;
        String operator = inequality.split(" ")[1];
        Double number = Double.parseDouble(inequality.split(" ")[2]);
        double limit = number;
        boolean isUpperLimit, includes;
        switch(operator) {
            case ">":
                isUpperLimit = false;
                includes = false;
                break;
            case ">=":
                isUpperLimit = false;
                includes = true;
                break;
            case "<":
                isUpperLimit = true;
                includes = false;
                break;
            case ">=:
                isUpperLimit = true;
                includes = true;
                break;
        }
        this.limit = new Limit(limit, isUpperLimit, includes);
    }
}

public class System {
    public Limit lowerLimit;
    public Limit upperLimit;
    public System(Inequality ie1, Inequality ie2) {
        if(ie1.limit.isUpperLimit == ie2.limit.isUpperLimit) { // if same direction
            if(ie1.limit.isUpperLimit == true) {
                this.upperLimit = (ie1.limit.limit >= ie2.limit.limit) ? ie1.limit : ie2.limit;
            } else {
                this.upperLimit = (ie2.limit.limit >= ie1.limit.limit) ? ie1.limit : ie2.limit;
            }
        }
    }
}

代码未经测试

如果您设置了系统,那么现在您可以使用它们的限制来确定最后一个方程是否可能。

【讨论】:

  • 感谢您的回答。我已经开始手动检查变量的域范围,但是当表达式可能变得更复杂时,评估会变得很麻烦。我会再考虑一下。
  • @labrassbandito 抱歉,代码太长且被混淆了。可能有一种更简单的方法(参见另一个答案,但我不知道它是如何工作的),但这是我能想到的最简单的方法。但我只是一个业余的青少年爱好者,从硬件上抽出时间来积累代表点,他们对一般编程知之甚少,并尽我所能帮助知识有限的人 =)。
【解决方案2】:

您的问题不清楚您是在谈论解析文本表达式还是在谈论允许定义谓词的库。

如果您指的是后者,Java 8 使定义谓词变得相当容易。您的谓词可以表示为:

List<BiFunction<Integer, Integer, Boolean>> conditionals;

然后设置为:

conditionals.add((x, y) -> x >= 2);
conditionals.add((x, y) -> x < 6);
conditionals.add((x, y) -> y > 2 * x);

等等。

然后针对定义的 x 和 y 范围进行测试可能如下所示:

private boolean anyMatch(int xMin, int xMax, int yMin, int yMax) {
    IntStream.rangeClosed(xMin, xMax).anyMatch(x ->
        IntStream.rangeClosed(yMin, yMax).anyMatch(y ->
            conditionals.stream().allMatch(c -> c.apply(x, y))));
}

目前这是假设两个变量。如果您想扩展以覆盖任何数字,仍然可以通过将变量的值表示为映射来使用内置类:

List<Function<Map<String, Integer>, Boolean>> conditionals;
conditionals.add(vars -> vars.get("x") >= 2);
conditionals.add(vars -> vars.get("y") > 2 * vars.get("x"));

这种设计可以很容易地用于排除添加在给定范围内不兼容的谓词。

如果您想做一些更复杂的事情,保留有关允许范围的信息而不迭代指定域,那么我认为您需要一个自定义类。

【讨论】:

  • 这看起来很有趣。 BitFunction 对我来说是新的。我还不确定是否会在内部使用 Java 8。我也必须检查一下。
  • @labrassbandito 您可以在 Java 7 中使用相同的方法,但您需要创建接口的匿名实现。但是,鉴于您上面关于必须解析字符串的评论,我的答案对您来说没有多大用处。
猜你喜欢
  • 2010-09-10
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 2013-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多