-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Run] Fix Scientific Notation Errors in Calculator Plugin #28884
[Run] Fix Scientific Notation Errors in Calculator Plugin #28884
Conversation
After adding logic to replace `e` as a mathematical constant, there are bugs when trying to use expressions like `5e3`. This change parses the `<number>e<number>` format into expanded form to prevent replacement with the constant. Regex explanation: `(\d+\.*\d*)[eE](-*\d+) `(\d+\.*\d*)`: Match any number of digits, followed by an optional `.` and more optional digits. The expression is used to capture things like: `5.0`, `1.`, `1` before the `e` `[eE]`: Match either upper or lowercase `e` `(-*\d+)`: Capture an optional `-` sign as well as a number of digits
The new regex captures a wider variety of numbers. See this post for details on the regex used: https://stackoverflow.com/a/23872060
@microsoft-github-policy-service agree |
Using `[` didn't capture the expression properly. Had to use `(` instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestions to improve/clarify regex included, but otherwise looks good.
src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/CalculateHelper.cs
Outdated
Show resolved
Hide resolved
src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/CalculateHelper.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add these fast
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, Sorry for the time I took in reviewing this PR. I thought changes were still being discussed.
Thanks for opening the PR.
It looks good to me, but I think scientific notation should only be with the upper case "E".
The main reason being that currently there can be some ambiguous expressions with the constant "e",
What do you think?
@viggyd , Please let me know what you think of the change I proposed (uppercase |
Sorry, for some reason I wasn't getting notifications for this. There is one change in the regex to make because it could accept multiple decimal points. I don't have strong opinions on the capital E, using lowercase is what I'm used to, but I agree it is ambiguous with other usage. I'll make it stricter to reduce that ambiguity. I can push the changes up this evening. If you need them sooner, you're welcome to make them also! |
Thanks @viggy . I'm not sure what you mean with the multiple decimal points. Anyway, I don't think this is ready to go in yet after a re-review, because it doesn't support different decimal or number grouping characters. |
Could you elaborate what you mean by different decimal or number grouping characters? I don't follow. I can add whatever additional changes are necessary |
Hi @viggyd , With these languages the calculator plugin supports the decimal point of the locale. Here's one example: There's even languages that use . as a group separator. Here's Germany(German), for example: But with this PR, it assumes . will always be the decimal separator: |
Are there any functions to get the decimal separator? |
In NumberTranslator.cs there's references to |
@viggyd |
@viggyd Any progress here? Do you need some more help? |
I'm sorry, I completely forgot about this issue. I'll be able to work on it this weekend, should have something that works by then |
Previous regular expression did not allow decimal separators that were not ".". The new expression uses the culture info decimal separator instead, which should work better.
Okay, I pushed my update that accounts for various decimal separators, sorry for the delay! |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two details
if (CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == ".") | ||
{ | ||
p = string.Format(CultureInfo.CurrentCulture, p, @"\."); | ||
} | ||
else | ||
{ | ||
p = string.Format( | ||
CultureInfo.CurrentCulture, | ||
p, | ||
CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, this can also be done with a ternary. But both would work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought a ternary would take too much horizontal space because the CultureInfo.CurrentCulture...
is a lot of characters so I left it at the expanded if/else instead
CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); | ||
} | ||
|
||
var r = "($1 * 10^($5))"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why create a variable for a single use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No particular reason, I was just following a similar format to other functions that are already in the file. I updated the code to remove the single use variable in my latest push
src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/CalculateHelper.cs
Outdated
Show resolved
Hide resolved
@@ -18,6 +20,7 @@ public static class CalculateHelper | |||
@"sinh\s*\(|cosh\s*\(|tanh\s*\(|arsinh\s*\(|arcosh\s*\(|artanh\s*\(|" + | |||
@"pi|" + | |||
@"==|~=|&&|\|\||" + | |||
@"((-?(\d+(\.\d*)?)|-?(\.\d+))[E](-?\d+\.*\d*))|" + /* expression from CheckScientificNotation between parenthesis */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it be updated here as well? only integer after E
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops. Fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks :) Change looks good to me, I'll just give it a test and then it'll be good to go! :)
Missed this expression in my last update. Whoops
* -?(\d+({0}\d*)?): Captures a decimal number starting with a number (e.g. "-1.23") | ||
* -?({0}\d+): Captures a decimal number without leading number (e.g. ".23") | ||
* E: Captures capital 'E' | ||
* (-?\d+{0}?\d*): Captures an integer number (e.g. "-1" or "23") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need a comment update here as well :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/CalculateHelper.cs
Outdated
Show resolved
Hide resolved
…lculator/CalculateHelper.cs
Part of the problem is that there's a lot of other expressions that already allow expressions in parentheses followed by any number of spaces and it treats that as valid. So I can do something like Edit: Just checked and it doesn't even have to be in parentheses. |
looks like we accept this in general. I'm still worried that e.g. 1E1.5 might confuse users, because 10^1.5 is valid math expression, but E shouldn't accept decimal after (Windows calculator also prevent this when using exp).. Let's keep it as is as we respect the rules here. there is another problem now. If I change the numbers format, as @jaimecbernardo mentioned above, to e.g. Portuguese: Regex is correctly matched, but the result is wrong 🤔 |
I see the problem. Ordinarily, the That being said, I'm not sure why the translator isn't properly parsing the input. Seems like it's not recognizing the I can try to either:
I think I'd prefer option 1 since that seems cleaner. I'll need to look into the translator and see how to make it recognize scientific notation input properly. |
I agree. Let's try the option number 1 |
Yeah, those different possibilities for decimals are always a trouble. Important Both "...just remove the decimal separator logic in the calculator engine" and "Just make the calculator engine replace any decimal separators" actually sound dangerous and could possibly lead to a regression resulting in bad calculations. Note that a number like "one-thousand two-hundred thirty four" in some languages is written as Whatever is going to be done, it needs to be tested with all permutations. |
Okay, I think the issue in the NumberTranslator's Because the regular expression is allowing characters I'm assuming the allowance of |
Darn it, you're absolutely right. In short, there is no way to tell if Having that said... Isn't scientific notation better to use for results, only? I mean, there's an inherent "insecurity" (or what's the word?) regarding significance. Like, when you say there are (about) 8 billion people on the planet, that's not an exact number. You could write it as 8B or 8E9. Note that both these are also valid as hexadecimal. What I mean is, you normally do not calculate anything with these kinds of estimates. |
The hex regex stuff is only used once, there's no need to keep track of it in the object's state. Just create it during the translation process.
I think maybe uncertainty is the word you're looking for? While that certainly is a use case, I have used scientific notation in PowerToys in the past for the purposes of calculation. It's a convenience when working with smaller numbers, so that rather than needing to put in It looks like PowerToys does require the Something like (pseudocode): string[] hex_norm_tokens = hexRegex.Split(input);
foreach (string token in hex_norm_tokens)
{
if (token.startswith == "0x")
{
// Add to output builder - no further processing needed
continue;
}
string[] reg_tokens = splitRegex.Split(token);
// All current tokenization happens here
...
} Should be able to split out hexadecimals on something like this: I tested this locally and its seems to work well. I'm wondering if I should update the unit tests as well. There's a few edge cases that we talked about during this conversation that'd be good to codify in unit tests somewhere to catch any regressions if they happen in the future |
Alrighty. If the 0x prefix is/becomes mandatory, we must make sure this clear in the documentations. But if it works, it works. |
Okay, pushed a change that now includes a unit test for scientific notation in other cultures. It's very small though, let me know if there are any other cases I should test. I couldn't think of anything else that wasn't covered by a different test somewhere else. I can also move the tests I added in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good now! Nice work! Thanks for the contribution! :)
Summary of the Pull Request
This PR allows the Calculator plugin in PowerToys Run to use scientific notation (e.g.
5e3 = 5000
). The PR fixes a regression in PowerToys that was introduced in v0.69.1.PR Checklist
Detailed Description of the Pull Request / Additional comments
Nothing else fixed.
Validation Steps Performed
I updated the Calculator unit tests to include various expressions using this notation and confirmed that they all pass.