public void Evaluate_Function_Log() { ArithmeticExpression ae = ArithmeticExpression.Parse("log(10 * 10 * 10 * 10)"); double result = ae.Evaluate(double.NaN); Assert.AreEqual(4.0, result); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_SimpleFunction_AutoMultiply() { ArithmeticExpression ae = ArithmeticExpression.Parse("5sqrt(x)"); double result = ae.Evaluate(16); Assert.AreEqual(5.0 * Math.Sqrt(16), result); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Precedence() { ArithmeticExpression ae = ArithmeticExpression.Parse("1 / (2 * 4) ^ 2"); double result = ae.Evaluate(double.NaN); Assert.AreEqual(1.0 / Math.Pow(2.0 * 4.0, 2), result); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_SimpleExpression() { ArithmeticExpression ae = ArithmeticExpression.Parse("(2 - 1 + 6) % 5"); double result = ae.Evaluate(double.NaN); Assert.AreEqual((2 - 1 + 6) % 5, result); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Parentheses() { ArithmeticExpression ae = ArithmeticExpression.Parse("((( ((( ((( 1 + 2 ))) + 3 ))) + 4 ))) + 5"); double result = ae.Evaluate(double.NaN); Assert.AreEqual(1 + 2 + 3 + 4 + 5, result); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Function_RoundDown() { ArithmeticExpression ae = ArithmeticExpression.Parse("round(z)"); double result = ae.Evaluate(6.49); Assert.AreEqual(6.0, result); Assert.AreEqual("z", ae.VariableName); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_SimpleFunction() { ArithmeticExpression ae = ArithmeticExpression.Parse("cos(custom)"); double result = ae.Evaluate(0); Assert.AreEqual(1.0, result); Assert.AreEqual("custom", ae.VariableName); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Variable() { ArithmeticExpression ae = ArithmeticExpression.Parse("x"); double result = ae.Evaluate(-10); Assert.AreEqual(-10, result); Assert.AreEqual("x", ae.VariableName); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Constant_AutoMultiply() { ArithmeticExpression ae = ArithmeticExpression.Parse("2pi"); double result = ae.Evaluate(double.NaN); Assert.AreEqual(2.0 * Math.PI, result); Assert.IsNull(ae.VariableName); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Constant_3() { ArithmeticExpression ae = ArithmeticExpression.Parse("6e-3"); double result = ae.Evaluate(double.NaN); Assert.AreEqual(0.006, result); Assert.IsNull(ae.VariableName); Assert.IsTrue(ae.IsSimpleConstantOnly); }
public void Evaluate_Comment() { ArithmeticExpression ae = ArithmeticExpression.Parse("1 + 2 + 3 # This is comment!"); double result = ae.Evaluate(double.NaN); Assert.AreEqual(6, result); Assert.IsNull(ae.VariableName); Assert.IsFalse(ae.IsSimpleConstantOnly); }
public void Evaluate_Variable_2() { ArithmeticExpression ae1 = ArithmeticExpression.Parse("sin(x)"); double result1 = ae1.Evaluate(10); ArithmeticExpression ae2 = ArithmeticExpression.Parse("sin(10)"); double result2 = ae2.Evaluate(double.NaN); Assert.AreEqual(result1, result2); }
public void Evaluate_KnownConstants() { ArithmeticExpression ae1 = ArithmeticExpression.Parse("pi"); double result1 = ae1.Evaluate(double.NaN); Assert.AreEqual(Math.PI, result1); ArithmeticExpression ae2 = ArithmeticExpression.Parse("e"); double result2 = ae2.Evaluate(double.NaN); Assert.AreEqual(Math.E, result2); }
public void Evaluate_Callbacks() { ArithmeticExpression ae = ArithmeticExpression.Parse("(+1) * (-2) * 3"); DotNetOperatorCallbacks callbacks = new DotNetOperatorCallbacks(); ae.Callbacks = callbacks; double result = ae.Evaluate(0); Assert.AreEqual((+1) * (-2) * 3, result); Assert.AreEqual(callbacks, ae.Callbacks); Assert.IsFalse(callbacks.IsDisposed); callbacks.Dispose(); Assert.IsTrue(callbacks.IsDisposed); }
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Text") { ListView.Item item = (ListView.Item)sender; if (string.IsNullOrEmpty(item.Text)) { item.NumericValueSource = null; item.TextDisplay = "\f[0x999999]" + Tx.T("main.enter expression"); } else { try { ArithmeticExpression ae = ArithmeticExpression.Parse(item.Text); ae.Callbacks = item.OperatorCallbacks; item.NumericValueSource = ae; int i = item.Text.IndexOf('#'); if (i != -1) { while (i > 0 && item.Text[i - 1] == ' ') { i--; } StringBuilder sb = new StringBuilder(); sb.Append(item.Text, 0, i); if (ae.VariableName == null && !ae.IsSimpleConstantOnly) { double result = ae.Evaluate(double.NaN); sb.Append("\f[I]\f[0x999999] = "); sb.Append(result.ToExactString().LimitSize(32)); sb.Append(" \f[I]"); } sb.Append("\f[0x498E3E]"); sb.Append(item.Text, i, item.Text.Length - i); CheckCallbacks(item, sb); item.TextDisplay = sb.ToString(); } else { if (ae.VariableName == null && !ae.IsSimpleConstantOnly) { StringBuilder sb = new StringBuilder(); sb.Append(item.Text); double result = ae.Evaluate(double.NaN); sb.Append("\f[I]\f[0x999999] = "); if (double.IsPositiveInfinity(result)) { sb.Append("+∞"); } else if (double.IsNegativeInfinity(result)) { sb.Append("−∞"); } else { sb.Append(result.ToExactString().LimitSize(32)); } sb.Append("\f[I]"); CheckCallbacks(item, sb); item.TextDisplay = sb.ToString(); } else { StringBuilder sb = new StringBuilder(); sb.Append(item.Text); CheckCallbacks(item, sb); item.TextDisplay = sb.ToString(); } } } catch (SyntaxException ex) { item.NumericValueSource = null; StringBuilder sb = new StringBuilder(); sb.Append("\f[0x8b0000]"); int length = ex.Input.IndexOf('#'); if (length == -1) { length = ex.Input.Length; } if (length < 3) { sb.Append(ex.Input); } else { if (ex.Index - 1 < 0) { sb.Append("\f[U]"); } else { sb.Append(ex.Input, 0, ex.Index - 1); sb.Append("\f[U]\f[0xd00000]"); sb.Append(ex.Input[ex.Index - 1]); } sb.Append("\f[0xff0000]"); sb.Append(ex.Input[ex.Index]); if (ex.Index + 1 < length) { sb.Append("\f[0xd00000]"); sb.Append(ex.Input[ex.Index + 1]); sb.Append("\f[0x8b0000]\f[U]"); if (ex.Index + 2 < length) { sb.Append(ex.Input, ex.Index + 2, length - (ex.Index + 2)); } } else { sb.Append("\f[0xd00000] \f[U]"); } } switch (ex.ExceptionType) { case SyntaxException.Type.Unknown: break; case SyntaxException.Type.InvalidNumber: sb.Append(" \f[-]\f[image:warning] \f[0xaa6400]\f[I]"); sb.Append(Tx.T("expression.errors.invalid number")); break; case SyntaxException.Type.DistinctVariableCountExceeded: sb.Append(" \f[-]\f[image:warning] \f[0xaa6400]\f[I]"); sb.Append(Tx.T("expression.errors.distinct variable count exceeded")); break; case SyntaxException.Type.ParenthesesCountMismatch: sb.Append(" \f[-]\f[image:warning] \f[0xaa6400]\f[I]"); sb.Append(Tx.T("expression.errors.parentheses count mismatch")); break; default: throw new InvalidEnumArgumentException("ex.ExceptionType", (int)ex.ExceptionType, typeof(SyntaxException.Type)); } item.TextDisplay = sb.ToString(); } catch (Exception ex) { item.NumericValueSource = null; item.TextDisplay = "\f[0x8b0000]" + item.Text + " \f[-]\f[image:warning] \f[0xaa6400]\f[I]" + ex.Message; } } item.CheckEnabled = (item.NumericValueSource != null); RefreshToolStrip(); } else if (e.PropertyName == "OperatorCallbacks") { ListView.Item item = (ListView.Item)sender; ArithmeticExpression arithmeticExpression = item.NumericValueSource as ArithmeticExpression; if (arithmeticExpression != null) { arithmeticExpression.Callbacks = item.OperatorCallbacks; OnItemPropertyChanged(item, new PropertyChangedEventArgs("Text")); } item.Description = item.OperatorCallbacks.ImplementationName; } }
private unsafe void OnExportSelectedButtonClick(object sender, EventArgs e) { ListView.Item selected = listView.FocusedItem; if (selected == null) { // Nothing to export... return; } ArithmeticExpression ae = selected.NumericValueSource as ArithmeticExpression; if (ae == null) { MessageBox.Show(this, Tx.T("dataset.errors.item not supported"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } long xFi = 0, xLi = 0, distance = 0; if (ae.VariableName != null) { double xF_ = graph.MinVisibleX; double xL_ = graph.MaxVisibleX; if (xF_ >= xL_) { MessageBox.Show(this, Tx.T("dataset.errors.cannot determine interval"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (Math.Sign(xF_) != Math.Sign(xL_)) { MessageBox.Show(this, Tx.T("dataset.errors.interval with zero"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Swap first and last for negative "x" values xFi = *(long *)&xF_; xLi = *(long *)&xL_; if (xFi > xLi) { long swap = xLi; xLi = xFi; xFi = swap; } distance = (xLi - xFi); if (distance < 0) { MessageBox.Show(this, Tx.T("dataset.errors.interval too big"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (distance > 10 * 1000 * 1000) { long sizeInMB = (distance * 8 * 2 / 1024 / 1024); string sizeString; if (sizeInMB > 100L * 1024L) { sizeString = Tx.N(sizeInMB / 1024) + " GB"; } else { sizeString = Tx.N(sizeInMB) + " MB"; } if (MessageBox.Show(this, Tx.T("dataset.errors.file too big", Tx.N(distance), sizeString), Tx.T("main.warning"), MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) { return; } } } using (SaveFileDialog dialog = new SaveFileDialog()) { const string ext = ".fvis-values"; dialog.Filter = Tx.T("dataset.filetype") + " (*" + ext + ")|*" + ext; dialog.FilterIndex = 0; dialog.RestoreDirectory = true; dialog.Title = Tx.T("dataset.save"); string filename = selected.Text; char[] invalidChars = Path.GetInvalidFileNameChars(); for (int i = 0; i < invalidChars.Length; i++) { filename = filename.Replace(invalidChars[i], '_'); } dialog.FileName = filename + ext; if (dialog.ShowDialog(this) != DialogResult.OK) { return; } filename = dialog.FileName; ProgressDialog progressDialog = new ProgressDialog(); progressDialog.Text = Tx.T("dataset.saving.title"); progressDialog.MainInstruction = Tx.T("dataset.saving.description"); progressDialog.Line1 = Tx.T("dataset.saving.progress", "0", Tx.N(xLi - xFi)); progressDialog.Show(this); ThreadPool.UnsafeQueueUserWorkItem(delegate { using (FileStream s = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)) using (BinaryWriter bw = new BinaryWriter(s)) { bw.Write(new[] { (byte)'f', (byte)'V', (byte)'i', (byte)'s' }); const int flags = 0; bw.Write(flags); string description = selected.Text; bw.Write(description); // Save graph viewport settings long axisX = graph.AxisX; long axisY = graph.AxisY; double scaleFactor = graph.ScaleFactor; bw.Write(axisX); bw.Write(axisY); bw.Write(scaleFactor); if (ae.VariableName == null) { // Constant function, save only one value double y = ae.Evaluate(double.NaN); const long count = 2; bw.Write(count); bw.Write(double.MinValue); bw.Write(y); bw.Write(double.MaxValue); bw.Write(y); } else { bw.Write(distance + 1); Stopwatch sw = Stopwatch.StartNew(); long lastProcessed = xFi; for (long xi = xFi; xi <= xLi; xi++) { double x = *(double *)ξ double y = ae.Evaluate(x); bw.Write(x); bw.Write(y); if (sw.ElapsedMilliseconds > 4000) { if (progressDialog.IsCancelled) { break; } sw.Stop(); long delta = (xi - lastProcessed); long rate = delta * 1000 / (long)sw.Elapsed.TotalMilliseconds; TimeSpan remaining = TimeSpan.FromSeconds((xLi - xi) / rate); lastProcessed = xi; BeginInvoke((MethodInvoker) delegate { progressDialog.Line1 = Tx.T("dataset.saving.progress", Tx.N(lastProcessed - xFi), Tx.N(xLi - xFi)); progressDialog.Line2 = Tx.T("main.remaining time", remaining.ToTextString()); progressDialog.Progress = (int)((lastProcessed - xFi) * 100 / (xLi - xFi)); }); sw.Restart(); } } sw.Stop(); } } if (progressDialog.IsCancelled) { try { File.Delete(filename); } catch { // Nothing to do... } } BeginInvoke((MethodInvoker) delegate { progressDialog.TaskCompleted(); }); }, null); } }