Fix #222: Wrong result for e.g. √(2.25) - 1.5 #222#2424
Fix #222: Wrong result for e.g. √(2.25) - 1.5 #222#2424tian-lt merged 5 commits intomicrosoft:mainfrom
Conversation
@microsoft-github-policy-service agree |
|
@tian-lt, are you the maintainer of this repo? Could you please take a look at the PR? |
There was a problem hiding this comment.
Pull request overview
This PR fixes issues #222, #309, and #574 where calculations involving irrational number approximations (like √2.25 - 1.5) produced tiny non-zero results instead of zero due to approximation errors in the Ratpak calculation engine.
Key Changes:
- Introduced
_snaprathelper function to detect and snap results to zero when they are magnitudes smaller than input operands beyond precision threshold - Refactored
addrat,subrat, andlogratto have internal versions (_addrat,_subrat,_lograt) without snapping, with public versions applying snapping for user-facing results - Updated all internal Ratpack function calls to use the underscore-prefixed versions to avoid unnecessary snapping during intermediate calculations
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/CalcManager/Ratpack/rat.cpp | Implements the core fix: adds _snaprat function and refactors addrat/subrat to include internal versions without snapping |
| src/CalcManager/Ratpack/exp.cpp | Refactors lograt into internal _lograt and __lograt versions, with public lograt applying snapping; updates internal calls to use _subrat/_addrat |
| src/CalcManager/Ratpack/ratpak.h | Adds function declarations for _addrat, _subrat, _lograt, _snaprat, and moves ABSRAT macro from fact.cpp for reuse |
| src/CalcManager/Ratpack/support.cpp | Updates internal calls to use _addrat/_subrat/_lograt versions |
| src/CalcManager/Ratpack/trans.cpp | Updates internal calls to use _subrat version |
| src/CalcManager/Ratpack/transh.cpp | Updates internal calls to use _subrat/_addrat versions |
| src/CalcManager/Ratpack/itrans.cpp | Updates internal calls to use _addrat/_subrat versions |
| src/CalcManager/Ratpack/itransh.cpp | Updates internal calls to use _addrat/_subrat/_lograt versions |
| src/CalcManager/Ratpack/fact.cpp | Updates internal calls to use _addrat/_subrat/_lograt versions; removes local ABSRAT macro (now in ratpak.h) |
| src/CalcManager/Ratpack/logic.cpp | Updates internal call to use _addrat version |
| src/CalculatorUnitTests/CalculatorManagerTest.cpp | Adds test cases for sqrt(2.25) - 1.5 in both Standard and Scientific modes, and log(sqrt(2.25) / 1.5) test |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/CalcManager/Ratpack/rat.cpp
Outdated
| DUPRAT(threshold, absA); | ||
| } | ||
|
|
There was a problem hiding this comment.
This line has trailing whitespace that should be removed.
| DUPRAT(threshold, absA); | |
| } | |
| DUPRAT(threshold, absA); | |
| } |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@guihuaz |
@tian-lt I thought about adding the change in
|
|
The changes look good to me. |
Looks good to me, too. I tested several cases, and they all passed😉 |
|
It seems that this PR has broken lograt. For example log of 9.e+99 now returns 0 instead of 99.954... |
@axtar do you have dev env? If so, could you please try to try removing _snaprat inside lograt to see if it fixes the issue? I'm not on my windows machine, right now. I might have time to try this weekend. |
|
@guihuaz removing _snaprat in lograt fixes the problem but then of course the problem with log( tan₀( 45 ) ) reappears. |
|
@guihuaz As a temporary solution, I added a check in my project so that _snaprat only snaps to zero if absR is also smaller than rat_smallest. |
| ABSRAT(absR); | ||
|
|
||
| // if absResult < threshold => snap to zero | ||
| if (rat_lt(absR, threshold, precision)) |
There was a problem hiding this comment.
(@axtar , move comment here to have a thread)
Do you add a check here? I think this is safe change. Could you please send a PR to add the additional check absR < rat_smallest?
It may expose some other edge cases back, but _snaprat does not likely catch all these cases. In my understanding, the issue is fundamental design flaw in Ratpack. Ratpack, as the name implies, is for arbitrary precision rational math. But it tries to include some irrational math using approximation and rounding. I think this would inevitably introduce errors.
There was a problem hiding this comment.
Yes, I have added an “&&” to that “if”.
I’m sorry but I don’t have the skills to contribute to this repository. I don’t even really know how to make a pull request. I’m simply using ratpak on a microcontroller for a hobbyist hardware calculator project. That’s why I found the issue.
Approximation and rounding issues are difficult to fix but for a calculator arbitrary precision is always better than 64-bit floating point arithmetic. I really like ratpak, it's small and very efficient. But it has a lot of memory leaks that I had to fix to run it on a microcontroller.
Fixes #222, #309, #574
Description of the changes:
sqrt(2.25) - 1.5for example.sqrt(2.25)might be approximated to1.499...998...depending on the precision. When this number subtracted1.5, the Ratpak got0.000...001....Ratpak took up to precision number of digits and converts to scientific format, which resulted-1.2566515751494548126925332972115e-47. This PR checks the magnitude difference between the result and the input operands. Since the result is too close to47magnitude smaller than original subtraction operands1.499...998...and1.5, it would be snapped to0.logratas well.How changes were validated:
CalculatorManagerTestStandardto verify addrat.CalculatorManagerTestScientificto verify addrat and logratlog(sqrt(2.25)/1.5)