Compare commits

..

15 Commits
main ... dkj

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

@ -1,5 +1,5 @@
## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details.
## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details.
pipelines:
141517:
retail:

@ -0,0 +1,2 @@
# calculator-z

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 206 KiB

@ -1,135 +1,135 @@
id:
name: GitOps.PullRequestIssueManagement
description: GitOps.PullRequestIssueManagement primitive
owner:
resource: repository
disabled: false
where:
configuration:
resourceManagementConfiguration:
scheduledSearches:
- description:
frequencies:
- hourly:
hour: 3
filters:
- isPullRequest
- isOpen
- hasLabel:
label: needs author feedback
- noActivitySince:
days: 7
- isNotLabeledWith:
label: no recent activity
actions:
- addLabel:
label: no recent activity
- addReply:
reply: This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. Thank you for your contributions to Windows Calculator!
eventResponderTasks:
- if:
- payloadType: Issue_Comment
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Issues
- isAction:
action: Closed
then:
- removeLabel:
label: needs pitch review
- removeLabel:
label: needs more info
- removeLabel:
label: needs spec
- removeLabel:
label: no recent activity
- removeLabel:
label: help wanted
- removeLabel:
label: needs spec review
- removeLabel:
label: needs spec
description:
triggerOnOwnActions: true
- if:
- payloadType: Pull_Request_Review
- isAction:
action: Submitted
- isReviewState:
reviewState: Changes_requested
then:
- addLabel:
label: needs author feedback
description:
- if:
- payloadType: Pull_Request
- isActivitySender:
issueAuthor: True
- not:
isAction:
action: Closed
- hasLabel:
label: needs author feedback
then:
- removeLabel:
label: needs author feedback
description:
- if:
- payloadType: Issue_Comment
- isActivitySender:
issueAuthor: True
- hasLabel:
label: needs author feedback
then:
- removeLabel:
label: needs author feedback
description:
- if:
- payloadType: Pull_Request_Review
- isActivitySender:
issueAuthor: True
- hasLabel:
label: needs author feedback
then:
- removeLabel:
label: needs author feedback
description:
- if:
- payloadType: Pull_Request
- not:
isAction:
action: Closed
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Issue_Comment
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Pull_Request_Review
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Issue_Comment
then:
- cleanEmailReply
description:
onFailure:
onSuccess:
id:
name: GitOps.PullRequestIssueManagement
description: GitOps.PullRequestIssueManagement primitive
owner:
resource: repository
disabled: false
where:
configuration:
resourceManagementConfiguration:
scheduledSearches:
- description:
frequencies:
- hourly:
hour: 3
filters:
- isPullRequest
- isOpen
- hasLabel:
label: needs author feedback
- noActivitySince:
days: 7
- isNotLabeledWith:
label: no recent activity
actions:
- addLabel:
label: no recent activity
- addReply:
reply: This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. Thank you for your contributions to Windows Calculator!
eventResponderTasks:
- if:
- payloadType: Issue_Comment
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Issues
- isAction:
action: Closed
then:
- removeLabel:
label: needs pitch review
- removeLabel:
label: needs more info
- removeLabel:
label: needs spec
- removeLabel:
label: no recent activity
- removeLabel:
label: help wanted
- removeLabel:
label: needs spec review
- removeLabel:
label: needs spec
description:
triggerOnOwnActions: true
- if:
- payloadType: Pull_Request_Review
- isAction:
action: Submitted
- isReviewState:
reviewState: Changes_requested
then:
- addLabel:
label: needs author feedback
description:
- if:
- payloadType: Pull_Request
- isActivitySender:
issueAuthor: True
- not:
isAction:
action: Closed
- hasLabel:
label: needs author feedback
then:
- removeLabel:
label: needs author feedback
description:
- if:
- payloadType: Issue_Comment
- isActivitySender:
issueAuthor: True
- hasLabel:
label: needs author feedback
then:
- removeLabel:
label: needs author feedback
description:
- if:
- payloadType: Pull_Request_Review
- isActivitySender:
issueAuthor: True
- hasLabel:
label: needs author feedback
then:
- removeLabel:
label: needs author feedback
description:
- if:
- payloadType: Pull_Request
- not:
isAction:
action: Closed
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Issue_Comment
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Pull_Request_Review
- hasLabel:
label: no recent activity
then:
- removeLabel:
label: no recent activity
description:
- if:
- payloadType: Issue_Comment
then:
- cleanEmailReply
description:
onFailure:
onSuccess:

@ -1,99 +0,0 @@
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: true
BreakStringLiterals: true
ColumnLimit: 160
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Single
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
#...
# unsupported rules
#BreakInheritanceList: AfterColon
#Language: None
#ObjCBinPackProtocolList: Auto
#PenaltyBreakTemplateDeclaration: 10
#SpaceBeforeCpp11BracedList: false
#SpaceBeforeCtorInitializerColon: true
#SpaceBeforeInheritanceColon: true
#SpaceBeforeRangeBasedForLoopColon: true

@ -1,10 +0,0 @@
## IDE-independent coding style via EditorConfig: https://editorconfig.org/
root = true
[*]
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

@ -1,40 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
*.cs diff=csharp
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
*.jpg binary
*.png binary
*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

@ -1,298 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Code
.vscode/
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# Calculator specific
Generated Files/
src/GraphControl/GraphingImplOverrides.props
src/CalcViewModel/DataLoaders/DataLoaderConstants.h
!src/x64
!src/x86
!src/out

@ -1,104 +0,0 @@
# Contributing to Calculator
The Calculator team encourages community feedback and contributions. Thank you for your interest in
making Calculator better! There are several ways you can get involved.
## Reporting issues and suggesting new features
If Calculator is not working properly, please file a report in the
[Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130&newFeedback=True).
Feedback Hub reports automatically include diagnostic data, such as the version of Calculator
you're using.
We are happy to hear your ideas for the future of Calculator. Check the
[Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130) and see if others have
submitted similar feedback. You can upvote existing feedback or submit a new suggestion.
We always look at upvoted items in Feedback Hub when we decide what to work on next. We read the
comments in both Feedback Hub and GitHub, and we look forward to hearing your input. Remember that
all community interactions must abide by the [Code of Conduct](CODE_OF_CONDUCT.md).
## Finding issues you can help with
Looking for something to work on?
Issues marked [``good first issue``](https://github.com/Microsoft/calculator/labels/good%20first%20issue)
are a good place to start.
You can also check the [``help wanted``](https://github.com/Microsoft/calculator/labels/help%20wanted) tag to find
other issues to help with. If you're interested in working on a fix, leave a comment to let everyone know and to help
avoid duplicated effort from others.
## Contributions we accept
We welcome your contributions to the Calculator project, especially to fix bugs and to make
improvements which address the top issues reported by Calculator users. Some general guidelines:
* **DO** create one pull request per Issue, and ensure that the Issue is linked in the pull request.
* **DO** follow our [Coding and Style](#style-guidelines) guidelines, and keep code changes as small as possible.
* **DO** include corresponding tests whenever possible.
* **DO** check for additional occurrences of the same problem in other parts of the codebase before submitting your PR.
* **DO** [link the issue](https://github.com/blog/957-introducing-issue-mentions) you are addressing in the
pull request.
* **DO** write a good description for your pull request. More detail is better. Describe *why* the change is being
made and *why* you have chosen a particular solution. Describe any manual testing you performed to validate your change.
* **DO NOT** submit a PR unless it is linked to an Issue marked
[`triage approved`](https://github.com/Microsoft/calculator/issues?q=is%3Aissue+is%3Aopen+label%3A%22Triage%3A+Approved%22).
This enables us to have a discussion on the idea before anyone invests time in an implementation.
* **DO NOT** merge multiple changes into one PR unless they have the same root cause.
* **DO NOT** submit pure formatting/typo changes to code that has not been modified otherwise.
We follow a [user-centered process for developing features](docs/NewFeatureProcess.md). New features
need sponsorship from the Calculator team, but we welcome community contributions at many stages of
the process.
> Submitting a pull request for an approved Issue is not a guarantee it will be approved.
> The change must meet our high bar for code quality, architecture, and performance, as well as
> [other requirements](#docs/NewFeatureProcess.md#technical-review).
## Making changes to the code
### Preparing your development environment
To learn how to build the code and run tests, follow the instructions in the [README](README.md).
### Style guidelines
The code in this project uses several different coding styles, depending on the age and history of
the code. Please attempt to match the style of surrounding code as much as possible. In new
components, prefer the patterns described in the
[C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)
and the [modern C++/WinRT language projections](https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/).
### Testing
Your change should include tests to verify new functionality wherever possible. Code should be
structured so that it can be unit tested independently of the UI. [Manual test cases](docs/ManualTests.md)
should be used where automated testing is not feasible.
### Git workflow
Calculator uses the [GitHub flow](https://guides.github.com/introduction/flow/) where most
development happens directly on the `main` branch. The `main` branch should always be in a
healthy state which is ready for release.
If your change is complex, please clean up the branch history before submitting a pull request.
You can use [git rebase](https://docs.microsoft.com/en-us/azure/devops/repos/git/rebase#squash-local-commits)
to group your changes into a small number of commits which we can review one at a time.
When completing a pull request, we will generally squash your changes into a single commit. Please
let us know if your pull request needs to be merged as separate commits.
## Review Process
After submitting a pull request, members of the calculator team will review your code. We will
assign the request to an appropriate reviewer. Any member of the community may
participate in the review, but at least one member of the Calculator team will ultimately approve
the request.
Often, multiple iterations will be needed to responding to feedback from reviewers. Try looking at
[past pull requests](https://github.com/Microsoft/calculator/pulls?q=is%3Apr+is%3Aclosed) to see
what the experience might be like.
## Contributor License Agreement
Before we can review and accept a pull request from you, you'll need to sign a Contributor License
Agreement (CLA). The CLA ensures that the community is free to use your contributions. More
information about the agreement is available on the [Microsoft web site](https://cla.opensource.microsoft.com/).
Signing the CLA is an automated process, and you only need to do it once for Microsoft projects on
GitHub.
You don't need to sign a CLA until you're ready to create a pull request. When your pull request is
created, it is classified by a bot. If the change is trivial (i.e. you just fixed a typo) then the
bot will label the PR `cla-not-required`. Otherwise, it's classified as `cla-required`. In that
case, the system will also tell you how you can sign the CLA. Once you have signed a CLA, the
current and all future pull requests will be labeled as `cla-signed`.

@ -1,21 +0,0 @@
Copyright (c) Microsoft Corporation. All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,39 +0,0 @@
THIRD PARTY SOFTWARE NOTICES AND INFORMATION
Do Not Translate or Localize
This software incorporates material from third parties. Microsoft makes certain
open source code available at https://3rdpartysource.microsoft.com, or you may
send a check or money order for US $5.00, including the product name, the open
source component name, and version number, to:
Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA
Notwithstanding any other terms, you may reverse engineer this software to the
extent required to debug changes to any libraries licensed under the GNU Lesser
General Public License.
---
Hebrew OpenType Layout logic
The MIT License (MIT)
Copyright (c) 2003, 2007 Ralph Hancock & John Hudson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,76 +0,0 @@
# Calculator
The Windows Calculator app is a modern Windows app written in C++ and C# that ships pre-installed with Windows.
The app provides standard, scientific, and programmer calculator functionality, as well as a set of converters between various units of measurement and currencies.
Calculator ships regularly with new features and bug fixes. You can get the latest version of Calculator in the [Microsoft Store](https://www.microsoft.com/store/apps/9WZDNCRFHVN5).
[![Continuous Integration](https://github.com/microsoft/calculator/actions/workflows/action-ci.yml/badge.svg)](https://github.com/microsoft/calculator/actions/workflows/action-ci.yml)
<img src="docs/Images/CalculatorScreenshot.png" alt="Calculator Screenshot" width="450px" />
## Features
- Standard Calculator functionality which offers basic operations and evaluates commands immediately as they are entered.
- Scientific Calculator functionality which offers expanded operations and evaluates commands using order of operations.
- Programmer Calculator functionality which offers common mathematical operations for developers including conversion between common bases.
- Date Calculation functionality which offers the difference between two dates, as well as the ability to add/subtract years, months and/or days to/from a given input date.
- Calculation history and memory capabilities.
- Conversion between many units of measurement.
- Currency conversion based on data retrieved from [Bing](https://www.bing.com).
- [Infinite precision](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) for basic
arithmetic operations (addition, subtraction, multiplication, division) so that calculations
never lose precision.
## Getting started
Prerequisites:
- Your computer must be running Windows 11, build 22000 or newer.
- Install the latest version of [Visual Studio](https://developer.microsoft.com/en-us/windows/downloads) (the free community edition is sufficient).
- Install the "Universal Windows Platform Development" workload.
- Install the optional "C++ Universal Windows Platform tools" component.
- Install the latest Windows 11 SDK.
![Visual Studio Installation Screenshot](docs/Images/VSInstallationScreenshot.png)
- Install the [XAML Styler](https://marketplace.visualstudio.com/items?itemName=TeamXavalon.XAMLStyler) Visual Studio extension.
- Get the code:
```
git clone https://github.com/Microsoft/calculator.git
```
- Open [src\Calculator.sln](/src/Calculator.sln) in Visual Studio to build and run the Calculator app.
- For a general description of the Calculator project architecture see [ApplicationArchitecture.md](docs/ApplicationArchitecture.md).
- To run the UI Tests, you need to make sure that
[Windows Application Driver (WinAppDriver)](https://github.com/microsoft/WinAppDriver/releases/latest)
is installed.
## Contributing
Want to contribute? The team encourages community feedback and contributions. Please follow our [contributing guidelines](CONTRIBUTING.md).
If Calculator is not working properly, please file a report in the [Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130).
We also welcome [issues submitted on GitHub](https://github.com/Microsoft/calculator/issues).
## Roadmap
For information regarding Windows Calculator plans and release schedule, please see the [Windows Calculator Roadmap](docs/Roadmap.md).
### Graphing Mode
Adding graphing calculator functionality [is on the project roadmap](https://github.com/Microsoft/calculator/issues/338) and we hope that this project can create a great end-user experience around graphing. To that end, the UI from the official in-box Windows Calculator is currently part of this repository, although the proprietary Microsoft-built graphing engine, which also drives graphing in Microsoft Mathematics and OneNote, is not. Community members can still be involved in the creation of the UI, however developer builds will not have graphing functionality due to the use of a [mock implementation of the engine](/src/GraphingImpl/Mocks) built on top of a
[common graphing API](/src/GraphingInterfaces).
## Diagnostic Data
This project collects usage data and sends it to Microsoft to help improve our products and services.
Read our [privacy statement](https://go.microsoft.com/fwlink/?LinkId=521839) to learn more.
Diagnostic data is disabled in development builds by default, and can be enabled with the `SEND_DIAGNOSTICS`
build flag.
## Currency Converter
Windows Calculator includes a currency converter feature that uses mock data in developer builds. The data that
Microsoft uses for the currency converter feature (e.g., in the retail version of the application) is not licensed
for your use. The mock data will be clearly identifiable as it references planets instead of countries,
and remains static regardless of selected inputs.
## Reporting Security Issues
Please refer to [SECURITY.md](./SECURITY.md).
## License
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the [MIT License](./LICENSE).

@ -1,48 +0,0 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.1 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all
source code repositories managed through our GitHub organizations, which include
[Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure),
[DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet),
[Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets
Microsoft's [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10))
of a security vulnerability, please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.** Instead, please
report them to the Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com).
If possible, encrypt your message with our PGP key; please download it from the
[Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155).
You should receive a response within 24 hours. If for some reason you do not, please follow up via
email to ensure we received your original message. Additional information can be found at
[microsoft.com/msrc](https://www.microsoft.com/msrc).
Please include the requested information listed below (as much as you can provide) to help us better
understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of
[Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>

@ -1,339 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include <sstream>
#include "Header Files/CalcEngine.h"
using namespace std;
using namespace CalcEngine;
constexpr int C_NUM_MAX_DIGITS = MAX_STRLEN;
constexpr int C_EXP_MAX_DIGITS = 4;
void CalcNumSec::Clear()
{
value.clear();
m_isNegative = false;
}
void CalcInput::Clear()
{
m_base.Clear();
m_exponent.Clear();
m_hasExponent = false;
m_hasDecimal = false;
m_decPtIndex = 0;
}
bool CalcInput::TryToggleSign(bool isIntegerMode, wstring_view maxNumStr)
{
// Zero is always positive
if (m_base.IsEmpty())
{
m_base.IsNegative(false);
m_exponent.IsNegative(false);
}
else if (m_hasExponent)
{
m_exponent.IsNegative(!m_exponent.IsNegative());
}
else
{
// When in integer only mode, it isn't always allowed to toggle, as toggling can cause the num to be out of
// bounds. For eg. in byte -128 is valid, but when it toggled it becomes 128, which is more than 127.
if (isIntegerMode && m_base.IsNegative())
{
// Decide if this additional digit will fit for the given bit width
if (m_base.value.size() >= maxNumStr.size() && m_base.value.back() > maxNumStr.back())
{
// Last digit is more than the allowed positive number. Fail
return false;
}
}
m_base.IsNegative(!m_base.IsNegative());
}
return true;
}
bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, wstring_view maxNumStr, int32_t wordBitWidth, int maxDigits)
{
// Convert from an integer into a character
// This includes both normal digits and alpha 'digits' for radixes > 10
auto chDigit = static_cast<wchar_t>((value < 10) ? (L'0' + value) : (L'A' + value - 10));
CalcNumSec* pNumSec;
size_t maxCount;
if (m_hasExponent)
{
pNumSec = &m_exponent;
maxCount = C_EXP_MAX_DIGITS;
}
else
{
pNumSec = &m_base;
maxCount = maxDigits;
// Don't include the decimal point in the count. In that way you can enter the maximum allowed precision.
// Precision doesn't include decimal point.
if (HasDecimalPt())
{
maxCount++;
}
// First leading 0 is not counted in input restriction as the output can be of that form
// See NumberToString algorithm. REVIEW: We don't have such input restriction mimicking based on output of NumberToString for exponent
// NumberToString can give 10 digit exponent, but we still restrict the exponent here to be only 4 digits.
if (!pNumSec->IsEmpty() && pNumSec->value.front() == L'0')
{
maxCount++;
}
}
// Ignore leading zeros
if (pNumSec->IsEmpty() && (value == 0))
{
return true;
}
if (pNumSec->value.size() < maxCount)
{
pNumSec->value += chDigit;
return true;
}
// if we are in integer mode, within the base, and we're on the last digit then
// there are special cases where we can actually add one more digit.
if (isIntegerMode && pNumSec->value.size() == maxCount && !m_hasExponent)
{
bool allowExtraDigit = false;
if (radix == 8)
{
switch (wordBitWidth % 3)
{
case 1:
// in 16 or 64bit word size, if the first digit is a 1 we can enter 6 (16bit) or 22 (64bit) digits
allowExtraDigit = (pNumSec->value.front() == L'1');
break;
case 2:
// in 8 or 32bit word size, if the first digit is a 3 or less we can enter 3 (8bit) or 11 (32bit) digits
allowExtraDigit = (pNumSec->value.front() <= L'3');
break;
}
}
else if (radix == 10)
{
// If value length is at least the max, we know we can't add another digit.
if (pNumSec->value.size() < maxNumStr.size())
{
// Compare value to substring of maxNumStr of value.size() length.
// If cmpResult > 0:
// eg. max is "127", and the current number is "20". first digit itself says we are out.
// Additional digit is not possible
// If cmpResult < 0:
// Success case. eg. max is "127", and current number is say "11". The second digit '1' being <
// corresponding digit '2', means all digits are possible to append, like 119 will still be < 127
// If cmpResult == 0:
// Undecided still. The case when max is "127", and current number is "12". Look for the new number being 7 or less to allow
auto cmpResult = pNumSec->value.compare(0, wstring::npos, maxNumStr, 0, pNumSec->value.size());
if (cmpResult < 0)
{
allowExtraDigit = true;
}
else if (cmpResult == 0)
{
auto lastChar = maxNumStr[pNumSec->value.size()];
if (chDigit <= lastChar)
{
allowExtraDigit = true;
}
else if (pNumSec->IsNegative() && chDigit <= lastChar + 1)
{
// Negative value case, eg. max is "127", and current number is "-12". Then 8 is also valid, as the range
// is always from -(max+1)...max in signed mode
allowExtraDigit = true;
}
}
}
}
if (allowExtraDigit)
{
pNumSec->value += chDigit;
return true;
}
}
return false;
}
bool CalcInput::TryAddDecimalPt()
{
// Already have a decimal pt or we're in the exponent
if (m_hasDecimal || m_hasExponent)
{
return false;
}
if (m_base.IsEmpty())
{
m_base.value += L'0'; // Add a leading zero
}
m_decPtIndex = m_base.value.size();
m_base.value += m_decSymbol;
m_hasDecimal = true;
return true;
}
bool CalcInput::HasDecimalPt()
{
return m_hasDecimal;
}
bool CalcInput::TryBeginExponent()
{
// For compatibility, add a trailing dec point to base num if it doesn't have one
TryAddDecimalPt();
if (m_hasExponent) // Already entering exponent
{
return false;
}
m_hasExponent = true; // Entering exponent
return true;
}
void CalcInput::Backspace()
{
if (m_hasExponent)
{
if (!m_exponent.IsEmpty())
{
m_exponent.value.pop_back();
if (m_exponent.IsEmpty())
{
m_exponent.Clear();
}
}
else
{
m_hasExponent = false;
}
}
else
{
if (!m_base.IsEmpty())
{
m_base.value.pop_back();
if (m_base.value == L"0")
{
m_base.value.pop_back();
}
}
if (m_base.value.size() <= m_decPtIndex)
{
// Backed up over decimal point
m_hasDecimal = false;
m_decPtIndex = 0;
}
if (m_base.IsEmpty())
{
m_base.Clear();
}
}
}
void CalcInput::SetDecimalSymbol(wchar_t decSymbol)
{
if (m_decSymbol != decSymbol)
{
m_decSymbol = decSymbol;
if (m_hasDecimal)
{
// Change to new decimal pt
m_base.value[m_decPtIndex] = m_decSymbol;
}
}
}
bool CalcInput::IsEmpty()
{
return m_base.IsEmpty() && !m_hasExponent && m_exponent.IsEmpty() && !m_hasDecimal;
}
wstring CalcInput::ToString(uint32_t radix)
{
// In theory both the base and exponent could be C_NUM_MAX_DIGITS long.
if ((m_base.value.size() > MAX_STRLEN) || (m_hasExponent && m_exponent.value.size() > MAX_STRLEN))
{
return wstring();
}
wstring result;
if (m_base.IsNegative())
{
result = L'-';
}
if (m_base.IsEmpty())
{
result += L'0';
}
else
{
result += m_base.value;
}
if (m_hasExponent)
{
// Add a decimal point if it is not already there
if (!m_hasDecimal)
{
result += m_decSymbol;
}
result += ((radix == 10) ? L'e' : L'^');
result += (m_exponent.IsNegative() ? L'-' : L'+');
if (m_exponent.IsEmpty())
{
result += L'0';
}
else
{
result += m_exponent.value;
}
}
// Base and Exp can each be up to C_NUM_MAX_DIGITS in length, plus 4 characters for sign, dec, exp, and expSign.
if (result.size() > C_NUM_MAX_DIGITS * 2 + 4)
{
return wstring();
}
return result;
}
Rational CalcInput::ToRational(uint32_t radix, int32_t precision)
{
PRAT rat = StringToRat(m_base.IsNegative(), m_base.value, m_exponent.IsNegative(), m_exponent.value, radix, precision);
if (rat == nullptr)
{
return 0;
}
Rational result{ rat };
destroyrat(rat);
return result;
}

@ -1,56 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
bool IsOpInRange(OpCode op, uint32_t x, uint32_t y)
{
return ((op >= x) && (op <= y));
}
bool IsBinOpCode(OpCode opCode)
{
return IsOpInRange(opCode, IDC_AND, IDC_PWR) || IsOpInRange(opCode, IDC_BINARYEXTENDEDFIRST, IDC_BINARYEXTENDEDLAST);
}
// WARNING: IDC_SIGN is a special unary op but still this doesn't catch this. Caller has to be aware
// of it and catch it themselves or not needing this
bool IsUnaryOpCode(OpCode opCode)
{
return (IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST) || IsOpInRange(opCode, IDC_UNARYEXTENDEDFIRST, IDC_UNARYEXTENDEDLAST));
}
bool IsDigitOpCode(OpCode opCode)
{
return IsOpInRange(opCode, IDC_0, IDC_F);
}
// Some commands are not affecting the state machine state of the calc flow. But these are more of
// some gui mode kind of settings (eg Inv button, or Deg,Rad , Back etc.). This list is getting bigger & bigger
// so we abstract this as a separate routine. Note: There is another side to this. Some commands are not
// gui mode setting to begin with, but once it is discovered it is invalid and we want to behave as though it
// was never inout, we need to revert the state changes made as a result of this test
bool IsGuiSettingOpCode(OpCode opCode)
{
if (IsOpInRange(opCode, IDM_HEX, IDM_BIN) || IsOpInRange(opCode, IDM_QWORD, IDM_BYTE) || IsOpInRange(opCode, IDM_DEG, IDM_GRAD))
{
return true;
}
switch (opCode)
{
case IDC_INV:
case IDC_FE:
case IDC_MCLEAR:
case IDC_BACK:
case IDC_EXP:
case IDC_STORE:
case IDC_MPLUS:
case IDC_MMINUS:
return true;
}
// most of the commands
return false;
}

@ -1,521 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "Header Files/CalcEngine.h"
#include "Command.h"
#include "winerror_cross_platform.h"
constexpr int ASCII_0 = 48;
using namespace std;
using namespace CalcEngine;
namespace
{
template <typename T>
static void Truncate(vector<T>& v, unsigned int index)
{
if (index >= v.size())
{
throw E_BOUNDS;
}
auto startIter = v.begin() + index;
v.erase(startIter, v.end());
}
}
void CHistoryCollector::ReinitHistory()
{
m_lastOpStartIndex = -1;
m_lastBinOpStartIndex = -1;
m_curOperandIndex = 0;
m_bLastOpndBrace = false;
if (m_spTokens != nullptr)
{
m_spTokens->clear();
}
if (m_spCommands != nullptr)
{
m_spCommands->clear();
}
}
// Constructor
// Can throw Out of memory error
CHistoryCollector::CHistoryCollector(ICalcDisplay* pCalcDisplay, std::shared_ptr<IHistoryDisplay> pHistoryDisplay, wchar_t decimalSymbol)
: m_pHistoryDisplay(pHistoryDisplay)
, m_pCalcDisplay(pCalcDisplay)
, m_iCurLineHistStart(-1)
, m_decimalSymbol(decimalSymbol)
{
ReinitHistory();
}
CHistoryCollector::~CHistoryCollector()
{
m_pHistoryDisplay = nullptr;
m_pCalcDisplay = nullptr;
if (m_spTokens != nullptr)
{
m_spTokens->clear();
}
}
void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& rat, bool fRepetition)
{
int iCommandEnd = AddCommand(GetOperandCommandsFromString(numStr, rat));
m_lastOpStartIndex = IchAddSzToEquationSz(numStr, iCommandEnd);
if (fRepetition)
{
SetExpressionDisplay();
}
m_bLastOpndBrace = false;
m_lastBinOpStartIndex = -1;
}
void CHistoryCollector::RemoveLastOpndFromHistory()
{
TruncateEquationSzFromIch(m_lastOpStartIndex);
SetExpressionDisplay();
m_lastOpStartIndex = -1;
// This will not restore the m_lastBinOpStartIndex, as it isn't possible to remove that also later
}
void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool isIntegerMode, bool fNoRepetition)
{
int iCommandEnd = AddCommand(std::make_shared<CBinaryCommand>(nOpCode));
m_lastBinOpStartIndex = IchAddSzToEquationSz(L" ", -1);
IchAddSzToEquationSz(CCalcEngine::OpCodeToBinaryString(nOpCode, isIntegerMode), iCommandEnd);
IchAddSzToEquationSz(L" ", -1);
if (fNoRepetition)
{
SetExpressionDisplay();
}
m_lastOpStartIndex = -1;
}
// This is expected to be called when a binary op in the last say 1+2+ is changing to another one say 1+2* (+ changed to *)
// It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new
// one isn't. (Eg. 1*2* to 1*2^). It can add explicit brackets to ensure the precedence is inverted. (Eg. (1*2) ^)
void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntegerMode)
{
TruncateEquationSzFromIch(m_lastBinOpStartIndex);
if (fPrecInvToHigher)
{
EnclosePrecInversionBrackets();
}
AddBinOpToHistory(nOpCode, isIntegerMode);
}
void CHistoryCollector::PushLastOpndStart(int ichOpndStart)
{
int ich = (ichOpndStart == -1) ? m_lastOpStartIndex : ichOpndStart;
if (m_curOperandIndex < static_cast<int>(m_operandIndices.size()))
{
m_operandIndices[m_curOperandIndex++] = ich;
}
}
void CHistoryCollector::PopLastOpndStart()
{
if (m_curOperandIndex > 0)
{
m_lastOpStartIndex = m_operandIndices[--m_curOperandIndex];
}
}
void CHistoryCollector::AddOpenBraceToHistory()
{
AddCommand(std::make_shared<CParentheses>(IDC_OPENP));
int ichOpndStart = IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_OPENP), -1);
PushLastOpndStart(ichOpndStart);
SetExpressionDisplay();
m_lastBinOpStartIndex = -1;
}
void CHistoryCollector::AddCloseBraceToHistory()
{
AddCommand(std::make_shared<CParentheses>(IDC_CLOSEP));
IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_CLOSEP), -1);
SetExpressionDisplay();
PopLastOpndStart();
m_lastBinOpStartIndex = -1;
m_bLastOpndBrace = true;
}
void CHistoryCollector::EnclosePrecInversionBrackets()
{
// Top of the Opnd starts index or 0 is nothing is in top
int ichStart = (m_curOperandIndex > 0) ? m_operandIndices[m_curOperandIndex - 1] : 0;
InsertSzInEquationSz(CCalcEngine::OpCodeToString(IDC_OPENP), -1, ichStart);
IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_CLOSEP), -1);
}
bool CHistoryCollector::FOpndAddedToHistory() const
{
return (-1 != m_lastOpStartIndex);
}
// AddUnaryOpToHistory
//
// This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt),
// this routine will ensure the last sqrt call unary operator, actually goes back in history and wraps 4 in sqrt(4)
//
void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, AngleType angletype)
{
int iCommandEnd;
// When successfully applying a unary op, there should be an opnd already
// A very special case of % which is a funny post op unary op.
if (IDC_PERCENT == nOpCode)
{
iCommandEnd = AddCommand(std::make_shared<CUnaryCommand>(nOpCode));
IchAddSzToEquationSz(CCalcEngine::OpCodeToString(nOpCode), iCommandEnd);
}
else // all the other unary ops
{
std::shared_ptr<IOperatorCommand> spExpressionCommand;
if (IDC_SIGN == nOpCode)
{
spExpressionCommand = std::make_shared<CUnaryCommand>(nOpCode);
}
else
{
CalculationManager::Command angleOpCode;
if (angletype == AngleType::Degrees)
{
angleOpCode = CalculationManager::Command::CommandDEG;
}
else if (angletype == AngleType::Radians)
{
angleOpCode = CalculationManager::Command::CommandRAD;
}
else // (angletype == AngleType::Gradians)
{
angleOpCode = CalculationManager::Command::CommandGRAD;
}
int command = nOpCode;
switch (nOpCode)
{
case IDC_SIN:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandASIN) : IDC_SIN;
spExpressionCommand = std::make_shared<CUnaryCommand>(static_cast<int>(angleOpCode), command);
break;
case IDC_COS:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandACOS) : IDC_COS;
spExpressionCommand = std::make_shared<CUnaryCommand>(static_cast<int>(angleOpCode), command);
break;
case IDC_TAN:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandATAN) : IDC_TAN;
spExpressionCommand = std::make_shared<CUnaryCommand>(static_cast<int>(angleOpCode), command);
break;
case IDC_SINH:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandASINH) : IDC_SINH;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
case IDC_COSH:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandACOSH) : IDC_COSH;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
case IDC_TANH:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandATANH) : IDC_TANH;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
case IDC_SEC:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandASEC) : IDC_SEC;
spExpressionCommand = std::make_shared<CUnaryCommand>(static_cast<int>(angleOpCode), command);
break;
case IDC_CSC:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandACSC) : IDC_CSC;
spExpressionCommand = std::make_shared<CUnaryCommand>(static_cast<int>(angleOpCode), command);
break;
case IDC_COT:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandACOT) : IDC_COT;
spExpressionCommand = std::make_shared<CUnaryCommand>(static_cast<int>(angleOpCode), command);
break;
case IDC_SECH:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandASECH) : IDC_SECH;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
case IDC_CSCH:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandACSCH) : IDC_CSCH;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
case IDC_COTH:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandACOTH) : IDC_COTH;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
case IDC_LN:
command = fInv ? static_cast<int>(CalculationManager::Command::CommandPOWE) : IDC_LN;
spExpressionCommand = std::make_shared<CUnaryCommand>(command);
break;
default:
spExpressionCommand = std::make_shared<CUnaryCommand>(nOpCode);
}
}
iCommandEnd = AddCommand(spExpressionCommand);
wstring operandStr{ CCalcEngine::OpCodeToUnaryString(nOpCode, fInv, angletype) };
if (!m_bLastOpndBrace) // The opnd is already covered in braces. No need for additional braces around it
{
operandStr.append(CCalcEngine::OpCodeToString(IDC_OPENP));
}
InsertSzInEquationSz(operandStr, iCommandEnd, m_lastOpStartIndex);
if (!m_bLastOpndBrace)
{
IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_CLOSEP), -1);
}
}
SetExpressionDisplay();
m_bLastOpndBrace = false;
// m_lastOpStartIndex remains the same as last opnd is just replaced by unaryop(lastopnd)
m_lastBinOpStartIndex = -1;
}
// Called after = with the result of the equation
// Responsible for clearing the top line of current running history display, as well as adding yet another element to
// history of equations
void CHistoryCollector::CompleteHistoryLine(wstring_view numStr)
{
if (nullptr != m_pHistoryDisplay)
{
unsigned int addedItemIndex = m_pHistoryDisplay->AddToHistory(m_spTokens, m_spCommands, numStr);
m_pCalcDisplay->OnHistoryItemAdded(addedItemIndex);
}
m_spTokens = nullptr;
m_spCommands = nullptr;
m_iCurLineHistStart = -1; // It will get recomputed at the first Opnd
ReinitHistory();
}
void CHistoryCollector::CompleteEquation(std::wstring_view numStr)
{
// Add only '=' token and not add EQU command, because
// EQU command breaks loading from history (it duplicate history entries).
IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_EQU), -1);
SetExpressionDisplay();
CompleteHistoryLine(numStr);
}
void CHistoryCollector::ClearHistoryLine(wstring_view errStr)
{
if (errStr.empty()) // in case of error let the display stay as it is
{
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(
std::make_shared<std::vector<std::pair<std::wstring, int>>>(), std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>());
}
m_iCurLineHistStart = -1; // It will get recomputed at the first Opnd
ReinitHistory();
}
}
// Adds the given string psz to the globally maintained current equation string at the end.
// Also returns the 0 based index in the string just added. Can throw out of memory error
int CHistoryCollector::IchAddSzToEquationSz(wstring_view str, int icommandIndex)
{
if (m_spTokens == nullptr)
{
m_spTokens = std::make_shared<std::vector<std::pair<std::wstring, int>>>();
}
m_spTokens->push_back(std::pair(wstring(str), icommandIndex));
return static_cast<int>(m_spTokens->size() - 1);
}
// Inserts a given string into the global m_pszEquation at the given index ich taking care of reallocations etc.
void CHistoryCollector::InsertSzInEquationSz(wstring_view str, int icommandIndex, int ich)
{
m_spTokens->emplace(m_spTokens->begin() + ich, wstring(str), icommandIndex);
}
// Chops off the current equation string from the given index
void CHistoryCollector::TruncateEquationSzFromIch(int ich)
{
// Truncate commands
int minIdx = -1;
unsigned int nTokens = static_cast<unsigned int>(m_spTokens->size());
for (unsigned int i = ich; i < nTokens; i++)
{
const auto& currentPair = (*m_spTokens)[i];
int curTokenId = currentPair.second;
if (curTokenId != -1)
{
if ((minIdx != -1) || (curTokenId < minIdx))
{
minIdx = curTokenId;
Truncate(*m_spCommands, minIdx);
}
}
}
Truncate(*m_spTokens, ich);
}
// Adds the m_pszEquation into the running history text
void CHistoryCollector::SetExpressionDisplay()
{
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(m_spTokens, m_spCommands);
}
}
int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand)
{
if (m_spCommands == nullptr)
{
m_spCommands = std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>();
}
m_spCommands->push_back(spCommand);
return static_cast<int>(m_spCommands->size() - 1);
}
// To Update the operands in the Expression according to the current Radix
void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precision)
{
if (m_spTokens == nullptr)
{
return;
}
for (auto& token : *m_spTokens)
{
int commandPosition = token.second;
if (commandPosition != -1)
{
const std::shared_ptr<IExpressionCommand>& expCommand = m_spCommands->at(commandPosition);
if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
{
const std::shared_ptr<COpndCommand>& opndCommand = std::static_pointer_cast<COpndCommand>(expCommand);
if (opndCommand != nullptr)
{
token.first = opndCommand->GetString(radix, precision);
opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
}
}
}
}
SetExpressionDisplay();
}
void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)
{
m_decimalSymbol = decimalSymbol;
}
// Update the commands corresponding to the passed string Number
std::shared_ptr<std::vector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) const
{
std::shared_ptr<std::vector<int>> commands = std::make_shared<std::vector<int>>();
// Check for negate
bool fNegative = (numStr[0] == L'-');
for (size_t i = (fNegative ? 1 : 0); i < numStr.length(); i++)
{
if (numStr[i] == m_decimalSymbol)
{
commands->push_back(IDC_PNT);
}
else if (numStr[i] == L'e')
{
commands->push_back(IDC_EXP);
}
else if (numStr[i] == L'-')
{
commands->push_back(IDC_SIGN);
}
else if (numStr[i] == L'+')
{
// Ignore.
}
// Number
else
{
int num = static_cast<int>(numStr[i]) - ASCII_0;
num += IDC_0;
commands->push_back(num);
}
}
// If the number is negative, append a sign command at the end.
if (fNegative)
{
commands->push_back(IDC_SIGN);
}
return commands;
}
std::shared_ptr<COpndCommand> CHistoryCollector::GetOperandCommandsFromString(std::wstring_view numStr, Rational const& rat) const
{
std::shared_ptr<std::vector<int>> commands = std::make_shared<vector<int>>();
// Check for negate
bool fNegative = (numStr[0] == L'-');
bool fSciFmt = false;
bool fDecimal = false;
for (size_t i = (fNegative ? 1 : 0); i < numStr.length(); i++)
{
if (numStr[i] == m_decimalSymbol)
{
commands->push_back(IDC_PNT);
if (!fSciFmt)
{
fDecimal = true;
}
}
else if (numStr[i] == L'e')
{
commands->push_back(IDC_EXP);
fSciFmt = true;
}
else if (numStr[i] == L'-')
{
commands->push_back(IDC_SIGN);
}
else if (numStr[i] == L'+')
{
// Ignore.
}
// Number
else
{
int num = static_cast<int>(numStr[i]) - ASCII_0;
num += IDC_0;
commands->push_back(num);
}
}
auto operandCommand = std::make_shared<COpndCommand>(commands, fNegative, fDecimal, fSciFmt);
operandCommand->Initialize(rat);
return operandCommand;
}
std::vector<std::shared_ptr<IExpressionCommand>> CHistoryCollector::GetCommands() const
{
std::vector<std::shared_ptr<IExpressionCommand>> commands;
if (m_spCommands != nullptr)
{
commands = *m_spCommands;
}
return commands;
}

@ -1,65 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include <algorithm>
#include "Header Files/Number.h"
using namespace std;
namespace CalcEngine
{
Number::Number() noexcept
: Number(1, 0, { 0 })
{
}
Number::Number(int32_t sign, int32_t exp, vector<uint32_t> const& mantissa) noexcept
: m_sign{ sign }
, m_exp{ exp }
, m_mantissa{ mantissa }
{
}
Number::Number(PNUMBER p) noexcept
: m_sign{ p->sign }
, m_exp{ p->exp }
{
m_mantissa.reserve(p->cdigit);
copy_n(p->mant, p->cdigit, back_inserter(m_mantissa));
}
PNUMBER Number::ToPNUMBER() const
{
PNUMBER ret = _createnum(static_cast<uint32_t>(this->Mantissa().size()) + 1);
ret->sign = this->Sign();
ret->exp = this->Exp();
ret->cdigit = static_cast<int32_t>(this->Mantissa().size());
MANTTYPE* ptrRet = ret->mant;
for (auto const& digit : this->Mantissa())
{
*ptrRet++ = digit;
}
return ret;
}
int32_t const& Number::Sign() const
{
return m_sign;
}
int32_t const& Number::Exp() const
{
return m_exp;
}
vector<uint32_t> const& Number::Mantissa() const
{
return m_mantissa;
}
bool Number::IsZero() const
{
return all_of(m_mantissa.begin(), m_mantissa.end(), [](auto&& i) { return i == 0; });
}
}

@ -1,501 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "Header Files/Rational.h"
using namespace std;
namespace CalcEngine
{
Rational::Rational() noexcept
: m_p{}
, m_q{ 1, 0, { 1 } }
{
}
Rational::Rational(Number const& n) noexcept
{
int32_t qExp = 0;
if (n.Exp() < 0)
{
qExp -= n.Exp();
}
m_p = Number(n.Sign(), 0, n.Mantissa());
m_q = Number(1, qExp, { 1 });
}
Rational::Rational(Number const& p, Number const& q) noexcept
: m_p{ p }
, m_q{ q }
{
}
Rational::Rational(int32_t i)
{
PRAT pr = i32torat(static_cast<int32_t>(i));
m_p = Number{ pr->pp };
m_q = Number{ pr->pq };
destroyrat(pr);
}
Rational::Rational(uint32_t ui)
{
PRAT pr = Ui32torat(static_cast<uint32_t>(ui));
m_p = Number{ pr->pp };
m_q = Number{ pr->pq };
destroyrat(pr);
}
Rational::Rational(uint64_t ui)
{
uint32_t hi = (uint32_t)(((ui) >> 32) & 0xffffffff);
uint32_t lo = (uint32_t)ui;
Rational temp = (Rational{ hi } << 32) | lo;
m_p = Number{ temp.P() };
m_q = Number{ temp.Q() };
}
Rational::Rational(PRAT prat) noexcept
: m_p{ Number{ prat->pp } }
, m_q{ Number{ prat->pq } }
{
}
PRAT Rational::ToPRAT() const
{
PRAT ret = _createrat();
ret->pp = this->P().ToPNUMBER();
ret->pq = this->Q().ToPNUMBER();
return ret;
}
Number const& Rational::P() const
{
return m_p;
}
Number const& Rational::Q() const
{
return m_q;
}
Rational Rational::operator-() const
{
return Rational{ Number{ -1 * m_p.Sign(), m_p.Exp(), m_p.Mantissa() }, m_q };
}
Rational& Rational::operator+=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
addrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator-=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
subrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator*=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
mulrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator/=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
divrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
/// <summary>
/// Calculate the remainder after division, the sign of a result will match the sign of the current object.
/// </summary>
/// <remarks>
/// This function has the same behavior as the standard C/C++ operator '%'
/// to calculate the modulus after division instead, use <see cref="RationalMath::Mod"/> instead.
/// </remarks>
Rational& Rational::operator%=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
remrat(&lhsRat, rhsRat);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator<<=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
lshrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator>>=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
rshrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator&=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
andrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator|=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
orrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational& Rational::operator^=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
try
{
xorrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
*this = Rational{ lhsRat };
destroyrat(lhsRat);
return *this;
}
Rational operator+(Rational lhs, Rational const& rhs)
{
lhs += rhs;
return lhs;
}
Rational operator-(Rational lhs, Rational const& rhs)
{
lhs -= rhs;
return lhs;
}
Rational operator*(Rational lhs, Rational const& rhs)
{
lhs *= rhs;
return lhs;
}
Rational operator/(Rational lhs, Rational const& rhs)
{
lhs /= rhs;
return lhs;
}
/// <summary>
/// Calculate the remainder after division, the sign of a result will match the sign of lhs.
/// </summary>
/// <remarks>
/// This function has the same behavior as the standard C/C++ operator '%', to calculate the modulus after division instead, use <see
/// cref="Rational::operator%"/> instead.
/// </remarks>
Rational operator%(Rational lhs, Rational const& rhs)
{
lhs %= rhs;
return lhs;
}
Rational operator<<(Rational lhs, Rational const& rhs)
{
lhs <<= rhs;
return lhs;
}
Rational operator>>(Rational lhs, Rational const& rhs)
{
lhs >>= rhs;
return lhs;
}
Rational operator&(Rational lhs, Rational const& rhs)
{
lhs &= rhs;
return lhs;
}
Rational operator|(Rational lhs, Rational const& rhs)
{
lhs |= rhs;
return lhs;
}
Rational operator^(Rational lhs, Rational const& rhs)
{
lhs ^= rhs;
return lhs;
}
bool operator==(Rational const& lhs, Rational const& rhs)
{
PRAT lhsRat = lhs.ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
bool result = false;
try
{
result = rat_equ(lhsRat, rhsRat, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
destroyrat(lhsRat);
destroyrat(rhsRat);
return result;
}
bool operator!=(Rational const& lhs, Rational const& rhs)
{
return !(lhs == rhs);
}
bool operator<(Rational const& lhs, Rational const& rhs)
{
PRAT lhsRat = lhs.ToPRAT();
PRAT rhsRat = rhs.ToPRAT();
bool result = false;
try
{
result = rat_lt(lhsRat, rhsRat, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
throw(error);
}
destroyrat(lhsRat);
destroyrat(rhsRat);
return result;
}
bool operator>(Rational const& lhs, Rational const& rhs)
{
return rhs < lhs;
}
bool operator<=(Rational const& lhs, Rational const& rhs)
{
return !(lhs > rhs);
}
bool operator>=(Rational const& lhs, Rational const& rhs)
{
return !(lhs < rhs);
}
wstring Rational::ToString(uint32_t radix, NumberFormat fmt, int32_t precision) const
{
PRAT rat = this->ToPRAT();
wstring result{};
try
{
result = RatToString(rat, fmt, radix, precision);
}
catch (uint32_t error)
{
destroyrat(rat);
throw(error);
}
destroyrat(rat);
return result;
}
uint64_t Rational::ToUInt64_t() const
{
PRAT rat = this->ToPRAT();
uint64_t result;
try
{
result = rattoUi64(rat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(rat);
throw(error);
}
destroyrat(rat);
return result;
}
}

@ -1,418 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "Header Files/RationalMath.h"
using namespace std;
using namespace CalcEngine;
Rational RationalMath::Frac(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
fracrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Integer(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
intrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Pow(Rational const& base, Rational const& pow)
{
PRAT baseRat = base.ToPRAT();
PRAT powRat = pow.ToPRAT();
try
{
powrat(&baseRat, powRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(powRat);
}
catch (uint32_t error)
{
destroyrat(baseRat);
destroyrat(powRat);
throw(error);
}
Rational result{ baseRat };
destroyrat(baseRat);
return result;
}
Rational RationalMath::Root(Rational const& base, Rational const& root)
{
return Pow(base, Invert(root));
}
Rational RationalMath::Fact(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
factrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Exp(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
exprat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Log(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
lograt(&prat, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Log10(Rational const& rat)
{
return Log(rat) / Rational{ ln_ten };
}
Rational RationalMath::Invert(Rational const& rat)
{
return 1 / rat;
}
Rational RationalMath::Abs(Rational const& rat)
{
return Rational{ Number{ 1, rat.P().Exp(), rat.P().Mantissa() }, Number{ 1, rat.Q().Exp(), rat.Q().Mantissa() } };
}
Rational RationalMath::Sin(Rational const& rat, AngleType angletype)
{
PRAT prat = rat.ToPRAT();
try
{
sinanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Cos(Rational const& rat, AngleType angletype)
{
PRAT prat = rat.ToPRAT();
try
{
cosanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Tan(Rational const& rat, AngleType angletype)
{
PRAT prat = rat.ToPRAT();
try
{
tananglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::ASin(Rational const& rat, AngleType angletype)
{
PRAT prat = rat.ToPRAT();
try
{
asinanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::ACos(Rational const& rat, AngleType angletype)
{
PRAT prat = rat.ToPRAT();
try
{
acosanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::ATan(Rational const& rat, AngleType angletype)
{
PRAT prat = rat.ToPRAT();
try
{
atananglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Sinh(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
sinhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Cosh(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
coshrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::Tanh(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
tanhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::ASinh(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
asinhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::ACosh(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
acoshrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
Rational RationalMath::ATanh(Rational const& rat)
{
PRAT prat = rat.ToPRAT();
try
{
atanhrat(&prat, RATIONAL_PRECISION);
}
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
}
/// <summary>
/// Calculate the modulus after division, the sign of the result will match the sign of b.
/// </summary>
/// <remarks>
/// When one of the operand is negative
/// the result will differ from the C/C++ operator '%'
/// use <see cref="Rational::operator%"/> instead to calculate the remainder after division.
/// </remarks>
Rational RationalMath::Mod(Rational const& a, Rational const& b)
{
PRAT prat = a.ToPRAT();
PRAT pn = b.ToPRAT();
try
{
modrat(&prat, pn);
destroyrat(pn);
}
catch (uint32_t error)
{
destroyrat(prat);
destroyrat(pn);
throw(error);
}
auto res = Rational{ prat };
destroyrat(prat);
return res;
}

@ -1,214 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include <cassert>
#include "Header Files/CalcEngine.h"
#include "CalculatorResource.h"
using namespace std;
using namespace CalcEngine;
/**************************************************************************/
/*** Global variable declarations and initializations ***/
/**************************************************************************/
static constexpr int DEFAULT_MAX_DIGITS = 32;
static constexpr int DEFAULT_PRECISION = 32;
static constexpr int32_t DEFAULT_RADIX = 10;
static constexpr wchar_t DEFAULT_DEC_SEPARATOR = L'.';
static constexpr wchar_t DEFAULT_GRP_SEPARATOR = L',';
static constexpr wstring_view DEFAULT_GRP_STR = L"3;0";
static constexpr wstring_view DEFAULT_NUMBER_STR = L"0";
// Read strings for keys, errors, trig types, etc.
// These will be copied from the resources to local memory.
unordered_map<wstring_view, wstring> CCalcEngine::s_engineStrings;
void CCalcEngine::LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider)
{
for (const auto& sid : g_sids)
{
auto locString = resourceProvider.GetCEngineString(sid);
if (!locString.empty())
{
s_engineStrings[sid] = locString;
}
}
}
//////////////////////////////////////////////////
//
// InitialOneTimeOnlyNumberSetup
//
//////////////////////////////////////////////////
void CCalcEngine::InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider)
{
LoadEngineStrings(resourceProvider);
// we must now set up all the ratpak constants and our arrayed pointers
// to these constants.
ChangeBaseConstants(DEFAULT_RADIX, DEFAULT_MAX_DIGITS, DEFAULT_PRECISION);
}
//////////////////////////////////////////////////
//
// CCalcEngine::CCalcEngine
//
//////////////////////////////////////////////////
CCalcEngine::CCalcEngine(
bool fPrecedence,
bool fIntegerMode,
CalculationManager::IResourceProvider* const pResourceProvider,
__in_opt ICalcDisplay* pCalcDisplay,
__in_opt shared_ptr<IHistoryDisplay> pHistoryDisplay)
: m_fPrecedence(fPrecedence)
, m_fIntegerMode(fIntegerMode)
, m_pCalcDisplay(pCalcDisplay)
, m_resourceProvider(pResourceProvider)
, m_nOpCode(0)
, m_nPrevOpCode(0)
, m_bChangeOp(false)
, m_bRecord(false)
, m_bSetCalcState(false)
, m_input(DEFAULT_DEC_SEPARATOR)
, m_nFE(NumberFormat::Float)
, m_memoryValue{ make_unique<Rational>() }
, m_holdVal{}
, m_currentVal{}
, m_lastVal{}
, m_parenVals{}
, m_precedenceVals{}
, m_bError(false)
, m_bInv(false)
, m_bNoPrevEqu(true)
, m_radix(DEFAULT_RADIX)
, m_precision(DEFAULT_PRECISION)
, m_cIntDigitsSav(DEFAULT_MAX_DIGITS)
, m_decGrouping()
, m_numberString(DEFAULT_NUMBER_STR)
, m_nTempCom(0)
, m_openParenCount(0)
, m_nOp()
, m_nPrecOp()
, m_precedenceOpCount(0)
, m_nLastCom(0)
, m_angletype(AngleType::Degrees)
, m_numwidth(NUM_WIDTH::QWORD_WIDTH)
, m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR)
, m_groupSeparator(DEFAULT_GRP_SEPARATOR)
{
InitChopNumbers();
m_dwWordBitWidth = DwWordBitWidthFromNumWidth(m_numwidth);
m_maxTrigonometricNum = RationalMath::Pow(10, 100);
SetRadixTypeAndNumWidth(RadixType::Decimal, m_numwidth);
SettingsChanged();
DisplayNum();
}
void CCalcEngine::InitChopNumbers()
{
// these rat numbers are set only once and then never change regardless of
// base or precision changes
assert(m_chopNumbers.size() >= 4);
m_chopNumbers[0] = Rational{ rat_qword };
m_chopNumbers[1] = Rational{ rat_dword };
m_chopNumbers[2] = Rational{ rat_word };
m_chopNumbers[3] = Rational{ rat_byte };
// initialize the max dec number you can support for each of the supported bit lengths
// this is basically max num in that width / 2 in integer
assert(m_chopNumbers.size() == m_maxDecimalValueStrings.size());
for (size_t i = 0; i < m_chopNumbers.size(); i++)
{
auto maxVal = m_chopNumbers[i] / 2;
maxVal = RationalMath::Integer(maxVal);
m_maxDecimalValueStrings[i] = maxVal.ToString(10, NumberFormat::Float, m_precision);
}
}
CalcEngine::Rational CCalcEngine::GetChopNumber() const
{
return m_chopNumbers[static_cast<int>(m_numwidth)];
}
std::wstring CCalcEngine::GetMaxDecimalValueString() const
{
return m_maxDecimalValueStrings[static_cast<int>(m_numwidth)];
}
// Gets the number in memory for UI to keep it persisted and set it again to a different instance
// of CCalcEngine. Otherwise it will get destructed with the CalcEngine
unique_ptr<Rational> CCalcEngine::PersistedMemObject()
{
return move(m_memoryValue);
}
void CCalcEngine::PersistedMemObject(Rational const& memObject)
{
m_memoryValue = make_unique<Rational>(memObject);
}
void CCalcEngine::SettingsChanged()
{
wchar_t lastDec = m_decimalSeparator;
wstring decStr = m_resourceProvider->GetCEngineString(L"sDecimal");
m_decimalSeparator = decStr.empty() ? DEFAULT_DEC_SEPARATOR : decStr.at(0);
// Until it can be removed, continue to set ratpak decimal here
SetDecimalSeparator(m_decimalSeparator);
wchar_t lastSep = m_groupSeparator;
wstring sepStr = m_resourceProvider->GetCEngineString(L"sThousand");
m_groupSeparator = sepStr.empty() ? DEFAULT_GRP_SEPARATOR : sepStr.at(0);
auto lastDecGrouping = m_decGrouping;
wstring grpStr = m_resourceProvider->GetCEngineString(L"sGrouping");
m_decGrouping = DigitGroupingStringToGroupingVector(grpStr.empty() ? DEFAULT_GRP_STR : grpStr);
bool numChanged = false;
// if the grouping pattern or thousands symbol changed we need to refresh the display
if (m_decGrouping != lastDecGrouping || m_groupSeparator != lastSep)
{
numChanged = true;
}
// if the decimal symbol has changed we always do the following things
if (m_decimalSeparator != lastDec)
{
// Re-initialize member variables' decimal point.
m_input.SetDecimalSymbol(m_decimalSeparator);
m_HistoryCollector.SetDecimalSymbol(m_decimalSeparator);
// put the new decimal symbol into the table used to draw the decimal key
s_engineStrings[SIDS_DECIMAL_SEPARATOR] = m_decimalSeparator;
// we need to redraw to update the decimal point button
numChanged = true;
}
if (numChanged)
{
DisplayNum();
}
}
wchar_t CCalcEngine::DecimalSeparator() const
{
return m_decimalSeparator;
}
std::vector<std::shared_ptr<IExpressionCommand>> CCalcEngine::GetHistoryCollectorCommandsSnapshot() const
{
auto commands = m_HistoryCollector.GetCommands();
if (!m_HistoryCollector.FOpndAddedToHistory() && m_bRecord)
{
commands.push_back(m_HistoryCollector.GetOperandCommandsFromString(m_numberString, m_currentVal));
}
return commands;
}

File diff suppressed because it is too large Load Diff

@ -1,384 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/****************************Module*Header***********************************\
* Module Name: SCIDISP.C
*
* Module Description:
*
* Warnings:
*
* Created:
*
* Author:
\****************************************************************************/
#include <sstream>
#include <regex>
#include "Header Files/CalcEngine.h"
using namespace std;
using namespace CalcEngine;
constexpr int MAX_EXPONENT = 4;
constexpr uint32_t MAX_GROUPING_SIZE = 16;
constexpr wstring_view c_decPreSepStr = L"[+-]?(\\d*)[";
constexpr wstring_view c_decPostSepStr = L"]?(\\d*)(?:e[+-]?(\\d*))?$";
/****************************************************************************\
* void DisplayNum(void)
*
* Convert m_currentVal to a string in the current radix.
*
* Updates the following variables:
* m_currentVal, m_numberString
\****************************************************************************/
//
// State of calc last time DisplayNum was called
//
typedef struct
{
Rational value;
int32_t precision;
uint32_t radix;
int nFE;
NUM_WIDTH numwidth;
bool fIntMath;
bool bRecord;
bool bUseSep;
} LASTDISP;
static LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
// Truncates if too big, makes it a non negative - the number in rat. Doesn't do anything if not in INT mode
CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational const& rat)
{
if (!m_fIntegerMode)
{
return rat;
}
// Truncate to an integer. Do not round here.
auto result = RationalMath::Integer(rat);
// Can be converting a dec negative number to Hex/Oct/Bin rep. Use 2's complement form
// Check the range.
if (result < 0)
{
// if negative make positive by doing a twos complement
result = -(result)-1;
result ^= GetChopNumber();
}
result &= GetChopNumber();
return result;
}
void CCalcEngine::DisplayNum(void)
{
//
// Only change the display if
// we are in record mode -OR-
// this is the first time DisplayNum has been called, -OR-
// something important has changed since the last time DisplayNum was
// called.
//
if (m_bRecord || gldPrevious.value != m_currentVal || gldPrevious.precision != m_precision || gldPrevious.radix != m_radix || gldPrevious.nFE != (int)m_nFE
|| !gldPrevious.bUseSep || gldPrevious.numwidth != m_numwidth || gldPrevious.fIntMath != m_fIntegerMode || gldPrevious.bRecord != m_bRecord)
{
gldPrevious.precision = m_precision;
gldPrevious.radix = m_radix;
gldPrevious.nFE = (int)m_nFE;
gldPrevious.numwidth = m_numwidth;
gldPrevious.fIntMath = m_fIntegerMode;
gldPrevious.bRecord = m_bRecord;
gldPrevious.bUseSep = true;
if (m_bRecord)
{
// Display the string and return.
m_numberString = m_input.ToString(m_radix);
}
else
{
// If we're in Programmer mode, perform integer truncation so e.g. 5 / 2 * 2 results in 4, not 5.
if (m_fIntegerMode)
{
m_currentVal = TruncateNumForIntMath(m_currentVal);
}
m_numberString = GetStringForDisplay(m_currentVal, m_radix);
}
// Displayed number can go through transformation. So copy it after transformation
gldPrevious.value = m_currentVal;
if ((m_radix == 10) && IsNumberInvalid(m_numberString, MAX_EXPONENT, m_precision, m_radix))
{
DisplayError(CALC_E_OVERFLOW);
}
else
{
// Display the string and return.
SetPrimaryDisplay(GroupDigitsPerRadix(m_numberString, m_radix));
}
}
}
int CCalcEngine::IsNumberInvalid(const wstring& numberString, int iMaxExp, int iMaxMantissa, uint32_t radix) const
{
int iError = 0;
if (radix == 10)
{
// start with an optional + or -
// followed by zero or more digits
// followed by an optional decimal point
// followed by zero or more digits
// followed by an optional exponent
// in case there's an exponent:
// its optionally followed by a + or -
// which is followed by zero or more digits
wregex rx(wstring{ c_decPreSepStr } + m_decimalSeparator + wstring{ c_decPostSepStr });
wsmatch matches;
if (regex_match(numberString, matches, rx))
{
// Check that exponent isn't too long
if (matches.length(3) > iMaxExp)
{
iError = IDS_ERR_INPUT_OVERFLOW;
}
else
{
wstring exp = matches.str(1);
auto intItr = exp.begin();
auto intEnd = exp.end();
while (intItr != intEnd && *intItr == L'0')
{
intItr++;
}
auto iMantissa = distance(intItr, intEnd) + matches.length(2);
if (iMantissa > iMaxMantissa)
{
iError = IDS_ERR_INPUT_OVERFLOW;
}
}
}
else
{
iError = IDS_ERR_UNK_CH;
}
}
else
{
for (const wchar_t& c : numberString)
{
if (radix == 16)
{
if (!(iswdigit(c) || (c >= L'A' && c <= L'F')))
{
iError = IDS_ERR_UNK_CH;
}
}
else if (c < L'0' || c >= L'0' + radix)
{
iError = IDS_ERR_UNK_CH;
}
}
}
return iError;
}
/****************************************************************************\
*
* DigitGroupingStringToGroupingVector
*
* Description:
* This will take the digit grouping string found in the regional applet and
* represent this string as a vector.
*
* groupingString
* 0;0 - no grouping
* 3;0 - group every 3 digits
* 3 - group 1st 3, then no grouping after
* 3;0;0 - group 1st 3, then no grouping after
* 3;2;0 - group 1st 3 and then every 2 digits
* 4;0 - group every 4 digits
* 5;3;2;0 - group 5, then 3, then every 2
* 5;3;2 - group 5, then 3, then 2, then no grouping after
*
* Returns: the groupings as a vector
*
\****************************************************************************/
vector<uint32_t> CCalcEngine::DigitGroupingStringToGroupingVector(wstring_view groupingString)
{
vector<uint32_t> grouping;
uint32_t currentGroup = 0;
wchar_t* next = nullptr;
const wchar_t* begin = groupingString.data();
const wchar_t* end = begin + groupingString.length();
for (auto itr = begin; itr != end; ++itr)
{
// Try to parse a grouping number from the string
currentGroup = wcstoul(itr, &next, 10);
// If we successfully parsed a group, add it to the grouping.
if (currentGroup < MAX_GROUPING_SIZE)
{
grouping.emplace_back(currentGroup);
}
// If we found a grouping and aren't at the end of the string yet,
// jump to the next position in the string (the ';').
// The loop will then increment us to the next character, which should be a number.
if (next && (static_cast<size_t>(next - begin) < groupingString.length()))
{
itr = next;
}
}
return grouping;
}
wstring CCalcEngine::GroupDigitsPerRadix(wstring_view numberString, uint32_t radix)
{
if (numberString.empty())
{
return wstring{};
}
switch (radix)
{
case 10:
return GroupDigits(wstring{ m_groupSeparator }, m_decGrouping, numberString, (L'-' == numberString[0]));
case 8:
return GroupDigits(L" ", { 3, 0 }, numberString);
case 2:
case 16:
return GroupDigits(L" ", { 4, 0 }, numberString);
default:
return wstring{ numberString };
}
}
/****************************************************************************\
*
* GroupDigits
*
* Description:
* This routine will take a grouping vector and the display string and
* add the separator according to the pattern indicated by the separator.
*
* Grouping
* 0,0 - no grouping
* 3,0 - group every 3 digits
* 3 - group 1st 3, then no grouping after
* 3,0,0 - group 1st 3, then no grouping after
* 3,2,0 - group 1st 3 and then every 2 digits
* 4,0 - group every 4 digits
* 5,3,2,0 - group 5, then 3, then every 2
* 5,3,2 - group 5, then 3, then 2, then no grouping after
*
\***************************************************************************/
wstring CCalcEngine::GroupDigits(wstring_view delimiter, vector<uint32_t> const& grouping, wstring_view displayString, bool isNumNegative)
{
// if there's nothing to do, bail
if (delimiter.empty() || grouping.empty())
{
return wstring{ displayString };
}
// Find the position of exponential 'e' in the string
size_t exp = displayString.find(L'e');
bool hasExponent = (exp != wstring_view::npos);
// Find the position of decimal point in the string
size_t dec = displayString.find(m_decimalSeparator);
bool hasDecimal = (dec != wstring_view::npos);
// Create an iterator that points to the end of the portion of the number subject to grouping (i.e. left of the decimal)
auto ritr = displayString.rend();
if (hasDecimal)
{
ritr -= dec;
}
else if (hasExponent)
{
ritr -= exp;
}
else
{
ritr = displayString.rbegin();
}
wstring result;
uint32_t groupingSize = 0;
auto groupItr = grouping.begin();
auto currGrouping = *groupItr;
// Mark the 'end' of the string as either rend() or rend()-1 if there is a negative sign
// We exclude the sign here because we don't want to end up with e.g. "-,123,456"
// Then, iterate from back to front, adding group delimiters as needed.
auto reverse_end = displayString.rend() - (isNumNegative ? 1 : 0);
while (ritr != reverse_end)
{
result += *ritr++;
groupingSize++;
// If a group is complete, add a separator
// Do not add a separator if:
// - grouping size is 0
// - we are at the end of the digit string
if (currGrouping != 0 && (groupingSize % currGrouping) == 0 && ritr != reverse_end)
{
result += delimiter;
groupingSize = 0; // reset for a new group
// Shift the grouping to next values if they exist
if (groupItr != grouping.end())
{
++groupItr;
// Loop through grouping vector until we find a non-zero value.
// "0" values may appear in a form of either e.g. "3;0" or "3;0;0".
// A 0 in the last position means repeat the previous grouping.
// A 0 in another position is a group. So, "3;0;0" means "group 3, then group 0 repeatedly"
// This could be expressed as just "3" but GetLocaleInfo is returning 3;0;0 in some cases instead.
for (currGrouping = 0; groupItr != grouping.end(); ++groupItr)
{
// If it's a non-zero value, that's our new group
if (*groupItr != 0)
{
currGrouping = *groupItr;
break;
}
// Otherwise, save the previous grouping in case we need to repeat it
currGrouping = *(groupItr - 1);
}
}
}
}
// now copy the negative sign if it is there
if (isNumNegative)
{
result += displayString[0];
}
reverse(result.begin(), result.end());
// Add the right (fractional or exponential) part of the number to the final string.
if (hasDecimal)
{
result += displayString.substr(dec);
}
else if (hasExponent)
{
result += displayString.substr(exp);
}
return result;
}

@ -1,305 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/**************************************************************************/
/*** SCICALC Scientific Calculator for Windows 3.00.12 ***/
/*** (c)1989 Microsoft Corporation. All Rights Reserved. ***/
/*** ***/
/*** scifunc.c ***/
/*** ***/
/*** Functions contained: ***/
/*** SciCalcFunctions--do sin, cos, tan, com, log, ln, rec, fac, etc.***/
/*** DisplayError--Error display driver. ***/
/*** ***/
/*** Functions called: ***/
/*** SciCalcFunctions call DisplayError. ***/
/*** ***/
/*** ***/
/**************************************************************************/
#include "Header Files/CalcEngine.h"
#include "winerror_cross_platform.h"
using namespace std;
using namespace CalcEngine;
using namespace CalcEngine::RationalMath;
/* Routines for more complex mathematical functions/error checking. */
CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op)
{
Rational result{};
try
{
switch (op)
{
case IDC_CHOP:
result = m_bInv ? Frac(rat) : Integer(rat);
break;
/* Return complement. */
case IDC_COM:
if (m_radix == 10 && !m_fIntegerMode)
{
result = -(RationalMath::Integer(rat) + 1);
}
else
{
result = rat ^ GetChopNumber();
}
break;
case IDC_ROL:
case IDC_ROLC:
if (m_fIntegerMode)
{
result = Integer(rat);
uint64_t w64Bits = result.ToUInt64_t();
uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
w64Bits <<= 1; // LShift by 1
if (op == IDC_ROL)
{
w64Bits |= msb; // Set the prev Msb as the current Lsb
}
else
{
w64Bits |= m_carryBit; // Set the carry bit as the LSB
m_carryBit = msb; // Store the msb as the next carry bit
}
result = w64Bits;
}
break;
case IDC_ROR:
case IDC_RORC:
if (m_fIntegerMode)
{
result = Integer(rat);
uint64_t w64Bits = result.ToUInt64_t();
uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0;
w64Bits >>= 1; // RShift by 1
if (op == IDC_ROR)
{
w64Bits |= (lsb << (m_dwWordBitWidth - 1));
}
else
{
w64Bits |= (m_carryBit << (m_dwWordBitWidth - 1));
m_carryBit = lsb;
}
result = w64Bits;
}
break;
case IDC_PERCENT:
{
// If the operator is multiply/divide, we evaluate this as "X [op] (Y%)"
// Otherwise, we evaluate it as "X [op] (X * Y%)"
if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV)
{
result = rat / 100;
}
else
{
result = rat * (m_lastVal / 100);
}
break;
}
case IDC_SIN: /* Sine; normal and arc */
if (!m_fIntegerMode)
{
result = m_bInv ? ASin(rat, m_angletype) : Sin(rat, m_angletype);
}
break;
case IDC_SINH: /* Sine- hyperbolic and archyperbolic */
if (!m_fIntegerMode)
{
result = m_bInv ? ASinh(rat) : Sinh(rat);
}
break;
case IDC_COS: /* Cosine, follows convention of sine function. */
if (!m_fIntegerMode)
{
result = m_bInv ? ACos(rat, m_angletype) : Cos(rat, m_angletype);
}
break;
case IDC_COSH: /* Cosine hyperbolic, follows convention of sine h function. */
if (!m_fIntegerMode)
{
result = m_bInv ? ACosh(rat) : Cosh(rat);
}
break;
case IDC_TAN: /* Same as sine and cosine. */
if (!m_fIntegerMode)
{
result = m_bInv ? ATan(rat, m_angletype) : Tan(rat, m_angletype);
}
break;
case IDC_TANH: /* Same as sine h and cosine h. */
if (!m_fIntegerMode)
{
result = m_bInv ? ATanh(rat) : Tanh(rat);
}
break;
case IDC_SEC:
if (!m_fIntegerMode)
{
result = m_bInv ? ACos(Invert(rat), m_angletype) : Invert(Cos(rat, m_angletype));
}
break;
case IDC_CSC:
if (!m_fIntegerMode)
{
result = m_bInv ? ASin(Invert(rat), m_angletype) : Invert(Sin(rat, m_angletype));
}
break;
case IDC_COT:
if (!m_fIntegerMode)
{
result = m_bInv ? ATan(Invert(rat), m_angletype) : Invert(Tan(rat, m_angletype));
}
break;
case IDC_SECH:
if (!m_fIntegerMode)
{
result = m_bInv ? ACosh(Invert(rat)) : Invert(Cosh(rat));
}
break;
case IDC_CSCH:
if (!m_fIntegerMode)
{
result = m_bInv ? ASinh(Invert(rat)) : Invert(Sinh(rat));
}
break;
case IDC_COTH:
if (!m_fIntegerMode)
{
result = m_bInv ? ATanh(Invert(rat)) : Invert(Tanh(rat));
}
break;
case IDC_REC: /* Reciprocal. */
result = Invert(rat);
break;
case IDC_SQR: /* Square */
result = Pow(rat, 2);
break;
case IDC_SQRT: /* Square Root */
result = Root(rat, 2);
break;
case IDC_CUBEROOT:
case IDC_CUB: /* Cubing and cube root functions. */
result = IDC_CUBEROOT == op ? Root(rat, 3) : Pow(rat, 3);
break;
case IDC_LOG: /* Functions for common log. */
result = Log10(rat);
break;
case IDC_POW10:
result = Pow(10, rat);
break;
case IDC_POW2:
result = Pow(2, rat);
break;
case IDC_LN: /* Functions for natural log. */
result = m_bInv ? Exp(rat) : Log(rat);
break;
case IDC_FAC: /* Calculate factorial. Inverse is ineffective. */
result = Fact(rat);
break;
case IDC_DEGREES:
ProcessCommand(IDC_INV);
// This case falls through to IDC_DMS case because in the old Win32 Calc,
// the degrees functionality was achieved as 'Inv' of 'dms' operation,
// so setting the IDC_INV command first and then performing 'dms' operation as global variables m_bInv, m_bRecord
// are set properly through ProcessCommand(IDC_INV)
[[fallthrough]];
case IDC_DMS:
{
if (!m_fIntegerMode)
{
auto shftRat{ m_bInv ? 100 : 60 };
Rational degreeRat = Integer(rat);
Rational minuteRat = (rat - degreeRat) * shftRat;
Rational secondRat = minuteRat;
minuteRat = Integer(minuteRat);
secondRat = (secondRat - minuteRat) * shftRat;
//
// degreeRat == degrees, minuteRat == minutes, secondRat == seconds
//
shftRat = m_bInv ? 60 : 100;
secondRat /= shftRat;
minuteRat = (minuteRat + secondRat) / shftRat;
result = degreeRat + minuteRat;
}
break;
}
case IDC_CEIL:
result = (Frac(rat) > 0) ? Integer(rat + 1) : Integer(rat);
break;
case IDC_FLOOR:
result = (Frac(rat) < 0) ? Integer(rat - 1) : Integer(rat);
break;
case IDC_ABS:
result = Abs(rat);
break;
} // end switch( op )
}
catch (uint32_t nErrCode)
{
DisplayError(nErrCode);
result = rat;
}
return result;
}
/* Routine to display error messages and set m_bError flag. Errors are */
/* called with DisplayError (n), where n is a uint32_t between 0 and 5. */
void CCalcEngine::DisplayError(uint32_t nError)
{
wstring errorString{ GetString(IDS_ERRORS_FIRST + SCODE_CODE(nError)) };
SetPrimaryDisplay(errorString, true /*isError*/);
m_bError = true; /* Set error flag. Only cleared with CLEAR or CENTR. */
m_HistoryCollector.ClearHistoryLine(errorString);
}

@ -1,175 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
using namespace CalcEngine::RationalMath;
// Routines to perform standard operations &|^~<<>>+-/*% and pwr.
CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs)
{
// Remove any variance in how 0 could be represented in rat e.g. -0, 0/n, etc.
auto result = (lhs != 0 ? lhs : 0);
try
{
switch (operation)
{
case IDC_AND:
result &= rhs;
break;
case IDC_OR:
result |= rhs;
break;
case IDC_XOR:
result ^= rhs;
break;
case IDC_NAND:
result = (result & rhs) ^ GetChopNumber();
break;
case IDC_NOR:
result = (result | rhs) ^ GetChopNumber();
break;
case IDC_RSHF:
{
if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0
{
throw CALC_E_NORESULT;
}
uint64_t w64Bits = rhs.ToUInt64_t();
bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
Rational holdVal = result;
result = rhs >> holdVal;
if (fMsb)
{
result = Integer(result);
auto tempRat = GetChopNumber() >> holdVal;
tempRat = Integer(tempRat);
result |= tempRat ^ GetChopNumber();
}
break;
}
case IDC_RSHFL:
{
if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0
{
throw CALC_E_NORESULT;
}
result = rhs >> result;
break;
}
case IDC_LSHF:
if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0
{
throw CALC_E_NORESULT;
}
result = rhs << result;
break;
case IDC_ADD:
result += rhs;
break;
case IDC_SUB:
result = rhs - result;
break;
case IDC_MUL:
result *= rhs;
break;
case IDC_DIV:
case IDC_MOD:
{
int iNumeratorSign = 1, iDenominatorSign = 1;
auto temp = result;
result = rhs;
if (m_fIntegerMode)
{
uint64_t w64Bits = rhs.ToUInt64_t();
bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
if (fMsb)
{
result = (rhs ^ GetChopNumber()) + 1;
iNumeratorSign = -1;
}
w64Bits = temp.ToUInt64_t();
fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
if (fMsb)
{
temp = (temp ^ GetChopNumber()) + 1;
iDenominatorSign = -1;
}
}
if (operation == IDC_DIV)
{
result /= temp;
if (m_fIntegerMode && (iNumeratorSign * iDenominatorSign) == -1)
{
result = -(Integer(result));
}
}
else
{
if (m_fIntegerMode)
{
// Programmer mode, use remrat (remainder after division)
result %= temp;
if (iNumeratorSign == -1)
{
result = -(Integer(result));
}
}
else
{
// other modes, use modrat (modulus after division)
result = Mod(result, temp);
}
}
break;
}
case IDC_PWR: // Calculates rhs to the result(th) power.
result = Pow(rhs, result);
break;
case IDC_ROOT: // Calculates rhs to the result(th) root.
result = Root(rhs, result);
break;
case IDC_LOGBASEY:
result = (Log(rhs) / Log(result));
break;
}
}
catch (uint32_t dwErrCode)
{
DisplayError(dwErrCode);
// On error, return the original value
result = lhs;
}
return result;
}

@ -1,186 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
using namespace CalcEngine::RationalMath;
using namespace std;
// To be called when either the radix or num width changes. You can use -1 in either of these values to mean
// dont change that.
void CCalcEngine::SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidth)
{
// When in integer mode, the number is represented in 2's complement form. When a bit width is changing, we can
// change the number representation back to sign, abs num form in ratpak. Soon when display sees this, it will
// convert to 2's complement form, but this time all high bits will be propagated. Eg. -127, in byte mode is
// represented as 1000,0001. This puts it back as sign=-1, 01111111 . But DisplayNum will see this and convert it
// back to 1111,1111,1000,0001 when in Word mode.
if (m_fIntegerMode)
{
uint64_t w64Bits = m_currentVal.ToUInt64_t();
bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; // make sure you use the old width
if (fMsb)
{
// If high bit is set, then get the decimal number in -ve 2'scompl form.
auto tempResult = m_currentVal ^ GetChopNumber();
m_currentVal = -(tempResult + 1);
}
}
if (radixtype >= RadixType::Hex && radixtype <= RadixType::Binary)
{
m_radix = NRadixFromRadixType(radixtype);
// radixtype is not even saved
}
if (numwidth >= NUM_WIDTH::QWORD_WIDTH && numwidth <= NUM_WIDTH::BYTE_WIDTH)
{
m_numwidth = numwidth;
m_dwWordBitWidth = DwWordBitWidthFromNumWidth(numwidth);
}
// inform ratpak that a change in base or precision has occurred
BaseOrPrecisionChanged();
// display the correct number for the new state (ie convert displayed
// number to correct base)
DisplayNum();
}
int32_t CCalcEngine::DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth)
{
switch (numwidth)
{
case NUM_WIDTH::DWORD_WIDTH:
return 32;
case NUM_WIDTH::WORD_WIDTH:
return 16;
case NUM_WIDTH::BYTE_WIDTH:
return 8;
case NUM_WIDTH::QWORD_WIDTH:
default:
return 64;
}
}
uint32_t CCalcEngine::NRadixFromRadixType(RadixType radixtype)
{
switch (radixtype)
{
case RadixType::Hex:
return 16;
case RadixType::Octal:
return 8;
case RadixType::Binary:
return 2;
case RadixType::Decimal:
default:
return 10;
}
}
// Toggles a given bit into the number representation. returns true if it changed it actually.
bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno)
{
uint32_t wmax = DwWordBitWidthFromNumWidth(m_numwidth);
if (wbitno >= wmax)
{
return false; // ignore error cant happen
}
Rational result = Integer(rat);
// Remove any variance in how 0 could be represented in rat e.g. -0, 0/n, etc.
result = (result != 0 ? result : 0);
// XOR the result with 2^wbitno power
rat = result ^ Pow(2, static_cast<int32_t>(wbitno));
return true;
}
// Returns the nearest power of two
int CCalcEngine::QuickLog2(int iNum)
{
int iRes = 0;
// while first digit is a zero
while (!(iNum & 1))
{
iRes++;
iNum >>= 1;
}
// if our number isn't a perfect square
iNum = iNum >> 1;
if (iNum)
{
// find the largest digit
for (iNum = iNum >> 1; iNum; iNum = iNum >> 1)
++iRes;
// and then add two
iRes += 2;
}
return iRes;
}
////////////////////////////////////////////////////////////////////////
//
// UpdateMaxIntDigits
//
// determine the maximum number of digits needed for the current precision,
// word size, and base. This number is conservative towards the small side
// such that there may be some extra bits left over. For example, base 8 requires 3 bits per digit.
// A word size of 32 bits allows for 10 digits with a remainder of two bits. Bases
// that require variable number of bits (non-power-of-two bases) are approximated
// by the next highest power-of-two base (again, to be conservative and guarantee
// there will be no over flow verse the current word size for numbers entered).
// Base 10 is a special case and always uses the base 10 precision (m_nPrecisionSav).
void CCalcEngine::UpdateMaxIntDigits()
{
if (m_radix == 10)
{
// if in integer mode you still have to honor the max digits you can enter based on bit width
if (m_fIntegerMode)
{
m_cIntDigitsSav = static_cast<int>(GetMaxDecimalValueString().length()) - 1;
// This is the max digits you can enter a decimal in fixed width mode aka integer mode -1. The last digit
// has to be checked separately
}
else
{
m_cIntDigitsSav = m_precision;
}
}
else
{
m_cIntDigitsSav = m_dwWordBitWidth / CCalcEngine::QuickLog2(m_radix);
}
}
void CCalcEngine::ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision)
{
if (10 == radix)
{
ChangeConstants(radix, precision); // Base 10 precision for internal computing still needs to be 32, to
// take care of decimals precisely. For eg. to get the HI word of a qword, we do a rsh, which depends on getting
// 18446744073709551615 / 4294967296 = 4294967295.9999917... This is important it works this and doesn't reduce
// the precision to number of digits allowed to enter. In other words, precision and # of allowed digits to be
// entered are different.
}
else
{
ChangeConstants(radix, maxIntDigits + 1);
}
}
void CCalcEngine::BaseOrPrecisionChanged()
{
UpdateMaxIntDigits();
CCalcEngine::ChangeBaseConstants(m_radix, m_cIntDigitsSav, m_precision);
}

@ -1,288 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{311e866d-8b93-4609-a691-265941fee101}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>CalcManager</ProjectName>
<RootNamespace>CalcManager</RootNamespace>
<DisableAppLocalVCLibs>false</DisableAppLocalVCLibs>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.26100.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- This has to be exactly in this place for this to work -->
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
<GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- /utf-8 /w44242 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- /utf-8 /w44242 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- /utf-8 /w44242 %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- /utf-8 /w44242 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- /utf-8 /w44242 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- /utf-8 /w44242 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CalculatorHistory.h" />
<ClInclude Include="CalculatorManager.h" />
<ClInclude Include="CalculatorResource.h" />
<ClInclude Include="Command.h" />
<ClInclude Include="ExpressionCommand.h" />
<ClInclude Include="ExpressionCommandInterface.h" />
<ClInclude Include="Header Files\CalcEngine.h" />
<ClInclude Include="Header Files\CalcUtils.h" />
<ClInclude Include="Header Files\CCommand.h" />
<ClInclude Include="Header Files\EngineStrings.h" />
<ClInclude Include="Header Files\History.h" />
<ClInclude Include="Header Files\ICalcDisplay.h" />
<ClInclude Include="Header Files\CalcInput.h" />
<ClInclude Include="Header Files\IHistoryDisplay.h" />
<ClInclude Include="Header Files\Number.h" />
<ClInclude Include="Header Files\RadixType.h" />
<ClInclude Include="Header Files\Rational.h" />
<ClInclude Include="Header Files\RationalMath.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="Ratpack\CalcErr.h" />
<ClInclude Include="Ratpack\ratconst.h" />
<ClInclude Include="Ratpack\ratpak.h" />
<ClInclude Include="NumberFormattingUtils.h" />
<ClInclude Include="UnitConverter.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CalculatorHistory.cpp" />
<ClCompile Include="CalculatorManager.cpp" />
<ClCompile Include="CEngine\calc.cpp" />
<ClCompile Include="CEngine\CalcUtils.cpp" />
<ClCompile Include="CEngine\History.cpp" />
<ClCompile Include="CEngine\CalcInput.cpp" />
<ClCompile Include="CEngine\Number.cpp" />
<ClCompile Include="CEngine\Rational.cpp" />
<ClCompile Include="CEngine\scicomm.cpp" />
<ClCompile Include="CEngine\scidisp.cpp" />
<ClCompile Include="CEngine\scifunc.cpp" />
<ClCompile Include="CEngine\RationalMath.cpp" />
<ClCompile Include="CEngine\scioper.cpp" />
<ClCompile Include="CEngine\sciset.cpp" />
<ClCompile Include="ExpressionCommand.cpp" />
<ClCompile Include="Ratpack\basex.cpp" />
<ClCompile Include="Ratpack\conv.cpp" />
<ClCompile Include="Ratpack\exp.cpp" />
<ClCompile Include="Ratpack\fact.cpp" />
<ClCompile Include="Ratpack\itrans.cpp" />
<ClCompile Include="Ratpack\itransh.cpp" />
<ClCompile Include="Ratpack\logic.cpp" />
<ClCompile Include="Ratpack\num.cpp" />
<ClCompile Include="Ratpack\rat.cpp" />
<ClCompile Include="Ratpack\support.cpp" />
<ClCompile Include="Ratpack\trans.cpp" />
<ClCompile Include="Ratpack\transh.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="NumberFormattingUtils.cpp" />
<ClCompile Include="UnitConverter.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="ratpak.natvis" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="CEngine">
<UniqueIdentifier>{957a8e3c-00c7-48bc-b63c-83b2140a8251}</UniqueIdentifier>
</Filter>
<Filter Include="RatPack">
<UniqueIdentifier>{a1bae6f0-0a01-447d-9a3a-5c65bcd384e6}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{5149465e-c5c9-48a2-b676-f11380b733a0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="ExpressionCommand.cpp" />
<ClCompile Include="CEngine\calc.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\CalcUtils.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\History.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\scicomm.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\scidisp.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\scifunc.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\scioper.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\sciset.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="Ratpack\basex.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\conv.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\exp.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\fact.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\itrans.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\itransh.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\logic.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\num.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\rat.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\support.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\trans.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="Ratpack\transh.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="CalculatorHistory.cpp" />
<ClCompile Include="CalculatorManager.cpp" />
<ClCompile Include="UnitConverter.cpp" />
<ClCompile Include="CEngine\CalcInput.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\Number.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\Rational.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="CEngine\RationalMath.cpp">
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="NumberFormattingUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Command.h" />
<ClInclude Include="ExpressionCommand.h" />
<ClInclude Include="ExpressionCommandInterface.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="Header Files\History.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcEngine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CCommand.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\EngineStrings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Ratpack\CalcErr.h">
<Filter>RatPack</Filter>
</ClInclude>
<ClInclude Include="Ratpack\ratconst.h">
<Filter>RatPack</Filter>
</ClInclude>
<ClInclude Include="Ratpack\ratpak.h">
<Filter>RatPack</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcEngine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CCommand.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\EngineStrings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\History.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UnitConverter.h" />
<ClInclude Include="CalculatorHistory.h" />
<ClInclude Include="CalculatorManager.h" />
<ClInclude Include="CalculatorResource.h" />
<ClInclude Include="Header Files\ICalcDisplay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcInput.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\IHistoryDisplay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\Number.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\Rational.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\RadixType.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\RationalMath.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NumberFormattingUtils.h" />
</ItemGroup>
<ItemGroup>
<Natvis Include="ratpak.natvis">
<Filter>RatPack</Filter>
</Natvis>
</ItemGroup>
</Project>

@ -1,89 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include <cassert>
#include "CalculatorHistory.h"
using namespace std;
using namespace CalculationManager;
namespace
{
static wstring GetGeneratedExpression(const vector<pair<wstring, int>>& tokens)
{
wstring expression;
bool isFirst = true;
for (auto const& token : tokens)
{
if (isFirst)
{
isFirst = false;
}
else
{
expression += L' ';
}
expression.append(token.first);
}
return expression;
}
}
CalculatorHistory::CalculatorHistory(size_t maxSize)
: m_maxHistorySize(maxSize)
{
}
unsigned int CalculatorHistory::AddToHistory(
_In_ shared_ptr<vector<pair<wstring, int>>> const& tokens,
_In_ shared_ptr<vector<shared_ptr<IExpressionCommand>>> const& commands,
wstring_view result)
{
shared_ptr<HISTORYITEM> spHistoryItem = make_shared<HISTORYITEM>();
spHistoryItem->historyItemVector.spTokens = tokens;
spHistoryItem->historyItemVector.spCommands = commands;
spHistoryItem->historyItemVector.expression = GetGeneratedExpression(*tokens);
spHistoryItem->historyItemVector.result = wstring(result);
return AddItem(spHistoryItem);
}
unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const& spHistoryItem)
{
if (m_historyItems.size() >= m_maxHistorySize)
{
m_historyItems.erase(m_historyItems.begin());
}
m_historyItems.push_back(spHistoryItem);
return static_cast<unsigned>(m_historyItems.size() - 1);
}
bool CalculatorHistory::RemoveItem(unsigned int uIdx)
{
if (uIdx < m_historyItems.size())
{
m_historyItems.erase(m_historyItems.begin() + uIdx);
return true;
}
return false;
}
vector<shared_ptr<HISTORYITEM>> const& CalculatorHistory::GetHistory()
{
return m_historyItems;
}
shared_ptr<HISTORYITEM> const& CalculatorHistory::GetHistoryItem(unsigned int uIdx)
{
assert(uIdx < m_historyItems.size());
return m_historyItems.at(uIdx);
}
void CalculatorHistory::ClearHistory()
{
m_historyItems.clear();
}

@ -1,45 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "ExpressionCommandInterface.h"
#include "Header Files/IHistoryDisplay.h"
namespace CalculationManager
{
struct HISTORYITEMVECTOR
{
std::shared_ptr<std::vector<std::pair<std::wstring, int>>> spTokens;
std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> spCommands;
std::wstring expression;
std::wstring result;
};
struct HISTORYITEM
{
HISTORYITEMVECTOR historyItemVector;
};
class CalculatorHistory : public IHistoryDisplay
{
public:
CalculatorHistory(const size_t maxSize);
unsigned int AddToHistory(
_In_ std::shared_ptr<std::vector<std::pair<std::wstring, int>>> const& spTokens,
_In_ std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> const& spCommands,
std::wstring_view result);
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistory();
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(unsigned int uIdx);
void ClearHistory();
unsigned int AddItem(_In_ std::shared_ptr<HISTORYITEM> const& spHistoryItem);
bool RemoveItem(unsigned int uIdx);
size_t MaxHistorySize() const
{
return m_maxHistorySize;
}
private:
std::vector<std::shared_ptr<HISTORYITEM>> m_historyItems;
const size_t m_maxHistorySize;
};
}

@ -1,605 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include <climits> // for UCHAR_MAX
#include "Header Files/CalcEngine.h"
#include "CalculatorManager.h"
#include "CalculatorResource.h"
using namespace std;
using namespace CalcEngine;
static constexpr size_t MAX_HISTORY_ITEMS = 20;
#ifndef _MSC_VER
#define __pragma(x)
#endif
namespace CalculationManager
{
CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider)
: m_displayCallback(displayCallback)
, m_currentCalculatorEngine(nullptr)
, m_resourceProvider(resourceProvider)
, m_inHistoryItemLoadMode(false)
, m_persistedPrimaryValue()
, m_isExponentialFormat(false)
, m_currentDegreeMode(Command::CommandNULL)
, m_pStdHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
, m_pSciHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
, m_pHistory(nullptr)
{
CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider);
}
/// <summary>
/// Call the callback function using passed in IDisplayHelper.
/// Used to set the primary display value on ViewModel
/// </summary>
/// <param name="text">wstring representing text to be displayed</param>
void CalculatorManager::SetPrimaryDisplay(_In_ const wstring& displayString, _In_ bool isError)
{
if (!m_inHistoryItemLoadMode)
{
m_displayCallback->SetPrimaryDisplay(displayString, isError);
}
}
void CalculatorManager::SetIsInError(bool isError)
{
m_displayCallback->SetIsInError(isError);
}
void CalculatorManager::DisplayPasteError()
{
m_currentCalculatorEngine->DisplayError(CALC_E_DOMAIN /*code for "Invalid input" error*/);
}
void CalculatorManager::MaxDigitsReached()
{
m_displayCallback->MaxDigitsReached();
}
void CalculatorManager::BinaryOperatorReceived()
{
m_displayCallback->BinaryOperatorReceived();
}
void CalculatorManager::MemoryItemChanged(unsigned int indexOfMemory)
{
m_displayCallback->MemoryItemChanged(indexOfMemory);
}
void CalculatorManager::InputChanged()
{
m_displayCallback->InputChanged();
}
/// <summary>
/// Call the callback function using passed in IDisplayHelper.
/// Used to set the expression display value on ViewModel
/// </summary>
/// <param name="expressionString">wstring representing expression to be displayed</param>
void CalculatorManager::SetExpressionDisplay(
_Inout_ shared_ptr<vector<pair<wstring, int>>> const& tokens,
_Inout_ shared_ptr<vector<shared_ptr<IExpressionCommand>>> const& commands)
{
if (!m_inHistoryItemLoadMode)
{
m_displayCallback->SetExpressionDisplay(tokens, commands);
}
}
/// <summary>
/// Callback from the CalculatorControl
/// Passed in string representations of memorized numbers get passed to the client
/// </summary>
/// <param name="memorizedNumber">vector containing wstring values of memorized numbers</param>
void CalculatorManager::SetMemorizedNumbers(_In_ const vector<wstring>& memorizedNumbers)
{
m_displayCallback->SetMemorizedNumbers(memorizedNumbers);
}
/// <summary>
/// Callback from the engine
/// </summary>
/// <param name="parenthesisCount">string containing the parenthesis count</param>
void CalculatorManager::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
m_displayCallback->SetParenthesisNumber(parenthesisCount);
}
/// <summary>
/// Callback from the engine
/// </summary>
void CalculatorManager::OnNoRightParenAdded()
{
m_displayCallback->OnNoRightParenAdded();
}
/// <summary>
/// Reset CalculatorManager.
/// Set the mode to the standard calculator
/// Set the degree mode as regular degree (as oppose to Rad or Grad)
/// Clear all the entries and memories
/// Clear Memory if clearMemory parameter is true.(Default value is true)
/// </summary>
void CalculatorManager::Reset(bool clearMemory /* = true*/)
{
SetStandardMode();
if (m_scientificCalculatorEngine)
{
m_scientificCalculatorEngine->ProcessCommand(IDC_DEG);
m_scientificCalculatorEngine->ProcessCommand(IDC_CLEAR);
if (m_isExponentialFormat)
{
m_isExponentialFormat = false;
m_scientificCalculatorEngine->ProcessCommand(IDC_FE);
}
}
if (m_programmerCalculatorEngine)
{
m_programmerCalculatorEngine->ProcessCommand(IDC_CLEAR);
}
if (clearMemory)
{
this->MemorizedNumberClearAll();
}
}
/// <summary>
/// Change the current calculator engine to standard calculator engine.
/// </summary>
void CalculatorManager::SetStandardMode()
{
if (!m_standardCalculatorEngine)
{
m_standardCalculatorEngine =
make_unique<CCalcEngine>(false /* Respect Order of Operations */, false /* Set to Integer Mode */, m_resourceProvider, this, m_pStdHistory);
}
m_currentCalculatorEngine = m_standardCalculatorEngine.get();
m_currentCalculatorEngine->ProcessCommand(IDC_DEC);
m_currentCalculatorEngine->ProcessCommand(IDC_CLEAR);
m_currentCalculatorEngine->ChangePrecision(static_cast<int>(CalculatorPrecision::StandardModePrecision));
UpdateMaxIntDigits();
m_pHistory = m_pStdHistory.get();
}
/// <summary>
/// Change the current calculator engine to scientific calculator engine.
/// </summary>
void CalculatorManager::SetScientificMode()
{
if (!m_scientificCalculatorEngine)
{
m_scientificCalculatorEngine =
make_unique<CCalcEngine>(true /* Respect Order of Operations */, false /* Set to Integer Mode */, m_resourceProvider, this, m_pSciHistory);
}
m_currentCalculatorEngine = m_scientificCalculatorEngine.get();
m_currentCalculatorEngine->ProcessCommand(IDC_DEC);
m_currentCalculatorEngine->ProcessCommand(IDC_CLEAR);
m_currentCalculatorEngine->ChangePrecision(static_cast<int>(CalculatorPrecision::ScientificModePrecision));
m_pHistory = m_pSciHistory.get();
}
/// <summary>
/// Change the current calculator engine to scientific calculator engine.
/// </summary>
void CalculatorManager::SetProgrammerMode()
{
if (!m_programmerCalculatorEngine)
{
m_programmerCalculatorEngine =
make_unique<CCalcEngine>(true /* Respect Order of Operations */, true /* Set to Integer Mode */, m_resourceProvider, this, nullptr);
}
m_currentCalculatorEngine = m_programmerCalculatorEngine.get();
m_currentCalculatorEngine->ProcessCommand(IDC_DEC);
m_currentCalculatorEngine->ProcessCommand(IDC_CLEAR);
m_currentCalculatorEngine->ChangePrecision(static_cast<int>(CalculatorPrecision::ProgrammerModePrecision));
}
/// <summary>
/// Send command to the Calc Engine
/// Cast Command Enum to OpCode.
/// Handle special commands such as mode change and combination of two commands.
/// </summary>
/// <param name="command">Enum Command</command>
void CalculatorManager::SendCommand(_In_ Command command)
{
// When the expression line is cleared, we save the current state, which includes,
// primary display, memory, and degree mode
if (command == Command::CommandCLEAR || command == Command::CommandEQU || command == Command::ModeBasic || command == Command::ModeScientific
|| command == Command::ModeProgrammer)
{
switch (command)
{
case Command::ModeBasic:
this->SetStandardMode();
break;
case Command::ModeScientific:
this->SetScientificMode();
break;
case Command::ModeProgrammer:
this->SetProgrammerMode();
break;
default:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(command));
}
InputChanged();
return;
}
if (command == Command::CommandDEG || command == Command::CommandRAD || command == Command::CommandGRAD)
{
m_currentDegreeMode = command;
}
switch (command)
{
case Command::CommandASIN:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandSIN));
break;
case Command::CommandACOS:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandCOS));
break;
case Command::CommandATAN:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandTAN));
break;
case Command::CommandPOWE:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandLN));
break;
case Command::CommandASINH:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandSINH));
break;
case Command::CommandACOSH:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandCOSH));
break;
case Command::CommandATANH:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandTANH));
break;
case Command::CommandASEC:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandSEC));
break;
case Command::CommandACSC:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandCSC));
break;
case Command::CommandACOT:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandCOT));
break;
case Command::CommandASECH:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandSECH));
break;
case Command::CommandACSCH:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandCSCH));
break;
case Command::CommandACOTH:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandCOTH));
break;
case Command::CommandFE:
m_isExponentialFormat = !m_isExponentialFormat;
[[fallthrough]];
default:
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(command));
break;
}
InputChanged();
}
/// <summary>
/// Load the persisted value that is saved in memory of CalcEngine
/// </summary>
void CalculatorManager::LoadPersistedPrimaryValue()
{
m_currentCalculatorEngine->PersistedMemObject(m_persistedPrimaryValue);
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
InputChanged();
}
/// <summary>
/// Memorize the current displayed value
/// Notify the client with new the new memorize value vector
/// </summary>
void CalculatorManager::MemorizeNumber()
{
if (m_currentCalculatorEngine->FInErrorState())
{
return;
}
m_currentCalculatorEngine->ProcessCommand(IDC_STORE);
auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObjectPtr != nullptr)
{
m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr);
}
if (m_memorizedNumbers.size() > m_maximumMemorySize)
{
m_memorizedNumbers.resize(m_maximumMemorySize);
}
this->SetMemorizedNumbersString();
}
/// <summary>
/// Recall the memorized number.
/// The memorized number gets loaded to the primary display
/// </summary>
/// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory)
{
if (m_currentCalculatorEngine->FInErrorState())
{
return;
}
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
InputChanged();
}
/// <summary>
/// Do the addition to the selected memory
/// It adds primary display value to the selected memory
/// Notify the client with new the new memorize value vector
/// </summary>
/// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory)
{
if (m_currentCalculatorEngine->FInErrorState())
{
return;
}
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
}
void CalculatorManager::MemorizedNumberClear(_In_ unsigned int indexOfMemory)
{
if (indexOfMemory < m_memorizedNumbers.size())
{
m_memorizedNumbers.erase(m_memorizedNumbers.begin() + indexOfMemory);
}
}
/// <summary>
/// Do the subtraction to the selected memory
/// It adds primary display value to the selected memory
/// Notify the client with new the new memorize value vector
/// </summary>
/// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory)
{
if (m_currentCalculatorEngine->FInErrorState())
{
return;
}
// To add negative of the number on display to the memory -x = x - 2x
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
this->MemorizedNumberSubtract(0);
this->MemorizedNumberSubtract(0);
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
}
/// <summary>
/// Clear all the memorized values
/// Notify the client with new the new memorize value vector
/// </summary>
void CalculatorManager::MemorizedNumberClearAll()
{
m_memorizedNumbers.clear();
m_currentCalculatorEngine->ProcessCommand(IDC_MCLEAR);
this->SetMemorizedNumbersString();
}
/// <summary>
/// Helper function that selects a memory from the vector and set it to CCalcEngine
/// Saved RAT number needs to be copied and passed in, as CCalcEngine destroyed the passed in RAT
/// </summary>
/// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberSelect(_In_ unsigned int indexOfMemory)
{
if (m_currentCalculatorEngine->FInErrorState())
{
return;
}
auto memoryObject = m_memorizedNumbers.at(indexOfMemory);
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
}
/// <summary>
/// Helper function that needs to be executed when memory is modified
/// When memory is modified, destroy the old RAT and put the new RAT in vector
/// </summary>
/// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory)
{
if (m_currentCalculatorEngine->FInErrorState())
{
return;
}
auto memoryObject = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObject != nullptr)
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject;
}
}
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems() const
{
return m_pHistory->GetHistory();
}
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems(_In_ CalculatorMode mode) const
{
return (mode == CalculatorMode::Standard) ? m_pStdHistory->GetHistory() : m_pSciHistory->GetHistory();
}
void CalculatorManager::SetHistoryItems(_In_ std::vector<std::shared_ptr<HISTORYITEM>> const& historyItems)
{
for (auto const& historyItem : historyItems)
{
auto index = m_pHistory->AddItem(historyItem);
OnHistoryItemAdded(index);
}
}
shared_ptr<HISTORYITEM> const& CalculatorManager::GetHistoryItem(_In_ unsigned int uIdx)
{
return m_pHistory->GetHistoryItem(uIdx);
}
void CalculatorManager::OnHistoryItemAdded(_In_ unsigned int addedItemIndex)
{
m_displayCallback->OnHistoryItemAdded(addedItemIndex);
}
bool CalculatorManager::RemoveHistoryItem(_In_ unsigned int uIdx)
{
return m_pHistory->RemoveItem(uIdx);
}
void CalculatorManager::ClearHistory()
{
m_pHistory->ClearHistory();
}
void CalculatorManager::SetRadix(RadixType iRadixType)
{
switch (iRadixType)
{
case RadixType::Hex:
m_currentCalculatorEngine->ProcessCommand(IDC_HEX);
break;
case RadixType::Decimal:
m_currentCalculatorEngine->ProcessCommand(IDC_DEC);
break;
case RadixType::Octal:
m_currentCalculatorEngine->ProcessCommand(IDC_OCT);
break;
case RadixType::Binary:
m_currentCalculatorEngine->ProcessCommand(IDC_BIN);
break;
default:
break;
}
SetMemorizedNumbersString();
}
void CalculatorManager::SetMemorizedNumbersString()
{
vector<wstring> resultVector;
for (auto const& memoryItem : m_memorizedNumbers)
{
auto radix = m_currentCalculatorEngine->GetCurrentRadix();
wstring stringValue = m_currentCalculatorEngine->GetStringForDisplay(memoryItem, radix);
if (!stringValue.empty())
{
resultVector.push_back(m_currentCalculatorEngine->GroupDigitsPerRadix(stringValue, radix));
}
}
m_displayCallback->SetMemorizedNumbers(resultVector);
}
CalculationManager::Command CalculatorManager::GetCurrentDegreeMode()
{
if (m_currentDegreeMode == Command::CommandNULL)
{
m_currentDegreeMode = Command::CommandDEG;
}
return m_currentDegreeMode;
}
wstring CalculatorManager::GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix)
{
return m_currentCalculatorEngine ? m_currentCalculatorEngine->GetCurrentResultForRadix(radix, precision, groupDigitsPerRadix) : L"";
}
void CalculatorManager::SetPrecision(int32_t precision)
{
m_currentCalculatorEngine->ChangePrecision(precision);
}
void CalculatorManager::UpdateMaxIntDigits()
{
m_currentCalculatorEngine->UpdateMaxIntDigits();
}
wchar_t CalculatorManager::DecimalSeparator()
{
return m_currentCalculatorEngine ? m_currentCalculatorEngine->DecimalSeparator() : m_resourceProvider->GetCEngineString(L"sDecimal")[0];
}
bool CalculatorManager::IsEngineRecording()
{
return m_currentCalculatorEngine->FInRecordingState();
}
bool CalculatorManager::IsInputEmpty()
{
return m_currentCalculatorEngine->IsInputEmpty();
}
void CalculatorManager::SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode)
{
m_inHistoryItemLoadMode = isHistoryItemLoadMode;
}
std::vector<std::shared_ptr<IExpressionCommand>> CalculatorManager::GetDisplayCommandsSnapshot() const
{
return m_currentCalculatorEngine->GetHistoryCollectorCommandsSnapshot();
}
}

@ -1,124 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalculatorHistory.h"
#include "Header Files/CalcEngine.h"
#include "Header Files/Rational.h"
#include "Header Files/ICalcDisplay.h"
namespace CalculationManager
{
enum class Command;
struct HISTORYITEM;
enum class CalculatorMode
{
Standard = 0,
Scientific,
};
enum class CalculatorPrecision
{
StandardModePrecision = 16,
ScientificModePrecision = 32,
ProgrammerModePrecision = 64
};
// Numbering continues from the Enum Command from Command.h
// with some gap to ensure there is no overlap of these ids
// when static_cast<unsigned char> is performed on these ids
// they shouldn't fall in any number range greater than 80. So never
// make the memory command ids go below 330
enum class MemoryCommand
{
MemorizeNumber = 330,
MemorizedNumberLoad = 331,
MemorizedNumberAdd = 332,
MemorizedNumberSubtract = 333,
MemorizedNumberClearAll = 334,
MemorizedNumberClear = 335
};
class CalculatorManager final : public ICalcDisplay
{
private:
static const unsigned int m_maximumMemorySize = 100;
ICalcDisplay* const m_displayCallback;
CCalcEngine* m_currentCalculatorEngine;
std::unique_ptr<CCalcEngine> m_scientificCalculatorEngine;
std::unique_ptr<CCalcEngine> m_standardCalculatorEngine;
std::unique_ptr<CCalcEngine> m_programmerCalculatorEngine;
IResourceProvider* const m_resourceProvider;
bool m_inHistoryItemLoadMode;
std::vector<CalcEngine::Rational> m_memorizedNumbers;
CalcEngine::Rational m_persistedPrimaryValue;
bool m_isExponentialFormat;
Command m_currentDegreeMode;
void MemorizedNumberSelect(_In_ unsigned int);
void MemorizedNumberChanged(_In_ unsigned int);
void LoadPersistedPrimaryValue();
std::shared_ptr<CalculatorHistory> m_pStdHistory;
std::shared_ptr<CalculatorHistory> m_pSciHistory;
CalculatorHistory* m_pHistory;
public:
// ICalcDisplay
void SetPrimaryDisplay(_In_ const std::wstring& displayString, _In_ bool isError) override;
void SetIsInError(bool isError) override;
void SetExpressionDisplay(
_Inout_ std::shared_ptr<std::vector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> const& commands) override;
void SetMemorizedNumbers(_In_ const std::vector<std::wstring>& memorizedNumbers) override;
void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override;
void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override;
void OnNoRightParenAdded() override;
void DisplayPasteError();
void MaxDigitsReached() override;
void BinaryOperatorReceived() override;
void MemoryItemChanged(unsigned int indexOfMemory) override;
void InputChanged() override;
CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider);
void Reset(bool clearMemory = true);
void SetStandardMode();
void SetScientificMode();
void SetProgrammerMode();
void SendCommand(_In_ Command command);
void MemorizeNumber();
void MemorizedNumberLoad(_In_ unsigned int);
void MemorizedNumberAdd(_In_ unsigned int);
void MemorizedNumberSubtract(_In_ unsigned int);
void MemorizedNumberClear(_In_ unsigned int);
void MemorizedNumberClearAll();
bool IsEngineRecording();
bool IsInputEmpty();
void SetRadix(RadixType iRadixType);
void SetMemorizedNumbersString();
std::wstring GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
void SetPrecision(int32_t precision);
void UpdateMaxIntDigits();
wchar_t DecimalSeparator();
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistoryItems() const;
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistoryItems(_In_ CalculatorMode mode) const;
void SetHistoryItems(_In_ std::vector<std::shared_ptr<HISTORYITEM>> const& historyItems);
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(_In_ unsigned int uIdx);
bool RemoveHistoryItem(_In_ unsigned int uIdx);
void ClearHistory();
size_t MaxHistorySize() const
{
return m_pHistory->MaxHistorySize();
}
CalculationManager::Command GetCurrentDegreeMode();
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);
std::vector<std::shared_ptr<IExpressionCommand>> GetDisplayCommandsSnapshot() const;
};
}

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <string_view>
namespace CalculationManager
{
class IResourceProvider
{
public:
virtual ~IResourceProvider()
{
}
// Should return a string from the resource table for strings used
// by the calculation engine. The strings that must be defined
// and the ids to define them with can be seen in EngineStrings.h
// with SIDS prefix. Additionally it must provide values for string
// ids "sDecimal", "sThousand" and "sGrouping". See
// https://technet.microsoft.com/en-us/library/cc782655(v=ws.10).aspx
// for what these values refer to.
virtual std::wstring GetCEngineString(std::wstring_view id) = 0;
};
}

@ -1,155 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <string>
#include <vector>
#include "winerror_cross_platform.h"
#include "Ratpack/CalcErr.h"
#include <stdexcept> // for std::out_of_range
#include "sal_cross_platform.h" // for SAL
template <typename TType>
class CalculatorVector
{
public:
ResultCode GetAt(_In_opt_ unsigned int index, _Out_ TType* item)
{
try
{
*item = m_vector.at(index);
}
catch (const std::out_of_range& /*ex*/)
{
return E_BOUNDS;
}
return S_OK;
}
ResultCode GetSize(_Out_ unsigned int* size)
{
*size = static_cast<unsigned>(m_vector.size());
return S_OK;
}
ResultCode SetAt(_In_ unsigned int index, _In_opt_ TType item)
{
try
{
m_vector[index] = item;
}
catch (const std::out_of_range& /*ex*/)
{
return E_BOUNDS;
}
return S_OK;
}
ResultCode RemoveAt(_In_ unsigned int index)
{
if (index < m_vector.size())
{
m_vector.erase(m_vector.begin() + index);
}
else
{
return E_BOUNDS;
}
return S_OK;
}
ResultCode InsertAt(_In_ unsigned int index, _In_ TType item)
{
try
{
auto iter = m_vector.begin() + index;
m_vector.insert(iter, item);
}
catch (const std::bad_alloc& /*ex*/)
{
return E_OUTOFMEMORY;
}
return S_OK;
}
ResultCode Truncate(_In_ unsigned int index)
{
if (index < m_vector.size())
{
auto startIter = m_vector.begin() + index;
m_vector.erase(startIter, m_vector.end());
}
else
{
return E_BOUNDS;
}
return S_OK;
}
ResultCode Append(_In_opt_ TType item)
{
try
{
m_vector.push_back(item);
}
catch (const std::bad_alloc& /*ex*/)
{
return E_OUTOFMEMORY;
}
return S_OK;
}
ResultCode RemoveAtEnd()
{
m_vector.erase(--(m_vector.end()));
return S_OK;
}
ResultCode Clear()
{
m_vector.clear();
return S_OK;
}
ResultCode GetString(_Out_ std::wstring* expression)
{
unsigned int nTokens = 0;
ResultCode hr = this->GetSize(&nTokens);
if (SUCCEEDED(hr))
{
std::pair<std::wstring, int> currentPair;
for (unsigned int i = 0; i < nTokens; i++)
{
hr = this->GetAt(i, &currentPair);
if (SUCCEEDED(hr))
{
expression->append(currentPair.first);
if (i != (nTokens - 1))
{
expression->append(L" ");
}
}
}
std::wstring expressionSuffix{};
hr = GetExpressionSuffix(&expressionSuffix);
if (SUCCEEDED(hr))
{
expression->append(expressionSuffix);
}
}
return hr;
}
ResultCode GetExpressionSuffix(_Out_ std::wstring* suffix)
{
*suffix = L" =";
return S_OK;
}
private:
std::vector<TType> m_vector;
};

@ -1,271 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace UnitConversionManager
{
enum class Command
{
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Decimal,
Negate,
Backspace,
Clear,
Reset,
None
};
}
namespace CurrencyConversionManager
{
enum class Command
{
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Decimal,
Negate,
Backspace,
Clear,
None
};
}
namespace CalculationManager
{
enum class CommandType
{
UnaryCommand,
BinaryCommand,
OperandCommand,
Parentheses
};
enum class Command
{
// Commands for programmer calculators are omitted.
CommandDEG = 321,
CommandRAD = 322,
CommandGRAD = 323,
CommandDegrees = 324,
CommandHYP = 325,
CommandNULL = 0,
CommandSIGN = 80,
CommandCLEAR = 81,
CommandCENTR = 82,
CommandBACK = 83,
CommandPNT = 84,
// Hole 85
// Unused commands defined in Command.h is omitted.
CommandXor = 88,
CommandLSHF = 89,
CommandRSHF = 90,
CommandDIV = 91,
CommandMUL = 92,
CommandADD = 93,
CommandSUB = 94,
CommandMOD = 95,
CommandROOT = 96,
CommandPWR = 97,
CommandCHOP = 98, // Unary operators must be between CommandCHOP and CommandEQU
CommandROL = 99,
CommandROR = 100,
CommandCOM = 101,
CommandSIN = 102,
CommandCOS = 103,
CommandTAN = 104,
CommandSINH = 105,
CommandCOSH = 106,
CommandTANH = 107,
CommandLN = 108,
CommandLOG = 109,
CommandSQRT = 110,
CommandSQR = 111,
CommandCUB = 112,
CommandFAC = 113,
CommandREC = 114,
CommandDMS = 115,
CommandCUBEROOT = 116, // x ^ 1/3
CommandPOW10 = 117, // 10 ^ x
CommandPERCENT = 118,
CommandFE = 119,
CommandPI = 120,
CommandEQU = 121,
CommandMCLEAR = 122,
CommandRECALL = 123,
CommandSTORE = 124,
CommandMPLUS = 125,
CommandMMINUS = 126,
CommandEXP = 127,
CommandOPENP = 128,
CommandCLOSEP = 129,
Command0 = 130, // The controls for 0 through F must be consecutive and in order
Command1 = 131,
Command2 = 132,
Command3 = 133,
Command4 = 134,
Command5 = 135,
Command6 = 136,
Command7 = 137,
Command8 = 138,
Command9 = 139,
CommandA = 140,
CommandB = 141,
CommandC = 142,
CommandD = 143,
CommandE = 144,
CommandF = 145, // this is last control ID which must match the string table
CommandINV = 146,
CommandSET_RESULT = 147,
CommandSEC = 400,
CommandASEC = 401,
CommandCSC = 402,
CommandACSC = 403,
CommandCOT = 404,
CommandACOT = 405,
CommandSECH = 406,
CommandASECH = 407,
CommandCSCH = 408,
CommandACSCH = 409,
CommandCOTH = 410,
CommandACOTH = 411,
CommandPOW2 = 412, // 2 ^ x
CommandAbs = 413,
CommandFloor = 414,
CommandCeil = 415,
CommandROLC = 416,
CommandRORC = 417,
CommandLogBaseY = 500,
CommandNand = 501,
CommandNor = 502,
CommandRSHFL = 505,
CommandRand = 600,
CommandEuler = 601,
CommandAnd = 86,
CommandOR = 87,
CommandNot = 101,
ModeBasic = 200,
ModeScientific = 201,
CommandASIN = 202,
CommandACOS = 203,
CommandATAN = 204,
CommandPOWE = 205,
CommandASINH = 206,
CommandACOSH = 207,
CommandATANH = 208,
ModeProgrammer = 209,
CommandHex = 313,
CommandDec = 314,
CommandOct = 315,
CommandBin = 316,
CommandQword = 317,
CommandDword = 318,
CommandWord = 319,
CommandByte = 320,
CommandBINEDITSTART = 700,
CommandBINPOS0 = 700,
CommandBINPOS1 = 701,
CommandBINPOS2 = 702,
CommandBINPOS3 = 703,
CommandBINPOS4 = 704,
CommandBINPOS5 = 705,
CommandBINPOS6 = 706,
CommandBINPOS7 = 707,
CommandBINPOS8 = 708,
CommandBINPOS9 = 709,
CommandBINPOS10 = 710,
CommandBINPOS11 = 711,
CommandBINPOS12 = 712,
CommandBINPOS13 = 713,
CommandBINPOS14 = 714,
CommandBINPOS15 = 715,
CommandBINPOS16 = 716,
CommandBINPOS17 = 717,
CommandBINPOS18 = 718,
CommandBINPOS19 = 719,
CommandBINPOS20 = 720,
CommandBINPOS21 = 721,
CommandBINPOS22 = 722,
CommandBINPOS23 = 723,
CommandBINPOS24 = 724,
CommandBINPOS25 = 725,
CommandBINPOS26 = 726,
CommandBINPOS27 = 727,
CommandBINPOS28 = 728,
CommandBINPOS29 = 729,
CommandBINPOS30 = 730,
CommandBINPOS31 = 731,
CommandBINPOS32 = 732,
CommandBINPOS33 = 733,
CommandBINPOS34 = 734,
CommandBINPOS35 = 735,
CommandBINPOS36 = 736,
CommandBINPOS37 = 737,
CommandBINPOS38 = 738,
CommandBINPOS39 = 739,
CommandBINPOS40 = 740,
CommandBINPOS41 = 741,
CommandBINPOS42 = 742,
CommandBINPOS43 = 743,
CommandBINPOS44 = 744,
CommandBINPOS45 = 745,
CommandBINPOS46 = 746,
CommandBINPOS47 = 747,
CommandBINPOS48 = 748,
CommandBINPOS49 = 749,
CommandBINPOS50 = 750,
CommandBINPOS51 = 751,
CommandBINPOS52 = 752,
CommandBINPOS53 = 753,
CommandBINPOS54 = 754,
CommandBINPOS55 = 755,
CommandBINPOS56 = 756,
CommandBINPOS57 = 757,
CommandBINPOS58 = 758,
CommandBINPOS59 = 759,
CommandBINPOS60 = 760,
CommandBINPOS61 = 761,
CommandBINPOS62 = 762,
CommandBINPOS63 = 763,
CommandBINEDITEND = 763
};
}

@ -1,289 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include <string>
#include "Header Files/CCommand.h"
#include "ExpressionCommand.h"
using namespace std;
using namespace CalcEngine;
constexpr wchar_t chNegate = L'-';
constexpr wchar_t chExp = L'e';
constexpr wchar_t chPlus = L'+';
CParentheses::CParentheses(_In_ int command)
: m_command(command)
{
}
int CParentheses::GetCommand() const
{
return m_command;
}
CalculationManager::CommandType CParentheses::GetCommandType() const
{
return CalculationManager::CommandType::Parentheses;
}
void CParentheses::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}
CUnaryCommand::CUnaryCommand(int command)
{
m_command = make_shared<vector<int>>();
m_command->push_back(command);
}
CUnaryCommand::CUnaryCommand(int command1, int command2)
{
m_command = make_shared<vector<int>>();
m_command->push_back(command1);
m_command->push_back(command2);
}
const shared_ptr<vector<int>>& CUnaryCommand::GetCommands() const
{
return m_command;
}
CalculationManager::CommandType CUnaryCommand::GetCommandType() const
{
return CalculationManager::CommandType::UnaryCommand;
}
void CUnaryCommand::SetCommand(int command)
{
m_command->clear();
m_command->push_back(command);
}
void CUnaryCommand::SetCommands(int command1, int command2)
{
m_command->clear();
m_command->push_back(command1);
m_command->push_back(command2);
}
void CUnaryCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}
CBinaryCommand::CBinaryCommand(int command)
: m_command(command)
{
}
void CBinaryCommand::SetCommand(int command)
{
m_command = command;
}
int CBinaryCommand::GetCommand() const
{
return m_command;
}
CalculationManager::CommandType CBinaryCommand::GetCommandType() const
{
return CalculationManager::CommandType::BinaryCommand;
}
void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}
COpndCommand::COpndCommand(shared_ptr<vector<int>> const& commands, bool fNegative, bool fDecimal, bool fSciFmt)
: m_commands(commands)
, m_fNegative(fNegative)
, m_fSciFmt(fSciFmt)
, m_fDecimal(fDecimal)
, m_fInitialized(false)
, m_value{}
{
}
void COpndCommand::Initialize(Rational const& rat)
{
m_value = rat;
m_fInitialized = true;
}
const shared_ptr<vector<int>>& COpndCommand::GetCommands() const
{
return m_commands;
}
void COpndCommand::SetCommands(shared_ptr<vector<int>> const& commands)
{
m_commands = commands;
}
void COpndCommand::AppendCommand(int command)
{
if (m_fSciFmt)
{
ClearAllAndAppendCommand(static_cast<CalculationManager::Command>(command));
}
else
{
m_commands->push_back(command);
}
if (command == IDC_PNT)
{
m_fDecimal = true;
}
}
void COpndCommand::ToggleSign()
{
for (int nOpCode : *m_commands)
{
if (nOpCode != IDC_0)
{
m_fNegative = !m_fNegative;
break;
}
}
}
void COpndCommand::RemoveFromEnd()
{
if (m_fSciFmt)
{
ClearAllAndAppendCommand(CalculationManager::Command::Command0);
}
else
{
const size_t nCommands = m_commands->size();
if (nCommands == 1)
{
ClearAllAndAppendCommand(CalculationManager::Command::Command0);
}
else
{
int nOpCode = m_commands->at(nCommands - 1);
if (nOpCode == IDC_PNT)
{
m_fDecimal = false;
}
m_commands->pop_back();
}
}
}
bool COpndCommand::IsNegative() const
{
return m_fNegative;
}
bool COpndCommand::IsSciFmt() const
{
return m_fSciFmt;
}
bool COpndCommand::IsDecimalPresent() const
{
return m_fDecimal;
}
CalculationManager::CommandType COpndCommand::GetCommandType() const
{
return CalculationManager::CommandType::OperandCommand;
}
void COpndCommand::ClearAllAndAppendCommand(CalculationManager::Command command)
{
m_commands->clear();
m_commands->push_back(static_cast<int>(command));
m_fSciFmt = false;
m_fNegative = false;
m_fDecimal = false;
}
const wstring& COpndCommand::GetToken(wchar_t decimalSymbol)
{
static const wchar_t chZero = L'0';
const size_t nCommands = m_commands->size();
m_token.clear();
for (size_t i = 0; i < nCommands; i++)
{
int nOpCode = (*m_commands)[i];
if (nOpCode == IDC_PNT)
{
m_token += decimalSymbol;
}
else if (nOpCode == IDC_EXP)
{
m_token += chExp;
int nextOpCode = m_commands->at(i + 1);
if (nextOpCode != IDC_SIGN)
{
m_token += chPlus;
}
}
else if (nOpCode == IDC_SIGN)
{
m_token += chNegate;
}
else
{
wstring num = to_wstring(nOpCode - IDC_0);
m_token.append(num);
}
}
// Remove zeros
for (size_t i = 0; i < m_token.size(); i++)
{
if (m_token.at(i) != chZero)
{
if (m_token.at(i) == decimalSymbol)
{
m_token.erase(0, i - 1);
}
else
{
m_token.erase(0, i);
}
if (m_fNegative)
{
m_token.insert(0, 1, chNegate);
}
return m_token;
}
}
m_token = chZero;
return m_token;
}
wstring COpndCommand::GetString(uint32_t radix, int32_t precision)
{
if (m_fInitialized)
{
return m_value.ToString(radix, NumberFormat::Float, precision);
}
return wstring{};
}
void COpndCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}

@ -1,86 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "ExpressionCommandInterface.h"
#include "Header Files/CalcEngine.h"
#include "Header Files/Rational.h"
class CParentheses final : public IParenthesisCommand
{
public:
CParentheses(_In_ int command);
int GetCommand() const override;
CalculationManager::CommandType GetCommandType() const override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
private:
int m_command;
};
class CUnaryCommand final : public IUnaryCommand
{
public:
CUnaryCommand(int command);
CUnaryCommand(int command1, int command2);
const std::shared_ptr<std::vector<int>>& GetCommands() const override;
CalculationManager::CommandType GetCommandType() const override;
void SetCommand(int command) override;
void SetCommands(int command1, int command2) override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
private:
std::shared_ptr<std::vector<int>> m_command;
};
class CBinaryCommand final : public IBinaryCommand
{
public:
CBinaryCommand(int command);
void SetCommand(int command) override;
int GetCommand() const override;
CalculationManager::CommandType GetCommandType() const override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
private:
int m_command;
};
class COpndCommand final : public IOpndCommand
{
public:
COpndCommand(std::shared_ptr<std::vector<int>> const& commands, bool fNegative, bool fDecimal, bool fSciFmt);
void Initialize(CalcEngine::Rational const& rat);
const std::shared_ptr<std::vector<int>>& GetCommands() const override;
void SetCommands(std::shared_ptr<std::vector<int>> const& commands) override;
void AppendCommand(int command) override;
void ToggleSign() override;
void RemoveFromEnd() override;
bool IsNegative() const override;
bool IsSciFmt() const override;
bool IsDecimalPresent() const override;
const std::wstring& GetToken(wchar_t decimalSymbol) override;
CalculationManager::CommandType GetCommandType() const override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
std::wstring GetString(uint32_t radix, int32_t precision);
private:
std::shared_ptr<std::vector<int>> m_commands;
bool m_fNegative;
bool m_fSciFmt;
bool m_fDecimal;
bool m_fInitialized;
std::wstring m_token;
CalcEngine::Rational m_value;
void ClearAllAndAppendCommand(CalculationManager::Command command);
};
class ISerializeCommandVisitor
{
public:
virtual void Visit(_In_ COpndCommand& opndCmd) = 0;
virtual void Visit(_In_ CUnaryCommand& unaryCmd) = 0;
virtual void Visit(_In_ CBinaryCommand& binaryCmd) = 0;
virtual void Visit(_In_ CParentheses& paraCmd) = 0;
};

@ -1,58 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <memory> // for std::shared_ptr
#include <vector>
#include "Command.h"
#include "sal_cross_platform.h"
class ISerializeCommandVisitor;
class IExpressionCommand
{
public:
virtual CalculationManager::CommandType GetCommandType() const = 0;
virtual void Accept(_In_ ISerializeCommandVisitor& commandVisitor) = 0;
};
class IOperatorCommand : public IExpressionCommand
{
public:
virtual void SetCommand(int command) = 0;
};
class IUnaryCommand : public IOperatorCommand
{
public:
virtual const std::shared_ptr<std::vector<int>>& GetCommands() const = 0;
virtual void SetCommands(int command1, int command2) = 0;
};
class IBinaryCommand : public IOperatorCommand
{
public:
virtual void SetCommand(int command) override = 0;
virtual int GetCommand() const = 0;
};
class IOpndCommand : public IExpressionCommand
{
public:
virtual const std::shared_ptr<std::vector<int>>& GetCommands() const = 0;
virtual void AppendCommand(int command) = 0;
virtual void ToggleSign() = 0;
virtual void RemoveFromEnd() = 0;
virtual bool IsNegative() const = 0;
virtual bool IsSciFmt() const = 0;
virtual bool IsDecimalPresent() const = 0;
virtual const std::wstring& GetToken(wchar_t decimalSymbol) = 0;
virtual void SetCommands(std::shared_ptr<std::vector<int>> const& commands) = 0;
};
class IParenthesisCommand : public IExpressionCommand
{
public:
virtual int GetCommand() const = 0;
};

@ -1,249 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/****************************Module*Header***********************************
* Module Name: CCommand.h
*
* Module Description:
* Resource ID's for the Engine Commands exposed.
*
* Warnings:
*
* Created: 13-Feb-2008
*
\****************************************************************************/
#pragma once
// The following are the valid id's which can be passed to CCalcEngine::ProcessCommand
#define IDM_HEX 313
#define IDM_DEC 314
#define IDM_OCT 315
#define IDM_BIN 316
#define IDM_QWORD 317
#define IDM_DWORD 318
#define IDM_WORD 319
#define IDM_BYTE 320
#define IDM_DEG 321
#define IDM_RAD 322
#define IDM_GRAD 323
#define IDM_DEGREES 324
#define IDC_HEX IDM_HEX
#define IDC_DEC IDM_DEC
#define IDC_OCT IDM_OCT
#define IDC_BIN IDM_BIN
#define IDC_DEG IDM_DEG
#define IDC_RAD IDM_RAD
#define IDC_GRAD IDM_GRAD
#define IDC_DEGREES IDM_DEGREES
#define IDC_QWORD IDM_QWORD
#define IDC_DWORD IDM_DWORD
#define IDC_WORD IDM_WORD
#define IDC_BYTE IDM_BYTE
// Key IDs:
// These id's must be consecutive from IDC_FIRSTCONTROL to IDC_LASTCONTROL.
// The actual values don't matter but the order and sequence are very important.
// Also, the order of the controls must match the order of the control names
// in the string table.
// For example you want to declare the color for the control IDC_ST_AVE
// Find the string id for that control from the rc file
// Now define the control's id as IDC_FRISTCONTROL+stringID(IDC_ST_AVE)
#define IDC_FIRSTCONTROL IDC_SIGN
#define IDC_SIGN 80
#define IDC_CLEAR 81
#define IDC_CENTR 82
#define IDC_BACK 83
#define IDC_PNT 84
// Hole 85
#define IDC_AND 86 // Binary operators must be between IDC_AND and IDC_PWR
#define IDC_OR 87
#define IDC_XOR 88
#define IDC_LSHF 89
#define IDC_RSHF 90
#define IDC_DIV 91
#define IDC_MUL 92
#define IDC_ADD 93
#define IDC_SUB 94
#define IDC_MOD 95
#define IDC_ROOT 96
#define IDC_PWR 97
#define IDC_UNARYFIRST IDC_CHOP
#define IDC_CHOP 98 // Unary operators must be between IDC_CHOP and IDC_EQU
#define IDC_ROL 99
#define IDC_ROR 100
#define IDC_COM 101
#define IDC_SIN 102
#define IDC_COS 103
#define IDC_TAN 104
#define IDC_SINH 105
#define IDC_COSH 106
#define IDC_TANH 107
#define IDC_LN 108
#define IDC_LOG 109
#define IDC_SQRT 110
#define IDC_SQR 111
#define IDC_CUB 112
#define IDC_FAC 113
#define IDC_REC 114
#define IDC_DMS 115
#define IDC_CUBEROOT 116 // x ^ 1/3
#define IDC_POW10 117 // 10 ^ x
#define IDC_PERCENT 118
#define IDC_UNARYLAST IDC_PERCENT
#define IDC_FE 119
#define IDC_PI 120
#define IDC_EQU 121
#define IDC_MCLEAR 122
#define IDC_RECALL 123
#define IDC_STORE 124
#define IDC_MPLUS 125
#define IDC_MMINUS 126
#define IDC_EXP 127
#define IDC_OPENP 128
#define IDC_CLOSEP 129
#define IDC_0 130 // The controls for 0 through F must be consecutive and in order
#define IDC_1 131
#define IDC_2 132
#define IDC_3 133
#define IDC_4 134
#define IDC_5 135
#define IDC_6 136
#define IDC_7 137
#define IDC_8 138
#define IDC_9 139
#define IDC_A 140
#define IDC_B 141
#define IDC_C 142
#define IDC_D 143
#define IDC_E 144
#define IDC_F 145 // this is last control ID which must match the string table
#define IDC_INV 146
#define IDC_SET_RESULT 147
#define IDC_STRING_MAPPED_VALUES 400
#define IDC_UNARYEXTENDEDFIRST IDC_STRING_MAPPED_VALUES
#define IDC_SEC 400 // Secant
// 401 reserved for inverse
#define IDC_CSC 402 // Cosecant
// 403 reserved for inverse
#define IDC_COT 404 // Cotangent
// 405 reserved for inverse
#define IDC_SECH 406 // Hyperbolic Secant
// 407 reserved for inverse
#define IDC_CSCH 408 // Hyperbolic Cosecant
// 409 reserved for inverse
#define IDC_COTH 410 // Hyperbolic Cotangent
// 411 reserved for inverse
#define IDC_POW2 412 // 2 ^ x
#define IDC_ABS 413 // Absolute Value
#define IDC_FLOOR 414 // Floor
#define IDC_CEIL 415 // Ceiling
#define IDC_ROLC 416 // Rotate Left Circular
#define IDC_RORC 417 // Rotate Right Circular
#define IDC_UNARYEXTENDEDLAST IDC_RORC
#define IDC_LASTCONTROL IDC_CEIL
#define IDC_BINARYEXTENDEDFIRST 500
#define IDC_LOGBASEY 500 // logy(x)
#define IDC_NAND 501 // Nand
#define IDC_NOR 502 // Nor
#define IDC_RSHFL 505 // Right Shift Logical
#define IDC_BINARYEXTENDEDLAST IDC_RSHFL
#define IDC_RAND 600 // Random
#define IDC_EULER 601 // e Constant
#define IDC_BINEDITSTART 700
#define IDC_BINPOS0 700
#define IDC_BINPOS1 701
#define IDC_BINPOS2 702
#define IDC_BINPOS3 703
#define IDC_BINPOS4 704
#define IDC_BINPOS5 705
#define IDC_BINPOS6 706
#define IDC_BINPOS7 707
#define IDC_BINPOS8 708
#define IDC_BINPOS9 709
#define IDC_BINPOS10 710
#define IDC_BINPOS11 711
#define IDC_BINPOS12 712
#define IDC_BINPOS13 713
#define IDC_BINPOS14 714
#define IDC_BINPOS15 715
#define IDC_BINPOS16 716
#define IDC_BINPOS17 717
#define IDC_BINPOS18 718
#define IDC_BINPOS19 719
#define IDC_BINPOS20 720
#define IDC_BINPOS21 721
#define IDC_BINPOS22 722
#define IDC_BINPOS23 723
#define IDC_BINPOS24 724
#define IDC_BINPOS25 725
#define IDC_BINPOS26 726
#define IDC_BINPOS27 727
#define IDC_BINPOS28 728
#define IDC_BINPOS29 729
#define IDC_BINPOS30 730
#define IDC_BINPOS31 731
#define IDC_BINPOS32 732
#define IDC_BINPOS33 733
#define IDC_BINPOS34 734
#define IDC_BINPOS35 735
#define IDC_BINPOS36 736
#define IDC_BINPOS37 737
#define IDC_BINPOS38 738
#define IDC_BINPOS39 739
#define IDC_BINPOS40 740
#define IDC_BINPOS41 741
#define IDC_BINPOS42 742
#define IDC_BINPOS43 743
#define IDC_BINPOS44 744
#define IDC_BINPOS45 745
#define IDC_BINPOS46 746
#define IDC_BINPOS47 747
#define IDC_BINPOS48 748
#define IDC_BINPOS49 749
#define IDC_BINPOS50 750
#define IDC_BINPOS51 751
#define IDC_BINPOS52 752
#define IDC_BINPOS53 753
#define IDC_BINPOS54 754
#define IDC_BINPOS55 755
#define IDC_BINPOS56 756
#define IDC_BINPOS57 757
#define IDC_BINPOS58 758
#define IDC_BINPOS59 759
#define IDC_BINPOS60 760
#define IDC_BINPOS61 761
#define IDC_BINPOS62 762
#define IDC_BINPOS63 763
#define IDC_BINEDITEND 763
// The strings in the following range IDS_ENGINESTR_FIRST ... IDS_ENGINESTR_MAX are strings allocated in the
// resource for the purpose internal to Engine and cant be used by the clients
#define IDS_ENGINESTR_FIRST 0
#define IDS_ENGINESTR_MAX 200

@ -1,209 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
/****************************Module*Header***********************************\
* Module Name: CalcEngine.h
*
* Module Description:
* The class definition for the Calculator's engine class CCalcEngine
*
* Warnings:
*
* Created: 17-Jan-2008
*
\****************************************************************************/
#include <random>
#include "CCommand.h"
#include "EngineStrings.h"
#include "../Command.h"
#include "../ExpressionCommand.h"
#include "RadixType.h"
#include "History.h" // for History Collector
#include "CalcInput.h"
#include "CalcUtils.h"
#include "ICalcDisplay.h"
#include "Rational.h"
#include "RationalMath.h"
// The following are NOT real exports of CalcEngine, but for forward declarations
// The real exports follows later
// This is expected to be in same order as IDM_QWORD, IDM_DWORD etc.
enum class NUM_WIDTH
{
QWORD_WIDTH, // Number width of 64 bits mode (default)
DWORD_WIDTH, // Number width of 32 bits mode
WORD_WIDTH, // Number width of 16 bits mode
BYTE_WIDTH // Number width of 16 bits mode
};
static constexpr size_t NUM_WIDTH_LENGTH = 4;
namespace CalculationManager
{
class IResourceProvider;
}
namespace CalculatorEngineTests
{
class CalcEngineTests;
}
class CCalcEngine
{
public:
CCalcEngine(
bool fPrecedence,
bool fIntegerMode,
CalculationManager::IResourceProvider* const pResourceProvider,
__in_opt ICalcDisplay* pCalcDisplay,
__in_opt std::shared_ptr<IHistoryDisplay> pHistoryDisplay);
void ProcessCommand(OpCode wID);
void DisplayError(uint32_t nError);
std::unique_ptr<CalcEngine::Rational> PersistedMemObject();
void PersistedMemObject(CalcEngine::Rational const& memObject);
bool FInErrorState()
{
return m_bError;
}
bool IsInputEmpty()
{
return m_input.IsEmpty() && (m_numberString.empty() || m_numberString == L"0");
}
bool FInRecordingState()
{
return m_bRecord;
}
void SettingsChanged();
bool IsCurrentTooBigForTrig();
uint32_t GetCurrentRadix();
std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
void ChangePrecision(int32_t precision)
{
m_precision = precision;
ChangeConstants(m_radix, precision);
}
std::wstring GroupDigitsPerRadix(std::wstring_view numberString, uint32_t radix);
std::wstring GetStringForDisplay(CalcEngine::Rational const& rat, uint32_t radix);
void UpdateMaxIntDigits();
wchar_t DecimalSeparator() const;
std::vector<std::shared_ptr<IExpressionCommand>> GetHistoryCollectorCommandsSnapshot() const;
// Static methods for the instance
static void
InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider); // Once per load time to call to initialize all shared global variables
// returns the ptr to string representing the operator. Mostly same as the button, but few special cases for x^y etc.
static std::wstring_view GetString(int ids)
{
return s_engineStrings[std::to_wstring(ids)];
}
static std::wstring_view GetString(std::wstring_view ids)
{
return s_engineStrings[ids];
}
static std::wstring_view OpCodeToString(int nOpCode)
{
return GetString(IdStrFromCmdId(nOpCode));
}
static std::wstring_view OpCodeToUnaryString(int nOpCode, bool fInv, AngleType angletype);
static std::wstring_view OpCodeToBinaryString(int nOpCode, bool isIntegerMode);
private:
bool m_fPrecedence;
bool m_fIntegerMode; /* This is true if engine is explicitly called to be in integer mode. All bases are restricted to be in integers only */
ICalcDisplay* m_pCalcDisplay;
CalculationManager::IResourceProvider* const m_resourceProvider;
int m_nOpCode; /* ID value of operation. */
int m_nPrevOpCode; // opcode which computed the number in m_currentVal. 0 if it is already bracketed or plain number or
// if it hasn't yet been computed
bool m_bChangeOp; // Flag for changing operation
bool m_bRecord; // Global mode: recording or displaying
bool m_bSetCalcState; // Flag for setting the engine result state
CalcEngine::CalcInput m_input; // Global calc input object for decimal strings
NumberFormat m_nFE; // Scientific notation conversion flag
CalcEngine::Rational m_maxTrigonometricNum;
std::unique_ptr<CalcEngine::Rational> m_memoryValue; // Current memory value.
CalcEngine::Rational m_holdVal; // For holding the second operand in repetitive calculations ( pressing "=" continuously)
CalcEngine::Rational m_currentVal; // Currently displayed number used everywhere.
CalcEngine::Rational m_lastVal; // Number before operation (left operand).
std::array<CalcEngine::Rational, MAXPRECDEPTH> m_parenVals; // Holding array for parenthesis values.
std::array<CalcEngine::Rational, MAXPRECDEPTH> m_precedenceVals; // Holding array for precedence values.
bool m_bError; // Error flag.
bool m_bInv; // Inverse on/off flag.
bool m_bNoPrevEqu; /* Flag for previous equals. */
uint32_t m_radix;
int32_t m_precision;
int m_cIntDigitsSav;
std::vector<uint32_t> m_decGrouping; // Holds the decimal digit grouping number
std::wstring m_numberString;
int m_nTempCom; /* Holding place for the last command. */
size_t m_openParenCount; // Number of open parentheses.
std::array<int, MAXPRECDEPTH> m_nOp; /* Holding array for parenthesis operations. */
std::array<int, MAXPRECDEPTH> m_nPrecOp; /* Holding array for precedence operations. */
size_t m_precedenceOpCount; /* Current number of precedence ops in holding. */
int m_nLastCom; // Last command entered.
AngleType m_angletype; // Current Angle type when in dec mode. one of deg, rad or grad
NUM_WIDTH m_numwidth; // one of qword, dword, word or byte mode.
int32_t m_dwWordBitWidth; // # of bits in currently selected word size
std::unique_ptr<std::mt19937> m_randomGeneratorEngine;
std::unique_ptr<std::uniform_real_distribution<>> m_distr;
uint64_t m_carryBit;
CHistoryCollector m_HistoryCollector; // Accumulator of each line of history as various commands are processed
std::array<CalcEngine::Rational, NUM_WIDTH_LENGTH> m_chopNumbers; // word size enforcement
std::array<std::wstring, NUM_WIDTH_LENGTH> m_maxDecimalValueStrings; // maximum values represented by a given word width based off m_chopNumbers
static std::unordered_map<std::wstring_view, std::wstring> s_engineStrings; // the string table shared across all instances
wchar_t m_decimalSeparator;
wchar_t m_groupSeparator;
private:
void ProcessCommandWorker(OpCode wParam);
void ResolveHighestPrecedenceOperation();
void HandleErrorCommand(OpCode idc);
void HandleMaxDigitsReached();
void DisplayNum(void);
int IsNumberInvalid(const std::wstring& numberString, int iMaxExp, int iMaxMantissa, uint32_t radix) const;
void DisplayAnnounceBinaryOperator();
void SetPrimaryDisplay(const std::wstring& szText, bool isError = false);
void ClearTemporaryValues();
void ClearDisplay();
CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat);
CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op);
CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs);
void SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidth);
int32_t DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth);
uint32_t NRadixFromRadixType(RadixType radixtype);
double GenerateRandomNumber();
bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno);
void CheckAndAddLastBinOpToHistory(bool addToHistory = true);
void InitChopNumbers();
CalcEngine::Rational GetChopNumber() const;
std::wstring GetMaxDecimalValueString() const;
static void LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider);
static int IdStrFromCmdId(int id)
{
return id - IDC_FIRSTCONTROL + IDS_ENGINESTR_FIRST;
}
static std::vector<uint32_t> DigitGroupingStringToGroupingVector(std::wstring_view groupingString);
std::wstring GroupDigits(std::wstring_view delimiter, std::vector<uint32_t> const& grouping, std::wstring_view displayString, bool isNumNegative = false);
static int QuickLog2(int iNum);
static void ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision);
void BaseOrPrecisionChanged();
friend class CalculatorEngineTests::CalcEngineTests;
};

@ -1,81 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Rational.h"
// Space to hold enough digits for a quadword binary number (64) plus digit separator strings for that number (20)
constexpr int MAX_STRLEN = 84;
namespace CalcEngine
{
class CalcNumSec
{
public:
CalcNumSec()
: value()
, m_isNegative(false)
{
}
void Clear();
bool IsEmpty()
{
return value.empty();
}
bool IsNegative()
{
return m_isNegative;
}
void IsNegative(bool isNegative)
{
m_isNegative = isNegative;
}
std::wstring value;
private:
bool m_isNegative;
};
class CalcInput
{
public:
CalcInput()
: CalcInput(L'.')
{
}
CalcInput(wchar_t decSymbol)
: m_hasExponent(false)
, m_hasDecimal(false)
, m_decPtIndex(0)
, m_decSymbol(decSymbol)
, m_base()
, m_exponent()
{
}
void Clear();
bool TryToggleSign(bool isIntegerMode, std::wstring_view maxNumStr);
bool TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, std::wstring_view maxNumStr, int32_t wordBitWidth, int maxDigits);
bool TryAddDecimalPt();
bool HasDecimalPt();
bool TryBeginExponent();
void Backspace();
void SetDecimalSymbol(wchar_t decSymbol);
bool IsEmpty();
std::wstring ToString(uint32_t radix);
Rational ToRational(uint32_t radix, int32_t precision);
private:
bool m_hasExponent;
bool m_hasDecimal;
size_t m_decPtIndex;
wchar_t m_decSymbol;
CalcNumSec m_base;
CalcNumSec m_exponent;
};
}

@ -1,15 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
using OpCode = uintptr_t;
bool IsOpInRange(OpCode op, uint32_t x, uint32_t y);
bool IsBinOpCode(OpCode opCode);
// WARNING: IDC_SIGN is a special unary op but still this doesn't catch this. Caller has to be aware
// of it and catch it themselves or not needing this
bool IsUnaryOpCode(OpCode opCode);
bool IsDigitOpCode(OpCode opCode);
bool IsGuiSettingOpCode(OpCode opCode);

@ -1,362 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/****************************Module*Header***********************************
* Module Name: EngineStrings.h
*
* Module Description:
* Resource String ID's for the private strings used by Engine. Internal to Engine related code
* not required by the clients
*
* Warnings:
*
* Created: 13-Feb-2008
*
\****************************************************************************/
#pragma once
#include <array>
#include <string>
#include <string_view>
#include <unordered_map>
inline constexpr auto IDS_ERRORS_FIRST = 99;
// This is the list of error strings corresponding to SCERR_DIVIDEZERO..
inline constexpr auto IDS_DIVBYZERO = IDS_ERRORS_FIRST;
inline constexpr auto IDS_DOMAIN = IDS_ERRORS_FIRST + 1;
inline constexpr auto IDS_UNDEFINED = IDS_ERRORS_FIRST + 2;
inline constexpr auto IDS_POS_INFINITY = IDS_ERRORS_FIRST + 3;
inline constexpr auto IDS_NEG_INFINITY = IDS_ERRORS_FIRST + 4;
inline constexpr auto IDS_NOMEM = IDS_ERRORS_FIRST + 6;
inline constexpr auto IDS_TOOMANY = IDS_ERRORS_FIRST + 7;
inline constexpr auto IDS_OVERFLOW = IDS_ERRORS_FIRST + 8;
inline constexpr auto IDS_NORESULT = IDS_ERRORS_FIRST + 9;
inline constexpr auto IDS_INSUFFICIENT_DATA = IDS_ERRORS_FIRST + 10;
inline constexpr auto CSTRINGSENGMAX = IDS_INSUFFICIENT_DATA + 1;
// Arithmetic expression evaluator error strings
inline constexpr auto IDS_ERR_UNK_CH = CSTRINGSENGMAX + 1;
inline constexpr auto IDS_ERR_UNK_FN = CSTRINGSENGMAX + 2;
inline constexpr auto IDS_ERR_UNEX_NUM = CSTRINGSENGMAX + 3;
inline constexpr auto IDS_ERR_UNEX_CH = CSTRINGSENGMAX + 4;
inline constexpr auto IDS_ERR_UNEX_SZ = CSTRINGSENGMAX + 5;
inline constexpr auto IDS_ERR_MISMATCH_CLOSE = CSTRINGSENGMAX + 6;
inline constexpr auto IDS_ERR_UNEX_END = CSTRINGSENGMAX + 7;
inline constexpr auto IDS_ERR_SG_INV_ERROR = CSTRINGSENGMAX + 8;
inline constexpr auto IDS_ERR_INPUT_OVERFLOW = CSTRINGSENGMAX + 9;
inline constexpr auto IDS_ERR_OUTPUT_OVERFLOW = CSTRINGSENGMAX + 10;
// Resource keys for CEngineStrings.resw
inline constexpr auto SIDS_PLUS_MINUS = L"0";
inline constexpr auto SIDS_CLEAR = L"1";
inline constexpr auto SIDS_CE = L"2";
inline constexpr auto SIDS_BACKSPACE = L"3";
inline constexpr auto SIDS_DECIMAL_SEPARATOR = L"4";
inline constexpr auto SIDS_EMPTY_STRING = L"5";
inline constexpr auto SIDS_AND = L"6";
inline constexpr auto SIDS_OR = L"7";
inline constexpr auto SIDS_XOR = L"8";
inline constexpr auto SIDS_LSH = L"9";
inline constexpr auto SIDS_RSH = L"10";
inline constexpr auto SIDS_DIVIDE = L"11";
inline constexpr auto SIDS_MULTIPLY = L"12";
inline constexpr auto SIDS_PLUS = L"13";
inline constexpr auto SIDS_MINUS = L"14";
inline constexpr auto SIDS_MOD = L"15";
inline constexpr auto SIDS_YROOT = L"16";
inline constexpr auto SIDS_POW_HAT = L"17";
inline constexpr auto SIDS_INT = L"18";
inline constexpr auto SIDS_ROL = L"19";
inline constexpr auto SIDS_ROR = L"20";
inline constexpr auto SIDS_NOT = L"21";
inline constexpr auto SIDS_SIN = L"22";
inline constexpr auto SIDS_COS = L"23";
inline constexpr auto SIDS_TAN = L"24";
inline constexpr auto SIDS_SINH = L"25";
inline constexpr auto SIDS_COSH = L"26";
inline constexpr auto SIDS_TANH = L"27";
inline constexpr auto SIDS_LN = L"28";
inline constexpr auto SIDS_LOG = L"29";
inline constexpr auto SIDS_SQRT = L"30";
inline constexpr auto SIDS_XPOW2 = L"31";
inline constexpr auto SIDS_XPOW3 = L"32";
inline constexpr auto SIDS_NFACTORIAL = L"33";
inline constexpr auto SIDS_RECIPROCAL = L"34";
inline constexpr auto SIDS_DMS = L"35";
inline constexpr auto SIDS_POWTEN = L"37";
inline constexpr auto SIDS_PERCENT = L"38";
inline constexpr auto SIDS_SCIENTIFIC_NOTATION = L"39";
inline constexpr auto SIDS_PI = L"40";
inline constexpr auto SIDS_EQUAL = L"41";
inline constexpr auto SIDS_MC = L"42";
inline constexpr auto SIDS_MR = L"43";
inline constexpr auto SIDS_MS = L"44";
inline constexpr auto SIDS_MPLUS = L"45";
inline constexpr auto SIDS_MMINUS = L"46";
inline constexpr auto SIDS_EXP = L"47";
inline constexpr auto SIDS_OPEN_PAREN = L"48";
inline constexpr auto SIDS_CLOSE_PAREN = L"49";
inline constexpr auto SIDS_0 = L"50";
inline constexpr auto SIDS_1 = L"51";
inline constexpr auto SIDS_2 = L"52";
inline constexpr auto SIDS_3 = L"53";
inline constexpr auto SIDS_4 = L"54";
inline constexpr auto SIDS_5 = L"55";
inline constexpr auto SIDS_6 = L"56";
inline constexpr auto SIDS_7 = L"57";
inline constexpr auto SIDS_8 = L"58";
inline constexpr auto SIDS_9 = L"59";
inline constexpr auto SIDS_A = L"60";
inline constexpr auto SIDS_B = L"61";
inline constexpr auto SIDS_C = L"62";
inline constexpr auto SIDS_D = L"63";
inline constexpr auto SIDS_E = L"64";
inline constexpr auto SIDS_F = L"65";
inline constexpr auto SIDS_FRAC = L"66";
inline constexpr auto SIDS_SIND = L"67";
inline constexpr auto SIDS_COSD = L"68";
inline constexpr auto SIDS_TAND = L"69";
inline constexpr auto SIDS_ASIND = L"70";
inline constexpr auto SIDS_ACOSD = L"71";
inline constexpr auto SIDS_ATAND = L"72";
inline constexpr auto SIDS_SINR = L"73";
inline constexpr auto SIDS_COSR = L"74";
inline constexpr auto SIDS_TANR = L"75";
inline constexpr auto SIDS_ASINR = L"76";
inline constexpr auto SIDS_ACOSR = L"77";
inline constexpr auto SIDS_ATANR = L"78";
inline constexpr auto SIDS_SING = L"79";
inline constexpr auto SIDS_COSG = L"80";
inline constexpr auto SIDS_TANG = L"81";
inline constexpr auto SIDS_ASING = L"82";
inline constexpr auto SIDS_ACOSG = L"83";
inline constexpr auto SIDS_ATANG = L"84";
inline constexpr auto SIDS_ASINH = L"85";
inline constexpr auto SIDS_ACOSH = L"86";
inline constexpr auto SIDS_ATANH = L"87";
inline constexpr auto SIDS_POWE = L"88";
inline constexpr auto SIDS_POWTEN2 = L"89";
inline constexpr auto SIDS_SQRT2 = L"90";
inline constexpr auto SIDS_SQR = L"91";
inline constexpr auto SIDS_CUBE = L"92";
inline constexpr auto SIDS_CUBERT = L"93";
inline constexpr auto SIDS_FACT = L"94";
inline constexpr auto SIDS_RECIPROC = L"95";
inline constexpr auto SIDS_DEGREES = L"96";
inline constexpr auto SIDS_NEGATE = L"97";
inline constexpr auto SIDS_RSH2 = L"98";
inline constexpr auto SIDS_DIVIDEBYZERO = L"99";
inline constexpr auto SIDS_DOMAIN = L"100";
inline constexpr auto SIDS_UNDEFINED = L"101";
inline constexpr auto SIDS_POS_INFINITY = L"102";
inline constexpr auto SIDS_NEG_INFINITY = L"103";
inline constexpr auto SIDS_ABORTED = L"104";
inline constexpr auto SIDS_NOMEM = L"105";
inline constexpr auto SIDS_TOOMANY = L"106";
inline constexpr auto SIDS_OVERFLOW = L"107";
inline constexpr auto SIDS_NORESULT = L"108";
inline constexpr auto SIDS_INSUFFICIENT_DATA = L"109";
// 110 is skipped by CSTRINGSENGMAX
inline constexpr auto SIDS_ERR_UNK_CH = L"111";
inline constexpr auto SIDS_ERR_UNK_FN = L"112";
inline constexpr auto SIDS_ERR_UNEX_NUM = L"113";
inline constexpr auto SIDS_ERR_UNEX_CH = L"114";
inline constexpr auto SIDS_ERR_UNEX_SZ = L"115";
inline constexpr auto SIDS_ERR_MISMATCH_CLOSE = L"116";
inline constexpr auto SIDS_ERR_UNEX_END = L"117";
inline constexpr auto SIDS_ERR_SG_INV_ERROR = L"118";
inline constexpr auto SIDS_ERR_INPUT_OVERFLOW = L"119";
inline constexpr auto SIDS_ERR_OUTPUT_OVERFLOW = L"120";
inline constexpr auto SIDS_SECD = L"SecDeg";
inline constexpr auto SIDS_SECR = L"SecRad";
inline constexpr auto SIDS_SECG = L"SecGrad";
inline constexpr auto SIDS_ASECD = L"InverseSecDeg";
inline constexpr auto SIDS_ASECR = L"InverseSecRad";
inline constexpr auto SIDS_ASECG = L"InverseSecGrad";
inline constexpr auto SIDS_CSCD = L"CscDeg";
inline constexpr auto SIDS_CSCR = L"CscRad";
inline constexpr auto SIDS_CSCG = L"CscGrad";
inline constexpr auto SIDS_ACSCD = L"InverseCscDeg";
inline constexpr auto SIDS_ACSCR = L"InverseCscRad";
inline constexpr auto SIDS_ACSCG = L"InverseCscGrad";
inline constexpr auto SIDS_COTD = L"CotDeg";
inline constexpr auto SIDS_COTR = L"CotRad";
inline constexpr auto SIDS_COTG = L"CotGrad";
inline constexpr auto SIDS_ACOTD = L"InverseCotDeg";
inline constexpr auto SIDS_ACOTR = L"InverseCotRad";
inline constexpr auto SIDS_ACOTG = L"InverseCotGrad";
inline constexpr auto SIDS_SECH = L"Sech";
inline constexpr auto SIDS_ASECH = L"InverseSech";
inline constexpr auto SIDS_CSCH = L"Csch";
inline constexpr auto SIDS_ACSCH = L"InverseCsch";
inline constexpr auto SIDS_COTH = L"Coth";
inline constexpr auto SIDS_ACOTH = L"InverseCoth";
inline constexpr auto SIDS_TWOPOWX = L"TwoPowX";
inline constexpr auto SIDS_LOGBASEY = L"LogBaseY";
inline constexpr auto SIDS_ABS = L"Abs";
inline constexpr auto SIDS_FLOOR = L"Floor";
inline constexpr auto SIDS_CEIL = L"Ceil";
inline constexpr auto SIDS_NAND = L"Nand";
inline constexpr auto SIDS_NOR = L"Nor";
inline constexpr auto SIDS_CUBEROOT = L"CubeRoot";
inline constexpr auto SIDS_PROGRAMMER_MOD = L"ProgrammerMod";
// Include the resource key ID from above into this vector to load it into memory for the engine to use
inline constexpr std::array<std::wstring_view, 152> g_sids = {
SIDS_PLUS_MINUS,
SIDS_C,
SIDS_CE,
SIDS_BACKSPACE,
SIDS_DECIMAL_SEPARATOR,
SIDS_EMPTY_STRING,
SIDS_AND,
SIDS_OR,
SIDS_XOR,
SIDS_LSH,
SIDS_RSH,
SIDS_DIVIDE,
SIDS_MULTIPLY,
SIDS_PLUS,
SIDS_MINUS,
SIDS_MOD,
SIDS_YROOT,
SIDS_POW_HAT,
SIDS_INT,
SIDS_ROL,
SIDS_ROR,
SIDS_NOT,
SIDS_SIN,
SIDS_COS,
SIDS_TAN,
SIDS_SINH,
SIDS_COSH,
SIDS_TANH,
SIDS_LN,
SIDS_LOG,
SIDS_SQRT,
SIDS_XPOW2,
SIDS_XPOW3,
SIDS_NFACTORIAL,
SIDS_RECIPROCAL,
SIDS_DMS,
SIDS_POWTEN,
SIDS_PERCENT,
SIDS_SCIENTIFIC_NOTATION,
SIDS_PI,
SIDS_EQUAL,
SIDS_MC,
SIDS_MR,
SIDS_MS,
SIDS_MPLUS,
SIDS_MMINUS,
SIDS_EXP,
SIDS_OPEN_PAREN,
SIDS_CLOSE_PAREN,
SIDS_0,
SIDS_1,
SIDS_2,
SIDS_3,
SIDS_4,
SIDS_5,
SIDS_6,
SIDS_7,
SIDS_8,
SIDS_9,
SIDS_A,
SIDS_B,
SIDS_C,
SIDS_D,
SIDS_E,
SIDS_F,
SIDS_FRAC,
SIDS_SIND,
SIDS_COSD,
SIDS_TAND,
SIDS_ASIND,
SIDS_ACOSD,
SIDS_ATAND,
SIDS_SINR,
SIDS_COSR,
SIDS_TANR,
SIDS_ASINR,
SIDS_ACOSR,
SIDS_ATANR,
SIDS_SING,
SIDS_COSG,
SIDS_TANG,
SIDS_ASING,
SIDS_ACOSG,
SIDS_ATANG,
SIDS_ASINH,
SIDS_ACOSH,
SIDS_ATANH,
SIDS_POWE,
SIDS_POWTEN2,
SIDS_SQRT2,
SIDS_SQR,
SIDS_CUBE,
SIDS_CUBERT,
SIDS_FACT,
SIDS_RECIPROC,
SIDS_DEGREES,
SIDS_NEGATE,
SIDS_RSH,
SIDS_DIVIDEBYZERO,
SIDS_DOMAIN,
SIDS_UNDEFINED,
SIDS_POS_INFINITY,
SIDS_NEG_INFINITY,
SIDS_ABORTED,
SIDS_NOMEM,
SIDS_TOOMANY,
SIDS_OVERFLOW,
SIDS_NORESULT,
SIDS_INSUFFICIENT_DATA,
SIDS_ERR_UNK_CH,
SIDS_ERR_UNK_FN,
SIDS_ERR_UNEX_NUM,
SIDS_ERR_UNEX_CH,
SIDS_ERR_UNEX_SZ,
SIDS_ERR_MISMATCH_CLOSE,
SIDS_ERR_UNEX_END,
SIDS_ERR_SG_INV_ERROR,
SIDS_ERR_INPUT_OVERFLOW,
SIDS_ERR_OUTPUT_OVERFLOW,
SIDS_SECD,
SIDS_SECG,
SIDS_SECR,
SIDS_ASECD,
SIDS_ASECR,
SIDS_ASECG,
SIDS_CSCD,
SIDS_CSCR,
SIDS_CSCG,
SIDS_ACSCD,
SIDS_ACSCR,
SIDS_ACSCG,
SIDS_COTD,
SIDS_COTR,
SIDS_COTG,
SIDS_ACOTD,
SIDS_ACOTR,
SIDS_ACOTG,
SIDS_SECH,
SIDS_ASECH,
SIDS_CSCH,
SIDS_ACSCH,
SIDS_COTH,
SIDS_ACOTH,
SIDS_TWOPOWX,
SIDS_LOGBASEY,
SIDS_ABS,
SIDS_FLOOR,
SIDS_CEIL,
SIDS_NAND,
SIDS_NOR,
SIDS_CUBEROOT,
SIDS_PROGRAMMER_MOD,
};

@ -1,69 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <array>
#include "ExpressionCommand.h"
#include "ICalcDisplay.h"
#include "IHistoryDisplay.h"
#include "Rational.h"
class COpndCommand;
// maximum depth you can get by precedence. It is just an array's size limit.
static constexpr size_t MAXPRECDEPTH = 25;
// Helper class really a internal class to CCalcEngine, to accumulate each history line of text by collecting the
// operands, operator, unary operator etc. Since it is a separate entity, it can be unit tested on its own but does
// rely on CCalcEngine calling it in appropriate order.
class CHistoryCollector
{
public:
CHistoryCollector(ICalcDisplay* pCalcDisplay, std::shared_ptr<IHistoryDisplay> pHistoryDisplay, wchar_t decimalSymbol); // Can throw errors
~CHistoryCollector();
void AddOpndToHistory(std::wstring_view numStr, CalcEngine::Rational const& rat, bool fRepetition = false);
void RemoveLastOpndFromHistory();
void AddBinOpToHistory(int nOpCode, bool isIntegerMode, bool fNoRepetition = true);
void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntegerMode);
void AddUnaryOpToHistory(int nOpCode, bool fInv, AngleType angletype);
void AddOpenBraceToHistory();
void AddCloseBraceToHistory();
void PushLastOpndStart(int ichOpndStart = -1);
void PopLastOpndStart();
void EnclosePrecInversionBrackets();
bool FOpndAddedToHistory() const;
void CompleteHistoryLine(std::wstring_view numStr);
void CompleteEquation(std::wstring_view numStr);
void ClearHistoryLine(std::wstring_view errStr);
int AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand);
void UpdateHistoryExpression(uint32_t radix, int32_t precision);
void SetDecimalSymbol(wchar_t decimalSymbol);
std::shared_ptr<COpndCommand> GetOperandCommandsFromString(std::wstring_view numStr, CalcEngine::Rational const& rat) const;
std::vector<std::shared_ptr<IExpressionCommand>> GetCommands() const;
private:
std::shared_ptr<IHistoryDisplay> m_pHistoryDisplay;
ICalcDisplay* m_pCalcDisplay;
int m_iCurLineHistStart; // index of the beginning of the current equation
// a sort of state, set to the index before 2 after 2 in the expression 2 + 3 say. Useful for auto correct portion of history and for
// attaching the unary op around the last operand
int m_lastOpStartIndex; // index of the beginning of the last operand added to the history
int m_lastBinOpStartIndex; // index of the beginning of the last binary operator added to the history
std::array<int, MAXPRECDEPTH>
m_operandIndices; // Stack of index of opnd's beginning for each '('. A parallel array to m_hnoParNum, but abstracted independently of that
int m_curOperandIndex; // Stack index for the above stack
bool m_bLastOpndBrace; // iff the last opnd in history is already braced so we can avoid putting another one for unary operator
wchar_t m_decimalSymbol;
std::shared_ptr<std::vector<std::pair<std::wstring, int>>> m_spTokens;
std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> m_spCommands;
private:
void ReinitHistory();
int IchAddSzToEquationSz(std::wstring_view str, int icommandIndex);
void TruncateEquationSzFromIch(int ich);
void SetExpressionDisplay();
void InsertSzInEquationSz(std::wstring_view str, int icommandIndex, int ich);
std::shared_ptr<std::vector<int>> GetOperandCommandsFromString(std::wstring_view numStr) const;
};

@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "../ExpressionCommandInterface.h"
// Callback interface to be implemented by the clients of CCalcEngine
class ICalcDisplay
{
public:
virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) = 0;
virtual void SetIsInError(bool isInError) = 0;
virtual void SetExpressionDisplay(
_Inout_ std::shared_ptr<std::vector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> const& commands) = 0;
virtual void SetParenthesisNumber(_In_ unsigned int count) = 0;
virtual void OnNoRightParenAdded() = 0;
virtual void MaxDigitsReached() = 0; // not an error but still need to inform UI layer.
virtual void BinaryOperatorReceived() = 0;
virtual void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) = 0;
virtual void SetMemorizedNumbers(const std::vector<std::wstring>& memorizedNumbers) = 0;
virtual void MemoryItemChanged(unsigned int indexOfMemory) = 0;
virtual void InputChanged() = 0;
};

@ -1,17 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "../ExpressionCommandInterface.h"
// Callback interface to be implemented by the clients of CCalcEngine if they require equation history
class IHistoryDisplay
{
public:
virtual ~IHistoryDisplay(){};
virtual unsigned int AddToHistory(
_In_ std::shared_ptr<std::vector<std::pair<std::wstring, int>>> const& tokens,
_In_ std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> const& commands,
_In_ std::wstring_view result) = 0;
};

@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <vector>
#include "Ratpack/ratpak.h"
namespace CalcEngine
{
class Number
{
public:
Number() noexcept;
Number(int32_t sign, int32_t exp, std::vector<uint32_t> const& mantissa) noexcept;
explicit Number(PNUMBER p) noexcept;
PNUMBER ToPNUMBER() const;
int32_t const& Sign() const;
int32_t const& Exp() const;
std::vector<uint32_t> const& Mantissa() const;
bool IsZero() const;
private:
int32_t m_sign;
int32_t m_exp;
std::vector<uint32_t> m_mantissa;
};
}

@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
// This is expected to be in same order as IDM_HEX, IDM_DEC, IDM_OCT, IDM_BIN
enum class RadixType
{
Hex,
Decimal,
Octal,
Binary
};

@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Number.h"
namespace CalcEngine
{
// Default Base/Radix to use for Rational calculations
// RatPack calculations currently support up to Base64.
inline constexpr uint32_t RATIONAL_BASE = 10;
// Default Precision to use for Rational calculations
inline constexpr int32_t RATIONAL_PRECISION = 128;
class Rational
{
public:
Rational() noexcept;
Rational(Number const& n) noexcept;
Rational(Number const& p, Number const& q) noexcept;
Rational(int32_t i);
Rational(uint32_t ui);
Rational(uint64_t ui);
explicit Rational(PRAT prat) noexcept;
PRAT ToPRAT() const;
Number const& P() const;
Number const& Q() const;
Rational operator-() const;
Rational& operator+=(Rational const& rhs);
Rational& operator-=(Rational const& rhs);
Rational& operator*=(Rational const& rhs);
Rational& operator/=(Rational const& rhs);
Rational& operator%=(Rational const& rhs);
Rational& operator<<=(Rational const& rhs);
Rational& operator>>=(Rational const& rhs);
Rational& operator&=(Rational const& rhs);
Rational& operator|=(Rational const& rhs);
Rational& operator^=(Rational const& rhs);
friend Rational operator+(Rational lhs, Rational const& rhs);
friend Rational operator-(Rational lhs, Rational const& rhs);
friend Rational operator*(Rational lhs, Rational const& rhs);
friend Rational operator/(Rational lhs, Rational const& rhs);
friend Rational operator%(Rational lhs, Rational const& rhs);
friend Rational operator<<(Rational lhs, Rational const& rhs);
friend Rational operator>>(Rational lhs, Rational const& rhs);
friend Rational operator&(Rational lhs, Rational const& rhs);
friend Rational operator|(Rational lhs, Rational const& rhs);
friend Rational operator^(Rational lhs, Rational const& rhs);
friend bool operator==(Rational const& lhs, Rational const& rhs);
friend bool operator!=(Rational const& lhs, Rational const& rhs);
friend bool operator<(Rational const& lhs, Rational const& rhs);
friend bool operator>(Rational const& lhs, Rational const& rhs);
friend bool operator<=(Rational const& lhs, Rational const& rhs);
friend bool operator>=(Rational const& lhs, Rational const& rhs);
std::wstring ToString(uint32_t radix, NumberFormat format, int32_t precision) const;
uint64_t ToUInt64_t() const;
private:
Number m_p;
Number m_q;
};
}

@ -1,38 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Rational.h"
namespace CalcEngine::RationalMath
{
Rational Frac(Rational const& rat);
Rational Integer(Rational const& rat);
Rational Pow(Rational const& base, Rational const& pow);
Rational Root(Rational const& base, Rational const& root);
Rational Fact(Rational const& rat);
Rational Mod(Rational const& a, Rational const& b);
Rational Exp(Rational const& rat);
Rational Log(Rational const& rat);
Rational Log10(Rational const& rat);
Rational Invert(Rational const& rat);
Rational Abs(Rational const& rat);
Rational Sin(Rational const& rat, AngleType angletype);
Rational Cos(Rational const& rat, AngleType angletype);
Rational Tan(Rational const& rat, AngleType angletype);
Rational ASin(Rational const& rat, AngleType angletype);
Rational ACos(Rational const& rat, AngleType angletype);
Rational ATan(Rational const& rat, AngleType angletype);
Rational Sinh(Rational const& rat);
Rational Cosh(Rational const& rat);
Rational Tanh(Rational const& rat);
Rational ASinh(Rational const& rat);
Rational ACosh(Rational const& rat);
Rational ATanh(Rational const& rat);
}

@ -1,80 +0,0 @@
#include "pch.h"
#include "NumberFormattingUtils.h"
using namespace std;
namespace UnitConversionManager::NumberFormattingUtils
{
/// <summary>
/// Trims out any trailing zeros or decimals in the given input string
/// </summary>
/// <param name="number">number to trim</param>
void TrimTrailingZeros(_Inout_ wstring& number)
{
if (number.find(L'.') == wstring::npos)
{
return;
}
if (auto i = number.find_last_not_of(L'0'); i != wstring::npos)
{
number.erase(number.cbegin() + i + 1, number.cend());
}
if (number.back() == L'.')
{
number.pop_back();
}
}
/// <summary>
/// Get number of digits (whole number part + decimal part)</summary>
/// <param name="value">the number</param>
unsigned int GetNumberDigits(wstring value)
{
TrimTrailingZeros(value);
unsigned int numberSignificantDigits = static_cast<unsigned int>(value.size());
if (value.find(L'.') != wstring::npos)
{
--numberSignificantDigits;
}
if (value.find(L'-') != wstring::npos)
{
--numberSignificantDigits;
}
return numberSignificantDigits;
}
/// <summary>
/// Get number of digits (whole number part only)</summary>
/// <param name="value">the number</param>
unsigned int GetNumberDigitsWholeNumberPart(double value)
{
return value == 0 ? 1u : static_cast<unsigned int>(1 + max(0.0, log10(abs(value))));
}
/// <summary>
/// Rounds the given double to the given number of significant digits
/// </summary>
/// <param name="num">input double</param>
/// <param name="numSignificant">unsigned int number of significant digits to round to</param>
wstring RoundSignificantDigits(double num, unsigned int numSignificant)
{
wstringstream out(wstringstream::out);
out << fixed;
out.precision(numSignificant);
out << num;
return out.str();
}
/// <summary>
/// Convert a Number to Scientific Notation
/// </summary>
/// <param name="number">number to convert</param>
wstring ToScientificNumber(double number)
{
wstringstream out(wstringstream::out);
out << scientific << number;
return out.str();
}
}

@ -1,16 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <string>
#include "sal_cross_platform.h"
namespace UnitConversionManager::NumberFormattingUtils
{
void TrimTrailingZeros(_Inout_ std::wstring& input);
unsigned int GetNumberDigits(std::wstring value);
unsigned int GetNumberDigitsWholeNumberPart(double value);
std::wstring RoundSignificantDigits(double value, unsigned int numberSignificantDigits);
std::wstring ToScientificNumber(double number);
}

@ -1,87 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <cstdint>
// CalcErr.h
//
// Defines the error codes thrown by ratpak and caught by Calculator
//
//
// Ratpak errors are 32 bit values laid out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +-+-------+---------------------+-------------------------------+
// |S| R | Facility | Code |
// +-+-------+---------------------+-------------------------------+
//
// where
//
// S - Severity - indicates success/fail
//
// 0 - Success
// 1 - Fail
//
// R - Reserved - not currently used for anything
//
// r - reserved portion of the facility code. Reserved for internal
// use. Used to indicate int32_t values that are not status
// values, but are instead message ids for display strings.
//
// Facility - is the facility code
//
// Code - is the actual error code
//
// This format is based loosely on an OLE HRESULT and is compatible with the
// SUCCEEDED and FAILED macros as well as the HRESULT_CODE macro
using ResultCode = int32_t;
// CALC_E_DIVIDEBYZERO
//
// The current operation would require a divide by zero to complete
static constexpr uint32_t CALC_E_DIVIDEBYZERO = (uint32_t)0x80000000;
// CALC_E_DOMAIN
//
// The given input is not within the domain of this function
static constexpr uint32_t CALC_E_DOMAIN = (uint32_t)0x80000001;
// CALC_E_INDEFINITE
//
// The result of this function is undefined
static constexpr uint32_t CALC_E_INDEFINITE = (uint32_t)0x80000002;
// CALC_E_POSINFINITY
//
// The result of this function is Positive Infinity.
static constexpr uint32_t CALC_E_POSINFINITY = (uint32_t)0x80000003;
// CALC_E_NEGINFINITY
//
// The result of this function is Negative Infinity
static constexpr uint32_t CALC_E_NEGINFINITY = (uint32_t)0x80000004;
// CALC_E_INVALIDRANGE
//
// The given input is within the domain of the function but is beyond
// the range for which calc can successfully compute the answer
static constexpr uint32_t CALC_E_INVALIDRANGE = (uint32_t)0x80000006;
// CALC_E_OUTOFMEMORY
//
// There is not enough free memory to complete the requested function
static constexpr uint32_t CALC_E_OUTOFMEMORY = (uint32_t)0x80000007;
// CALC_E_OVERFLOW
//
// The result of this operation is an overflow
static constexpr uint32_t CALC_E_OVERFLOW = (uint32_t)0x80000008;
// CALC_E_NORESULT
//
// The result of this operation is undefined
static constexpr uint32_t CALC_E_NORESULT = (uint32_t)0x80000009;

@ -1,362 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File basex.c
// Copyright (C) 1995-97 Microsoft
// Date 03-14-97
//
//
// Description
//
// Contains number routines for internal base computations, these assume
// internal base is a power of 2.
//
//-----------------------------------------------------------------------------
#include "ratpak.h"
#include <cstring> // for memmove
void _mulnumx(PNUMBER* pa, PNUMBER b);
//----------------------------------------------------------------------------
//
// FUNCTION: mulnumx
//
// ARGUMENTS: pointer to a number and a second number, the
// base is always BASEX.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa *= b.
// This is a stub which prevents multiplication by 1, this is a big speed
// improvement.
//
//----------------------------------------------------------------------------
void mulnumx(_Inout_ PNUMBER* pa, _In_ PNUMBER b)
{
if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0)
{
// If b is not one we multiply
if ((*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0)
{
// pa and b are both non-one.
_mulnumx(pa, b);
}
else
{
// if pa is one and b isn't just copy b. and adjust the sign.
int32_t sign = (*pa)->sign;
DUPNUM(*pa, b);
(*pa)->sign *= sign;
}
}
else
{
// B is +/- 1, But we do have to set the sign.
(*pa)->sign *= b->sign;
}
}
//----------------------------------------------------------------------------
//
// FUNCTION: _mulnumx
//
// ARGUMENTS: pointer to a number and a second number, the
// base is always BASEX.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa *= b.
// Assumes the base is BASEX of both numbers. This algorithm is the
// same one you learned in grade school, except the base isn't 10 it's
// BASEX.
//
//----------------------------------------------------------------------------
void _mulnumx(PNUMBER* pa, PNUMBER b)
{
PNUMBER c = nullptr; // c will contain the result.
PNUMBER a = nullptr; // a is the dereferenced number pointer from *pa
MANTTYPE* ptra; // ptra is a pointer to the mantissa of a.
MANTTYPE* ptrb; // ptrb is a pointer to the mantissa of b.
MANTTYPE* ptrc; // ptrc is a pointer to the mantissa of c.
MANTTYPE* ptrcoffset; // ptrcoffset, is the anchor location of the next
// single digit multiply partial result.
int32_t iadigit = 0; // Index of digit being used in the first number.
int32_t ibdigit = 0; // Index of digit being used in the second number.
MANTTYPE da = 0; // da is the digit from the fist number.
TWO_MANTTYPE cy = 0; // cy is the carry resulting from the addition of
// a multiplied row into the result.
TWO_MANTTYPE mcy = 0; // mcy is the resultant from a single
// multiply, AND the carry of that multiply.
int32_t icdigit = 0; // Index of digit being calculated in final result.
a = *pa;
ibdigit = a->cdigit + b->cdigit - 1;
createnum(c, ibdigit + 1);
c->cdigit = ibdigit;
c->sign = a->sign * b->sign;
c->exp = a->exp + b->exp;
ptra = a->mant;
ptrcoffset = c->mant;
for (iadigit = a->cdigit; iadigit > 0; iadigit--)
{
da = *ptra++;
ptrb = b->mant;
// Shift ptrc, and ptrcoffset, one for each digit
ptrc = ptrcoffset++;
for (ibdigit = b->cdigit; ibdigit > 0; ibdigit--)
{
cy = 0;
mcy = (uint64_t)da * (*ptrb);
if (mcy)
{
icdigit = 0;
if (ibdigit == 1 && iadigit == 1)
{
c->cdigit++;
}
}
// If result is nonzero, or while result of carry is nonzero...
while (mcy || cy)
{
// update carry from addition(s) and multiply.
cy += (TWO_MANTTYPE)ptrc[icdigit] + ((uint32_t)mcy & ((uint32_t)~BASEX));
// update result digit from
ptrc[icdigit++] = (MANTTYPE)((uint32_t)cy & ((uint32_t)~BASEX));
// update carries from
mcy >>= BASEXPWR;
cy >>= BASEXPWR;
}
ptrb++;
ptrc++;
}
}
// prevent different kinds of zeros, by stripping leading duplicate zeros.
// digits are in order of increasing significance.
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
destroynum(*pa);
*pa = c;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: numpowi32x
//
// ARGUMENTS: root as number power as int32_t
// number.
//
// RETURN: None root is changed.
//
// DESCRIPTION: changes numeric representation of root to
// root ** power. Assumes base BASEX
// decomposes the exponent into it's sums of powers of 2, so on average
// it will take n+n/2 multiplies where n is the highest on bit.
//
//-----------------------------------------------------------------------------
void numpowi32x(_Inout_ PNUMBER* proot, int32_t power)
{
PNUMBER lret = i32tonum(1, BASEX);
// Once the power remaining is zero we are done.
while (power > 0)
{
// If this bit in the power decomposition is on, multiply the result
// by the root number.
if (power & 1)
{
mulnumx(&lret, *proot);
}
// multiply the root number by itself to scale for the next bit (i.e.
// square it.
mulnumx(proot, *proot);
// move the next bit of the power into place.
power >>= 1;
}
destroynum(*proot);
*proot = lret;
}
void _divnumx(PNUMBER* pa, PNUMBER b, int32_t precision);
//----------------------------------------------------------------------------
//
// FUNCTION: divnumx
//
// ARGUMENTS: pointer to a number, a second number and precision.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa /= b.
// Assumes radix is the internal radix representation.
// This is a stub which prevents division by 1, this is a big speed
// improvement.
//
//----------------------------------------------------------------------------
void divnumx(_Inout_ PNUMBER* pa, _In_ PNUMBER b, int32_t precision)
{
if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0)
{
// b is not one.
if ((*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0)
{
// pa and b are both not one.
_divnumx(pa, b, precision);
}
else
{
// if pa is one and b is not one, just copy b, and adjust the sign.
int32_t sign = (*pa)->sign;
DUPNUM(*pa, b);
(*pa)->sign *= sign;
}
}
else
{
// b is one so don't divide, but set the sign.
(*pa)->sign *= b->sign;
}
}
//----------------------------------------------------------------------------
//
// FUNCTION: _divnumx
//
// ARGUMENTS: pointer to a number, a second number and precision.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa /= b.
// Assumes radix is the internal radix representation.
//
//----------------------------------------------------------------------------
void _divnumx(PNUMBER* pa, PNUMBER b, int32_t precision)
{
PNUMBER a = nullptr; // a is the dereferenced number pointer from *pa
PNUMBER c = nullptr; // c will contain the result.
PNUMBER lasttmp = nullptr; // lasttmp allows a backup when the algorithm
// guesses one bit too far.
PNUMBER tmp = nullptr; // current guess being worked on for divide.
PNUMBER rem = nullptr; // remainder after applying guess.
int32_t cdigits; // count of digits for answer.
MANTTYPE* ptrc; // ptrc is a pointer to the mantissa of c.
int32_t thismax = precision + g_ratio; // set a maximum number of internal digits
// to shoot for in the divide.
a = *pa;
if (thismax < a->cdigit)
{
// a has more digits than precision specified, bump up digits to shoot
// for.
thismax = a->cdigit;
}
if (thismax < b->cdigit)
{
// b has more digits than precision specified, bump up digits to shoot
// for.
thismax = b->cdigit;
}
// Create c (the divide answer) and set up exponent and sign.
createnum(c, thismax + 1);
c->exp = (a->cdigit + a->exp) - (b->cdigit + b->exp) + 1;
c->sign = a->sign * b->sign;
ptrc = c->mant + thismax;
cdigits = 0;
DUPNUM(rem, a);
rem->sign = b->sign;
rem->exp = b->cdigit + b->exp - rem->cdigit;
while (cdigits++ < thismax && !zernum(rem))
{
int32_t digit = 0;
*ptrc = 0;
while (!lessnum(rem, b))
{
digit = 1;
DUPNUM(tmp, b);
destroynum(lasttmp);
lasttmp = i32tonum(0, BASEX);
while (lessnum(tmp, rem))
{
destroynum(lasttmp);
DUPNUM(lasttmp, tmp);
addnum(&tmp, tmp, BASEX);
digit *= 2;
}
if (lessnum(rem, tmp))
{
// too far, back up...
destroynum(tmp);
digit /= 2;
tmp = lasttmp;
lasttmp = nullptr;
}
tmp->sign *= -1;
addnum(&rem, tmp, BASEX);
destroynum(tmp);
destroynum(lasttmp);
*ptrc |= digit;
}
rem->exp++;
ptrc--;
}
cdigits--;
if (c->mant != ++ptrc)
{
memmove(c->mant, ptrc, (int)(cdigits * sizeof(MANTTYPE)));
}
if (!cdigits)
{
// A zero, make sure no weird exponents creep in
c->exp = 0;
c->cdigit = 1;
}
else
{
c->cdigit = cdigits;
c->exp -= cdigits;
// prevent different kinds of zeros, by stripping leading duplicate
// zeros. digits are in order of increasing significance.
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
}
destroynum(rem);
destroynum(*pa);
*pa = c;
}

File diff suppressed because it is too large Load Diff

@ -1,527 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File exp.c
// Copyright (C) 1995-96 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains exp, and log functions for rationals
//
//
//-----------------------------------------------------------------------------
#include "ratpak.h"
//-----------------------------------------------------------------------------
//
// FUNCTION: exprat
//
// ARGUMENTS: x PRAT representation of number to exponentiate
//
// RETURN: exp of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___
// \ ] X
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j j+1
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
//-----------------------------------------------------------------------------
void _exprat(_Inout_ PRAT* px, int32_t precision)
{
CREATETAYLOR();
addnum(&(pret->pp), num_one, BASEX);
addnum(&(pret->pq), num_one, BASEX);
DUPRAT(thisterm, pret);
n2 = i32tonum(0L, BASEX);
do
{
NEXTTERM(*px, INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void exprat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
PRAT pwr = nullptr;
PRAT pint = nullptr;
if (rat_gt(*px, rat_max_exp, precision) || rat_lt(*px, rat_min_exp, precision))
{
// Don't attempt exp of anything large.
throw(CALC_E_DOMAIN);
}
DUPRAT(pwr, rat_exp);
DUPRAT(pint, *px);
intrat(&pint, radix, precision);
const int32_t intpwr = rattoi32(pint, radix, precision);
ratpowi32(&pwr, intpwr, precision);
subrat(px, pint, precision);
// It just so happens to be an integral power of e.
if (rat_gt(*px, rat_negsmallest, precision) && rat_lt(*px, rat_smallest, precision))
{
DUPRAT(*px, pwr);
}
else
{
_exprat(px, precision);
mulrat(px, pwr, precision);
}
destroyrat(pwr);
destroyrat(pint);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: lograt, _lograt
//
// ARGUMENTS: x PRAT representation of number to logarithim
//
// RETURN: log of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___
// \ ] j*(1-X)
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j j+1
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
// Number is scaled between one and e_to_one_half prior to taking the
// log. This is to keep execution time from exploding.
//
//
//-----------------------------------------------------------------------------
void _lograt(PRAT* px, int32_t precision)
{
CREATETAYLOR();
createrat(thisterm);
// sub one from x
(*px)->pq->sign *= -1;
addnum(&((*px)->pp), (*px)->pq, BASEX);
(*px)->pq->sign *= -1;
DUPRAT(pret, *px);
DUPRAT(thisterm, *px);
n2 = i32tonum(1L, BASEX);
(*px)->pp->sign *= -1;
do
{
NEXTTERM(*px, MULNUM(n2) INC(n2) DIVNUM(n2), precision);
TRIMTOP(*px, precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void lograt(_Inout_ PRAT* px, int32_t precision)
{
PRAT pwr = nullptr; // pwr is the large scaling factor.
PRAT offset = nullptr; // offset is the incremental scaling factor.
// Check for someone taking the log of zero or a negative number.
if (rat_le(*px, rat_zero, precision))
{
throw(CALC_E_DOMAIN);
}
// Get number > 1, for scaling
bool fneglog = rat_lt(*px, rat_one, precision);
if (fneglog)
{
PNUMBER pnumtemp = (*px)->pp;
(*px)->pp = (*px)->pq;
(*px)->pq = pnumtemp;
}
// Scale the number within BASEX factor of 1, for the large scale.
// log(x*2^(BASEXPWR*k)) = BASEXPWR*k*log(2)+log(x)
if (LOGRAT2(*px) > 1)
{
const int32_t intpwr = LOGRAT2(*px) - 1;
(*px)->pq->exp += intpwr;
pwr = i32torat(intpwr * BASEXPWR);
mulrat(&pwr, ln_two, precision);
// ln(x+e)-ln(x) looks close to e when x is close to one using some
// expansions. This means we can trim past precision digits+1.
TRIMTOP(*px, precision);
}
else
{
DUPRAT(pwr, rat_zero);
}
DUPRAT(offset, rat_zero);
// Scale the number between 1 and e_to_one_half, for the small scale.
while (rat_gt(*px, e_to_one_half, precision))
{
divrat(px, e_to_one_half, precision);
addrat(&offset, rat_one, precision);
}
_lograt(px, precision);
// Add the large and small scaling factors, take into account
// small scaling was done in e_to_one_half chunks.
divrat(&offset, rat_two, precision);
addrat(&pwr, offset, precision);
// And add the resulting scaling factor to the answer.
addrat(px, pwr, precision);
trimit(px, precision);
// If number started out < 1 rescale answer to negative.
if (fneglog)
{
(*px)->pp->sign *= -1;
}
destroyrat(offset);
destroyrat(pwr);
}
void log10rat(_Inout_ PRAT* px, int32_t precision)
{
lograt(px, precision);
divrat(px, ln_ten, precision);
}
//
// return if the given x is even number. The assumption here is its denominator is 1 and we are testing the numerator is
// even or not
bool IsEven(PRAT x, uint32_t radix, int32_t precision)
{
PRAT tmp = nullptr;
bool bRet = false;
DUPRAT(tmp, x);
divrat(&tmp, rat_two, precision);
fracrat(&tmp, radix, precision);
addrat(&tmp, tmp, precision);
subrat(&tmp, rat_one, precision);
if (rat_lt(tmp, rat_zero, precision))
{
bRet = true;
}
destroyrat(tmp);
return bRet;
}
//---------------------------------------------------------------------------
//
// FUNCTION: powrat
//
// ARGUMENTS: PRAT *px, PRAT y, uint32_t radix, int32_t precision
//
// RETURN: none, sets *px to *px to the y.
//
// EXPLANATION: Calculates the power of both px and
// handles special cases where px is a perfect root.
// Assumes, all checking has been done on validity of numbers.
//
//
//---------------------------------------------------------------------------
void powrat(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision)
{
// Handle cases where px or y is 0 by calling powratcomp directly
if (zerrat(*px) || zerrat(y))
{
powratcomp(px, y, radix, precision);
return;
}
// When y is 1, return px
if (rat_equ(y, rat_one, precision))
{
return;
}
try
{
powratNumeratorDenominator(px, y, radix, precision);
}
catch (...)
{
// If calculating the power using numerator/denominator
// failed, fall back to the less accurate method of
// passing in the original y
powratcomp(px, y, radix, precision);
}
}
void powratNumeratorDenominator(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision)
{
// Prepare rationals
PRAT yNumerator = nullptr;
PRAT yDenominator = nullptr;
DUPRAT(yNumerator, rat_zero); // yNumerator->pq is 1 one
DUPRAT(yDenominator, rat_zero); // yDenominator->pq is 1 one
DUPNUM(yNumerator->pp, y->pp);
DUPNUM(yDenominator->pp, y->pq);
// Calculate the following use the Powers of Powers rule:
// px ^ (yNum/yDenom) == px ^ yNum ^ (1/yDenom)
// 1. For px ^ yNum, we call powratcomp directly which will call ratpowi32
// and store the result in pxPowNum
// 2. For pxPowNum ^ (1/yDenom), we call powratcomp
// 3. Validate the result of 2 by adding/subtracting 0.5, flooring and call powratcomp with yDenom
// on the floored result.
// 1. Initialize result.
PRAT pxPow = nullptr;
DUPRAT(pxPow, *px);
// 2. Calculate pxPow = px ^ yNumerator
// if yNumerator is not 1
if (!rat_equ(yNumerator, rat_one, precision))
{
powratcomp(&pxPow, yNumerator, radix, precision);
}
// 2. Calculate pxPowNumDenom = pxPowNum ^ (1/yDenominator),
// if yDenominator is not 1
if (!rat_equ(yDenominator, rat_one, precision))
{
// Calculate 1 over y
PRAT oneoveryDenom = nullptr;
DUPRAT(oneoveryDenom, rat_one);
divrat(&oneoveryDenom, yDenominator, precision);
// ##################################
// Take the oneoveryDenom power
// ##################################
PRAT originalResult = nullptr;
DUPRAT(originalResult, pxPow);
powratcomp(&originalResult, oneoveryDenom, radix, precision);
// ##################################
// Round the originalResult to roundedResult
// ##################################
PRAT roundedResult = nullptr;
DUPRAT(roundedResult, originalResult);
if (roundedResult->pp->sign == -1)
{
subrat(&roundedResult, rat_half, precision);
}
else
{
addrat(&roundedResult, rat_half, precision);
}
intrat(&roundedResult, radix, precision);
// ##################################
// Take the yDenom power of the roundedResult.
// ##################################
PRAT roundedPower = nullptr;
DUPRAT(roundedPower, roundedResult);
powratcomp(&roundedPower, yDenominator, radix, precision);
// ##################################
// if roundedPower == px,
// we found an exact power in roundedResult
// ##################################
if (rat_equ(roundedPower, pxPow, precision))
{
DUPRAT(*px, roundedResult);
}
else
{
DUPRAT(*px, originalResult);
}
destroyrat(oneoveryDenom);
destroyrat(originalResult);
destroyrat(roundedResult);
destroyrat(roundedPower);
}
else
{
DUPRAT(*px, pxPow);
}
destroyrat(yNumerator);
destroyrat(yDenominator);
destroyrat(pxPow);
}
//---------------------------------------------------------------------------
//
// FUNCTION: powratcomp
//
// ARGUMENTS: PRAT *px, and PRAT y
//
// RETURN: none, sets *px to *px to the y.
//
// EXPLANATION: This uses x^y=e(y*ln(x)), or a more exact calculation where
// y is an integer.
// Assumes, all checking has been done on validity of numbers.
//
//
//---------------------------------------------------------------------------
void powratcomp(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision)
{
int32_t sign = SIGN(*px);
// Take the absolute value
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if (zerrat(*px))
{
// *px is zero.
if (rat_lt(y, rat_zero, precision))
{
throw(CALC_E_DOMAIN);
}
else if (zerrat(y))
{
// *px and y are both zero, special case a 1 return.
DUPRAT(*px, rat_one);
// Ensure sign is positive.
sign = 1;
}
}
else
{
PRAT pxint = nullptr;
DUPRAT(pxint, *px);
subrat(&pxint, rat_one, precision);
if (rat_gt(pxint, rat_negsmallest, precision) && rat_lt(pxint, rat_smallest, precision) && (sign == 1))
{
// *px is one, special case a 1 return.
DUPRAT(*px, rat_one);
// Ensure sign is positive.
sign = 1;
}
else
{
// Only do the exp if the number isn't zero or one
PRAT podd = nullptr;
DUPRAT(podd, y);
fracrat(&podd, radix, precision);
if (rat_gt(podd, rat_negsmallest, precision) && rat_lt(podd, rat_smallest, precision))
{
// If power is an integer let ratpowi32 deal with it.
PRAT iy = nullptr;
DUPRAT(iy, y);
subrat(&iy, podd, precision);
int32_t inty = rattoi32(iy, radix, precision);
PRAT plnx = nullptr;
DUPRAT(plnx, *px);
lograt(&plnx, precision);
mulrat(&plnx, iy, precision);
if (rat_gt(plnx, rat_max_exp, precision) || rat_lt(plnx, rat_min_exp, precision))
{
// Don't attempt exp of anything large or small.A
destroyrat(plnx);
destroyrat(iy);
destroyrat(pxint);
destroyrat(podd);
throw(CALC_E_DOMAIN);
}
destroyrat(plnx);
ratpowi32(px, inty, precision);
if ((inty & 1) == 0)
{
sign = 1;
}
destroyrat(iy);
}
else
{
// power is a fraction
if (sign == -1)
{
// Need to throw an error if the exponent has an even denominator.
// As a first step, the numerator and denominator must be divided by 2 as many times as
// possible, so that 2/6 is allowed.
// If the final numerator is still even, the end result should be positive.
PRAT pNumerator = nullptr;
PRAT pDenominator = nullptr;
bool fBadExponent = false;
// Get the numbers in arbitrary precision rational number format
DUPRAT(pNumerator, rat_zero); // pNumerator->pq is 1 one
DUPRAT(pDenominator, rat_zero); // pDenominator->pq is 1 one
DUPNUM(pNumerator->pp, y->pp);
pNumerator->pp->sign = 1;
DUPNUM(pDenominator->pp, y->pq);
pDenominator->pp->sign = 1;
while (IsEven(pNumerator, radix, precision) && IsEven(pDenominator, radix, precision)) // both Numerator & denominator is even
{
divrat(&pNumerator, rat_two, precision);
divrat(&pDenominator, rat_two, precision);
}
if (IsEven(pDenominator, radix, precision)) // denominator is still even
{
fBadExponent = true;
}
if (IsEven(pNumerator, radix, precision)) // numerator is still even
{
sign = 1;
}
destroyrat(pNumerator);
destroyrat(pDenominator);
if (fBadExponent)
{
throw(CALC_E_DOMAIN);
}
}
else
{
// If the exponent is not odd disregard the sign.
sign = 1;
}
lograt(px, precision);
mulrat(px, y, precision);
exprat(px, radix, precision);
}
destroyrat(podd);
}
destroyrat(pxint);
}
(*px)->pp->sign *= sign;
}

@ -1,247 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File fact.c
// Copyright (C) 1995-96 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains fact(orial) and supporting _gamma functions.
//
//-----------------------------------------------------------------------------
#include "ratpak.h"
#define ABSRAT(x) (((x)->pp->sign = 1), ((x)->pq->sign = 1))
#define NEGATE(x) ((x)->pp->sign *= -1)
//-----------------------------------------------------------------------------
//
// FUNCTION: factrat, _gamma, gamma
//
// ARGUMENTS: x PRAT representation of number to take the sine of
//
// RETURN: factorial of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2j
// n \ ] A 1 A
// A \ -----[ ---- - ---------------]
// / (2j)! n+2j (n+2j+1)(2j+1)
// /__]
// j=0
//
// / oo
// | n-1 -x __
// This was derived from | x e dx = |
// | | (n) { = (n-1)! for +integers}
// / 0
//
// It can be shown that the above series is within precision if A is chosen
// big enough.
// A n precision
// Based on the relation ne = A 10 A was chosen as
//
// precision
// A = ln(Base /n)+1
// A += n*ln(A) This is close enough for precision > base and n < 1.5
//
//
//-----------------------------------------------------------------------------
void _gamma(PRAT* pn, uint32_t radix, int32_t precision)
{
PRAT factorial = nullptr;
PNUMBER count = nullptr;
PRAT tmp = nullptr;
PRAT one_pt_five = nullptr;
PRAT a = nullptr;
PRAT a2 = nullptr;
PRAT term = nullptr;
PRAT sum = nullptr;
PRAT err = nullptr;
PRAT mpy = nullptr;
// Set up constants and initial conditions
PRAT ratprec = i32torat(precision);
// Find the best 'A' for convergence to the required precision.
a = i32torat(radix);
lograt(&a, precision);
mulrat(&a, ratprec, precision);
// Really is -ln(n)+1, but -ln(n) will be < 1
// if we scale n between 0.5 and 1.5
addrat(&a, rat_two, precision);
DUPRAT(tmp, a);
lograt(&tmp, precision);
mulrat(&tmp, *pn, precision);
addrat(&a, tmp, precision);
addrat(&a, rat_one, precision);
// Calculate the necessary bump in precision and up the precision.
// The following code is equivalent to
// precision += ln(exp(a)*pow(a,n+1.5))-ln(radix));
DUPRAT(tmp, *pn);
one_pt_five = i32torat(3L);
divrat(&one_pt_five, rat_two, precision);
addrat(&tmp, one_pt_five, precision);
DUPRAT(term, a);
powratcomp(&term, tmp, radix, precision);
DUPRAT(tmp, a);
exprat(&tmp, radix, precision);
mulrat(&term, tmp, precision);
lograt(&term, precision);
const auto ratRadix = i32torat(radix);
DUPRAT(tmp, ratRadix);
lograt(&tmp, precision);
subrat(&term, tmp, precision);
precision += rattoi32(term, radix, precision);
// Set up initial terms for series, refer to series in above comment block.
DUPRAT(factorial, rat_one); // Start factorial out with one
count = i32tonum(0L, BASEX);
DUPRAT(mpy, a);
powratcomp(&mpy, *pn, radix, precision);
// a2=a^2
DUPRAT(a2, a);
mulrat(&a2, a, precision);
// sum=(1/n)-(a/(n+1))
DUPRAT(sum, rat_one);
divrat(&sum, *pn, precision);
DUPRAT(tmp, *pn);
addrat(&tmp, rat_one, precision);
DUPRAT(term, a);
divrat(&term, tmp, precision);
subrat(&sum, term, precision);
DUPRAT(err, ratRadix);
NEGATE(ratprec);
powratcomp(&err, ratprec, radix, precision);
divrat(&err, ratRadix, precision);
// Just get something not tiny in term
DUPRAT(term, rat_two);
// Loop until precision is reached, or asked to halt.
while (!zerrat(term) && rat_gt(term, err, precision))
{
addrat(pn, rat_two, precision);
// WARNING: mixing numbers and rationals here.
// for speed and efficiency.
INC(count);
mulnumx(&(factorial->pp), count);
INC(count)
mulnumx(&(factorial->pp), count);
divrat(&factorial, a2, precision);
DUPRAT(tmp, *pn);
addrat(&tmp, rat_one, precision);
destroyrat(term);
createrat(term);
DUPNUM(term->pp, count);
DUPNUM(term->pq, num_one);
addrat(&term, rat_one, precision);
mulrat(&term, tmp, precision);
DUPRAT(tmp, a);
divrat(&tmp, term, precision);
DUPRAT(term, rat_one);
divrat(&term, *pn, precision);
subrat(&term, tmp, precision);
divrat(&term, factorial, precision);
addrat(&sum, term, precision);
ABSRAT(term);
}
// Multiply by factor.
mulrat(&sum, mpy, precision);
// And cleanup
destroyrat(ratprec);
destroyrat(err);
destroyrat(term);
destroyrat(a);
destroyrat(a2);
destroyrat(tmp);
destroyrat(one_pt_five);
destroynum(count);
destroyrat(factorial);
destroyrat(*pn);
DUPRAT(*pn, sum);
destroyrat(sum);
}
void factrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
PRAT fact = nullptr;
PRAT frac = nullptr;
PRAT neg_rat_one = nullptr;
if (rat_gt(*px, rat_max_fact, precision) || rat_lt(*px, rat_min_fact, precision))
{
// Don't attempt factorial of anything too large or small.
throw CALC_E_OVERFLOW;
}
DUPRAT(fact, rat_one);
DUPRAT(neg_rat_one, rat_one);
neg_rat_one->pp->sign *= -1;
DUPRAT(frac, *px);
fracrat(&frac, radix, precision);
// Check for negative integers and throw an error.
if ((zerrat(frac) || (LOGRATRADIX(frac) <= -precision)) && (SIGN(*px) == -1))
{
throw CALC_E_DOMAIN;
}
while (rat_gt(*px, rat_zero, precision) && (LOGRATRADIX(*px) > -precision))
{
mulrat(&fact, *px, precision);
subrat(px, rat_one, precision);
}
// Added to make numbers 'close enough' to integers use integer factorial.
if (LOGRATRADIX(*px) <= -precision)
{
DUPRAT((*px), rat_zero);
intrat(&fact, radix, precision);
}
while (rat_lt(*px, neg_rat_one, precision))
{
addrat(px, rat_one, precision);
divrat(&fact, *px, precision);
}
if (rat_neq(*px, rat_zero, precision))
{
addrat(px, rat_one, precision);
_gamma(px, radix, precision);
mulrat(px, fact, precision);
}
else
{
DUPRAT(*px, fact);
}
destroyrat(fact);
destroyrat(frac);
destroyrat(neg_rat_one);
}

@ -1,327 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File itrans.c
// Copyright (C) 1995-96 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains inverse sin, cos, tan functions for rationals
//
// Special Information
//
//-----------------------------------------------------------------------------
#include "ratpak.h"
void ascalerat(_Inout_ PRAT* pa, AngleType angletype, int32_t precision)
{
switch (angletype)
{
case AngleType::Radians:
break;
case AngleType::Degrees:
divrat(pa, two_pi, precision);
mulrat(pa, rat_360, precision);
break;
case AngleType::Gradians:
divrat(pa, two_pi, precision);
mulrat(pa, rat_400, precision);
break;
}
}
//-----------------------------------------------------------------------------
//
// FUNCTION: asinrat, _asinrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// sine of
// RETURN: asin of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2 2
// \ ] (2j+1) X
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)*(2j+3)
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
// If abs(x) > 0.85 then an alternate form is used
// pi/2-sgn(x)*asin(sqrt(1-x^2)
//
//
//-----------------------------------------------------------------------------
void _asinrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
DUPRAT(pret, *px);
DUPRAT(thisterm, *px);
DUPNUM(n2, num_one);
do
{
NEXTTERM(xx, MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void asinanglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
{
asinrat(pa, radix, precision);
ascalerat(pa, angletype, precision);
}
void asinrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
PRAT pret = nullptr;
PRAT phack = nullptr;
int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
// Avoid the really bad part of the asin curve near +/-1.
DUPRAT(phack, *px);
subrat(&phack, rat_one, precision);
// Since *px might be epsilon near zero we must set it to zero.
if (rat_le(phack, rat_smallest, precision) && rat_ge(phack, rat_negsmallest, precision))
{
destroyrat(phack);
DUPRAT(*px, pi_over_two);
}
else
{
destroyrat(phack);
if (rat_gt(*px, pt_eight_five, precision))
{
if (rat_gt(*px, rat_one, precision))
{
subrat(px, rat_one, precision);
if (rat_gt(*px, rat_smallest, precision))
{
throw(CALC_E_DOMAIN);
}
else
{
DUPRAT(*px, rat_one);
}
}
DUPRAT(pret, *px);
mulrat(px, pret, precision);
(*px)->pp->sign *= -1;
addrat(px, rat_one, precision);
rootrat(px, rat_two, radix, precision);
_asinrat(px, precision);
(*px)->pp->sign *= -1;
addrat(px, pi_over_two, precision);
destroyrat(pret);
}
else
{
_asinrat(px, precision);
}
}
(*px)->pp->sign = sgn;
(*px)->pq->sign = 1;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: acosrat, _acosrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// cosine of
// RETURN: acos of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2 2
// \ ] (2j+1) X
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)*(2j+3)
// /__]
// j=0
//
// thisterm = 1 ; and stop when thisterm < precision used.
// 0 n
//
// In this case pi/2-asin(x) is used. At least for now _acosrat isn't
// called.
//
//-----------------------------------------------------------------------------
void acosanglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
{
acosrat(pa, radix, precision);
ascalerat(pa, angletype, precision);
}
void _acosrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
createrat(thisterm);
thisterm->pp = i32tonum(1L, BASEX);
thisterm->pq = i32tonum(1L, BASEX);
DUPNUM(n2, num_one);
do
{
NEXTTERM(xx, MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void acosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if (rat_equ(*px, rat_one, precision))
{
if (sgn == -1)
{
DUPRAT(*px, pi);
}
else
{
DUPRAT(*px, rat_zero);
}
}
else
{
(*px)->pp->sign = sgn;
asinrat(px, radix, precision);
(*px)->pp->sign *= -1;
addrat(px, pi_over_two, precision);
}
}
//-----------------------------------------------------------------------------
//
// FUNCTION: atanrat, _atanrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// hyperbolic tangent of
//
// RETURN: atanh of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2
// \ ] (2j)*X (-1^j)
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
// If abs(x) > 0.85 then an alternate form is used
// asin(x/sqrt(q+x^2))
//
// And if abs(x) > 2.0 then this form is used.
//
// pi/2 - atan(1/x)
//
//-----------------------------------------------------------------------------
void atananglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
{
atanrat(pa, radix, precision);
ascalerat(pa, angletype, precision);
}
void _atanrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
DUPRAT(pret, *px);
DUPRAT(thisterm, *px);
DUPNUM(n2, num_one);
xx->pp->sign *= -1;
do
{
NEXTTERM(xx, MULNUM(n2) INC(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void atanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
PRAT tmpx = nullptr;
int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if (rat_gt((*px), pt_eight_five, precision))
{
if (rat_gt((*px), rat_two, precision))
{
(*px)->pp->sign = sgn;
(*px)->pq->sign = 1;
DUPRAT(tmpx, rat_one);
divrat(&tmpx, (*px), precision);
_atanrat(&tmpx, precision);
tmpx->pp->sign = sgn;
tmpx->pq->sign = 1;
DUPRAT(*px, pi_over_two);
subrat(px, tmpx, precision);
destroyrat(tmpx);
}
else
{
(*px)->pp->sign = sgn;
DUPRAT(tmpx, *px);
mulrat(&tmpx, *px, precision);
addrat(&tmpx, rat_one, precision);
rootrat(&tmpx, rat_two, radix, precision);
divrat(px, tmpx, precision);
destroyrat(tmpx);
asinrat(px, radix, precision);
(*px)->pp->sign = sgn;
(*px)->pq->sign = 1;
}
}
else
{
(*px)->pp->sign = sgn;
(*px)->pq->sign = 1;
_atanrat(px, precision);
}
if (rat_gt(*px, pi_over_two, precision))
{
subrat(px, pi, precision);
}
}

@ -1,153 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File itransh.c
// Copyright (C) 1995-97 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains inverse hyperbolic sin, cos, and tan functions.
//
// Special Information
//
//
//-----------------------------------------------------------------------------
#include "ratpak.h"
//-----------------------------------------------------------------------------
//
// FUNCTION: asinhrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// hyperbolic sine of
// RETURN: asinh of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2 2
// \ ] -(2j+1) X
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)*(2j+3)
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
// For abs(x) < .85, and
//
// asinh(x) = log(x+sqrt(x^2+1))
//
// For abs(x) >= .85
//
//-----------------------------------------------------------------------------
void asinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
PRAT neg_pt_eight_five = nullptr;
DUPRAT(neg_pt_eight_five, pt_eight_five);
neg_pt_eight_five->pp->sign *= -1;
if (rat_gt(*px, pt_eight_five, precision) || rat_lt(*px, neg_pt_eight_five, precision))
{
PRAT ptmp = nullptr;
DUPRAT(ptmp, (*px));
mulrat(&ptmp, *px, precision);
addrat(&ptmp, rat_one, precision);
rootrat(&ptmp, rat_two, radix, precision);
addrat(px, ptmp, precision);
lograt(px, precision);
destroyrat(ptmp);
}
else
{
CREATETAYLOR();
xx->pp->sign *= -1;
DUPRAT(pret, (*px));
DUPRAT(thisterm, (*px));
DUPNUM(n2, num_one);
do
{
NEXTTERM(xx, MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
destroyrat(neg_pt_eight_five);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: acoshrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// hyperbolic cose of
// RETURN: acosh of x in PRAT form.
//
// EXPLANATION: This uses
//
// acosh(x)=ln(x+sqrt(x^2-1))
//
// For x >= 1
//
//-----------------------------------------------------------------------------
void acoshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
if (rat_lt(*px, rat_one, precision))
{
throw CALC_E_DOMAIN;
}
else
{
PRAT ptmp = nullptr;
DUPRAT(ptmp, (*px));
mulrat(&ptmp, *px, precision);
subrat(&ptmp, rat_one, precision);
rootrat(&ptmp, rat_two, radix, precision);
addrat(px, ptmp, precision);
lograt(px, precision);
destroyrat(ptmp);
}
}
//-----------------------------------------------------------------------------
//
// FUNCTION: atanhrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// hyperbolic tangent of
//
// RETURN: atanh of x in PRAT form.
//
// EXPLANATION: This uses
//
// 1 x+1
// atanh(x) = -*ln(----)
// 2 x-1
//
//-----------------------------------------------------------------------------
void atanhrat(_Inout_ PRAT* px, int32_t precision)
{
PRAT ptmp = nullptr;
DUPRAT(ptmp, (*px));
subrat(&ptmp, rat_one, precision);
addrat(px, rat_one, precision);
divrat(px, ptmp, precision);
(*px)->pp->sign *= -1;
lograt(px, precision);
divrat(px, rat_two, precision);
destroyrat(ptmp);
}

@ -1,256 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//---------------------------------------------------------------------------
// Package Title ratpak
// File num.c
// Copyright (C) 1995-99 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains routines for and, or, xor, not and other support
//
//---------------------------------------------------------------------------
#include "ratpak.h"
using namespace std;
void lshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
{
PRAT pwr = nullptr;
intrat(pa, radix, precision);
if (!zernum((*pa)->pp))
{
// If input is zero we're done.
if (rat_gt(b, rat_max_exp, precision))
{
// Don't attempt lsh of anything big
throw(CALC_E_DOMAIN);
}
const int32_t intb = rattoi32(b, radix, precision);
DUPRAT(pwr, rat_two);
ratpowi32(&pwr, intb, precision);
mulrat(pa, pwr, precision);
destroyrat(pwr);
}
}
void rshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
{
PRAT pwr = nullptr;
intrat(pa, radix, precision);
if (!zernum((*pa)->pp))
{
// If input is zero we're done.
if (rat_lt(b, rat_min_exp, precision))
{
// Don't attempt rsh of anything big and negative.
throw(CALC_E_DOMAIN);
}
const int32_t intb = rattoi32(b, radix, precision);
DUPRAT(pwr, rat_two);
ratpowi32(&pwr, intb, precision);
divrat(pa, pwr, precision);
destroyrat(pwr);
}
}
void boolrat(PRAT* pa, PRAT b, int func, uint32_t radix, int32_t precision);
void boolnum(PNUMBER* pa, PNUMBER b, int func);
enum
{
FUNC_AND,
FUNC_OR,
FUNC_XOR
} BOOL_FUNCS;
void andrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
{
boolrat(pa, b, FUNC_AND, radix, precision);
}
void orrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
{
boolrat(pa, b, FUNC_OR, radix, precision);
}
void xorrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
{
boolrat(pa, b, FUNC_XOR, radix, precision);
}
//---------------------------------------------------------------------------
//
// FUNCTION: boolrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa op= b;
//
//---------------------------------------------------------------------------
void boolrat(PRAT* pa, PRAT b, int func, uint32_t radix, int32_t precision)
{
PRAT tmp = nullptr;
intrat(pa, radix, precision);
DUPRAT(tmp, b);
intrat(&tmp, radix, precision);
boolnum(&((*pa)->pp), tmp->pp, func);
destroyrat(tmp);
}
//---------------------------------------------------------------------------
//
// FUNCTION: boolnum
//
// ARGUMENTS: pointer to a number a second number
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa &= b.
// radix doesn't matter for logicals.
// WARNING: Assumes numbers are unsigned.
//
//---------------------------------------------------------------------------
void boolnum(PNUMBER* pa, PNUMBER b, int func)
{
PNUMBER c = nullptr;
PNUMBER a = nullptr;
MANTTYPE* pcha;
MANTTYPE* pchb;
MANTTYPE* pchc;
int32_t cdigits;
int32_t mexp;
MANTTYPE da;
MANTTYPE db;
a = *pa;
cdigits = max(a->cdigit + a->exp, b->cdigit + b->exp) - min(a->exp, b->exp);
createnum(c, cdigits);
c->exp = min(a->exp, b->exp);
mexp = c->exp;
c->cdigit = cdigits;
pcha = a->mant;
pchb = b->mant;
pchc = c->mant;
for (; cdigits > 0; cdigits--, mexp++)
{
da = (((mexp >= a->exp) && (cdigits + a->exp - c->exp > (c->cdigit - a->cdigit))) ? *pcha++ : 0);
db = (((mexp >= b->exp) && (cdigits + b->exp - c->exp > (c->cdigit - b->cdigit))) ? *pchb++ : 0);
switch (func)
{
case FUNC_AND:
*pchc++ = da & db;
break;
case FUNC_OR:
*pchc++ = da | db;
break;
case FUNC_XOR:
*pchc++ = da ^ db;
break;
}
}
c->sign = a->sign;
while (c->cdigit > 1 && *(--pchc) == 0)
{
c->cdigit--;
}
destroynum(*pa);
*pa = c;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: remrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes pointer.
//
// DESCRIPTION: Calculate the remainder of *pa / b,
// equivalent of 'pa % b' in C/C++ and produces a result
// that is either zero or has the same sign as the dividend.
//
//-----------------------------------------------------------------------------
void remrat(_Inout_ PRAT* pa, _In_ PRAT b)
{
if (zerrat(b))
{
throw CALC_E_INDEFINITE;
}
PRAT tmp = nullptr;
DUPRAT(tmp, b);
mulnumx(&((*pa)->pp), tmp->pq);
mulnumx(&(tmp->pp), (*pa)->pq);
remnum(&((*pa)->pp), tmp->pp, BASEX);
mulnumx(&((*pa)->pq), tmp->pq);
// Get *pa back in the integer over integer form.
RENORMALIZE(*pa);
destroyrat(tmp);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: modrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes pointer.
//
// DESCRIPTION: Calculate the remainder of *pa / b, with the sign of the result
// either zero or has the same sign as the divisor.
// NOTE: When *pa or b are negative, the result won't be the same as
// the C/C++ operator %, use remrat if it's the behavior you expect.
//
//-----------------------------------------------------------------------------
void modrat(_Inout_ PRAT* pa, _In_ PRAT b)
{
// contrary to remrat(X, 0) returning 0, modrat(X, 0) must return X
if (zerrat(b))
{
return;
}
PRAT tmp = nullptr;
DUPRAT(tmp, b);
auto needAdjust = (SIGN(*pa) == -1 ? (SIGN(b) == 1) : (SIGN(b) == -1));
mulnumx(&((*pa)->pp), tmp->pq);
mulnumx(&(tmp->pp), (*pa)->pq);
remnum(&((*pa)->pp), tmp->pp, BASEX);
mulnumx(&((*pa)->pq), tmp->pq);
if (needAdjust && !zerrat(*pa))
{
addrat(pa, b, BASEX);
}
// Get *pa back in the integer over integer form.
RENORMALIZE(*pa);
destroyrat(tmp);
}

@ -1,622 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File num.c
// Copyright (C) 1995-97 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains number routines for add, mul, div, rem and other support
// and longs.
//
// Special Information
//
//
//-----------------------------------------------------------------------------
#include <list>
#include <cstring> // for memmove
#include "ratpak.h"
using namespace std;
//----------------------------------------------------------------------------
//
// FUNCTION: addnum
//
// ARGUMENTS: pointer to a number a second number, and the
// radix.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa += b.
// Assumes radix is the base of both numbers.
//
// ALGORITHM: Adds each digit from least significant to most
// significant.
//
//
//----------------------------------------------------------------------------
void _addnum(PNUMBER* pa, PNUMBER b, uint32_t radix);
void addnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix)
{
if (b->cdigit > 1 || b->mant[0] != 0)
{ // If b is zero we are done.
if ((*pa)->cdigit > 1 || (*pa)->mant[0] != 0)
{ // pa and b are both nonzero.
_addnum(pa, b, radix);
}
else
{ // if pa is zero and b isn't just copy b.
DUPNUM(*pa, b);
}
}
}
void _addnum(PNUMBER* pa, PNUMBER b, uint32_t radix)
{
PNUMBER c = nullptr; // c will contain the result.
PNUMBER a = nullptr; // a is the dereferenced number pointer from *pa
MANTTYPE* pcha; // pcha is a pointer to the mantissa of a.
MANTTYPE* pchb; // pchb is a pointer to the mantissa of b.
MANTTYPE* pchc; // pchc is a pointer to the mantissa of c.
int32_t cdigits; // cdigits is the max count of the digits results used as a counter.
int32_t mexp; // mexp is the exponent of the result.
MANTTYPE da; // da is a single 'digit' after possible padding.
MANTTYPE db; // db is a single 'digit' after possible padding.
MANTTYPE cy = 0; // cy is the value of a carry after adding two 'digits'
int32_t fcompla = 0; // fcompla is a flag to signal a is negative.
int32_t fcomplb = 0; // fcomplb is a flag to signal b is negative.
a = *pa;
// Calculate the overlap of the numbers after alignment, this includes
// necessary padding 0's
cdigits = max(a->cdigit + a->exp, b->cdigit + b->exp) - min(a->exp, b->exp);
createnum(c, cdigits + 1);
c->exp = min(a->exp, b->exp);
mexp = c->exp;
c->cdigit = cdigits;
pcha = a->mant;
pchb = b->mant;
pchc = c->mant;
// Figure out the sign of the numbers
if (a->sign != b->sign)
{
cy = 1;
fcompla = (a->sign == -1);
fcomplb = (b->sign == -1);
}
// Loop over all the digits, real and 0 padded. Here we know a and b are
// aligned
for (; cdigits > 0; cdigits--, mexp++)
{
// Get digit from a, taking padding into account.
da = (((mexp >= a->exp) && (cdigits + a->exp - c->exp > (c->cdigit - a->cdigit))) ? *pcha++ : 0);
// Get digit from b, taking padding into account.
db = (((mexp >= b->exp) && (cdigits + b->exp - c->exp > (c->cdigit - b->cdigit))) ? *pchb++ : 0);
// Handle complementing for a and b digit. Might be a better way, but
// haven't found it yet.
if (fcompla)
{
da = (MANTTYPE)(radix)-1 - da;
}
if (fcomplb)
{
db = (MANTTYPE)(radix)-1 - db;
}
// Update carry as necessary
cy = da + db + cy;
*pchc++ = (MANTTYPE)(cy % (MANTTYPE)radix);
cy /= (MANTTYPE)radix;
}
// Handle carry from last sum as extra digit
if (cy && !(fcompla || fcomplb))
{
*pchc++ = cy;
c->cdigit++;
}
// Compute sign of result
if (!(fcompla || fcomplb))
{
c->sign = a->sign;
}
else
{
if (cy)
{
c->sign = 1;
}
else
{
// In this particular case an overflow or underflow has occurred
// and all the digits need to be complemented, at one time an
// attempt to handle this above was made, it turned out to be much
// slower on average.
c->sign = -1;
cy = 1;
for ((cdigits = c->cdigit), (pchc = c->mant); cdigits > 0; cdigits--)
{
cy = (MANTTYPE)radix - (MANTTYPE)1 - *pchc + cy;
*pchc++ = (MANTTYPE)(cy % (MANTTYPE)radix);
cy /= (MANTTYPE)radix;
}
}
}
// Remove leading zeros, remember digits are in order of
// increasing significance. i.e. 100 would be 0,0,1
while (c->cdigit > 1 && *(--pchc) == 0)
{
c->cdigit--;
}
destroynum(*pa);
*pa = c;
}
//----------------------------------------------------------------------------
//
// FUNCTION: mulnum
//
// ARGUMENTS: pointer to a number a second number, and the
// radix.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa *= b.
// Assumes radix is the radix of both numbers. This algorithm is the
// same one you learned in grade school.
//
//----------------------------------------------------------------------------
void _mulnum(PNUMBER* pa, PNUMBER b, uint32_t radix);
void mulnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix)
{
if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0)
{ // If b is one we don't multiply exactly.
if ((*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0)
{ // pa and b are both non-one.
_mulnum(pa, b, radix);
}
else
{ // if pa is one and b isn't just copy b, and adjust the sign.
int32_t sign = (*pa)->sign;
DUPNUM(*pa, b);
(*pa)->sign *= sign;
}
}
else
{ // But we do have to set the sign.
(*pa)->sign *= b->sign;
}
}
void _mulnum(PNUMBER* pa, PNUMBER b, uint32_t radix)
{
PNUMBER c = nullptr; // c will contain the result.
PNUMBER a = nullptr; // a is the dereferenced number pointer from *pa
MANTTYPE* pcha; // pcha is a pointer to the mantissa of a.
MANTTYPE* pchb; // pchb is a pointer to the mantissa of b.
MANTTYPE* pchc; // pchc is a pointer to the mantissa of c.
MANTTYPE* pchcoffset; // pchcoffset, is the anchor location of the next
// single digit multiply partial result.
int32_t iadigit = 0; // Index of digit being used in the first number.
int32_t ibdigit = 0; // Index of digit being used in the second number.
MANTTYPE da = 0; // da is the digit from the fist number.
TWO_MANTTYPE cy = 0; // cy is the carry resulting from the addition of
// a multiplied row into the result.
TWO_MANTTYPE mcy = 0; // mcy is the resultant from a single
// multiply, AND the carry of that multiply.
int32_t icdigit = 0; // Index of digit being calculated in final result.
a = *pa;
ibdigit = a->cdigit + b->cdigit - 1;
createnum(c, ibdigit + 1);
c->cdigit = ibdigit;
c->sign = a->sign * b->sign;
c->exp = a->exp + b->exp;
pcha = a->mant;
pchcoffset = c->mant;
for (iadigit = a->cdigit; iadigit > 0; iadigit--)
{
da = *pcha++;
pchb = b->mant;
// Shift pchc, and pchcoffset, one for each digit
pchc = pchcoffset++;
for (ibdigit = b->cdigit; ibdigit > 0; ibdigit--)
{
cy = 0;
mcy = (TWO_MANTTYPE)da * *pchb;
if (mcy)
{
icdigit = 0;
if (ibdigit == 1 && iadigit == 1)
{
c->cdigit++;
}
}
// If result is nonzero, or while result of carry is nonzero...
while (mcy || cy)
{
// update carry from addition(s) and multiply.
cy += (TWO_MANTTYPE)pchc[icdigit] + (mcy % (TWO_MANTTYPE)radix);
// update result digit from
pchc[icdigit++] = (MANTTYPE)(cy % (TWO_MANTTYPE)radix);
// update carries from
mcy /= (TWO_MANTTYPE)radix;
cy /= (TWO_MANTTYPE)radix;
}
pchb++;
pchc++;
}
}
// prevent different kinds of zeros, by stripping leading duplicate zeros.
// digits are in order of increasing significance.
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
destroynum(*pa);
*pa = c;
}
//----------------------------------------------------------------------------
//
// FUNCTION: remnum
//
// ARGUMENTS: pointer to a number a second number, and the
// radix.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa %= b.
// Repeatedly subtracts off powers of 2 of b until *pa < b.
//
//
//----------------------------------------------------------------------------
void remnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix)
{
PNUMBER tmp = nullptr; // tmp is the working remainder.
PNUMBER lasttmp = nullptr; // lasttmp is the last remainder which worked.
// Once *pa is less than b, *pa is the remainder.
while (!lessnum(*pa, b))
{
DUPNUM(tmp, b);
if (lessnum(tmp, *pa))
{
// Start off close to the right answer for subtraction.
tmp->exp = (*pa)->cdigit + (*pa)->exp - tmp->cdigit;
if (MSD(*pa) <= MSD(tmp))
{
// Don't take the chance that the numbers are equal.
tmp->exp--;
}
}
destroynum(lasttmp);
lasttmp = i32tonum(0, radix);
while (lessnum(tmp, *pa))
{
DUPNUM(lasttmp, tmp);
addnum(&tmp, tmp, radix);
}
if (lessnum(*pa, tmp))
{
// too far, back up...
destroynum(tmp);
tmp = lasttmp;
lasttmp = nullptr;
}
// Subtract the working remainder from the remainder holder.
tmp->sign = -1 * (*pa)->sign;
addnum(pa, tmp, radix);
destroynum(tmp);
destroynum(lasttmp);
}
}
//---------------------------------------------------------------------------
//
// FUNCTION: divnum
//
// ARGUMENTS: pointer to a number a second number, and the
// radix.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the number equivalent of *pa /= b.
// Assumes radix is the radix of both numbers.
//
//---------------------------------------------------------------------------
void _divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision);
void divnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix, int32_t precision)
{
if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0)
{
// b is not one
_divnum(pa, b, radix, precision);
}
else
{ // But we do have to set the sign.
(*pa)->sign *= b->sign;
}
}
void _divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision)
{
PNUMBER a = *pa;
int32_t thismax = precision + 2;
if (thismax < a->cdigit)
{
thismax = a->cdigit;
}
if (thismax < b->cdigit)
{
thismax = b->cdigit;
}
PNUMBER c = nullptr;
createnum(c, thismax + 1);
c->exp = (a->cdigit + a->exp) - (b->cdigit + b->exp) + 1;
c->sign = a->sign * b->sign;
MANTTYPE* ptrc = c->mant + thismax;
PNUMBER rem = nullptr;
PNUMBER tmp = nullptr;
DUPNUM(rem, a);
DUPNUM(tmp, b);
tmp->sign = a->sign;
rem->exp = b->cdigit + b->exp - rem->cdigit;
// Build a table of multiplications of the divisor, this is quicker for
// more than radix 'digits'
list<PNUMBER> numberList{ i32tonum(0L, radix) };
for (uint32_t i = 1; i < radix; i++)
{
PNUMBER newValue = nullptr;
DUPNUM(newValue, numberList.front());
addnum(&newValue, tmp, radix);
numberList.emplace_front(newValue);
}
destroynum(tmp);
int32_t digit;
int32_t cdigits = 0;
while (cdigits++ < thismax && !zernum(rem))
{
digit = radix - 1;
PNUMBER multiple = nullptr;
for (const auto& num : numberList)
{
if (!lessnum(rem, num) || !--digit)
{
multiple = num;
break;
}
}
if (digit)
{
multiple->sign *= -1;
addnum(&rem, multiple, radix);
multiple->sign *= -1;
}
rem->exp++;
*ptrc-- = (MANTTYPE)digit;
}
cdigits--;
if (c->mant != ++ptrc)
{
memmove(c->mant, ptrc, (int)(cdigits * sizeof(MANTTYPE)));
}
// Cleanup table structure
for (auto& num : numberList)
{
destroynum(num);
}
if (!cdigits)
{
c->cdigit = 1;
c->exp = 0;
}
else
{
c->cdigit = cdigits;
c->exp -= cdigits;
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
}
destroynum(rem);
destroynum(*pa);
*pa = c;
}
//---------------------------------------------------------------------------
//
// FUNCTION: equnum
//
// ARGUMENTS: two numbers.
//
// RETURN: Boolean
//
// DESCRIPTION: Does the number equivalent of ( a == b )
// Only assumes that a and b are the same radix.
//
//---------------------------------------------------------------------------
bool equnum(_In_ PNUMBER a, _In_ PNUMBER b)
{
int32_t diff;
MANTTYPE* pa;
MANTTYPE* pb;
int32_t cdigits;
int32_t ccdigits;
MANTTYPE da;
MANTTYPE db;
diff = (a->cdigit + a->exp) - (b->cdigit + b->exp);
if (diff < 0)
{
// If the exponents are different, these are different numbers.
return false;
}
else
{
if (diff > 0)
{
// If the exponents are different, these are different numbers.
return false;
}
else
{
// OK the exponents match.
pa = a->mant;
pb = b->mant;
pa += a->cdigit - 1;
pb += b->cdigit - 1;
cdigits = max(a->cdigit, b->cdigit);
ccdigits = cdigits;
// Loop over all digits until we run out of digits or there is a
// difference in the digits.
for (; cdigits > 0; cdigits--)
{
da = ((cdigits > (ccdigits - a->cdigit)) ? *pa-- : 0);
db = ((cdigits > (ccdigits - b->cdigit)) ? *pb-- : 0);
if (da != db)
{
return false;
}
}
// In this case, they are equal.
return true;
}
}
}
//---------------------------------------------------------------------------
//
// FUNCTION: lessnum
//
// ARGUMENTS: two numbers.
//
// RETURN: Boolean
//
// DESCRIPTION: Does the number equivalent of ( abs(a) < abs(b) )
// Only assumes that a and b are the same radix, WARNING THIS IS AN.
// UNSIGNED COMPARE!
//
//---------------------------------------------------------------------------
bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b)
{
int32_t diff = (a->cdigit + a->exp) - (b->cdigit + b->exp);
if (diff < 0)
{
// The exponent of a is less than b
return true;
}
if (diff > 0)
{
return false;
}
MANTTYPE* pa = a->mant;
MANTTYPE* pb = b->mant;
pa += a->cdigit - 1;
pb += b->cdigit - 1;
int32_t cdigits = max(a->cdigit, b->cdigit);
int32_t ccdigits = cdigits;
for (; cdigits > 0; cdigits--)
{
MANTTYPE da = ((cdigits > (ccdigits - a->cdigit)) ? *pa-- : 0);
MANTTYPE db = ((cdigits > (ccdigits - b->cdigit)) ? *pb-- : 0);
diff = da - db;
if (diff)
{
return (diff < 0);
}
}
// In this case, they are equal.
return false;
}
//----------------------------------------------------------------------------
//
// FUNCTION: zernum
//
// ARGUMENTS: number
//
// RETURN: Boolean
//
// DESCRIPTION: Does the number equivalent of ( !a )
//
//----------------------------------------------------------------------------
bool zernum(_In_ PNUMBER a)
{
int32_t length;
MANTTYPE* pcha;
length = a->cdigit;
pcha = a->mant;
// loop over all the digits until you find a nonzero or until you run
// out of digits
while (length-- > 0)
{
if (*pcha++)
{
// One of the digits isn't zero, therefore the number isn't zero
return false;
}
}
// All of the digits are zero, therefore the number is zero
return true;
}

@ -1,287 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
// Package Title ratpak
// File rat.c
// Copyright (C) 1995-96 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains mul, div, add, and other support functions for rationals.
//
//
//
//-----------------------------------------------------------------------------
#include "ratpak.h"
using namespace std;
//-----------------------------------------------------------------------------
//
// FUNCTION: gcdrat
//
// ARGUMENTS: pointer to a rational.
//
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Divides p and q in rational by the G.C.D.
// of both. It was hoped this would speed up some
// calculations, and until the above trimming was done it
// did, but after trimming gcdratting, only slows things
// down.
//
//-----------------------------------------------------------------------------
void gcdrat(_Inout_ PRAT* pa, int32_t precision)
{
PNUMBER pgcd = nullptr;
PRAT a = nullptr;
a = *pa;
pgcd = gcd(a->pp, a->pq);
if (!zernum(pgcd))
{
divnumx(&(a->pp), pgcd, precision);
divnumx(&(a->pq), pgcd, precision);
}
destroynum(pgcd);
*pa = a;
RENORMALIZE(*pa);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: fracrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes pointer.
//
// DESCRIPTION: Does the rational equivalent of frac(*pa);
//
//-----------------------------------------------------------------------------
void fracrat(_Inout_ PRAT* pa, uint32_t radix, int32_t precision)
{
// Only do the flatrat operation if number is nonzero.
// and only if the bottom part is not one.
if (!zernum((*pa)->pp) && !equnum((*pa)->pq, num_one))
{
flatrat(*pa, radix, precision);
}
remnum(&((*pa)->pp), (*pa)->pq, BASEX);
// Get *pa back in the integer over integer form.
RENORMALIZE(*pa);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: mulrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa *= b.
// Assumes radix is the radix of both numbers.
//
//-----------------------------------------------------------------------------
void mulrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision)
{
// Only do the multiply if it isn't zero.
if (!zernum((*pa)->pp))
{
mulnumx(&((*pa)->pp), b->pp);
mulnumx(&((*pa)->pq), b->pq);
trimit(pa, precision);
}
else
{
// If it is zero, blast a one in the denominator.
DUPNUM(((*pa)->pq), num_one);
}
#ifdef MULGCD
gcdrat(pa);
#endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: divrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa /= b.
// Assumes radix is the radix of both numbers.
//
//-----------------------------------------------------------------------------
void divrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision)
{
if (!zernum((*pa)->pp))
{
// Only do the divide if the top isn't zero.
mulnumx(&((*pa)->pp), b->pq);
mulnumx(&((*pa)->pq), b->pp);
if (zernum((*pa)->pq))
{
// raise an exception if the bottom is 0.
throw(CALC_E_DIVIDEBYZERO);
}
trimit(pa, precision);
}
else
{
// Top is zero.
if (zerrat(b))
{
// If bottom is zero
// 0 / 0 is indefinite, raise an exception.
throw(CALC_E_INDEFINITE);
}
else
{
// 0/x make a unique 0.
DUPNUM(((*pa)->pq), num_one);
}
}
#ifdef DIVGCD
gcdrat(pa);
#endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: subrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa += b.
// Assumes base is internal throughout.
//
//-----------------------------------------------------------------------------
void subrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision)
{
b->pp->sign *= -1;
addrat(pa, b, precision);
b->pp->sign *= -1;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: addrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa += b.
// Assumes base is internal throughout.
//
//-----------------------------------------------------------------------------
void addrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision)
{
PNUMBER bot = nullptr;
if (equnum((*pa)->pq, b->pq))
{
// Very special case, q's match.,
// make sure signs are involved in the calculation
// we have to do this since the optimization here is only
// working with the top half of the rationals.
(*pa)->pp->sign *= (*pa)->pq->sign;
(*pa)->pq->sign = 1;
b->pp->sign *= b->pq->sign;
b->pq->sign = 1;
addnum(&((*pa)->pp), b->pp, BASEX);
}
else
{
// Usual case q's aren't the same.
DUPNUM(bot, (*pa)->pq);
mulnumx(&bot, b->pq);
mulnumx(&((*pa)->pp), b->pq);
mulnumx(&((*pa)->pq), b->pp);
addnum(&((*pa)->pp), (*pa)->pq, BASEX);
destroynum((*pa)->pq);
(*pa)->pq = bot;
trimit(pa, precision);
// Get rid of negative zeros here.
(*pa)->pp->sign *= (*pa)->pq->sign;
(*pa)->pq->sign = 1;
}
#ifdef ADDGCD
gcdrat(pa);
#endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: rootrat
//
// PARAMETERS: y prat representation of number to take the root of
// n prat representation of the root to take.
//
// RETURN: bth root of a in rat form.
//
// EXPLANATION: This is now a stub function to powrat().
//
//-----------------------------------------------------------------------------
void rootrat(_Inout_ PRAT* py, _In_ PRAT n, uint32_t radix, int32_t precision)
{
// Initialize 1/n
PRAT oneovern = nullptr;
DUPRAT(oneovern, rat_one);
divrat(&oneovern, n, precision);
powrat(py, oneovern, radix, precision);
destroyrat(oneovern);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: zerrat
//
// ARGUMENTS: Rational number.
//
// RETURN: Boolean
//
// DESCRIPTION: Returns true if input is zero.
// False otherwise.
//
//-----------------------------------------------------------------------------
bool zerrat(_In_ PRAT a)
{
return (zernum(a->pp));
}

@ -1,594 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_num_one = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_num_two = { 1,
1,
0,
{
2,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_num_five = { 1,
1,
0,
{
5,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_num_six = { 1,
1,
0,
{
6,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_num_ten = { 1,
1,
0,
{
10,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_smallest = { 1,
1,
0,
{
1,
} };
inline const NUMBER init_q_rat_smallest = { 1,
4,
0,
{
0,
190439170,
901055854,
10097,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_negsmallest = { -1,
1,
0,
{
1,
} };
inline const NUMBER init_q_rat_negsmallest = { 1,
4,
0,
{
0,
190439170,
901055854,
10097,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_pt_eight_five = { 1,
1,
0,
{
85,
} };
inline const NUMBER init_q_pt_eight_five = { 1,
1,
0,
{
100,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_six = { 1,
1,
0,
{
6,
} };
inline const NUMBER init_q_rat_six = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_two = { 1,
1,
0,
{
2,
} };
inline const NUMBER init_q_rat_two = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_zero = { 1,
1,
0,
{
0,
} };
inline const NUMBER init_q_rat_zero = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_one = { 1,
1,
0,
{
1,
} };
inline const NUMBER init_q_rat_one = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_neg_one = { -1,
1,
0,
{
1,
} };
inline const NUMBER init_q_rat_neg_one = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_half = { 1,
1,
0,
{
1,
} };
inline const NUMBER init_q_rat_half = { 1,
1,
0,
{
2,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_ten = { 1,
1,
0,
{
10,
} };
inline const NUMBER init_q_rat_ten = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_pi = { 1,
6,
0,
{
125527896,
283898350,
1960493936,
1672850762,
1288168272,
8,
} };
inline const NUMBER init_q_pi = { 1,
6,
0,
{
1288380402,
1120116153,
1860424692,
1944118326,
1583591604,
2,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_two_pi = { 1,
6,
0,
{
251055792,
567796700,
1773504224,
1198217877,
428852897,
17,
} };
inline const NUMBER init_q_two_pi = { 1,
6,
0,
{
1288380402,
1120116153,
1860424692,
1944118326,
1583591604,
2,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_pi_over_two = { 1,
6,
0,
{
125527896,
283898350,
1960493936,
1672850762,
1288168272,
8,
} };
inline const NUMBER init_q_pi_over_two = { 1,
6,
0,
{
429277156,
92748659,
1573365737,
1740753005,
1019699561,
5,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_one_pt_five_pi = { 1,
6,
0,
{
1241201312,
270061909,
1051574664,
1924965045,
1340320627,
70,
} };
inline const NUMBER init_q_one_pt_five_pi = { 1,
6,
0,
{
1579671539,
1837970263,
1067644340,
523549916,
2119366659,
14,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_e_to_one_half = { 1,
6,
0,
{
256945612,
216219427,
223516738,
477442596,
581063757,
23,
} };
inline const NUMBER init_q_e_to_one_half = { 1,
6,
0,
{
1536828363,
698484484,
1127331835,
224219346,
245499408,
14,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_exp = { 1,
6,
0,
{
943665199,
1606559160,
1094967530,
1759391384,
1671799163,
1123581,
} };
inline const NUMBER init_q_rat_exp = { 1,
6,
0,
{
879242208,
2022880100,
617392930,
1374929092,
1367479163,
413342,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_ln_ten = { 1,
6,
0,
{
2086268922,
165794492,
1416063951,
1851428830,
1893239400,
65366841,
} };
inline const NUMBER init_q_ln_ten = { 1,
6,
0,
{
26790652,
564532679,
783998273,
216030448,
1564709968,
28388458,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_ln_two = { 1,
6,
0,
{
1789230241,
1057927868,
715399197,
908801241,
1411265331,
3,
} };
inline const NUMBER init_q_ln_two = { 1,
6,
0,
{
1559869847,
1930657510,
1228561531,
219003871,
593099283,
5,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rad_to_deg = { 1,
6,
0,
{
2127722024,
1904928383,
2016479213,
2048947859,
1578647346,
492,
} };
inline const NUMBER init_q_rad_to_deg = { 1,
6,
0,
{
125527896,
283898350,
1960493936,
1672850762,
1288168272,
8,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rad_to_grad = { 1,
6,
0,
{
2125526288,
684931327,
570267400,
129125085,
1038224725,
547,
} };
inline const NUMBER init_q_rad_to_grad = { 1,
6,
0,
{
125527896,
283898350,
1960493936,
1672850762,
1288168272,
8,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_qword = { 1,
3,
0,
{
2147483647,
2147483647,
3,
} };
inline const NUMBER init_q_rat_qword = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_dword = { 1,
2,
0,
{
2147483647,
1,
} };
inline const NUMBER init_q_rat_dword = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_max_i32 = { 1,
1,
0,
{
2147483647,
} };
inline const NUMBER init_q_rat_max_i32 = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_min_i32 = { -1,
2,
0,
{
0,
1,
} };
inline const NUMBER init_q_rat_min_i32 = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_word = { 1,
1,
0,
{
65535,
} };
inline const NUMBER init_q_rat_word = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_byte = { 1,
1,
0,
{
255,
} };
inline const NUMBER init_q_rat_byte = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_400 = { 1,
1,
0,
{
400,
} };
inline const NUMBER init_q_rat_400 = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_360 = { 1,
1,
0,
{
360,
} };
inline const NUMBER init_q_rat_360 = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_200 = { 1,
1,
0,
{
200,
} };
inline const NUMBER init_q_rat_200 = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_180 = { 1,
1,
0,
{
180,
} };
inline const NUMBER init_q_rat_180 = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_max_exp = { 1,
1,
0,
{
100000,
} };
inline const NUMBER init_q_rat_max_exp = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_min_exp = { -1,
1,
0,
{
100000,
} };
inline const NUMBER init_q_rat_min_exp = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_max_fact = { 1,
1,
0,
{
3249,
} };
inline const NUMBER init_q_rat_max_fact = { 1,
1,
0,
{
1,
} };
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_p_rat_min_fact = { -1,
1,
0,
{
1000,
} };
inline const NUMBER init_q_rat_min_fact = { 1,
1,
0,
{
1,
} };

@ -1,485 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
//-----------------------------------------------------------------------------
// Package Title ratpak
// File ratpak.h
// Copyright (C) 1995-99 Microsoft
// Date 01-16-95
//
//
// Description
//
// Infinite precision math package header file, if you use ratpak.lib you
// need to include this header.
//
//-----------------------------------------------------------------------------
#include <algorithm>
#include <string>
#include "CalcErr.h"
#include <cstring> // for memmove
#include "sal_cross_platform.h" // for SAL
static constexpr uint32_t BASEXPWR = 31L; // Internal log2(BASEX)
static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculations, hope to raise
// this to 2^32 after solving scaling problems with
// overflow detection esp. in mul
typedef uint32_t MANTTYPE;
typedef uint64_t TWO_MANTTYPE;
enum class NumberFormat
{
Float, // returns floating point, or exponential if number is too big
Scientific, // always returns scientific notation
Engineering // always returns engineering notation such that exponent is a multiple of 3
};
enum class AngleType
{
Degrees, // Calculate trig using 360 degrees per revolution
Radians, // Calculate trig using 2 pi radians per revolution
Gradians // Calculate trig using 400 gradians per revolution
};
//-----------------------------------------------------------------------------
//
// NUMBER type is a representation of a generic sized generic radix number
//
//-----------------------------------------------------------------------------
#pragma warning(push)
#pragma warning(disable : 4200) // nonstandard extension used : zero-sized array in struct/union
typedef struct _number
{
int32_t sign; // The sign of the mantissa, +1, or -1
int32_t cdigit; // The number of digits, or what passes for digits in the
// radix being used.
int32_t exp; // The offset of digits from the radix point
// (decimal point in radix 10)
MANTTYPE mant[];
// This is actually allocated as a continuation of the
// NUMBER structure.
} NUMBER, *PNUMBER, **PPNUMBER;
#pragma warning(pop)
//-----------------------------------------------------------------------------
//
// RAT type is a representation radix on 2 NUMBER types.
// pp/pq, where pp and pq are pointers to integral NUMBER types.
//
//-----------------------------------------------------------------------------
typedef struct _rat
{
PNUMBER pp;
PNUMBER pq;
} RAT, *PRAT;
static constexpr uint32_t MAX_LONG_SIZE = 33; // Base 2 requires 32 'digits'
//-----------------------------------------------------------------------------
//
// List of useful constants for evaluation, note this list needs to be
// initialized.
//
//-----------------------------------------------------------------------------
extern PNUMBER num_one;
extern PNUMBER num_two;
extern PNUMBER num_five;
extern PNUMBER num_six;
extern PNUMBER num_ten;
extern PRAT ln_ten;
extern PRAT ln_two;
extern PRAT rat_zero;
extern PRAT rat_neg_one;
extern PRAT rat_one;
extern PRAT rat_two;
extern PRAT rat_six;
extern PRAT rat_half;
extern PRAT rat_ten;
extern PRAT pt_eight_five;
extern PRAT pi;
extern PRAT pi_over_two;
extern PRAT two_pi;
extern PRAT one_pt_five_pi;
extern PRAT e_to_one_half;
extern PRAT rat_exp;
extern PRAT rad_to_deg;
extern PRAT rad_to_grad;
extern PRAT rat_qword;
extern PRAT rat_dword;
extern PRAT rat_word;
extern PRAT rat_byte;
extern PRAT rat_360;
extern PRAT rat_400;
extern PRAT rat_180;
extern PRAT rat_200;
extern PRAT rat_nRadix;
extern PRAT rat_smallest;
extern PRAT rat_negsmallest;
extern PRAT rat_max_exp;
extern PRAT rat_min_exp;
extern PRAT rat_max_fact;
extern PRAT rat_min_fact;
extern PRAT rat_max_i32;
extern PRAT rat_min_i32;
// DUPNUM Duplicates a number taking care of allocation and internals
#define DUPNUM(a, b) \
destroynum(a); \
createnum(a, (b)->cdigit); \
_dupnum(a, b);
// DUPRAT Duplicates a rational taking care of allocation and internals
#define DUPRAT(a, b) \
destroyrat(a); \
createrat(a); \
DUPNUM((a)->pp, (b)->pp); \
DUPNUM((a)->pq, (b)->pq);
// LOG*RADIX calculates the integral portion of the log of a number in
// the base currently being used, only accurate to within g_ratio
#define LOGNUMRADIX(pnum) (((pnum)->cdigit + (pnum)->exp) * g_ratio)
#define LOGRATRADIX(prat) (LOGNUMRADIX((prat)->pp) - LOGNUMRADIX((prat)->pq))
// LOG*2 calculates the integral portion of the log of a number in
// the internal base being used, only accurate to within g_ratio
#define LOGNUM2(pnum) ((pnum)->cdigit + (pnum)->exp)
#define LOGRAT2(prat) (LOGNUM2((prat)->pp) - LOGNUM2((prat)->pq))
// SIGN returns the sign of the rational
#define SIGN(prat) ((prat)->pp->sign * (prat)->pq->sign)
#if defined(DEBUG_RATPAK)
//-----------------------------------------------------------------------------
//
// Debug versions of rational number creation and destruction routines.
// used for debugging allocation errors.
//
//-----------------------------------------------------------------------------
#define createrat(y) \
(y) = _createrat(); \
{ \
std::wstringstream outputString; \
outputString << "createrat " << y << " " << #y << " file= " << __FILE__ << ", line= " << __LINE__ << "\n"; \
OutputDebugString(outputString.str().c_str()); \
}
#define destroyrat(x) \
{ \
std::wstringstream outputString; \
outputString << "destroyrat " << x << " file= " << __FILE__ << ", line= " << __LINE__ << "\n"; \
OutputDebugString(outputString.str().c_str()); \
} \
_destroyrat(x), (x) = nullptr
#define createnum(y, x) \
(y) = _createnum(x); \
{ \
std::wstringstream outputString; \
outputString << "createnum " << y << " " << #y << " file= " << __FILE__ << ", line= " << __LINE__ << "\n"; \
OutputDebugString(outputString.str().c_str()); \
}
#define destroynum(x) \
{ \
std::wstringstream outputString; \
outputString << "destroynum " << x << " file= " << __FILE__ << ", line= " << __LINE__ << "\n"; \
OutputDebugString(outputString.str().c_str()); \
} \
_destroynum(x), (x) = nullptr
#else
#define createrat(y) (y) = _createrat()
#define destroyrat(x) _destroyrat(x), (x) = nullptr
#define createnum(y, x) (y) = _createnum(x)
#define destroynum(x) _destroynum(x), (x) = nullptr
#endif
//-----------------------------------------------------------------------------
//
// Defines for checking when to stop taylor series expansions due to
// precision satisfaction.
//
//-----------------------------------------------------------------------------
// RENORMALIZE, gets the exponents non-negative.
#define RENORMALIZE(x) \
if ((x)->pp->exp < 0) \
{ \
(x)->pq->exp -= (x)->pp->exp; \
(x)->pp->exp = 0; \
} \
if ((x)->pq->exp < 0) \
{ \
(x)->pp->exp -= (x)->pq->exp; \
(x)->pq->exp = 0; \
}
// TRIMNUM ASSUMES the number is in radix form NOT INTERNAL BASEX!!!
#define TRIMNUM(x, precision) \
if (!g_ftrueinfinite) \
{ \
int32_t trim = (x)->cdigit - precision - g_ratio; \
if (trim > 1) \
{ \
memmove((x)->mant, &((x)->mant[trim]), sizeof(MANTTYPE) * ((x)->cdigit - trim)); \
(x)->cdigit -= trim; \
(x)->exp += trim; \
} \
}
// TRIMTOP ASSUMES the number is in INTERNAL BASEX!!!
#define TRIMTOP(x, precision) \
if (!g_ftrueinfinite) \
{ \
int32_t trim = (x)->pp->cdigit - (precision / g_ratio) - 2; \
if (trim > 1) \
{ \
memmove((x)->pp->mant, &((x)->pp->mant[trim]), sizeof(MANTTYPE) * ((x)->pp->cdigit - trim)); \
(x)->pp->cdigit -= trim; \
(x)->pp->exp += trim; \
} \
trim = std::min((x)->pp->exp, (x)->pq->exp); \
(x)->pp->exp -= trim; \
(x)->pq->exp -= trim; \
}
#define SMALL_ENOUGH_RAT(a, precision) (zernum((a)->pp) || ((((a)->pq->cdigit + (a)->pq->exp) - ((a)->pp->cdigit + (a)->pp->exp) - 1) * g_ratio > precision))
//-----------------------------------------------------------------------------
//
// Defines for setting up taylor series expansions for infinite precision
// functions.
//
//-----------------------------------------------------------------------------
#define CREATETAYLOR() \
PRAT xx = nullptr; \
PNUMBER n2 = nullptr; \
PRAT pret = nullptr; \
PRAT thisterm = nullptr; \
DUPRAT(xx, *px); \
mulrat(&xx, *px, precision); \
createrat(pret); \
pret->pp = i32tonum(0L, BASEX); \
pret->pq = i32tonum(0L, BASEX);
#define DESTROYTAYLOR() \
destroynum(n2); \
destroyrat(xx); \
destroyrat(thisterm); \
destroyrat(*px); \
trimit(&pret, precision); \
*px = pret;
// INC(a) is the rational equivalent of a++
// Check to see if we can avoid doing this the hard way.
#define INC(a) \
if ((a)->mant[0] < BASEX - 1) \
{ \
(a)->mant[0]++; \
} \
else \
{ \
addnum(&(a), num_one, BASEX); \
}
#define MSD(x) ((x)->mant[(x)->cdigit - 1])
// MULNUM(b) is the rational equivalent of thisterm *= b where thisterm is
// a rational and b is a number, NOTE this is a mixed type operation for
// efficiency reasons.
#define MULNUM(b) mulnumx(&(thisterm->pp), b);
// DIVNUM(b) is the rational equivalent of thisterm /= b where thisterm is
// a rational and b is a number, NOTE this is a mixed type operation for
// efficiency reasons.
#define DIVNUM(b) mulnumx(&(thisterm->pq), b);
// NEXTTERM(p,d) is the rational equivalent of
// thisterm *= p
// d <d is usually an expansion of operations to get thisterm updated.>
// pret += thisterm
#define NEXTTERM(p, d, precision) \
mulrat(&thisterm, p, precision); \
d addrat(&pret, thisterm, precision)
//-----------------------------------------------------------------------------
//
// External variables used in the math package.
//
//-----------------------------------------------------------------------------
extern bool g_ftrueinfinite; // set to true to allow infinite precision
// don't use unless you know what you are doing
// used to help decide when to stop calculating.
extern int32_t g_ratio; // Internally calculated ratio of internal radix
//-----------------------------------------------------------------------------
//
// External functions defined in the math package.
//
//-----------------------------------------------------------------------------
// Call whenever decimal separator character changes.
extern void SetDecimalSeparator(wchar_t decimalSeparator);
// Call whenever either radix or precision changes, is smarter about recalculating constants.
extern void ChangeConstants(uint32_t radix, int32_t precision);
extern bool equnum(_In_ PNUMBER a, _In_ PNUMBER b); // returns true of a == b
extern bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b); // returns true of a < b
extern bool zernum(_In_ PNUMBER a); // returns true of a == 0
extern bool zerrat(_In_ PRAT a); // returns true if a == 0/q
extern std::wstring NumberToString(_Inout_ PNUMBER& pnum, NumberFormat format, uint32_t radix, int32_t precision);
// returns a text representation of a PRAT
extern std::wstring RatToString(_Inout_ PRAT& prat, NumberFormat format, uint32_t radix, int32_t precision);
// converts a PRAT into a PNUMBER
extern PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision);
// flattens a PRAT by converting it to a PNUMBER and back to a PRAT
extern void flatrat(_Inout_ PRAT& prat, uint32_t radix, int32_t precision);
extern int32_t numtoi32(_In_ PNUMBER pnum, uint32_t radix);
extern int32_t rattoi32(_In_ PRAT prat, uint32_t radix, int32_t precision);
uint64_t rattoUi64(_In_ PRAT prat, uint32_t radix, int32_t precision);
extern PNUMBER _createnum(_In_ uint32_t size); // returns an empty number structure with size digits
extern PNUMBER nRadixxtonum(_In_ PNUMBER a, uint32_t radix, int32_t precision);
extern PNUMBER gcd(_In_ PNUMBER a, _In_ PNUMBER b);
extern PNUMBER StringToNumber(
std::wstring_view numberString,
uint32_t radix,
int32_t precision); // takes a text representation of a number and returns a number.
// takes a text representation of a number as a mantissa with sign and an exponent with sign.
extern PRAT
StringToRat(bool mantissaIsNegative, std::wstring_view mantissa, bool exponentIsNegative, std::wstring_view exponent, uint32_t radix, int32_t precision);
extern PNUMBER i32factnum(int32_t ini32, uint32_t radix);
extern PNUMBER i32prodnum(int32_t start, int32_t stop, uint32_t radix);
extern PNUMBER i32tonum(int32_t ini32, uint32_t radix);
extern PNUMBER Ui32tonum(uint32_t ini32, uint32_t radix);
extern PNUMBER numtonRadixx(_In_ PNUMBER a, uint32_t radix);
// creates a empty/undefined rational representation (p/q)
extern PRAT _createrat(void);
// returns a new rat structure with the acos of x->p/x->q taking into account
// angle type
extern void acosanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
// returns a new rat structure with the acosh of x->p/x->q
extern void acoshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the acos of x->p/x->q
extern void acosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the asin of x->p/x->q taking into account
// angle type
extern void asinanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
extern void asinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the asinh of x->p/x->q
// returns a new rat structure with the asin of x->p/x->q
extern void asinrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the atan of x->p/x->q taking into account
// angle type
extern void atananglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
// returns a new rat structure with the atanh of x->p/x->q
extern void atanhrat(_Inout_ PRAT* px, int32_t precision);
// returns a new rat structure with the atan of x->p/x->q
extern void atanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the cosh of x->p/x->q
extern void coshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the cos of x->p/x->q
extern void cosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the cos of x->p/x->q taking into account
// angle type
extern void cosanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
// returns a new rat structure with the exp of x->p/x->q this should not be called explicitly.
extern void _exprat(_Inout_ PRAT* px, int32_t precision);
// returns a new rat structure with the exp of x->p/x->q
extern void exprat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the log base 10 of x->p/x->q
extern void log10rat(_Inout_ PRAT* px, int32_t precision);
// returns a new rat structure with the natural log of x->p/x->q
extern void lograt(_Inout_ PRAT* px, int32_t precision);
extern PRAT i32torat(int32_t ini32);
extern PRAT Ui32torat(uint32_t inui32);
extern PRAT numtorat(_In_ PNUMBER pin, uint32_t radix);
extern void sinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
extern void sinrat(_Inout_ PRAT* px);
// returns a new rat structure with the sin of x->p/x->q taking into account
// angle type
extern void sinanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
extern void tanhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
extern void tanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
// returns a new rat structure with the tan of x->p/x->q taking into account
// angle type
extern void tananglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
extern void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER* const src);
extern void _destroynum(_Frees_ptr_opt_ PNUMBER pnum);
extern void _destroyrat(_Frees_ptr_opt_ PRAT prat);
extern void addnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix);
extern void addrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision);
extern void andrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void divnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix, int32_t precision);
extern void divnumx(_Inout_ PNUMBER* pa, _In_ PNUMBER b, int32_t precision);
extern void divrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision);
extern void fracrat(_Inout_ PRAT* pa, uint32_t radix, int32_t precision);
extern void factrat(_Inout_ PRAT* pa, uint32_t radix, int32_t precision);
extern void remrat(_Inout_ PRAT* pa, _In_ PRAT b);
extern void modrat(_Inout_ PRAT* pa, _In_ PRAT b);
extern void gcdrat(_Inout_ PRAT* pa, int32_t precision);
extern void intrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
extern void mulnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix);
extern void mulnumx(_Inout_ PNUMBER* pa, _In_ PNUMBER b);
extern void mulrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision);
extern void numpowi32(_Inout_ PNUMBER* proot, int32_t power, uint32_t radix, int32_t precision);
extern void numpowi32x(_Inout_ PNUMBER* proot, int32_t power);
extern void orrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void powrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void powratNumeratorDenominator(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void powratcomp(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void ratpowi32(_Inout_ PRAT* proot, int32_t power, int32_t precision);
extern void remnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix);
extern void rootrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void scale2pi(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
extern void scale(_Inout_ PRAT* px, _In_ PRAT scalefact, uint32_t radix, int32_t precision);
extern void subrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision);
extern void xorrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void lshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern void rshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision);
extern bool rat_equ(_In_ PRAT a, _In_ PRAT b, int32_t precision);
extern bool rat_neq(_In_ PRAT a, _In_ PRAT b, int32_t precision);
extern bool rat_gt(_In_ PRAT a, _In_ PRAT b, int32_t precision);
extern bool rat_ge(_In_ PRAT a, _In_ PRAT b, int32_t precision);
extern bool rat_lt(_In_ PRAT a, _In_ PRAT b, int32_t precision);
extern bool rat_le(_In_ PRAT a, _In_ PRAT b, int32_t precision);
extern void inbetween(_In_ PRAT* px, _In_ PRAT range, int32_t precision);
extern void trimit(_Inout_ PRAT* px, int32_t precision);
extern void _dumprawrat(_In_ const wchar_t* varname, _In_ PRAT rat, std::wostream& out);
extern void _dumprawnum(_In_ const wchar_t* varname, _In_ PNUMBER num, std::wostream& out);

@ -1,715 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//----------------------------------------------------------------------------
// Package Title ratpak
// File support.c
// Copyright (C) 1995-96 Microsoft
// Date 10-21-96
//
//
// Description
//
// Contains support functions for rationals and numbers.
//
// Special Information
//
//
//
//----------------------------------------------------------------------------
#include <string>
#include <cstring> // for memmove
#include <iostream> // for wostream
#include "ratpak.h"
using namespace std;
void _readconstants();
#if defined(GEN_CONST)
static int cbitsofprecision = 0;
#define READRAWRAT(v)
#define READRAWNUM(v)
#define DUMPRAWRAT(v) _dumprawrat(#v, v, wcout)
#define DUMPRAWNUM(v) \
fprintf(stderr, "// Autogenerated by _dumprawrat in support.cpp\n"); \
fprintf(stderr, "inline const NUMBER init_" #v "= {\n"); \
_dumprawnum(v, wcout); \
fprintf(stderr, "};\n")
#else
#define DUMPRAWRAT(v)
#define DUMPRAWNUM(v)
#define READRAWRAT(v) \
createrat(v); \
DUPNUM((v)->pp, (&(init_p_##v))); \
DUPNUM((v)->pq, (&(init_q_##v)));
#define READRAWNUM(v) DUPNUM(v, (&(init_##v)))
#define INIT_AND_DUMP_RAW_NUM_IF_NULL(r, v) \
if (r == nullptr) \
{ \
r = i32tonum(v, BASEX); \
DUMPRAWNUM(v); \
}
#define INIT_AND_DUMP_RAW_RAT_IF_NULL(r, v) \
if (r == nullptr) \
{ \
r = i32torat(v); \
DUMPRAWRAT(v); \
}
static constexpr int RATIO_FOR_DECIMAL = 9;
static constexpr int DECIMAL = 10;
static constexpr int CALC_DECIMAL_DIGITS_DEFAULT = 32;
static int cbitsofprecision = RATIO_FOR_DECIMAL * DECIMAL * CALC_DECIMAL_DIGITS_DEFAULT;
#include "ratconst.h"
#endif
bool g_ftrueinfinite = false; // Set to true if you don't want
// chopping internally
// precision used internally
PNUMBER num_one = nullptr;
PNUMBER num_two = nullptr;
PNUMBER num_five = nullptr;
PNUMBER num_six = nullptr;
PNUMBER num_ten = nullptr;
PRAT ln_ten = nullptr;
PRAT ln_two = nullptr;
PRAT rat_zero = nullptr;
PRAT rat_one = nullptr;
PRAT rat_neg_one = nullptr;
PRAT rat_two = nullptr;
PRAT rat_six = nullptr;
PRAT rat_half = nullptr;
PRAT rat_ten = nullptr;
PRAT pt_eight_five = nullptr;
PRAT pi = nullptr;
PRAT pi_over_two = nullptr;
PRAT two_pi = nullptr;
PRAT one_pt_five_pi = nullptr;
PRAT e_to_one_half = nullptr;
PRAT rat_exp = nullptr;
PRAT rad_to_deg = nullptr;
PRAT rad_to_grad = nullptr;
PRAT rat_qword = nullptr;
PRAT rat_dword = nullptr; // unsigned max ui32
PRAT rat_word = nullptr;
PRAT rat_byte = nullptr;
PRAT rat_360 = nullptr;
PRAT rat_400 = nullptr;
PRAT rat_180 = nullptr;
PRAT rat_200 = nullptr;
PRAT rat_nRadix = nullptr;
PRAT rat_smallest = nullptr;
PRAT rat_negsmallest = nullptr;
PRAT rat_max_exp = nullptr;
PRAT rat_min_exp = nullptr;
PRAT rat_max_fact = nullptr;
PRAT rat_min_fact = nullptr;
PRAT rat_min_i32 = nullptr; // min signed i32
PRAT rat_max_i32 = nullptr; // max signed i32
//----------------------------------------------------------------------------
//
// FUNCTION: ChangeConstants
//
// ARGUMENTS: base changing to, and precision to use.
//
// RETURN: None
//
// SIDE EFFECTS: sets a mess of constants.
//
//
//----------------------------------------------------------------------------
void ChangeConstants(uint32_t radix, int32_t precision)
{
// ratio is set to the number of digits in the current radix, you can get
// in the internal BASEX radix, this is important for length calculations
// in translating from radix to BASEX and back.
g_ratio = static_cast<int32_t>(ceil(BASEXPWR / log2(radix))) - 1;
destroyrat(rat_nRadix);
rat_nRadix = i32torat(radix);
// Check to see what we have to recalculate and what we don't
if (cbitsofprecision < (g_ratio * static_cast<int32_t>(radix) * precision))
{
g_ftrueinfinite = false;
INIT_AND_DUMP_RAW_NUM_IF_NULL(num_one, 1L);
INIT_AND_DUMP_RAW_NUM_IF_NULL(num_two, 2L);
INIT_AND_DUMP_RAW_NUM_IF_NULL(num_five, 5L);
INIT_AND_DUMP_RAW_NUM_IF_NULL(num_six, 6L);
INIT_AND_DUMP_RAW_NUM_IF_NULL(num_ten, 10L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_six, 6L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_two, 2L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_zero, 0L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_one, 1L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_neg_one, -1L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_ten, 10L);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_word, 0xffff);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_word, 0xff);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_400, 400);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_360, 360);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_200, 200);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_180, 180);
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_max_exp, 100000);
// 3248, is the max number for which calc is able to compute factorial, after that it is unable to compute due to overflow.
// Hence restricted factorial range as at most 3248.Beyond that calc will throw overflow error immediately.
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_max_fact, 3249);
// -1000, is the min number for which calc is able to compute factorial, after that it takes too long to compute.
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_min_fact, -1000);
DUPRAT(rat_smallest, rat_nRadix);
ratpowi32(&rat_smallest, -precision, precision);
DUPRAT(rat_negsmallest, rat_smallest);
rat_negsmallest->pp->sign = -1;
DUMPRAWRAT(rat_smallest);
DUMPRAWRAT(rat_negsmallest);
if (rat_half == nullptr)
{
createrat(rat_half);
DUPNUM(rat_half->pp, num_one);
DUPNUM(rat_half->pq, num_two);
DUMPRAWRAT(rat_half);
}
if (pt_eight_five == nullptr)
{
createrat(pt_eight_five);
pt_eight_five->pp = i32tonum(85L, BASEX);
pt_eight_five->pq = i32tonum(100L, BASEX);
DUMPRAWRAT(pt_eight_five);
}
DUPRAT(rat_qword, rat_two);
numpowi32(&(rat_qword->pp), 64, BASEX, precision);
subrat(&rat_qword, rat_one, precision);
DUMPRAWRAT(rat_qword);
DUPRAT(rat_dword, rat_two);
numpowi32(&(rat_dword->pp), 32, BASEX, precision);
subrat(&rat_dword, rat_one, precision);
DUMPRAWRAT(rat_dword);
DUPRAT(rat_max_i32, rat_two);
numpowi32(&(rat_max_i32->pp), 31, BASEX, precision);
DUPRAT(rat_min_i32, rat_max_i32);
subrat(&rat_max_i32, rat_one, precision); // rat_max_i32 = 2^31 -1
DUMPRAWRAT(rat_max_i32);
rat_min_i32->pp->sign *= -1; // rat_min_i32 = -2^31
DUMPRAWRAT(rat_min_i32);
DUPRAT(rat_min_exp, rat_max_exp);
rat_min_exp->pp->sign *= -1;
DUMPRAWRAT(rat_min_exp);
cbitsofprecision = g_ratio * radix * precision;
// Apparently when dividing 180 by pi, another (internal) digit of
// precision is needed.
int32_t extraPrecision = precision + g_ratio;
DUPRAT(pi, rat_half);
asinrat(&pi, radix, extraPrecision);
mulrat(&pi, rat_six, extraPrecision);
DUMPRAWRAT(pi);
DUPRAT(two_pi, pi);
DUPRAT(pi_over_two, pi);
DUPRAT(one_pt_five_pi, pi);
addrat(&two_pi, pi, extraPrecision);
DUMPRAWRAT(two_pi);
divrat(&pi_over_two, rat_two, extraPrecision);
DUMPRAWRAT(pi_over_two);
addrat(&one_pt_five_pi, pi_over_two, extraPrecision);
DUMPRAWRAT(one_pt_five_pi);
DUPRAT(e_to_one_half, rat_half);
_exprat(&e_to_one_half, extraPrecision);
DUMPRAWRAT(e_to_one_half);
DUPRAT(rat_exp, rat_one);
_exprat(&rat_exp, extraPrecision);
DUMPRAWRAT(rat_exp);
// WARNING: remember lograt uses exponent constants calculated above...
DUPRAT(ln_ten, rat_ten);
lograt(&ln_ten, extraPrecision);
DUMPRAWRAT(ln_ten);
DUPRAT(ln_two, rat_two);
lograt(&ln_two, extraPrecision);
DUMPRAWRAT(ln_two);
destroyrat(rad_to_deg);
rad_to_deg = i32torat(180L);
divrat(&rad_to_deg, pi, extraPrecision);
DUMPRAWRAT(rad_to_deg);
destroyrat(rad_to_grad);
rad_to_grad = i32torat(200L);
divrat(&rad_to_grad, pi, extraPrecision);
DUMPRAWRAT(rad_to_grad);
}
else
{
_readconstants();
DUPRAT(rat_smallest, rat_nRadix);
ratpowi32(&rat_smallest, -precision, precision);
DUPRAT(rat_negsmallest, rat_smallest);
rat_negsmallest->pp->sign = -1;
}
}
//----------------------------------------------------------------------------
//
// FUNCTION: intrat
//
// ARGUMENTS: pointer to x PRAT representation of number
//
// RETURN: no return value x PRAT is smashed with integral number
//
//
//----------------------------------------------------------------------------
void intrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
// Only do the intrat operation if number is nonzero.
// and only if the bottom part is not one.
if (!zernum((*px)->pp) && !equnum((*px)->pq, num_one))
{
flatrat(*px, radix, precision);
// Subtract the fractional part of the rational
PRAT pret = nullptr;
DUPRAT(pret, *px);
remrat(&pret, rat_one);
// Flatten pret in case it's not aligned with px after remrat operation
if (!equnum((*px)->pq, pret->pq))
{
flatrat(pret, radix, precision);
}
subrat(px, pret, precision);
destroyrat(pret);
// Simplify the value if possible to resolve rounding errors
flatrat(*px, radix, precision);
}
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_equ
//
// ARGUMENTS: PRAT a and PRAT b
//
// RETURN: true if equal false otherwise.
//
//
//---------------------------------------------------------------------------
bool rat_equ(_In_ PRAT a, _In_ PRAT b, int32_t precision)
{
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
rattmp->pp->sign *= -1;
addrat(&rattmp, b, precision);
bool bret = zernum(rattmp->pp);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_ge
//
// ARGUMENTS: PRAT a, PRAT b and int32_t precision
//
// RETURN: true if a is greater than or equal to b
//
//
//---------------------------------------------------------------------------
bool rat_ge(_In_ PRAT a, _In_ PRAT b, int32_t precision)
{
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = (zernum(rattmp->pp) || SIGN(rattmp) == 1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_gt
//
// ARGUMENTS: PRAT a and PRAT b
//
// RETURN: true if a is greater than b
//
//
//---------------------------------------------------------------------------
bool rat_gt(_In_ PRAT a, _In_ PRAT b, int32_t precision)
{
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = (!zernum(rattmp->pp) && SIGN(rattmp) == 1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_le
//
// ARGUMENTS: PRAT a, PRAT b and int32_t precision
//
// RETURN: true if a is less than or equal to b
//
//
//---------------------------------------------------------------------------
bool rat_le(_In_ PRAT a, _In_ PRAT b, int32_t precision)
{
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = (zernum(rattmp->pp) || SIGN(rattmp) == -1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_lt
//
// ARGUMENTS: PRAT a, PRAT b and int32_t precision
//
// RETURN: true if a is less than b
//
//
//---------------------------------------------------------------------------
bool rat_lt(_In_ PRAT a, _In_ PRAT b, int32_t precision)
{
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = (!zernum(rattmp->pp) && SIGN(rattmp) == -1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_neq
//
// ARGUMENTS: PRAT a and PRAT b
//
// RETURN: true if a is not equal to b
//
//
//---------------------------------------------------------------------------
bool rat_neq(_In_ PRAT a, _In_ PRAT b, int32_t precision)
{
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
rattmp->pp->sign *= -1;
addrat(&rattmp, b, precision);
bool bret = !(zernum(rattmp->pp));
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// function: scale
//
// ARGUMENTS: pointer to x PRAT representation of number, and scaling factor
//
// RETURN: no return, value x PRAT is smashed with a scaled number in the
// range of the scalefact.
//
//---------------------------------------------------------------------------
void scale(_Inout_ PRAT* px, _In_ PRAT scalefact, uint32_t radix, int32_t precision)
{
PRAT pret = nullptr;
DUPRAT(pret, *px);
// Logscale is a quick way to tell how much extra precision is needed for
// scaling by scalefact.
int32_t logscale = g_ratio * ((pret->pp->cdigit + pret->pp->exp) - (pret->pq->cdigit + pret->pq->exp));
if (logscale > 0)
{
precision += logscale;
}
divrat(&pret, scalefact, precision);
intrat(&pret, radix, precision);
mulrat(&pret, scalefact, precision);
pret->pp->sign *= -1;
addrat(px, pret, precision);
destroyrat(pret);
}
//---------------------------------------------------------------------------
//
// function: scale2pi
//
// ARGUMENTS: pointer to x PRAT representation of number
//
// RETURN: no return, value x PRAT is smashed with a scaled number in the
// range of 0..2pi
//
//---------------------------------------------------------------------------
void scale2pi(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
{
PRAT pret = nullptr;
PRAT my_two_pi = nullptr;
DUPRAT(pret, *px);
// Logscale is a quick way to tell how much extra precision is needed for
// scaling by 2 pi.
int32_t logscale = g_ratio * ((pret->pp->cdigit + pret->pp->exp) - (pret->pq->cdigit + pret->pq->exp));
if (logscale > 0)
{
precision += logscale;
DUPRAT(my_two_pi, rat_half);
asinrat(&my_two_pi, radix, precision);
mulrat(&my_two_pi, rat_six, precision);
mulrat(&my_two_pi, rat_two, precision);
}
else
{
DUPRAT(my_two_pi, two_pi);
logscale = 0;
}
divrat(&pret, my_two_pi, precision);
intrat(&pret, radix, precision);
mulrat(&pret, my_two_pi, precision);
pret->pp->sign *= -1;
addrat(px, pret, precision);
destroyrat(my_two_pi);
destroyrat(pret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: inbetween
//
// ARGUMENTS: PRAT *px, and PRAT range.
//
// RETURN: none, changes *px to -/+range, if px is outside -range..+range
//
//---------------------------------------------------------------------------
void inbetween(_In_ PRAT* px, _In_ PRAT range, int32_t precision)
{
if (rat_gt(*px, range, precision))
{
DUPRAT(*px, range);
}
else
{
range->pp->sign *= -1;
if (rat_lt(*px, range, precision))
{
DUPRAT(*px, range);
}
range->pp->sign *= -1;
}
}
//---------------------------------------------------------------------------
//
// FUNCTION: _dumprawrat
//
// ARGUMENTS: const wchar *name of variable, PRAT x, output stream out
//
// RETURN: none, prints the results of a dump of the internal structures
// of a PRAT, suitable for READRAWRAT to stderr.
//
//---------------------------------------------------------------------------
void _dumprawrat(_In_ const wchar_t* varname, _In_ PRAT rat, wostream& out)
{
_dumprawnum(varname, rat->pp, out);
_dumprawnum(varname, rat->pq, out);
}
//---------------------------------------------------------------------------
//
// FUNCTION: _dumprawnum
//
// ARGUMENTS: const wchar *name of variable, PNUMBER num, output stream out
//
// RETURN: none, prints the results of a dump of the internal structures
// of a PNUMBER, suitable for READRAWNUM to stderr.
//
//---------------------------------------------------------------------------
void _dumprawnum(_In_ const wchar_t* varname, _In_ PNUMBER num, wostream& out)
{
out << L"NUMBER " << varname << L" = {\n";
out << L"\t" << num->sign << L",\n";
out << L"\t" << num->cdigit << L",\n";
out << L"\t" << num->exp << L",\n";
out << L"\t{ ";
for (int i = 0; i < num->cdigit; i++)
{
out << L" " << num->mant[i] << L",";
}
out << L"}\n";
out << L"};\n";
}
void _readconstants(void)
{
READRAWNUM(num_one);
READRAWNUM(num_two);
READRAWNUM(num_five);
READRAWNUM(num_six);
READRAWNUM(num_ten);
READRAWRAT(pt_eight_five);
READRAWRAT(rat_six);
READRAWRAT(rat_two);
READRAWRAT(rat_zero);
READRAWRAT(rat_one);
READRAWRAT(rat_neg_one);
READRAWRAT(rat_half);
READRAWRAT(rat_ten);
READRAWRAT(pi);
READRAWRAT(two_pi);
READRAWRAT(pi_over_two);
READRAWRAT(one_pt_five_pi);
READRAWRAT(e_to_one_half);
READRAWRAT(rat_exp);
READRAWRAT(ln_ten);
READRAWRAT(ln_two);
READRAWRAT(rad_to_deg);
READRAWRAT(rad_to_grad);
READRAWRAT(rat_qword);
READRAWRAT(rat_dword);
READRAWRAT(rat_word);
READRAWRAT(rat_byte);
READRAWRAT(rat_360);
READRAWRAT(rat_400);
READRAWRAT(rat_180);
READRAWRAT(rat_200);
READRAWRAT(rat_smallest);
READRAWRAT(rat_negsmallest);
READRAWRAT(rat_max_exp);
READRAWRAT(rat_min_exp);
READRAWRAT(rat_max_fact);
READRAWRAT(rat_min_fact);
READRAWRAT(rat_min_i32);
READRAWRAT(rat_max_i32);
}
//---------------------------------------------------------------------------
//
// FUNCTION: trimit
//
// ARGUMENTS: PRAT *px, int32_t precision
//
//
// DESCRIPTION: Chops off digits from rational numbers to avoid time
// explosions in calculations of functions using series.
// It can be shown that it is enough to only keep the first n digits
// of the largest of p or q in the rational p over q form, and of course
// scale the smaller by the same number of digits. This will give you
// n-1 digits of accuracy. This dramatically speeds up calculations
// involving hundreds of digits or more.
// The last part of this trim dealing with exponents never affects accuracy
//
// RETURN: none, modifies the pointed to PRAT
//
//---------------------------------------------------------------------------
void trimit(_Inout_ PRAT* px, int32_t precision)
{
if (!g_ftrueinfinite)
{
PNUMBER pp = (*px)->pp;
PNUMBER pq = (*px)->pq;
int32_t trim = g_ratio * (min((pp->cdigit + pp->exp), (pq->cdigit + pq->exp)) - 1) - precision;
if (trim > g_ratio)
{
trim /= g_ratio;
if (trim <= pp->exp)
{
pp->exp -= trim;
}
else
{
memmove(pp->mant, &(pp->mant[trim - pp->exp]), sizeof(MANTTYPE) * (pp->cdigit - trim + pp->exp));
pp->cdigit -= trim - pp->exp;
pp->exp = 0;
}
if (trim <= pq->exp)
{
pq->exp -= trim;
}
else
{
memmove(pq->mant, &(pq->mant[trim - pq->exp]), sizeof(MANTTYPE) * (pq->cdigit - trim + pq->exp));
pq->cdigit -= trim - pq->exp;
pq->exp = 0;
}
}
trim = min(pp->exp, pq->exp);
pp->exp -= trim;
pq->exp -= trim;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save