问题
I've got a home automation system working in Java, and I want to add simple math capabilities such as addition, subtraction, multiplication, division, roots, and powers.
At the system current state, it can convert a phrase into tags, as shown in the following examples:
example:
Phrase: "what is one hundred twenty two to the power of seven"
Tagged: {QUESTION/math} {NUMBER/122} {MATH/pwr} {NUMBER/7}
example:
Phrase: "twenty seven plus pi 3 squared"
Tagged: {NUMBER/27} {MATH/add} {NUMBER/3.14159} {MATH/multiply} {MATH/pwr} {NUMBER/2}
This example could be just as easily converted to something like this:
27 + 3.14159 * 3^2
Each tag is an object that can be queried for it value.
Edit: Specific question:
So now I need a way to read that group of tags as an equation, and return a numerical result. As a last resort I could use google or wolfram alpha, but that will be slower, and I'm trying to keep the automation system completely self contained.
If you would like to see the entire source, here it is in github. Note that I have not committed the last few few changes, so some of the math related things I gave examples will not work.
回答1:
After some more googleing (I didn't know the name for what I was doing at first) I found someone who has done something similar already:
http://www.objecthunter.net/exp4j/
Edit: Finished: https://github.com/Sprakle/HomeAutomation/blob/master/HomeAutomation/src/net/sprakle/homeAutomation/interpretation/module/modules/math/Math.java
回答2:
What you need is a parsing method that will build an equation and return an answer from your text. I'll take a single line and walk through making such a method which you will then need to work out for yourself. Note that this is just a general idea and that some languages other than Java may be more suitable for this kind of operation.
{QUESTION/math} {NUMBER/122} {MATH/pwr} {NUMBER/7}
//let's assume that the preprocessor reduces the input to an array that is something like this:
// [122, pwr, 7] (this is a very common construction in a language like LISP).
public static int math(string[] question){
while(i < question.length){
if(question[i] == "pwr"){
return pow(Integer.parseInt(question[i-1]), Integer.parseInt(question[i+1]);
}
i++;
}
return 0;
}
Basically what you'll need is a nice way of going from infix to prefix notation with a little bit of string to whatever conversions.
There are likely nicer structures for doing this than what I've produced above, but something like this should get you going.
回答3:
Ben, he's right. The parsing action that takes natural language is much more difficult. What you need to do is add math precedence to the expression. The way you do that is to put the expression in some expected form, like post/pre/in-fix and provide an evaluation algorithm(post-fix ends up being pop(), pop(), evaluate(), push();
. This requires that you check the individual tokens against a table that investigates the intersection of the operators and operands. It isn't anything you can do quickly or easily.
回答4:
The code I wrote relies that the given order of tags is "NUMBER" "MATH" "NUMBER" "MATH" "NUMBER" and it completely ignores operational rules in math. It is just an outline of what you could do, so you may have to fix it up a bit to do what you want.
I have not tested this file due to lack of time, so debug it if necessary!
import net.sprakle.homeAutomation.interpretation.tagger.tags.*;
import java.util.List;
import java.util.Arrays;
public class Math {
private Tag[] tags; //Stores the converted tags as a "MathTag"
//Requires an array of tags
public Math(Tag[] inputTags) {
tags = new MathTag[inputTags.length]; //create a new MathTag array
System.arraycopy(inputTags, 0, tags, 0, tags.length); //Convert Tag array to MathTag array
}
//returns a value based on the tags
//TODO: ADD MATHEMATICAL ORDER OF OPERATIONS!!!
public double performMath() {
double value = 0;//initial value to return
for (int i = 0; i < tags.length; i++) { //perform initial check of the phrase given
if (tags[i].getType() = TagType.NUMBER && !tags[i].getWasChecked() && i + 1 < tags.length) {
value = performOperation(i, value, Double.parseDouble(tags[i].getValue()), tags[i+1].getType());
} else if (tags[i].getType() = TagType.MATH && !tags[i].getWasChecked() && i + 1 < tags.length) {
value = performOperation(i, value, Double.parseDouble(tags[i + 1].getValue()), tag.getType()); //I'm not positive if this would not cause issues
}
}
}
//Perform individual operations given the index of the operation, value1, value2, and the operation type
//The order of the array "operations" must match the order of the operations in the switch statement.
public double peformOperation(int i, double value1, double value2, String operation) {
String[] operations = {"add", "subtract", "multiply", "divide", "pwr", "root"}; //Array of operations
List list = Arrays.asList(operations); //Not exactly effecient, used to check what operation to perform
switch (list.indexOf(operation)) { //Perform a task based on the operation
case 0: //Addition
tags[i].setChecked(true); //Number
tags[i + 1].setChecked(true); //Operation
return value1 + value2;
case 1: //Subtraction
tags[i].setChecked(true); //Number
tags[i + 1].setChecked(true); //Operation
return value1 - value2;
case 2: //Multiplication
tags[i].setChecked(true); //Number
tags[i + 1].setChecked(true); //Operation
return value1 * value2;
case 3: //Division
tags[i].setChecked(true); //Number
tags[i + 1].setChecked(true); //Operation
return value1 / value2;
case 4: //Power
tags[i].setChecked(true); //Number
tags[i + 1].setChecked(true); //Operation
return value1 * value1;
case 5: //Square Root
tags[i].setChecked(true); //Number
tags[i + 1].setChecked(true); //Operation
return Math.sqrt(value1);
}
return error(); //Non-valid operation found
}
//Need some way to detect an error
public double error() {
return 0;
}
//Need some way to check if a tag was looked at before
class MathTag extends Tag {
protected static boolean wasChecked = false;
public void setChecked(boolean checked) {
wasChecked = true;
}
public boolean getWasChecked() {
return wasChecked;
}
}
}
来源:https://stackoverflow.com/questions/15869147/converting-natural-language-to-a-math-equation