It’s been quite a while since I posted anything, so I thought I’d give you an update on what I’m working on. School is still a major time sink, so I don’t know when any of these things will be finished.
Wait, WordPress 3.3.1 is out already? My ancient custom theme only works on an ancient version of WordPress, so it’s about time for a new one. I have a design in mind, but I haven’t started building it yet.
The latest Opera 12.00 snapshots have a vastly improved Tabs and Windows API. Tab Vault was made when said API sucked (as of Opera 11.62, it still does). I’ve rewritten much of the backend code to be able to take advantage of the new features. Now I’m waiting for the bugs in the new API to get fixed.
I’m currently about 2/3 done transcribing βίος-δ (Bios-delta) from Guilty Crown. I may attempt to transcribe the piano version of Light My Fire from Shakugan no Shana Final next, though the only available audio clips I have are from the show with people talking over the song. (If anyone can help me find all the episodes and times where the song is played, that would be most helpful!)
So, it turns out writing a parser is hard. Who knew? My new plan is to use ANTLR to generate a parser. I now have a mostly-working grammar based on a grammar for Python. It doesn’t yet understand that
2 x y should be evaluated as
2*x*y, but I may insert the multiplication operators before sending the expression to the parser (as I’m already doing in GlassCalc 1.x) because making the parser recognize this seems to require backtracking, which is slow. Given the computing power of modern computers and that the average expression isn’t very long, (compared to say a C++ source code file) this slowdown might not make much a difference.
I am also trying to balance power with ease of use in the new syntax. For example, can the value of a variable be a function? If not,
(x + 1)(x + 2) would evaluate to
x2 + 3x + 2 as it has in GlassCalc 1.x. If so, it would mean “try to call the result of
(x+1) as a function and pass
x+2 as the only argument”. At the moment, I’m leaning towards functions not being able to be stored as variable values, as I think the alternative is very powerful, yet very confusing.
As great as Mathieu Jacques’s MTParser is, it only supports double-precision floating point numbers and it only works with .NET through a COM interface, which means I have less control over the parser and I have to register the dll. Therefore, GlassCalc 2 will feature a new parser which I am writing from the ground up. I call this new parser GCParser. I am awesome at naming things.
Here is a fairly technical description of how GCParser will work:
Design Goals of GCParser
- The parser will operate on objects deriving from GCObject. This is a completely generic class, and in fact, the only function a GCObject must have converts the object to a string so it can be displayed.
- GCParser will have two types of GCObject out-of-the-metaphorical-box: numbers and arrays. Arrays are lists of GCObjects. This means GCParser will support vector operations, and since you can make arrays of arrays, probably matrix operations too.
a = [1, 2, 3] is a 3-element array.
a retrieves the first element of the array.
- GCObjects can have properties and functions. For instance, arrays will have x, y, and z properties to make 3d vector operations easy.
[1, 2, 3].x will return
[2, 3, 1].sort() would return
[1, 2, 3].
- GCParser will be able to operate on multiple types at once. For instance, when executing
2 * [3, 4] the parser would search for a Multiply function taking two arguments of types GCNumber and GCArray. This expression would evaluate to
[6, 8]. If no function was found, the parser would throw a type error.
- GCParser will be extensible. Extensions will be able to define not only constants and functions, but new GCObject types as well. For instance, a complex numbers extension could define a GCComplexNumber class, functions for operating on complex numbers, and a constant i. Since the parser will only create numbers and arrays normally, the extension would also need to define a constructor function,
Complex(real, imag), to make complex numbers. If the extension defined functions for adding/multiplying numbers and complex numbers together, the expression
1 + 2i would also work. The parser would interpret this as
(number: 1) + ((number: 2) * (complex: 0 + i)).
- I haven’t figured out how this would work yet, but I want GCParser to support expressions like
[1, 2, 3].sort((a,b) => b<a). This would send a predicate function to the sort function telling it how to sort—in this case, sort descending. Likewise,
Sum(n => 0.5^n, 1, 50) would sum 0.5n from n = 1 to 50.
- Parsing occurs in three stages: tokenization, parsing and evaluation. Tokenization takes the expression and figures out what all the individual parts mean. It also generates a structure which the syntax highlighter can use instead of the convoluted regular expression system GlassCalc currently uses. Parsing takes the tokenized expression and converts it into a binary tree of operations. Evaluation traverses the tree, running each operation until it gets a final result. Parsing and evaluation will not run on the UI thread, so the program won’t freeze up if you run a long calculation.
Things That Are Not Design Goals of GCParser
- GlassCalc 2 will have a new parser. It will be magic, rainbows and unicorns. It will calculate just about anything.
- If it can’t calculate something, you can probably write an extension so it can.
So, when will it be done? Eventually. I have the tokenizer mostly complete. I am waiting for .NET 4.5 to be released before I start work on the UI, as I will make use of its new asynchronous stuff.
It has been far too long since I last updated GlassCalc. There’s a new version with some bug fixes. Check the GlassCalc page for download links.
This update fixes some bugs caused by GlassCalc applying exponential formatting to hexadecimal numbers containing “e”. It also fixes a formatting bug where a thousands separator would appear next to a negative sign (ex:
-100 was displayed as
- 100) and a syntax highlighting bug where a variable ending with the name of a constant would be highlighted partially as a variable and partially as a constant.
Also, here’s a status update on GlassCalc 2: I’ve decided that MTParser isn’t capable of all the things I would like to do with GlassCalc, and none of the free parser libraries I’ve encountered are either, so I am now writing my own parser (MTParser is excellent, but its existence as a COM component makes installing GlassCalc a pain and it doesn’t support lists or higher precision math). The primary goals of the new parser are:
- Support all of the GlassCalc’s current syntax without tons of regex magic.
- Allow for basing syntax highlighting off of the parsed expression instead of using even more regex magic.
- Add support for lists (what you math people might call n-dimensional vectors) and possibly lists of lists (which could be used to perform matrix math).
- Possibly add support for high-precision math.
So far, I have a system that tokenizes an expression character-by-character as you type it—that is, it splits the expression up into numbers, operators, symbols, and so on. The cool thing about doing this character-by-character is that by the time you hit Enter to evaluate, part of the parsing work is already done. In fact, I can use this already-finished part to speed up syntax highlighting and to show you the result of simple calculations before you even hit enter without reparsing every time you add a character. Of course, if you start messing with the middle of your expression, I have to reparse everything.
I am also experimenting with different GUI designs. I may post some mock-ups here later to see what you think.
Also, once I have made a little more progress, I’m going to put GlassCalc 2 up on Github. That’s right, GlassCalc 2 is going to be open source. The only thing keeping me from open-sourcing GlassCalc was figuring out what MTParser’s license would and wouldn’t let me do with regards to distributing MTParser’s source/binaries. Now that I’m not using MTParser, there aren’t any problems with going open source.
When I first started writing GlassCalc, I never imagined how many cool new features I would come up with later. With the way some parts of GlassCalc are written, it’s becoming harder and harder for me to add in some of the things I want to add, so I’ve decided that the next major version of GlassCalc will be a rewrite of much of the code.
I’ve just started planning GlassCalc 2, and there are a few other projects I want to finish up before I even start writing code for it, (in other words, don’t expect it any time soon) but here are some of the features I have planned:
- Notify of updates with native Win 7 notifications if available. Clicking on notification bubble will open regular update window.
- Replace separate constants,variables, functions views with a single block containing all three items. Maybe use an accordion style control like Opera 11’s mail panel. This should save some vertical space and not look ugly when it is taller than the window.
- Replace function references block with a dedicated function reference window. Access it from the help menu. This window could also show the info that is currently in quickref.txt. Functions will be sortable alphabetically, by type, (trig, probability, etc.) or by the extension that added them.
- When hovering over a variable or custom function, show an “x” button to delete it.
- Remove “Input” text from input box. Put an “=” button to the right. Text/icon inside this button changes depending on context:
- If no text input, show “=”
- If auto-evaluate is on and input is simple, show result of expression. Button should smoothly expand to fit text.
- If auto-evaluate is on and input is complex (commands, multiple expressions) show “=”
- If another expression is still being evaluated, show spinner icon
- Add button to header of the history view that toggles between the view’s regular styling and plain text. This will allow selecting multiple lines at once.
- Redesign settings window. Most likely, place categories in list on the left like in Visual Studio. Keep window the same size no matter which category is selected.
- Maybe add a code-completion tooltip that would show all constants, variables or functions starting with what you’ve typed. Could activate automatically or on Ctrl+Space.
- Add option to display bases as a subscript, like 1001102
- Separate parser/evaluator from the UI thread so that GlassCalc will not freeze while performing long calculations.
- Add an “auto-evaluate” mode which evaluates expressions and displays the results as you type. Result of auto-evaluation will most likely appear to the right of the input box, though a dimmed result in the history view might work too.
- Replace slow, unfindable xml config files with an ini settings file at %AppData%\GlassCalc.
- Add extensions system. Extensions will be able to extend the default constants and functions and add scale factors. The user will be able to turn them on and off individually. Extensions will most likely consist of a single ini file with the extension’s name, author, and all the other info. If an extension requires a complex function that cannot be represented in a single GlassCalc expression, .cs scripts can be linked in. An xml file containing documentation can also be included.
I’m officially out of interesting titles for these update posts.
There are a good number of fixes and additions in this version. Check the changelog for all the changes, but here’s the highlights:
- Added sinc, rect, nCr and nPr functions. nCr and nPr are for combinations and permutations, respectively.
- Added phi and invphi functions. phi is the standard normal CDF function and invphi is its inverse. I’m not familiar with how this functions is supposed to work—I just used the implementation eli linked here—but it agrees with Wolfram Alpha for the few test values I tried. Please tell me if there are any cases where it gives a wrong answer.
- The “ans” variable now sticks to the bottom of the list so you can find it more easily.
- The side panel now shrinks a bit if you shrink the window so that the history view still gets at least half the width of the window.
- User-defined constants are now colored as such in the input box.
- Fixed a lot of formatting issues, especially with things not in base 10.
Check the GlassCalc page for download links.
GlassCalc 1.33 is a small update, but it adds one feature that should make it a little more convenient. Brace highlighting in the default mode now matches braces when the cursor is next to them but not between them. This means, when you type a closing brace, its opening brace will be highlighted so you can immediately see which brace you just closed.
Version 1.33 also fixes a bug where the code that found function aliases also matched things it shouldn’t have. For instance, when you type
atan2(y, x), GlassCalc changes it to
atan(y, x). Before this fix, GlassCalc would also change
Also, if you downloaded before November 10, I didn’t properly update the version number of the program, so GlassCalc would keep thinking it needs to be updated. This is now fixed.
Check the GlassCalc page for download links.
Today, I bring you yet another update to GlassCalc. Version 1.32 can now display output as fractions using an algorithm by John Kennedy described here. To display a result as a fraction, end it with
0.5->frac = 1/2. The
-> operator (for output in fractions and different bases) also has syntax highlighting now.
I got a bug report earlier alerting me that
22.4 - 21.5 resulted in 0.899999999999999. This happens because there are some numbers which cannot be represented exactly as floating point numbers. 22.4 and 0.9 happen to be two of those numbers. (If you don’t believe me, check out this floating point applet and enter “22.4” in the decimal box. GlassCalc has 64 bit precision instead of 32, but the same idea applies.) As a result,
22.4 - 21.5 almost equals 0.9, but not quite.
Unless someone invents a computer that operates in base 10, there’s no way to really fix this problem, but there are a couple ways to hide it. One is to use higher precision floating point numbers to reduce the error, but I can’t do that until I finish porting MTParser to C#. The other is to round results to hide the error in the last decimal place. By default, GlassCalc now rounds to 14 places when displaying numbers. You can change how much GlassCalc rounds (or turn rounding off) from the settings menu. This rounding only applies to the numbers when they are displayed, so your calculations will be just as accurate (or inaccurate) as they were before.
Pi is another number that cannot be represented exactly in floating point. (It can’t be represented exactly in decimal either) As a result,
sin(pi) resulted in very small, but non-zero numbers. I’ve added a couple overrides into cos() and sin() so that they will return exactly 0 when they’re supposed to. Again, this isn’t perfect.
sin(11pi) won’t return exactly 0, but it’s better than nothing.
Other improvements in the version include: smarter detection of changes in extensions.ini, single digit exponents are no longer padded with a zero, saved history no longer forgets the bases of results, and switching between radians and degrees scrolls the history list to the bottom.
Check the GlassCalc page for download links.
I still haven’t figured out the network problem, but it looks like POST requests involving 2000+ 1500+ characters get blocked.
This is mostly a bugfix release, but I’ve added one handy function: The delete command can now delete multiple variables/functions at once. You can now use expressions like
delete x y f() g(). The parser is also more lenient, so
delete f( will delete f(). Download the new release from the GlassCalc software page or just run the auto-updater.
Since the changelog page is big and my stupid network won’t let me edit big posts, here’s the changelog for this version:
Sorry, the changelog is too big. T_T
I’ll have to keep this short, because there’s some sort of network monster here that eats all of my long posts.
There was a bug in 1.30.1 and lower that caused a crash on startup if GlassCalc was set to save history items and the saved history contained a semicolon. This is now fixed. If you can start GlassCalc without it crashing, the updater should pick up the new version. Otherwise, download the new version (still 1.30) from the GlassCalc software page.
I uploaded GlassCalc 1.30 a few days ago, but a combination of strange network problems and lack of time has kept me from writing about until now. Thanks to the most bizarre network error I have ever seen, I cannot update the changelog page, but I can update everything else. Until I get some help from the campus network people, I’ll post the changes here.
This version mostly fixes a number of bugs. The inverse trig functions were all completely wrong. I promise I will never again blindly copy-paste code without testing it. There are also a number of fixes for non-default multiplication signs. I’ve also added a delete function, which is just another alias for unset, and undefine.
I am currently rewriting the parser code to separate it from the UI thread. This means GlassCalc will no longer freeze while performing long calculations like solve, and I can implement things like evaluating as you type. I have very little knowledge about multi-threaded applications, so the process is long, hard, and completely unlike what those of you with dirty minds are now thinking about. You can check the roadmap to see what else I am working on.
Aug 29, 2010: v1.30.1
- Fixed a problem with uppercase E not being recognized in exponential notation. This also fixed a problem with very large/small scale factors.
Aug 26, 2010: v1.30
- Fixed inverse trig functions (they were broken thanks to blind copy-paste. I’ve implemented unit tests to help keep this from happening again)
- Non-default multiplication sign gets proper syntax highlighting
- Syntax highlighting preview now uses correct multiplication sign
- Non-default multiplication sign will now trigger “ans” autocompletion.
- sinh and cosh now work with degree angles.
- factorial now works on negative numbers
- Added arccos, arcsin, arctan… aliases for acos, asin, atan…
- Added atan2(y,x). This is actually an alias for atan(y,x).
- You can no longer define functions with the same name as aliases.
- Added delete command as another alias for unset and undefine
- UI fixes. Clicking to the left of a result now selects it. Input box background color is once-again changeable.