As part of a personal project to calculate the Jordan normal form of square matrices, it turns out I need to parse polynomials with complex coefficients in order to ease a lot of the code.
(relevant code at the bottom of the post)
The polynomials I wish to parse are of the following form:
- A coefficient may be real, imaginary or complex.
- If the coefficient is complex, it would be wrapped with parentheses. If these parentheses are the leading coefficient, they won't be preceded by a
+
or-
. - If the coefficient is real, imaginary, or complex whose real and\or imaginary components are of magnitude 1, the
1
won't appear but only the sign. - Parentheses are to be preceded by
+
only. - The variable
x
may have a power (>2
), may have a power of 1 and then it appears just asx
, or may not appear at all. - There are no more rules concerning the text representation of the polynomial, i.e. powers aren't necessarily ordered in ascending\descending order.
Some examples of properly formatted polynomials:
1
-1
-2.1x
3i
x^2-1
-x^3+2x+1
(5-5i)x^2-x-1
(-1+i)x-5
-ix^3-x^2+1
..and some ill-formatted ones:
1x
(leading unnecessary1
)+(+1-2i)x
(parentheses have a leading+
, real component has leading+
)(5.1i)x^2
(no need for parenthesis since coefficient is imaginary)-(i-1)
(complex coefficient has leading-
)
After some reading online (SO, Java tutorials, Java API), I quickly came to the conclusion that a regex would be the easiest approach for parsing, considering all the restraints mentioned above. On the formal side, a regex for this task is possible, since I drew an NFA the accepts only such valid expressions.
I'm doing this TDD (via JUnit 4), and this test fails:
assertEquals("Polynomial parsed incorrectly.", poly07, PolyParser.parse(exp07));
where poly07
looks like this: (5-5i)x^2-x-1
.
This is the exception that's being raised:
java.lang.NumberFormatException: For input string: "5-5"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at PolyParser.parse(PolyParser.java:55)
at PolyParserTest.testParse(PolyParserTest.java:59)
I've tried debugging, and saw that the regex captures 5-5i
(and later strips the i
). It then tries to invoke Double.parseDouble
with the argument string 5-5
, which causes the exception.
After all the reading, I can't quite figure out what's the required adjustment in the regex in order for this whole show to work. Also, the regex isn't ordered like the representations constraints mentioned above, because I want to see if the coefficient is complex before trying to parse it as real; also encountered problems that real numbers (i.e. with decimal point) are parsed as integers, so that's why the regex treats real numbers first.
The regex:
public static final String POLYNOMIAL_REGEX =
"([+-])?" + // leading plus or minus
"(\\()?" + // parenthesis to denote the beginning of a complex number
"([+-])?(((\\d+.\\d+)|\\d+)i)?" + // component of coefficient, imaginary
"(((-)?\\d+.\\d+)|\\d+)?" + // component of coefficient, real
"(\\))?" + // parenthesis to denote the end of a complex number
"(x)?" + // variable
"(?:\\^(\\d+))?"; // power of the variable
I'm not going to post all of the relevant code here because it would clutter stuff up. All of the code is on GitHub, just be sure to switch to the branch PolyParser
.
Relevant code is in the files:
PolyParser.java
Polynomial.java
Complex.java
The test unit is in the file PolyParserTest.java
.