merge with master and use m_resolvedName for all GetLocalInfoEx calls in LocalizationSettings.h

This commit is contained in:
rudyhuyn 2019-05-09 01:26:46 -07:00
commit 677211e390
544 changed files with 19343 additions and 16219 deletions

99
.clang-format Normal file
View file

@ -0,0 +1,99 @@
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

23
.gitattributes vendored
View file

@ -12,29 +12,6 @@
###############################################################################
*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
*.sln merge=binary
*.csproj merge=binary
*.vbproj merge=binary
*.vcxproj merge=binary
*.vcproj merge=binary
*.dbproj merge=binary
*.fsproj merge=binary
*.lsproj merge=binary
*.wixproj merge=binary
*.modelproj merge=binary
*.sqlproj merge=binary
*.wwaproj merge=binary
###############################################################################
# behavior for image files
#

View file

@ -6,36 +6,45 @@ labels: ''
assignees: ''
---
<!--Before filing a bug
<!--
Before filing a bug
- Ensure the bug reproduces on the latest version of the app.
- Search existing issues and make sure this issue is not already filed.-->
- Search existing issues and make sure this issue is not already filed.
-->
**Describe the bug**
<!--A clear and concise description of what the bug is.-->
<!-- A clear and concise description of what the bug is. -->
**Steps To Reproduce**
<!--Steps to reproduce the behavior:
<!--
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error-->
4. See error
-->
**Expected behavior**
<!--A clear and concise description of what you expected to happen.-->
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
<!--If applicable, add screenshots to help explain your problem.-->
<!-- If applicable, add screenshots to help explain your problem. -->
**Device and Application Information (please complete the following information):**
**Device and Application Information**
- OS Build:
- Architecture:
- Application Version:
<!--Run the following commands in Powershell and copy/paste the output.
- Region:
- Dev Version Installed:
<!--
Run the following commands in Powershell and copy/paste the output.
" - OS Build: $([Environment]::OSVersion.Version)"
" - Architecture: $((Get-AppxPackage -Name Microsoft.WindowsCalculator).Architecture)"
" - Application Version: $((Get-AppxPackage -Name Microsoft.WindowsCalculator).Version)"
" - Region: $((Get-Culture).Name)"
" - Dev Version Installed: $($null -ne (Get-AppxPackage -Name Microsoft.WindowsCalculator.Dev))"
-->
**Additional context**
<!--Add any other context about the problem here.-->
<!-- Add any other context about the problem here. -->

View file

@ -2,42 +2,42 @@
name: Feature request
about: Propose a new feature in the app
title: ''
labels: ''
labels: 'Enhancement'
assignees: ''
---
<!--
See https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md for
suggestions on how to write a good feature pitch. Just want to submit an idea quickly? Try Feedback
Hub instead: https://insider.windows.com/en-us/fb/?contextid=130
See https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md for suggestions on how to write a good feature pitch. Just want to submit an idea quickly? Try Feedback Hub instead: https://insider.windows.com/en-us/fb/?contextid=130
-->
**Problem Statement**
<!-- What problem are we trying to solve? Whos the target audience? Is there a customer need or
pain point we need to remedy? Is there a business goal or metric we are trying to improve? Do we
have a hypothesis we want to prove or disprove? -->
<!--
What problem are we trying to solve? Whos the target audience? Is there a customer need or pain point we need to remedy? Is there a business goal or metric we are trying to improve? Do we have a hypothesis we want to prove or disprove?
-->
**Evidence or User Insights**
<!-- Why should we do this? Potential sources of data: Feedback Hub, other GitHub issues, other
anecdotes from listening to customers in person or online, request from another team, telemetry
data, user research, market or competitive research -->
<!--
Why should we do this? Potential sources of data: Feedback Hub, other GitHub issues, other anecdotes from listening to customers in person or online, request from another team, telemetry data, user research, market or competitive research
-->
**Proposal**
<!-- How will the solution/feature help us solve the problem? How will it meet the target
audiences needs? If there are business goals or metrics, how does this improve them? -->
<!--
How will the solution/feature help us solve the problem? How will it meet the target audiences needs? If there are business goals or metrics, how does this improve them?
-->
**Goals**
<!-- What you want to accomplish with this feature. Typical examples include
“User Can *perform some task*” -->
<!--
What you want to accomplish with this feature. Typical examples include
"User Can *perform some task*"
-->
**Non-Goals**
<!-- Things we are explicitly not doing or supporting or that are out of scope, including reasons
why. -->
<!--
Things we are explicitly not doing or supporting or that are out of scope, including reasons why.
-->
**Low-Fidelity Concept**
<!-- Show as much of the experience as needed to explain the idea. This can be as simple as a
napkin drawing but can also be a code prototype, a PowerPoint walkthrough, or a design
comp. -->
<!--
Show as much of the experience as needed to explain the idea. This can be as simple as a napkin drawing but can also be a code prototype, or a design comp. Keep it simple at this stage, as it can be refined later during the pre-production stage.
-->

View file

@ -0,0 +1,54 @@
---
name: Localization Suggestion
about: Report a problem or suggested change to Calculator's localized content.
title: '[Localization] '
labels: 'Area: World-Readiness'
assignees: ''
---
<!--
PLEASE NOTE:
We cannot _merge_ any suggested localization changes to our localized resources files. These files are automatically generated from an internal localization process. Any suggestion submitted this way will be duplicated into our internal localization system, and then closed here.
Alternatively, you can launch feedback-hub://, click on the "Language Community" tab on the left-side of the app, and follow the steps to submit a localization suggestion that way. (The "Language Community" tab currently will only be visible if your system is running a non-English language).
Before filing a bug
- Ensure the bug reproduces on the latest version of the app.
- Search existing issues and make sure this issue is not already filed.
-->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**Steps To Reproduce**
<!--
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Device and Application Information**
- OS Build:
- Architecture:
- Application Version:
- Region:
- Dev Version Installed:
<!--
Run the following commands in Powershell and copy/paste the output.
" - OS Build: $([Environment]::OSVersion.Version)"
" - Architecture: $((Get-AppxPackage -Name Microsoft.WindowsCalculator).Architecture)"
" - Application Version: $((Get-AppxPackage -Name Microsoft.WindowsCalculator).Version)"
" - Region: $((Get-Culture).Name)"
" - Dev Version Installed: $($null -ne (Get-AppxPackage -Name Microsoft.WindowsCalculator.Dev))"
-->
**Additional context**
<!-- Add any other context about the problem here. -->

2
.gitignore vendored
View file

@ -289,5 +289,7 @@ __pycache__/
# Calculator specific
Generated Files/
src/GraphControl/GraphingImplOverrides.props
!/build/config/TRexDefs/**
!src/Calculator/TemporaryKey.pfx
!src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx

View file

@ -3,7 +3,8 @@ The Calculator team encourages community feedback and contributions. Thank you f
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).
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.
@ -17,21 +18,38 @@ all community interactions must abide by the [Code of Conduct](CODE_OF_CONDUCT.m
## 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)
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* tag](https://github.com/Microsoft/calculator/labels/help%20wanted)
to find other issues to help with.
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.
improvements which address the top issues reported by Calculator users. Some general guidelines:
We have a high bar for new features and changes to the user experience. We prefer to evaluate
*prototypes* to ensure that the design meets users' needs before we start discussing implementation
details and reviewing code. 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.
* **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
@ -41,7 +59,8 @@ To learn how to build the code and run tests, follow the instructions in the [RE
### 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)
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
@ -61,18 +80,9 @@ to group your changes into a small number of commits which we can review one at
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.
## Submitting a pull request and participating in code review
Writing a good description for your pull request is crucial to help reviewers and future
maintainers understand your change. More detail is better.
- [Link the issue you're addressing in the pull request](https://github.com/blog/957-introducing-issue-mentions).
- Describe *why* the change is being made and *why* you've chosen a particular solution.
- Describe any manual testing you performed to validate your change.
Please submit one pull request per issue. Large pull requests which have unrelated changes can be
difficult to review.
## 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 within two days. Any member of the community may
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.

View file

@ -12,9 +12,13 @@ Calculator ships regularly with new features and bug fixes. You can get the late
- 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:

View file

@ -0,0 +1,91 @@
<#
.DESCRIPTION
Helper script to format all header and source files in the repository.
By default, the script will recursively search under the repo root for
files to format. Users can give explicit parameters indicating how the
search should include and exclude filetypes.
If users don't want the search functionality, they can instead provide
an explicit list of files to format.
.PARAMETER RepoRoot
Full path to the root of the repository which is the target of the search.
Will default to the root of the current working directory.
.PARAMETER Include
Array of filetype extensions to target for formatting.
By default, targets standard extensions for header and source files.
Follows the same rules as the -Include parameter for Get-ChildItem.
.PARAMETER Exclude
Array of filetype extensions to exclude from formatting.
By default, excludes generated XAML files.
Follows the same rules as the -Exclude paramter for Get-ChildItem.
.PARAMETER Files
Array of files to format. The script will exit if one of the provided
filepaths does not exist.
.EXAMPLE
.\clang-format-all.ps1
Formats all header and source files under the repository root.
.EXAMPLE
.\clang-format-all.ps1 -RepoRoot 'S:\repos\calculator' -Include '*.h', '*.cpp' -Exclude '*.g.*'
Formats all *.h and *.cpp files under 'S:\repos\calculator', excluding files with an extension
like *.g.*
.EXAMPLE
.\clang-format-all.ps1 -File 'S:\repos\calculator\src\CalcViewModel\UnitConverterViewModel.h', 'S:\repos\calculator\src\CalcViewModel\MemoryItemViewModel.cpp'
Formats the specified files.
#>
[CmdletBinding( DefaultParameterSetName = 'Search' )]
param(
[Parameter( ParameterSetName = 'Search' )]
[ValidateScript({ Test-Path -PathType Container -Path $_ })]
[string] $RepoRoot = "$( git rev-parse --show-toplevel )",
[Parameter( ParameterSetName = 'Search' )]
[string[]] $Include = ( '*.h', '*.hh', '*.hpp', '*.c', '*.cc', '*.cpp' ),
[Parameter( ParameterSetName = 'Search' )]
[string[]] $Exclude = '*.g.*',
[Parameter(
ParameterSetName = 'Explicit',
Mandatory)]
[ValidateScript({
$_ | Where-Object { -not (Test-Path -PathType Leaf -Path $_) } |
ForEach-Object { throw "Could not find file: [$_]" }
return $true
})]
[string[]] $Files
)
if ($PSCmdlet.ParameterSetName -eq 'Explicit')
{
# Use the file paths we were given.
$targetFiles = @($Files)
}
else
{
# Gather the files to be formatted.
$targetFiles = @(
Get-ChildItem -Recurse -Path $RepoRoot -Include $Include -Exclude $Exclude |
Select-Object -ExpandProperty FullName
)
}
# Format the files.
$formatParams = @(
'-i' # In-place
'-style=file' # Search for a .clang-format file in the parent directory of the source file.
'-verbose'
)
clang-format $formatParams $targetFiles

View file

@ -0,0 +1,53 @@
#!/bin/bash
function usage {
echo "Usage: $0 DIR..."
exit 1
}
# Variable that will hold the name of the clang-format command
FMT=""
# Some distros just call it clang-format. Others (e.g. Ubuntu) are insistent
# that the version number be part of the command. We prefer clang-format if
# that's present, otherwise we work backwards from highest version to lowest
# version.
for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do
if which "$clangfmt" &>/dev/null; then
FMT="$clangfmt"
break
fi
done
# Check if we found a working clang-format
if [ -z "$FMT" ]; then
echo "failed to find clang-format"
exit 1
fi
SRC_PATH="$@"
if [ -z "$SRC_PATH" ]; then
SRC_PATH="../../../src"
fi
# Check all of the arguments first to make sure they're all directories
for dir in "$SRC_PATH"; do
if [ ! -d "${dir}" ]; then
echo "${dir} is not a directory"
usage
fi
done
# Run clang-format -i on all of the things
for dir in "$SRC_PATH"; do
pushd "${dir}" &>/dev/null
find . \
\( -name '*.c' \
-o -name '*.cc' \
-o -name '*.cpp' \
-o -name '*.h' \
-o -name '*.hh' \
-o -name '*.hpp' \) \
-exec "${FMT}" -style=file -i '{}' \;
popd &>/dev/null
done

View file

@ -1,5 +1,5 @@
<SignConfigXML>
<job platform="" configuration="" certSubject="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" jobname="EngFunSimpleSign" approvers="gstolt;vigarg">
<job platform="" configuration="" certSubject="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" jobname="EngFunSimpleSign" approvers="">
<file src="__INPATHROOT__\Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle" signType="136020001" dest="__OUTPATHROOT__\Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle" />
</job>
</SignConfigXML>

View file

@ -33,6 +33,10 @@ jobs:
platform: ARM64
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/run-ui-tests.yaml
parameters:
platform: x64
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x64

View file

@ -15,30 +15,33 @@ name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
jobs:
- job: Localize
pool:
name: Package ES Custom Demands Lab A
demands:
- ClientAlias -equals PKGESUTILAPPS
workspace:
clean: outputs
vmImage: vs2017-win2016
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: self
clean: true
- task: PkgESSetupBuild@10
displayName: Initialize Package ES
- task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@1
displayName: Send resources to Touchdown Build
inputs:
productName: Calculator
branchVersion: true
teamId: 86
authId: d3dd8113-65b3-4526-bdca-a00a7d1c37ba
authKey: $(LocServiceKey)
isPreview: false
relativePathRoot: src/Calculator/Resources/en-US/
resourceFilePath: '*.resw'
outputDirectoryRoot: src/Calculator/Resources/
- task: PkgESTouchdownLocService@10
displayName: Package ES Touchdown Loc Service
- script: |
cd $(Build.SourcesDirectory)
git add -A
git diff --cached --exit-code
echo ##vso[task.setvariable variable=hasChanges]%errorlevel%
git diff --cached > $(Build.ArtifactStagingDirectory)\LocalizedStrings.patch
displayName: Check for changes and create patch file
- task: PublishPipelineArtifact@0
displayName: Publish patch file as artifact
condition: eq(variables['hasChanges'], '1')
inputs:
IsCallToServiceStepSelected: true
IsCheckedInFileSelected: true
CheckinFilesAtOriginFilePath: true
GitLocPath: Loc/Resources
LocConfigFile: build/config/LocConfigPackageEs.xml
AuthenticationMode: OAuth
ClientApplicationID: d3dd8113-65b3-4526-bdca-a00a7d1c37ba
ApplicationKeyID: $(LocServiceKey)
SendToLoc: true
artifactName: Patch
targetPath: $(Build.ArtifactStagingDirectory)

View file

@ -9,8 +9,8 @@ pr: none
variables:
versionMajor: 10
versionMinor: 1902
versionBuild: $[counter('10.1902.*', 0)]
versionMinor: 1904
versionBuild: $[counter('10.1904.*', 0)]
versionPatch: 0
name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)'

View file

@ -29,7 +29,7 @@ jobs:
downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsApps
vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.7
vstsPackageVersion: 0.0.10
- template: ./build-single-architecture.yaml
parameters:

View file

@ -30,7 +30,7 @@ steps:
inputs:
solution: src/Calculator.sln
vsVersion: 15.0
msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) ${{ parameters.extraMsBuildArgs }}
msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ ${{ parameters.extraMsBuildArgs }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: true

View file

@ -20,6 +20,8 @@ jobs:
vmImage: vs2017-win2016
workspace:
clean: outputs
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: self
clean: true

View file

@ -1,5 +1,5 @@
# This template contains a job which builds artifacts needed to release the app to the store and to
# Windows using Microsoft-internal systems. It relies Microsoft-internal resources and will not
# Windows using Microsoft-internal systems. It relies on Microsoft-internal resources and will not
# work outside of Microsoft.
# Specifically, this job:
# - Signs the bundle using a secure system. If you want to build your own, use SignTool following
@ -17,6 +17,8 @@ jobs:
name: Package ES Lab E
workspace:
clean: outputs
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: self
clean: true
@ -26,8 +28,8 @@ jobs:
- task: PkgESSetupBuild@10
displayName: Initialize Package ES
inputs:
productName: Calculator
disableWorkspace: true
productName: Calculator
disableWorkspace: true
env:
XES_DISABLEPROV: true
@ -44,6 +46,8 @@ jobs:
- task: PkgESCodeSign@10
displayName: Send bundle to Package ES code signing service
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
signConfigXml: build\config\SignConfig.xml
inPathRoot: $(Build.ArtifactStagingDirectory)\appxBundle
@ -58,25 +62,25 @@ jobs:
- task: CopyFiles@2
displayName: Copy signed AppxBundle to vpack staging folder
inputs:
sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
- task: PkgESVPack@10
displayName: Create and push vpack for app
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
description: VPack for the Calculator Application
pushPkgName: calculator.app
version: $(versionMajor).$(versionMinor).$(versionBuild)
owner: paxeeapps
sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
description: VPack for the Calculator Application
pushPkgName: calculator.app
version: $(versionMajor).$(versionMinor).$(versionBuild)
owner: paxeeapps
- task: PublishBuildArtifacts@1
displayName: Publish vpack\app artifact with vpack manifest
inputs:
pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
artifactName: vpack\app
pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
artifactName: vpack\app
# TODO (macool): create and push internal test packages and test config
@ -87,7 +91,7 @@ jobs:
downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsApps
vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.7
vstsPackageVersion: 0.0.10
- task: PkgESStoreBrokerPackage@10
displayName: Create StoreBroker Packages

View file

@ -0,0 +1,55 @@
# This template contains jobs to run UI tests using WinAppDriver.
parameters:
platform: ''
jobs:
- job: UITests${{ parameters.platform }}
displayName: UITests ${{ parameters.platform }}
dependsOn: Build${{ parameters.platform }}
condition: succeeded()
pool:
vmImage: windows-2019
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: Download AppxBundle and CalculatorUITests
inputs:
artifactName: drop
itemPattern: |
drop/Release/${{ parameters.platform }}/Calculator/AppPackages/**
drop/Release/${{ parameters.platform }}/publish/**
- task: PowerShell@2
displayName: Install certificate
inputs:
filePath: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Add-AppDevPackage.ps1
arguments: -CertificatePath $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Calculator_$(Build.BuildNumber)_${{ parameters.platform }}.cer -Force
- task: PowerShell@2
displayName: Install app
inputs:
filePath: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Add-AppDevPackage.ps1
arguments: -Force
- task: WinAppDriver.winappdriver-pipelines-task.winappdriver-pipelines-task.Windows Application Driver@0
displayName: 'WinAppDriver - Start'
inputs:
AgentResolution: 1080p
- task: VSTest@2
displayName: Run CalculatorUITests
inputs:
testAssemblyVer2: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.dll
vsTestVersion: 16.0
runSettingsFile: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.runsettings
platform: ${{ parameters.platform }}
configuration: Release
- task: WinAppDriver.winappdriver-pipelines-task.winappdriver-pipelines-task.Windows Application Driver@0
displayName: 'WinAppDriver - Stop'
inputs:
OperationType: Stop

View file

@ -14,6 +14,8 @@ jobs:
name: Essential Experiences Interactive
workspace:
clean: outputs
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: none

View file

@ -153,7 +153,9 @@ The CalcEngine contains the logic for interpreting and performing operations acc
### RatPack
The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for performing its mathematical operations. The interface to this layer is defined in [ratpak.h][ratpak.h].
The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for
performing its mathematical operations (using [infinite precision][Infinite Precision] arithmetic
instead of regular floating point arithmetic). The interface to this layer is defined in [ratpak.h][ratpak.h].
[References]:####################################################################################################

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Before After
Before After

View file

@ -1,7 +1,8 @@
# New feature process
## Where do I submit my idea for a new feature?
The easiest way to submit new feature requests is through [Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130).
The easiest way to submit new feature requests is through
[Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130).
In Feedback Hub, any Windows user (even if they aren't on GitHub) can upvote suggestions. The
Calculator team reviews these suggestions regularly, and when we're ready to work on an idea we
create [feature pitch issues here on GitHub](https://github.com/Microsoft/calculator/issues?q=is%3Aissue+is%3Aopen+project%3AMicrosoft%2Fcalculator%2F1).
@ -12,73 +13,45 @@ product. The [Feature Tracking board](https://github.com/Microsoft/calculator/pr
all the features we're working on and where they're at in the process.
## Do I need to follow this process? Can I just start coding and submit a PR?
You *do not* need to follow this process for bug fixes, performance improvements, or changes to the
development tools. To contribute these changes, [discuss the proposed change in an issue](https://github.com/Microsoft/calculator/issues/new)
You **do not** need to follow this process for bug fixes, performance improvements, or changes to the
development tools. To contribute these changes,
[discuss the proposed change in an issue](https://github.com/Microsoft/calculator/issues/new)
and then submit a pull request.
You *do* need to follow this process for any change which "users will notice". This applies
You **do** need to follow this process for any change which "users will notice". This applies
especially to new features and major visual changes.
## Step 1: Feature pitch
The feature pitch concisely describes a point of view on the problem the new feature should solve.
It will typically include these sections:
Feature pitches are submitted as issues on GitHub using the
[Feature Request template](https://github.com/Microsoft/calculator/issues/new?assignees=&labels=&template=feature_request.md&title=).
We encourage discussion on open issues, and as discussion progresses we will edit the issue description to refine the
idea until it is ready for review.
* **Problem Statement**: What problem are we trying to solve? Whos the target audience? Is there a
customer need or pain point we need to remedy? Is there a business goal or metric we are trying
to improve? Do we have a hypothesis we want to prove or disprove?
* **Evidence or User Insights**: Why should we do this? Potential sources of data: Feedback Hub,
other GitHub issues, other anecdotes from listening to customers in person or online, request
from another team, telemetry data, user research, market or competitive research
* **Proposal**: How will the solution/feature help us solve the problem? How will it meet the
target audiences needs? If there are business goals or metrics, how does this improve them?
* **Goals**: What you want to accomplish with this feature. Typical examples include “User Can
*perform some task*
* **Non-Goals**: Things we are explicitly not doing or supporting or that are out of scope,
including reasons why.
* **Low-Fidelity Concept**: Show as much of the experience as needed to explain the idea. This
can be as simple as a napkin drawing but can also be a code prototype, a PowerPoint walkthrough,
or a design comp.
The low-fidelity concept should be kept simple at this stage and refined during the pre-production
process.
Feature pitches are submitted as issues on GitHub. We encourage discussion on open issues, and as
discussion progresses we will edit the issue description to refine the idea.
We review pitches regularly, and will approve or close issues based on whether they broadly align with the
[Calculator roadmap](https://github.com/Microsoft/calculator/blob/master/docs/Roadmap.md). Approved pitches are moved
into [pre-production](https://github.com/Microsoft/calculator/projects/1) on the feature tracking board.
## Step 2: Pre-production
In the pre-production phase, we experiment with a variety of ways to address the goals described in
the feature pitch. The output of this phase is a specification which demonstrates how the feature
will work, supported by design renderings and code prototypes as needed. Sometimes we'll learn new
things about a feature proposal during pre-production, and we'll edit or close the original pitch.
For most features, the output of this phase is a specification which describes how the feature will work, supported by
design renderings and code prototypes as needed. The original issue will continue to track the overall progress of the
feature, but we will create and iterate on spec documentation in the
[Calculator Spec repo](https://github.com/Microsoft/calculator-specs). Sometimes we'll learn new things about a feature
proposal during pre-production, and we'll edit or close the original pitch.
We welcome community participation in the pre-production process. The GitHub issue will be the
primary place to share progress updates.
The best ideas often come from trying many ideas during the pre-production phase. To enable rapid
We welcome community participation throughout pre-production. The best ideas often come from trying many ideas during
the pre-production phase. To enable rapid
experimentation, we encourage developing and sharing rough ideas&mdash;maybe even with pencil and
paper&mdash;before making designs pixel-perfect or making code robust and maintainable.
### Spec review
Once there is a high-fidelity design which addresses the goals described in the original pitch, the
Microsoft product team will review the prototype and ensure all items on this checklist are
addressed:
- [ ] Is there a high-fidelity design which gives reviewers a clear idea of how the feature will
look and function when implemented?
- [ ] Has the plan been shared with the community (documented on the wiki and updates posted in the
original issue) and have others been given an opportunity to provide suggestions?
- [ ] Are [Fluent design principles](https://docs.microsoft.com/en-us/windows/uwp/design/fluent-design-system/)
followed? If we do something which deviates from the guidelines, do we have a good reason?
- [ ] Does the design include provisions for [all users](https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/designing-inclusive-software)
and [all cultures](https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/guidelines-and-checklist-for-globalizing-your-app)?
- [ ] Is it technically feasible to build this feature? Take a look at the "before committing"
checklist below and identify any issues which are likely to be blockers.
After the [spec review](https://github.com/Microsoft/calculator-specs#spec-review) is completed, we will move the issue
into [production](https://github.com/Microsoft/calculator/projects/1) on the feature tracking board. In _some_ cases,
all of the details of an idea can be captured concisely in original feature pitch. When that happens, we may move ideas
directly into production.
## Step 3: Production
A feature can be implemented by the original proposer, a Microsoft team member, or by other
community members. Code contributions and testing help are greatly appreciated. Please let us know
in the issue comments if you're actively working on a feature so we can ensure it's assigned to
you.
A feature can be implemented by the original submitter, a Microsoft team member, or by other
community members. Code contributions and testing help are greatly appreciated. Please let everyone know if you're
actively working on a feature to help avoid duplicated efforts from others.
You might be able to reuse code written during the prototype process, although there will typically
be more work required to make the solution robust. Once the code is ready, you can begin
@ -122,7 +95,8 @@ new features, the Microsoft team considers at least these items:
- [ ] Run the perf tests to measure any increase in startup time. Move work out of the startup
path if possible.
- [ ] If the change adds additional logging:
- [ ] All logging should use [TraceLogging](https://docs.microsoft.com/en-us/windows/desktop/tracelogging/trace-logging-about).
- [ ] All logging should use
[TraceLogging](https://docs.microsoft.com/en-us/windows/desktop/tracelogging/trace-logging-about).
- [ ] Unnecessary log events should be removed, or configured so that they are collected only when
needed to debug issues or measure feature usage.
- [ ] If the change reads user data from files or app settings:

View file

@ -9,6 +9,7 @@ In 2019, the Windows Calculator team is focused on:
* Iterating upon the existing app design based on the latest [Fluent Design guidelines](https://developer.microsoft.com/en-us/windows/apps/design)
* Improving testing and diagnostics within the project
* Investigating new features with a focus on addressing top user feedback, including:
* Adding graphing mode
* Adding the ability for users to pin Calculator on top of other windows
* Providing additional customization options
* [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started!

View file

@ -123,7 +123,7 @@
<AppxPackageTestDir>@(AppxBundleOutput->'%(RootDir)%(Directory)')</AppxPackageTestDir>
<UniversalTestCustomMacros Condition="'$(Configuration)'=='Debug'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.VCLibs.$(PlatformTarget).Debug.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)'=='Release'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.VCLibs.$(PlatformTarget).14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros>$(UniversalTestCustomMacros)AppxPackageWinUIDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.UI.Xaml.2.0.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros>$(UniversalTestCustomMacros)AppxPackageWinUIDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.UI.Xaml.2.1.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros>$(UniversalTestCustomMacros)AppxPackagePublicKeyFile=@(AppxPackagePublicKeyFile->'%(FullPath)');AppxBundleOutput=@(AppxBundleOutput->'%(FullPath)');</UniversalTestCustomMacros>
</PropertyGroup>
</Target>

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <sstream>
#include "Header Files/CalcEngine.h"
using namespace std;
@ -56,7 +56,7 @@ bool CalcInput::TryToggleSign(bool isIntegerMode, wstring_view maxNumStr)
return true;
}
bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, wstring_view maxNumStr, long wordBitWidth, int maxDigits)
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
@ -124,15 +124,15 @@ bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMo
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())
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.
// 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 <
// 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:
@ -151,7 +151,7 @@ bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMo
}
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
// 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;
}

View file

@ -1,27 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
bool IsOpInRange(WPARAM op, uint32_t x, uint32_t y)
bool IsOpInRange(OpCode op, uint32_t x, uint32_t y)
{
return ((op >= x) && (op <= y));
}
bool IsBinOpCode(WPARAM opCode)
bool IsBinOpCode(OpCode opCode)
{
return IsOpInRange(opCode, IDC_AND, IDC_PWR);
}
// 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(WPARAM opCode)
bool IsUnaryOpCode(OpCode opCode)
{
return IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST);
}
bool IsDigitOpCode(WPARAM opCode)
bool IsDigitOpCode(OpCode opCode)
{
return IsOpInRange(opCode, IDC_0, IDC_F);
}
@ -31,11 +31,9 @@ bool IsDigitOpCode(WPARAM opCode)
// 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(WPARAM opCode)
bool IsGuiSettingOpCode(OpCode opCode)
{
if (IsOpInRange(opCode, IDM_HEX, IDM_BIN) ||
IsOpInRange(opCode, IDM_QWORD, IDM_BYTE) ||
IsOpInRange(opCode, IDM_DEG, IDM_GRAD))
if (IsOpInRange(opCode, IDM_HEX, IDM_BIN) || IsOpInRange(opCode, IDM_QWORD, IDM_BYTE) || IsOpInRange(opCode, IDM_DEG, IDM_GRAD))
{
return true;
}

View file

@ -1,19 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#pragma once
#include "Header Files/CalcEngine.h"
#include "Command.h"
#include "CalculatorVector.h"
#include "ExpressionCommand.h"
#include "CalcException.h"
constexpr int ASCII_0 = 48;
using namespace std;
using namespace CalcEngine;
namespace
{
void IFT(ResultCode hr)
{
if (FAILED(hr))
{
throw hr;
}
}
}
void CHistoryCollector::ReinitHistory()
{
m_lastOpStartIndex = -1;
@ -32,11 +39,11 @@ void CHistoryCollector::ReinitHistory()
// 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)
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();
}
@ -129,7 +136,7 @@ void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool fNoRepetition)
}
// 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
// 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)
{
@ -196,7 +203,7 @@ bool CHistoryCollector::FOpndAddedToHistory()
// 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 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, ANGLE_TYPE angletype)
@ -290,13 +297,14 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a
}
// 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
// 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_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetExpressionDisplay(
std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
}
if (nullptr != m_pHistoryDisplay)
@ -317,14 +325,14 @@ void CHistoryCollector::ClearHistoryLine(wstring_view errStr)
{
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetExpressionDisplay(
std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<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)
@ -386,14 +394,13 @@ void CHistoryCollector::SetExpressionDisplay()
{
m_pCalcDisplay->SetExpressionDisplay(m_spTokens, m_spCommands);
}
}
int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand> & spCommand)
int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand)
{
if (m_spCommands == nullptr)
{
m_spCommands = std::make_shared <CalculatorVector<std::shared_ptr<IExpressionCommand>>>();
m_spCommands = std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>();
}
if (FAILED(m_spCommands->Append(spCommand)))
@ -406,37 +413,39 @@ int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand>
return nCommands - 1;
}
//To Update the operands in the Expression according to the current Radix
// 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)
if (m_spTokens == nullptr)
{
unsigned int size;
IFT(m_spTokens->GetSize(&size));
return;
}
for (unsigned int i = 0; i < size; ++i)
unsigned int size;
IFT(m_spTokens->GetSize(&size));
for (unsigned int i = 0; i < size; ++i)
{
std::pair<std::wstring, int> token;
IFT(m_spTokens->GetAt(i, &token));
int commandPosition = token.second;
if (commandPosition != -1)
{
std::pair<std::wstring, int> token;
IFT(m_spTokens->GetAt(i, &token));
int commandPosition = token.second;
if (commandPosition != -1)
std::shared_ptr<IExpressionCommand> expCommand;
IFT(m_spCommands->GetAt(commandPosition, &expCommand));
if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
{
std::shared_ptr<IExpressionCommand> expCommand;
IFT(m_spCommands->GetAt(commandPosition, &expCommand));
if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
std::shared_ptr<COpndCommand> opndCommand = std::static_pointer_cast<COpndCommand>(expCommand);
if (opndCommand != nullptr)
{
std::shared_ptr<COpndCommand> opndCommand = std::static_pointer_cast<COpndCommand>(expCommand);
if (opndCommand != nullptr)
{
token.first = opndCommand->GetString(radix, precision);
IFT(m_spTokens->SetAt(i, token));
opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
}
token.first = opndCommand->GetString(radix, precision);
IFT(m_spTokens->SetAt(i, token));
opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
}
}
}
SetExpressionDisplay();
}
SetExpressionDisplay();
}
void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)
@ -444,7 +453,7 @@ void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)
m_decimalSymbol = decimalSymbol;
}
//Update the commands corresponding to the passed string Number
// Update the commands corresponding to the passed string Number
std::shared_ptr<CalculatorVector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr)
{
std::shared_ptr<CalculatorVector<int>> commands = std::make_shared<CalculatorVector<int>>();

View file

@ -1,26 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "pch.h"
#include <algorithm>
#include "Header Files/Number.h"
using namespace std;
namespace CalcEngine
{
Number::Number() noexcept :
Number(1, 0, { 0 })
{}
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(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{}
Number::Number(PNUMBER p) noexcept
: m_sign{ p->sign }
, m_exp{ p->exp }
, m_mantissa{}
{
m_mantissa.reserve(p->cdigit);
copy(p->mant, p->mant + p->cdigit, back_inserter(m_mantissa));
@ -28,12 +30,12 @@ namespace CalcEngine
PNUMBER Number::ToPNUMBER() const
{
PNUMBER ret = _createnum(static_cast<ULONG>(this->Mantissa().size()) + 1);
PNUMBER ret = _createnum(static_cast<uint32_t>(this->Mantissa().size()) + 1);
ret->sign = this->Sign();
ret->exp = this->Exp();
ret->cdigit = static_cast<long>(this->Mantissa().size());
ret->cdigit = static_cast<int32_t>(this->Mantissa().size());
MANTTYPE *ptrRet = ret->mant;
MANTTYPE* ptrRet = ret->mant;
for (auto const& digit : this->Mantissa())
{
*ptrRet++ = digit;
@ -59,6 +61,6 @@ namespace CalcEngine
bool Number::IsZero() const
{
return all_of(m_mantissa.begin(), m_mantissa.end(), [](auto &&i) { return i == 0; });
return all_of(m_mantissa.begin(), m_mantissa.end(), [](auto&& i) { return i == 0; });
}
}

View file

@ -1,16 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "pch.h"
#include <intsafe.h>
#include "Header Files/Rational.h"
using namespace std;
namespace CalcEngine
{
Rational::Rational() noexcept :
m_p{},
m_q{ 1, 0, { 1 } }
{}
Rational::Rational() noexcept
: m_p{}
, m_q{ 1, 0, { 1 } }
{
}
Rational::Rational(Number const& n) noexcept
{
@ -24,14 +25,15 @@ namespace CalcEngine
m_q = Number(1, qExp, { 1 });
}
Rational::Rational(Number const& p, Number const& q) noexcept :
m_p{ p },
m_q{ q }
{}
Rational::Rational(Number const& p, Number const& q) noexcept
: m_p{ p }
, m_q{ q }
{
}
Rational::Rational(int32_t i)
{
PRAT pr = longtorat(static_cast<long>(i));
PRAT pr = i32torat(static_cast<int32_t>(i));
m_p = Number{ pr->pp };
m_q = Number{ pr->pq };
@ -41,7 +43,7 @@ namespace CalcEngine
Rational::Rational(uint32_t ui)
{
PRAT pr = Ulongtorat(static_cast<unsigned long>(ui));
PRAT pr = Ui32torat(static_cast<uint32_t>(ui));
m_p = Number{ pr->pp };
m_q = Number{ pr->pq };
@ -60,10 +62,11 @@ namespace CalcEngine
m_q = Number{ temp.Q() };
}
Rational::Rational(PRAT prat) noexcept :
m_p{ Number{prat->pp} },
m_q{ Number{prat->pq} }
{}
Rational::Rational(PRAT prat) noexcept
: m_p{ Number{ prat->pp } }
, m_q{ Number{ prat->pq } }
{
}
PRAT Rational::ToPRAT() const
{
@ -100,7 +103,7 @@ namespace CalcEngine
addrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -123,7 +126,7 @@ namespace CalcEngine
subrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -146,7 +149,7 @@ namespace CalcEngine
mulrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -169,7 +172,7 @@ namespace CalcEngine
divrat(&lhsRat, rhsRat, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -182,6 +185,13 @@ namespace CalcEngine
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();
@ -189,10 +199,10 @@ namespace CalcEngine
try
{
modrat(&lhsRat, rhsRat);
remrat(&lhsRat, rhsRat);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -215,7 +225,7 @@ namespace CalcEngine
lshrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -238,7 +248,7 @@ namespace CalcEngine
rshrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -261,7 +271,7 @@ namespace CalcEngine
andrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -283,7 +293,7 @@ namespace CalcEngine
orrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -305,7 +315,7 @@ namespace CalcEngine
xorrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(rhsRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -342,6 +352,13 @@ namespace CalcEngine
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;
@ -388,7 +405,7 @@ namespace CalcEngine
{
result = rat_equ(lhsRat, rhsRat, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -416,7 +433,7 @@ namespace CalcEngine
{
result = rat_lt(lhsRat, rhsRat, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(lhsRat);
destroyrat(rhsRat);
@ -453,7 +470,7 @@ namespace CalcEngine
{
result = RatToString(rat, fmt, radix, precision);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(rat);
throw(error);
@ -470,9 +487,9 @@ namespace CalcEngine
uint64_t result;
try
{
result = rattoUlonglong(rat, RATIONAL_BASE, RATIONAL_PRECISION);
result = rattoUi64(rat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(rat);
throw(error);

View file

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/RationalMath.h"
using namespace std;
@ -14,7 +13,7 @@ Rational RationalMath::Frac(Rational const& rat)
{
fracrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -33,7 +32,7 @@ Rational RationalMath::Integer(Rational const& rat)
{
intrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -55,7 +54,7 @@ Rational RationalMath::Pow(Rational const& base, Rational const& pow)
powrat(&baseRat, powRat, RATIONAL_BASE, RATIONAL_PRECISION);
destroyrat(powRat);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(baseRat);
destroyrat(powRat);
@ -81,7 +80,7 @@ Rational RationalMath::Fact(Rational const& rat)
{
factrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -101,7 +100,7 @@ Rational RationalMath::Exp(Rational const& rat)
{
exprat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -121,7 +120,7 @@ Rational RationalMath::Log(Rational const& rat)
{
lograt(&prat, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -156,7 +155,7 @@ Rational RationalMath::Sin(Rational const& rat, ANGLE_TYPE angletype)
{
sinanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -176,7 +175,7 @@ Rational RationalMath::Cos(Rational const& rat, ANGLE_TYPE angletype)
{
cosanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -196,7 +195,7 @@ Rational RationalMath::Tan(Rational const& rat, ANGLE_TYPE angletype)
{
tananglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -216,7 +215,7 @@ Rational RationalMath::ASin(Rational const& rat, ANGLE_TYPE angletype)
{
asinanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -236,7 +235,7 @@ Rational RationalMath::ACos(Rational const& rat, ANGLE_TYPE angletype)
{
acosanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -256,7 +255,7 @@ Rational RationalMath::ATan(Rational const& rat, ANGLE_TYPE angletype)
{
atananglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -276,7 +275,7 @@ Rational RationalMath::Sinh(Rational const& rat)
{
sinhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -296,7 +295,7 @@ Rational RationalMath::Cosh(Rational const& rat)
{
coshrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -316,7 +315,7 @@ Rational RationalMath::Tanh(Rational const& rat)
{
tanhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -336,7 +335,7 @@ Rational RationalMath::ASinh(Rational const& rat)
{
asinhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -356,7 +355,7 @@ Rational RationalMath::ACosh(Rational const& rat)
{
acoshrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -376,7 +375,7 @@ Rational RationalMath::ATanh(Rational const& rat)
{
atanhrat(&prat, RATIONAL_PRECISION);
}
catch (DWORD error)
catch (uint32_t error)
{
destroyrat(prat);
throw(error);
@ -387,3 +386,33 @@ Rational RationalMath::ATanh(Rational const& rat)
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;
}

View file

@ -1,9 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <cassert>
#include "Header Files/CalcEngine.h"
#include "CalculatorResource.h"
using namespace std;
@ -15,7 +14,7 @@ using namespace CalcEngine;
static constexpr int DEFAULT_MAX_DIGITS = 32;
static constexpr int DEFAULT_PRECISION = 32;
static constexpr long DEFAULT_RADIX = 10;
static constexpr int32_t DEFAULT_RADIX = 10;
static constexpr wchar_t DEFAULT_DEC_SEPARATOR = L'.';
static constexpr wchar_t DEFAULT_GRP_SEPARATOR = L',';
@ -25,13 +24,18 @@ 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.
array<wstring, CSTRINGSENGMAX> CCalcEngine::s_engineStrings;
unordered_map<wstring, wstring> CCalcEngine::s_engineStrings;
void CCalcEngine::LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider)
{
for (size_t i = 0; i < s_engineStrings.size(); i++)
for (const auto& sid : g_sids)
{
s_engineStrings[i] = resourceProvider.GetCEngineString(g_sids[i]);
auto locKey = wstring{ sid };
auto locString = resourceProvider.GetCEngineString(locKey);
if (!locString.empty())
{
s_engineStrings[locKey] = locString;
}
}
}
@ -54,42 +58,47 @@ void CCalcEngine::InitialOneTimeOnlySetup(CalculationManager::IResourceProvider&
// 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(FMT_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(ANGLE_DEG),
m_numwidth(QWORD_WIDTH),
m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR),
m_groupSeparator(DEFAULT_GRP_SEPARATOR)
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(FMT_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(ANGLE_DEG)
, m_numwidth(QWORD_WIDTH)
, m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR)
, m_groupSeparator(DEFAULT_GRP_SEPARATOR)
{
InitChopNumbers();
@ -168,7 +177,7 @@ void CCalcEngine::SettingsChanged()
m_HistoryCollector.SetDecimalSymbol(m_decimalSeparator);
// put the new decimal symbol into the table used to draw the decimal key
s_engineStrings[IDS_DECIMAL] = m_decimalSeparator;
s_engineStrings[SIDS_DECIMAL_SEPARATOR] = m_decimalSeparator;
// we need to redraw to update the decimal point button
numChanged = true;

View file

@ -12,53 +12,48 @@
*
* Author:
\****************************************************************************/
#include "pch.h"
#include <string>
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
#define IDC_RADSIN IDC_UNARYLAST+1
#define IDC_RADCOS IDC_UNARYLAST+2
#define IDC_RADTAN IDC_UNARYLAST+3
#define IDC_GRADSIN IDC_UNARYLAST+4
#define IDC_GRADCOS IDC_UNARYLAST+5
#define IDC_GRADTAN IDC_UNARYLAST+6
using namespace std;
using namespace CalcEngine;
// NPrecedenceOfOp
//
// returns a virtual number for precedence for the operator. We expect binary operator only, otherwise the lowest number
// 0 is returned. Higher the number, higher the precedence of the operator.
INT NPrecedenceOfOp(int nopCode)
namespace
{
static BYTE rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1,
IDC_ADD,2, IDC_SUB,2, IDC_RSHF,3, IDC_LSHF,3,
IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 };
int iPrec;
// NPrecedenceOfOp
//
// returns a virtual number for precedence for the operator. We expect binary operator only, otherwise the lowest number
// 0 is returned. Higher the number, higher the precedence of the operator.
int NPrecedenceOfOp(int nopCode)
{
static uint8_t rgbPrec[] = { 0, 0, IDC_OR, 0, IDC_XOR, 0, IDC_AND, 1, IDC_ADD, 2, IDC_SUB, 2, IDC_RSHF,
3, IDC_LSHF, 3, IDC_MOD, 3, IDC_DIV, 3, IDC_MUL, 3, IDC_PWR, 4, IDC_ROOT, 4 };
unsigned int iPrec;
iPrec = 0;
while ((iPrec < ARRAYSIZE(rgbPrec)) && (nopCode != rgbPrec[iPrec]))
{
iPrec += 2;
}
if (iPrec >= ARRAYSIZE(rgbPrec))
{
iPrec = 0;
while ((iPrec < size(rgbPrec)) && (nopCode != rgbPrec[iPrec]))
{
iPrec += 2;
}
if (iPrec >= size(rgbPrec))
{
iPrec = 0;
}
return rgbPrec[iPrec + 1];
}
return rgbPrec[iPrec + 1];
}
// HandleErrorCommand
//
// When it is discovered by the state machine that at this point the input is not valid (eg. "1+)"), we want to proceed as though this input never
// When it is discovered by the state machine that at this point the input is not valid (eg. "1+)"), we want to proceed as though this input never
// occurred and may be some feedback to user like Beep. The rest of input can then continue by just ignoring this command.
void CCalcEngine::HandleErrorCommand(WPARAM idc)
void CCalcEngine::HandleErrorCommand(OpCode idc)
{
if (!IsGuiSettingOpCode(idc))
{
// we would have saved the prev command. Need to forget this state
// We would have saved the prev command. Need to forget this state
m_nTempCom = m_nLastCom;
}
}
@ -81,7 +76,7 @@ void CCalcEngine::ClearTemporaryValues()
m_bError = false;
}
void CCalcEngine::ProcessCommand(WPARAM wParam)
void CCalcEngine::ProcessCommand(OpCode wParam)
{
if (wParam == IDC_SET_RESULT)
{
@ -92,9 +87,9 @@ void CCalcEngine::ProcessCommand(WPARAM wParam)
ProcessCommandWorker(wParam);
}
void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
void CCalcEngine::ProcessCommandWorker(OpCode wParam)
{
INT nx, ni;
int nx, ni;
// Save the last command. Some commands are not saved in this manor, these
// commands are:
@ -105,7 +100,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
if (!IsGuiSettingOpCode(wParam))
{
m_nLastCom = m_nTempCom;
m_nTempCom = (INT)wParam;
m_nTempCom = (int)wParam;
}
if (m_bError)
@ -126,21 +121,16 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
}
}
// Toggle Record/Display mode if appropriate.
// Toggle Record/Display mode if appropriate.
if (m_bRecord)
{
if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) ||
IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) ||
IsOpInRange(wParam, IDM_HEX, IDM_BIN) ||
IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) ||
IsOpInRange(wParam, IDM_DEG, IDM_GRAD) ||
IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) ||
(IDC_INV == wParam) ||
(IDC_SIGN == wParam && 10 != m_radix))
if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) || IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || IsOpInRange(wParam, IDM_HEX, IDM_BIN)
|| IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || IsOpInRange(wParam, IDM_DEG, IDM_GRAD)
|| IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) || (IDC_INV == wParam) || (IDC_SIGN == wParam && 10 != m_radix))
{
m_bRecord = false;
m_currentVal = m_input.ToRational(m_radix, m_precision);
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
}
}
else
@ -180,13 +170,13 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// BINARY OPERATORS:
if (IsBinOpCode(wParam))
{
/* Change the operation if last input was operation. */
// Change the operation if last input was operation.
if (IsBinOpCode(m_nLastCom))
{
INT nPrev;
int nPrev;
bool fPrecInvToHigher = false; // Is Precedence Inversion from lower to higher precedence happening ??
m_nOpCode = (INT)wParam;
m_nOpCode = (int)wParam;
// Check to see if by changing this binop, a Precedence inversion is happening.
// Eg. 1 * 2 + and + is getting changed to ^. The previous precedence rules would have already computed
@ -245,9 +235,9 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
else
{
/* do the last operation and then if the precedence array is not
* empty or the top is not the '(' demarcator then pop the top
* of the array and recheck precedence against the new operator
*/
* empty or the top is not the '(' demarcator then pop the top
* of the array and recheck precedence against the new operator
*/
m_currentVal = DoOperation(m_nOpCode, m_currentVal, m_lastVal);
m_nPrevOpCode = m_nOpCode;
@ -276,14 +266,13 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_HistoryCollector.PopLastOpndStart();
goto DoPrecedenceCheckAgain;
}
}
}
DisplayAnnounceBinaryOperator();
m_lastVal = m_currentVal;
m_nOpCode = (INT)wParam;
m_nOpCode = (int)wParam;
m_HistoryCollector.AddBinOpToHistory(m_nOpCode);
m_bNoPrevEqu = m_bChangeOp = true;
return;
@ -311,7 +300,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
m_HistoryCollector.AddUnaryOpToHistory((INT)wParam, m_bInv, m_angletype);
m_HistoryCollector.AddUnaryOpToHistory((int)wParam, m_bInv, m_angletype);
}
if ((wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH))
@ -324,7 +313,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
}
}
m_currentVal = SciCalcFunctions(m_currentVal, (DWORD)wParam);
m_currentVal = SciCalcFunctions(m_currentVal, (uint32_t)wParam);
if (m_bError)
return;
@ -341,11 +330,9 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
/* reset the m_bInv flag and indicators if it is set
and have been used */
if (m_bInv &&
((wParam == IDC_CHOP) ||
(wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) ||
(wParam == IDC_LN) || (wParam == IDC_DMS) || (wParam == IDC_DEGREES) ||
(wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)))
if (m_bInv
&& ((wParam == IDC_CHOP) || (wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_LN) || (wParam == IDC_DMS)
|| (wParam == IDC_DEGREES) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)))
{
m_bInv = false;
}
@ -364,7 +351,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
CheckAndAddLastBinOpToHistory();
if (TryToggleBit(m_currentVal, (DWORD)wParam - IDC_BINEDITSTART))
if (TryToggleBit(m_currentVal, (uint32_t)wParam - IDC_BINEDITSTART))
{
DisplayNum();
}
@ -390,13 +377,13 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_nPrevOpCode = 0;
m_bNoPrevEqu = true;
/* clear the parenthesis status box indicator, this will not be
cleared for CENTR */
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetParenDisplayText(L"");
m_pCalcDisplay->SetExpressionDisplay(make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetParenthesisNumber(0);
m_pCalcDisplay->SetExpressionDisplay(
make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
}
m_HistoryCollector.ClearHistoryLine(wstring());
@ -439,8 +426,8 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// automatic closing of all the parenthesis to get a meaningful result as well as ensure data integrity
m_nTempCom = m_nLastCom; // Put back this last saved command to the prev state so ) can be handled properly
ProcessCommand(IDC_CLOSEP);
m_nLastCom = m_nTempCom; // Actually this is IDC_CLOSEP
m_nTempCom = (INT)wParam; // put back in the state where last op seen was IDC_CLOSEP, and current op is IDC_EQU
m_nLastCom = m_nTempCom; // Actually this is IDC_CLOSEP
m_nTempCom = (int)wParam; // put back in the state where last op seen was IDC_CLOSEP, and current op is IDC_EQU
}
if (!m_bNoPrevEqu)
@ -461,45 +448,12 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
do {
if (m_nOpCode) /* Is there a valid operation around? */
{
/* If this is the first EQU in a string, set m_holdVal=m_currentVal */
/* Otherwise let m_currentVal=m_holdVal. This keeps m_currentVal constant */
/* through all EQUs in a row. */
if (m_bNoPrevEqu)
{
m_holdVal = m_currentVal;
}
else
{
m_currentVal = m_holdVal;
DisplayNum(); // to update the m_numberString
m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history
}
// Do the current or last operation.
m_currentVal = DoOperation(m_nOpCode, m_currentVal, m_lastVal);
m_nPrevOpCode = m_nOpCode;
m_lastVal = m_currentVal;
/* Check for errors. If this wasn't done, DisplayNum */
/* would immediately overwrite any error message. */
if (!m_bError)
DisplayNum();
/* No longer the first EQU. */
m_bNoPrevEqu = false;
}
else if (!m_bError)
DisplayNum();
if (m_precedenceOpCount == 0 || !m_fPrecedence)
break;
m_nOpCode = m_nPrecOp[--m_precedenceOpCount];
// Evaluate the precedence stack.
ResolveHighestPrecedenceOperation();
while (m_fPrecedence && m_precedenceOpCount > 0)
{
m_precedenceOpCount--;
m_nOpCode = m_nPrecOp[m_precedenceOpCount];
m_lastVal = m_precedenceVals[m_precedenceOpCount];
// Precedence Inversion check
@ -512,7 +466,9 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_HistoryCollector.PopLastOpndStart();
m_bNoPrevEqu = true;
} while (m_precedenceOpCount >= 0);
ResolveHighestPrecedenceOperation();
}
if (!m_bError)
{
@ -520,7 +476,8 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_HistoryCollector.CompleteHistoryLine(groupedString);
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetExpressionDisplay(
make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
}
}
@ -544,6 +501,11 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
if ((m_openParenCount >= MAXPRECDEPTH && nx) || (!m_openParenCount && !nx)
|| ((m_precedenceOpCount >= MAXPRECDEPTH && m_nPrecOp[m_precedenceOpCount - 1] != 0)))
{
if (!m_openParenCount && !nx)
{
m_pCalcDisplay->OnNoRightParenAdded();
}
HandleErrorCommand(wParam);
break;
}
@ -567,7 +529,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_lastVal = 0;
if (IsBinOpCode(m_nLastCom))
{
// We want 1 + ( to start as 1 + (0. Any number you type replaces 0. But if it is 1 + 3 (, it is
// We want 1 + ( to start as 1 + (0. Any number you type replaces 0. But if it is 1 + 3 (, it is
// treated as 1 + (3
m_currentVal = 0;
}
@ -625,7 +587,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// Set the "(=xx" indicator.
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetParenDisplayText(m_openParenCount ? to_wstring(m_openParenCount) : L"");
m_pCalcDisplay->SetParenthesisNumber(m_openParenCount >= 0 ? static_cast<unsigned int>(m_openParenCount) : 0);
}
if (!m_bError)
@ -779,7 +741,48 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_bInv = !m_bInv;
break;
}
}
// Helper function to resolve one item on the precedence stack.
void CCalcEngine::ResolveHighestPrecedenceOperation()
{
// Is there a valid operation around?
if (m_nOpCode)
{
// If this is the first EQU in a string, set m_holdVal=m_currentVal
// Otherwise let m_currentVal=m_holdVal. This keeps m_currentVal constant
// through all EQUs in a row.
if (m_bNoPrevEqu)
{
m_holdVal = m_currentVal;
}
else
{
m_currentVal = m_holdVal;
DisplayNum(); // to update the m_numberString
m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history
}
// Do the current or last operation.
m_currentVal = DoOperation(m_nOpCode, m_currentVal, m_lastVal);
m_nPrevOpCode = m_nOpCode;
m_lastVal = m_currentVal;
// Check for errors. If this wasn't done, DisplayNum
// would immediately overwrite any error message.
if (!m_bError)
{
DisplayNum();
}
// No longer the first EQU.
m_bNoPrevEqu = false;
}
else if (!m_bError)
{
DisplayNum();
}
}
// CheckAndAddLastBinOpToHistory
@ -796,13 +799,12 @@ void CCalcEngine::CheckAndAddLastBinOpToHistory(bool addToHistory)
{
if (m_HistoryCollector.FOpndAddedToHistory())
{
// if last time opnd was added but the last command was not a binary operator, then it must have come
// if last time opnd was added but the last command was not a binary operator, then it must have come
// from commands which add the operand, like unary operator. So history at this is showing 1 + sqrt(4)
// but in reality the sqrt(4) is getting replaced by new number (may be unary op, or MR or SUM etc.)
// So erase the last operand
m_HistoryCollector.RemoveLastOpndFromHistory();
}
}
else if (m_HistoryCollector.FOpndAddedToHistory() && !m_bError)
{
@ -811,8 +813,7 @@ void CCalcEngine::CheckAndAddLastBinOpToHistory(bool addToHistory)
// Let us make a current value =. So in case of 4 SQRT (or a equation under braces) and then a new equation is started, we can just form
// a useful equation of sqrt(4) = 2 and continue a new equation from now on. But no point in doing this for things like
// MR, SUM etc. All you will get is 5 = 5 kind of no useful equation.
if ((IsUnaryOpCode(m_nLastCom) || IDC_SIGN == m_nLastCom || IDC_CLOSEP == m_nLastCom) &&
0 == m_openParenCount)
if ((IsUnaryOpCode(m_nLastCom) || IDC_SIGN == m_nLastCom || IDC_CLOSEP == m_nLastCom) && 0 == m_openParenCount)
{
if (addToHistory)
{
@ -848,157 +849,95 @@ void CCalcEngine::DisplayAnnounceBinaryOperator()
}
// Unary operator Function Name table Element
// since unary operators button names aren't exactly friendly for history purpose,
// since unary operators button names aren't exactly friendly for history purpose,
// we have this separate table to get its localized name and for its Inv function if it exists.
typedef struct
struct FunctionNameElement
{
int idsFunc; // index of string for the unary op function. Can be NULL, in which case it same as button name
int idsFuncInv; // index of string for Inv of unary op. Can be NULL, in case it is same as idsFunc
bool fDontUseInExpEval; // true if this cant be used in reverse direction as well, ie. during expression evaluation
} UFNE;
wstring degreeString; // Used by default if there are no rad or grad specific strings.
wstring inverseDegreeString; // Will fall back to degreeString if empty
wstring radString;
wstring inverseRadString; // Will fall back to radString if empty
wstring gradString;
wstring inverseGradString; // Will fall back to gradString if empty
bool hasAngleStrings = ((!radString.empty()) || (!inverseRadString.empty()) || (!gradString.empty()) || (!inverseGradString.empty()));
};
// Table for each unary operator
static const UFNE rgUfne[] =
{
/* IDC_CHOP */{ 0, IDS_FRAC, false },
/* IDC_ROL */{ 0, 0, true },
/* IDC_ROR */{ 0, 0, true },
static const std::unordered_map<int, FunctionNameElement> unaryOperatorStringTable = {
{ IDC_CHOP, { L"", SIDS_FRAC } },
/* IDC_COM */{ 0, 0, true },
/* IDC_SIN */{ IDS_SIND, IDS_ASIND, false }, // default in this table is degrees for sin,cos & tan
/* IDC_COS */{ IDS_COSD, IDS_ACOSD, false },
/* IDC_TAN */{ IDS_TAND, IDS_ATAND, false },
{ IDC_SIN, { SIDS_SIND, SIDS_ASIND, SIDS_SINR, SIDS_ASINR, SIDS_SING, SIDS_ASING } },
{ IDC_COS, { SIDS_COSD, SIDS_ACOSD, SIDS_COSR, SIDS_ACOSR, SIDS_COSG, SIDS_ACOSG } },
{ IDC_TAN, { SIDS_TAND, SIDS_ATAND, SIDS_TANR, SIDS_ATANR, SIDS_TANG, SIDS_ATANG } },
/* IDC_SINH */{ 0, IDS_ASINH, false },
/* IDC_COSH */{ 0, IDS_ACOSH, false },
/* IDC_TANH */{ 0, IDS_ATANH, false },
{ IDC_SINH, { L"", SIDS_ASINH } },
{ IDC_COSH, { L"", SIDS_ACOSH } },
{ IDC_TANH, { L"", SIDS_ATANH } },
/* IDC_LN */{ 0, IDS_POWE, false },
/* IDC_LOG */{ 0, 0, false },
/* IDC_SQRT */{ 0, 0, false },
/* IDC_SQR */{ IDS_SQR, 0, false },
/* IDC_CUB */{ IDS_CUBE, 0, false },
/* IDC_FAC */{ IDS_FACT, 0, false },
/* IDC_REC */{ IDS_REC, 0, false },
/* IDC_DMS */{ 0, IDS_DEGREES, false },
/* IDC_CUBEROOT */{ 0, 0, false },
/* IDC_POW10 */{ 0, 0, false },
/* IDC_PERCENT */{ 0, 0, false },
/* IDC_RADSIN */{ IDS_SINR, IDS_ASINR, false },
/* IDC_RADCOS */{ IDS_COSR, IDS_ACOSR, false },
/* IDC_RADTAN */{ IDS_TANR, IDS_ATANR, false },
/* IDC_GRADCOS */{ IDS_SING, IDS_ASING, false },
/* IDC_GRADCOS */{ IDS_COSG, IDS_ACOSG, false },
/* IDC_GRADTAN */{ IDS_TANG, IDS_ATANG, false },
{ IDC_LN, { L"", SIDS_POWE } },
{ IDC_SQR, { SIDS_SQR } },
{ IDC_CUB, { SIDS_CUBE } },
{ IDC_FAC, { SIDS_FACT } },
{ IDC_REC, { SIDS_RECIPROC } },
{ IDC_DMS, { L"", SIDS_DEGREES } },
{ IDC_SIGN, { SIDS_NEGATE } },
{ IDC_DEGREES, { SIDS_DEGREES } }
};
wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype)
{
// Special cases for Sign and Degrees
if (IDC_SIGN == nOpCode)
{
return GetString(IDS_NEGATE);
}
if (IDC_DEGREES == nOpCode)
{
return GetString(IDS_DEGREES);
}
// Correct the trigonometric functions with type of angle argument they take
if (ANGLE_RAD == angletype)
{
switch (nOpCode)
{
case IDC_SIN:
nOpCode = IDC_RADSIN;
break;
case IDC_COS:
nOpCode = IDC_RADCOS;
break;
case IDC_TAN:
nOpCode = IDC_RADTAN;
break;
}
}
else if (ANGLE_GRAD == angletype)
{
switch (nOpCode)
{
case IDC_SIN:
nOpCode = IDC_GRADSIN;
break;
case IDC_COS:
nOpCode = IDC_GRADCOS;
break;
case IDC_TAN:
nOpCode = IDC_GRADTAN;
break;
}
}
// Try to lookup the ID in the UFNE table
int ids = 0;
int iufne = nOpCode - IDC_UNARYFIRST;
if (iufne >= 0 && iufne < ARRAYSIZE(rgUfne))
wstring ids = L"";
if (auto pair = unaryOperatorStringTable.find(nOpCode); pair != unaryOperatorStringTable.end())
{
if (fInv)
const FunctionNameElement& element = pair->second;
if (!element.hasAngleStrings || ANGLE_DEG == angletype)
{
ids = rgUfne[iufne].idsFuncInv;
if (fInv)
{
ids = element.inverseDegreeString;
}
if (ids.empty())
{
ids = element.degreeString;
}
}
if (0 == ids)
else if (ANGLE_RAD == angletype)
{
ids = rgUfne[iufne].idsFunc;
if (fInv)
{
ids = element.inverseRadString;
}
if (ids.empty())
{
ids = element.radString;
}
}
else if (ANGLE_GRAD == angletype)
{
if (fInv)
{
ids = element.inverseGradString;
}
if (ids.empty())
{
ids = element.gradString;
}
}
}
if (!ids.empty())
{
return GetString(ids);
}
// If we didn't find an ID in the table, use the op code.
if (0 == ids)
{
ids = IdStrFromCmdId(nOpCode);
}
return GetString(ids);
}
//
// Sets the Angle Mode for special unary op IDC's which are used to index to the table rgUfne
// and returns the equivalent plain IDC for trigonometric function. If it isn't a trigonometric function
// returns the passed in idc itself.
int CCalcEngine::IdcSetAngleTypeDecMode(int idc)
{
int idcAngleCmd = IDM_DEG;
switch (idc)
{
case IDC_RADSIN:
idcAngleCmd = IDM_RAD;
idc = IDC_SIN;
break;
case IDC_RADCOS:
idcAngleCmd = IDM_RAD;
idc = IDC_COS;
break;
case IDC_RADTAN:
idcAngleCmd = IDM_RAD;
idc = IDC_TAN;
break;
case IDC_GRADSIN:
idcAngleCmd = IDM_GRAD;
idc = IDC_SIN;
break;
case IDC_GRADCOS:
idcAngleCmd = IDM_GRAD;
idc = IDC_COS;
break;
case IDC_GRADTAN:
idcAngleCmd = IDM_GRAD;
idc = IDC_TAN;
break;
}
ProcessCommand(idcAngleCmd);
return idc;
return OpCodeToString(nOpCode);
}
bool CCalcEngine::IsCurrentTooBigForTrig()
@ -1020,7 +959,7 @@ wstring CCalcEngine::GetCurrentResultForRadix(uint32_t radix, int32_t precision)
wstring numberString = GetStringForDisplay(rat, radix);
if (!numberString.empty())
{
//revert the precision to previously stored precision
// Revert the precision to previously stored precision
ChangeConstants(m_radix, m_precision);
}
@ -1053,7 +992,7 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix)
result = tempRat.ToString(radix, m_nFE, m_precision);
}
catch (DWORD)
catch (uint32_t)
{
}
}

View file

@ -12,7 +12,9 @@
*
* Author:
\****************************************************************************/
#include "pch.h"
#include <sstream>
#include <regex>
#include "Header Files/CalcEngine.h"
using namespace std;
@ -23,7 +25,6 @@ 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)
*
@ -35,15 +36,16 @@ constexpr wstring_view c_decPostSepStr = L"]?(\\d*)(?:e[+-]?(\\d*))?$";
//
// State of calc last time DisplayNum was called
//
typedef struct {
typedef struct
{
Rational value;
int32_t precision;
uint32_t radix;
INT nFE;
NUM_WIDTH numwidth;
bool fIntMath;
bool bRecord;
bool bUseSep;
int nFE;
NUM_WIDTH numwidth;
bool fIntMath;
bool bRecord;
bool bUseSep;
} LASTDISP;
LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
@ -64,7 +66,7 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con
if (result < 0)
{
// if negative make positive by doing a twos complement
result = -(result) - 1;
result = -(result)-1;
result ^= m_chopNumbers[m_numwidth];
}
@ -82,15 +84,8 @@ void CCalcEngine::DisplayNum(void)
// 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 != true ||
gldPrevious.numwidth != m_numwidth ||
gldPrevious.fIntMath != m_fIntegerMode ||
gldPrevious.bRecord != m_bRecord)
if (m_bRecord || gldPrevious.value != m_currentVal || gldPrevious.precision != m_precision || gldPrevious.radix != m_radix || gldPrevious.nFE != (int)m_nFE
|| gldPrevious.bUseSep != true || gldPrevious.numwidth != m_numwidth || gldPrevious.fIntMath != m_fIntegerMode || gldPrevious.bRecord != m_bRecord)
{
gldPrevious.precision = m_precision;
gldPrevious.radix = m_radix;

View file

@ -16,7 +16,6 @@
/*** ***/
/*** ***/
/**************************************************************************/
#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace std;
@ -24,7 +23,7 @@ using namespace CalcEngine;
using namespace CalcEngine::RationalMath;
/* Routines for more complex mathematical functions/error checking. */
CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op)
CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op)
{
Rational result{};
try
@ -55,7 +54,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
uint64_t w64Bits = result.ToUInt64_t();
uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
w64Bits <<= 1; // LShift by 1
w64Bits <<= 1; // LShift by 1
w64Bits |= msb; // Set the prev Msb as the current Lsb
result = w64Bits;
@ -70,7 +69,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
uint64_t w64Bits = result.ToUInt64_t();
uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0;
w64Bits >>= 1; //RShift by 1
w64Bits >>= 1; // RShift by 1
w64Bits |= (lsb << (m_dwWordBitWidth - 1));
result = w64Bits;
@ -169,9 +168,9 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
case IDC_DEGREES:
ProcessCommand(IDC_INV);
// This case falls through to IDC_DMS case because in the old Win32 Calc,
// 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
// 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:
@ -203,9 +202,9 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
}
break;
}
} // end switch( op )
} // end switch( op )
}
catch (DWORD nErrCode)
catch (uint32_t nErrCode)
{
DisplayError(nErrCode);
result = rat;
@ -215,9 +214,9 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
}
/* Routine to display error messages and set m_bError flag. Errors are */
/* called with DisplayError (n), where n is a DWORD between 0 and 5. */
/* called with DisplayError (n), where n is a uint32_t between 0 and 5. */
void CCalcEngine::DisplayError(DWORD nError)
void CCalcEngine::DisplayError(uint32_t nError)
{
wstring errorString{ GetString(IDS_ERRORS_FIRST + SCODE_CODE(nError)) };
@ -227,4 +226,3 @@ void CCalcEngine::DisplayError(DWORD nError)
m_HistoryCollector.ClearHistoryLine(errorString);
}

View file

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
@ -78,7 +77,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
case IDC_DIV:
case IDC_MOD:
{
int iNumeratorSign = 1, iDenominatorSign = 1, iFinalSign = 1;
int iNumeratorSign = 1, iDenominatorSign = 1;
auto temp = result;
result = rhs;
@ -107,20 +106,30 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
if (operation == IDC_DIV)
{
iFinalSign = iNumeratorSign * iDenominatorSign;
result /= temp;
if (m_fIntegerMode && (iNumeratorSign * iDenominatorSign) == -1)
{
result = -(Integer(result));
}
}
else
{
iFinalSign = iNumeratorSign;
result %= temp;
}
if (m_fIntegerMode)
{
// Programmer mode, use remrat (remainder after division)
result %= temp;
if (m_fIntegerMode && iFinalSign == -1)
{
result = -(Integer(result));
if (iNumeratorSign == -1)
{
result = -(Integer(result));
}
}
else
{
// other modes, use modrat (modulus after division)
result = Mod(result, temp);
}
}
break;
}
@ -133,7 +142,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
break;
}
}
catch (DWORD dwErrCode)
catch (uint32_t dwErrCode)
{
DisplayError(dwErrCode);

View file

@ -1,20 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#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(RADIX_TYPE 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
// 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)
{
@ -45,17 +45,17 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwid
// inform ratpak that a change in base or precision has occurred
BaseOrPrecisionChanged();
// display the correct number for the new state (ie convert displayed
// display the correct number for the new state (ie convert displayed
// number to correct base)
DisplayNum();
}
LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
int32_t CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
{
static constexpr int nBitMax[] = { 64, 32, 16, 8 };
LONG wmax = nBitMax[0];
int32_t wmax = nBitMax[0];
if (m_numwidth >= 0 && m_numwidth < ARRAYSIZE(nBitMax))
if (m_numwidth >= 0 && (size_t)m_numwidth < size(nBitMax))
{
wmax = nBitMax[m_numwidth];
}
@ -64,11 +64,11 @@ LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype)
{
static constexpr uint32_t rgnRadish[4] = { 16, 10, 8, 2 }; /* Number bases in the same order as radixtype */
static constexpr uint32_t rgnRadish[4] = { 16, 10, 8, 2 }; /* Number bases in the same order as radixtype */
uint32_t radix = 10;
// convert special bases into symbolic values
if (radixtype >= 0 && radixtype < ARRAYSIZE(rgnRadish))
if (radixtype >= 0 && (size_t)radixtype < size(rgnRadish))
{
radix = rgnRadish[radixtype];
}
@ -76,9 +76,9 @@ uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype)
}
// Toggles a given bit into the number representation. returns true if it changed it actually.
bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, DWORD wbitno)
bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno)
{
DWORD wmax = DwWordBitWidthFromeNumWidth(m_numwidth);
uint32_t wmax = DwWordBitWidthFromeNumWidth(m_numwidth);
if (wbitno >= wmax)
{
return false; // ignore error cant happen
@ -142,7 +142,7 @@ void CCalcEngine::UpdateMaxIntDigits()
if (m_fIntegerMode)
{
m_cIntDigitsSav = static_cast<int>(m_maxDecimalValueStrings[m_numwidth].length()) - 1;
// This is the max digits you can enter a decimal in fixed width mode aka integer mode -1. The last digit
// 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
@ -160,10 +160,10 @@ void CCalcEngine::ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t
{
if (10 == radix)
{
ChangeConstants(radix, precision); // Base 10 precision for internal computing still needs to be 32, to
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
// 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

View file

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
class CalcException : public std::exception
{
public:
CalcException(HRESULT hr)
{
m_hr = hr;
}
HRESULT GetException()
{
return m_hr;
}
private:
HRESULT m_hr;
};
void IFT(HRESULT hr)
{
if (FAILED(hr))
{
CalcException exception(hr);
throw(exception);
}
}

View file

@ -157,6 +157,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -173,6 +174,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -189,6 +191,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -205,6 +208,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -222,6 +226,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -238,6 +243,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -254,6 +260,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -270,6 +277,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -278,7 +286,6 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CalcException.h" />
<ClInclude Include="CalculatorHistory.h" />
<ClInclude Include="CalculatorManager.h" />
<ClInclude Include="CalculatorResource.h" />

View file

@ -119,7 +119,6 @@
<ClInclude Include="Ratpack\ratpak.h">
<Filter>RatPack</Filter>
</ClInclude>
<ClInclude Include="CalcException.h" />
<ClInclude Include="CalculatorVector.h" />
<ClInclude Include="Header Files\CalcEngine.h">
<Filter>Header Files</Filter>
@ -162,4 +161,4 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>

View file

@ -1,18 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <cassert>
#include "CalculatorHistory.h"
using namespace std;
using namespace CalculationManager;
CalculatorHistory::CalculatorHistory(CALCULATOR_MODE eMode, size_t maxSize) :
m_mode(eMode),
m_maxHistorySize(maxSize)
{}
CalculatorHistory::CalculatorHistory(size_t maxSize)
: m_maxHistorySize(maxSize)
{
}
unsigned int CalculatorHistory::AddToHistory(_In_ shared_ptr<CalculatorVector <pair<wstring, int>>> const &tokens, _In_ shared_ptr<CalculatorVector<shared_ptr<IExpressionCommand>>> const &commands, _In_ wstring_view result)
unsigned int CalculatorHistory::AddToHistory(
_In_ shared_ptr<CalculatorVector<pair<wstring, int>>> const& tokens,
_In_ shared_ptr<CalculatorVector<shared_ptr<IExpressionCommand>>> const& commands,
_In_ wstring_view result)
{
unsigned int addedIndex;
wstring generatedExpression;
@ -23,7 +26,7 @@ unsigned int CalculatorHistory::AddToHistory(_In_ shared_ptr<CalculatorVector <p
// to be changed when pszexp is back
tokens->GetString(&generatedExpression);
// Prefixing and suffixing the special Unicode markers to ensure that the expression
// Prefixing and suffixing the special Unicode markers to ensure that the expression
// in the history doesn't get broken for RTL languages
spHistoryItem->historyItemVector.expression = L'\u202d' + generatedExpression + L'\u202c';
spHistoryItem->historyItemVector.result = wstring(result);
@ -32,18 +35,15 @@ unsigned int CalculatorHistory::AddToHistory(_In_ shared_ptr<CalculatorVector <p
return addedIndex;
}
unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const &spHistoryItem)
unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const& spHistoryItem)
{
int lastIndex;
if (m_historyItems.size() >= m_maxHistorySize)
{
m_historyItems.erase(m_historyItems.begin());
}
m_historyItems.push_back(spHistoryItem);
lastIndex = static_cast<unsigned>(m_historyItems.size() - 1);
unsigned int lastIndex = static_cast<unsigned>(m_historyItems.size() - 1);
return lastIndex;
}

View file

@ -15,10 +15,10 @@ namespace CalculationManager
struct HISTORYITEMVECTOR
{
std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> spTokens;
std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> spTokens;
std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> spCommands;
std::wstring expression;
std::wstring result;
std::wstring expression;
std::wstring result;
};
struct HISTORYITEM
@ -26,24 +26,27 @@ namespace CalculationManager
HISTORYITEMVECTOR historyItemVector;
};
class CalculatorHistory :
public IHistoryDisplay
class CalculatorHistory : public IHistoryDisplay
{
public:
CalculatorHistory(CALCULATOR_MODE eMode, const size_t maxSize);
unsigned int AddToHistory(_In_ std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const &spTokens, _In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &spCommands, std::wstring_view result);
CalculatorHistory(const size_t maxSize);
unsigned int AddToHistory(
_In_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const& spTokens,
_In_ std::shared_ptr<CalculatorVector<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);
unsigned int AddItem(_In_ std::shared_ptr<HISTORYITEM> const& spHistoryItem);
bool RemoveItem(unsigned int uIdx);
const size_t MaxHistorySize() const { return m_maxHistorySize; }
size_t MaxHistorySize() const
{
return m_maxHistorySize;
}
~CalculatorHistory(void);
private:
std::vector<std::shared_ptr<HISTORYITEM>> m_historyItems;
CALCULATOR_MODE m_mode;
const size_t m_maxHistorySize;
};
}

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <climits> // for UCHAR_MAX
#include "Header Files/CalcEngine.h"
#include "CalculatorManager.h"
#include "CalculatorResource.h"
@ -14,25 +14,21 @@ static constexpr size_t SERIALIZED_NUMBER_MINSIZE = 3;
// Converts Memory Command enum value to unsigned char,
// while ignoring Warning C4309: 'conversion' : truncation of constant value
#define MEMORY_COMMAND_TO_UNSIGNED_CHAR(c)\
__pragma(warning(push))\
__pragma(warning(disable: 4309))\
static_cast<unsigned char>(c)\
__pragma(warning(pop))
#define MEMORY_COMMAND_TO_UNSIGNED_CHAR(c) __pragma(warning(push)) __pragma(warning(disable : 4309)) static_cast<unsigned char>(c) __pragma(warning(pop))
namespace CalculationManager
{
CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider) :
m_displayCallback(displayCallback),
m_resourceProvider(resourceProvider),
m_currentDegreeMode(Command::CommandNULL),
m_savedDegreeMode(Command::CommandDEG),
m_isExponentialFormat(false),
m_persistedPrimaryValue(),
m_currentCalculatorEngine(nullptr),
m_pStdHistory(new CalculatorHistory(CM_STD, MAX_HISTORY_ITEMS)),
m_pSciHistory(new CalculatorHistory(CM_SCI, MAX_HISTORY_ITEMS)),
m_inHistoryItemLoadMode(false)
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_savedDegreeMode(Command::CommandDEG)
, m_pStdHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
, m_pSciHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
{
CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider);
}
@ -89,7 +85,9 @@ namespace CalculationManager
/// 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<CalculatorVector<pair<wstring, int>>> const &tokens, _Inout_ shared_ptr<CalculatorVector<shared_ptr<IExpressionCommand>>> const &commands)
void CalculatorManager::SetExpressionDisplay(
_Inout_ shared_ptr<CalculatorVector<pair<wstring, int>>> const& tokens,
_Inout_ shared_ptr<CalculatorVector<shared_ptr<IExpressionCommand>>> const& commands)
{
if (!m_inHistoryItemLoadMode)
{
@ -109,12 +107,19 @@ namespace CalculationManager
/// <summary>
/// Callback from the engine
/// Used to set the current unmatched open parenthesis count
/// </summary>
/// <param name="parenthesisCount">string containing the parenthesis count</param>
void CalculatorManager::SetParenDisplayText(const wstring& parenthesisCount)
void CalculatorManager::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
m_displayCallback->SetParenDisplayText(parenthesisCount);
m_displayCallback->SetParenthesisNumber(parenthesisCount);
}
/// <summary>
/// Callback from the engine
/// </summary>
void CalculatorManager::OnNoRightParenAdded()
{
m_displayCallback->OnNoRightParenAdded();
}
/// <summary>
@ -158,7 +163,8 @@ namespace CalculationManager
{
if (!m_standardCalculatorEngine)
{
m_standardCalculatorEngine = make_unique<CCalcEngine>(false /* Respect Order of Operations */, false /* Set to Integer Mode */, m_resourceProvider, this, m_pStdHistory);
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();
@ -176,7 +182,8 @@ namespace CalculationManager
{
if (!m_scientificCalculatorEngine)
{
m_scientificCalculatorEngine = make_unique<CCalcEngine>(true /* Respect Order of Operations */, false /* Set to Integer Mode */, m_resourceProvider, this, m_pSciHistory);
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();
@ -191,9 +198,10 @@ namespace CalculationManager
/// </summary>
void CalculatorManager::SetProgrammerMode()
{
if(!m_programmerCalculatorEngine)
if (!m_programmerCalculatorEngine)
{
m_programmerCalculatorEngine = make_unique<CCalcEngine>(true /* Respect Order of Operations */, true /* Set to Integer Mode */, m_resourceProvider, this, nullptr);
m_programmerCalculatorEngine =
make_unique<CCalcEngine>(true /* Respect Order of Operations */, true /* Set to Integer Mode */, m_resourceProvider, this, nullptr);
}
m_currentCalculatorEngine = m_programmerCalculatorEngine.get();
@ -202,10 +210,9 @@ namespace CalculationManager
m_currentCalculatorEngine->ChangePrecision(static_cast<int>(CalculatorPrecision::ProgrammerModePrecision));
}
/// <summary>
/// Send command to the Calc Engine
/// Cast Command Enum to WPARAM.
/// Cast Command Enum to OpCode.
/// Handle special commands such as mode change and combination of two commands.
/// </summary>
/// <param name="command">Enum Command</command>
@ -213,8 +220,8 @@ namespace CalculationManager
{
// 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)
if (command == Command::CommandCLEAR || command == Command::CommandEQU || command == Command::ModeBasic || command == Command::ModeScientific
|| command == Command::ModeProgrammer)
{
switch (command)
{
@ -228,7 +235,7 @@ namespace CalculationManager
this->SetProgrammerMode();
break;
default:
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(command));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(command));
}
m_savedCommands.clear(); // Clear the previous command history
@ -256,44 +263,44 @@ namespace CalculationManager
switch (command)
{
case Command::CommandASIN:
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandSIN));
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<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandCOS));
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<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandTAN));
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<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandLN));
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<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandSINH));
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<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandCOSH));
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<WPARAM>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(Command::CommandTANH));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandINV));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(Command::CommandTANH));
break;
case Command::CommandFE:
m_isExponentialFormat = !m_isExponentialFormat;
// fall through
[[fallthrough]];
default:
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(command));
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(command));
break;
}
}
/// <summary>
/// Convert Command to unsigned char.
/// Convert Command to unsigned char.
/// Since some Commands are higher than 255, they are saved after subtracting 255
/// The smallest Command is CommandSIGN = 80, thus, subtracted value does not overlap with other values.
/// </summary>
@ -301,7 +308,10 @@ namespace CalculationManager
unsigned char CalculatorManager::MapCommandForSerialize(Command command)
{
unsigned int commandToSave = static_cast<unsigned int>(command);
commandToSave > UCHAR_MAX ? commandToSave -= UCHAR_MAX : commandToSave;
if (commandToSave > UCHAR_MAX)
{
commandToSave -= UCHAR_MAX;
}
return static_cast<unsigned char>(commandToSave);
}
@ -351,9 +361,9 @@ namespace CalculationManager
/// DeSerialize the primary display from vector of long
/// </summary>
/// <param name = "serializedPrimaryDisplay">Serialized Rational of primary display</param>
void CalculatorManager::DeSerializePrimaryDisplay(const vector<long> &serializedPrimaryDisplay)
void CalculatorManager::DeSerializePrimaryDisplay(const vector<long>& serializedPrimaryDisplay)
{
if (serializedPrimaryDisplay.size() == 0)
if (serializedPrimaryDisplay.empty())
{
return;
}
@ -394,7 +404,7 @@ namespace CalculationManager
/// DeSerialize the Memory from vector of long
/// </summary>
/// <param name = "serializedMemory">Serialized Rational of memory</param>
void CalculatorManager::DeSerializeMemory(const vector<long> &serializedMemory)
void CalculatorManager::DeSerializeMemory(const vector<long>& serializedMemory)
{
vector<long>::const_iterator itr = serializedMemory.begin();
while (itr != serializedMemory.end())
@ -425,12 +435,12 @@ namespace CalculationManager
for (auto commandItr = serializedData.begin(); commandItr != serializedData.end(); ++commandItr)
{
if (*commandItr >= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber) &&
*commandItr <= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizedNumberClearAll))
if (*commandItr >= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber)
&& *commandItr <= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizedNumberClearAll))
{
//MemoryCommands(which have values above 255) are pushed on m_savedCommands upon casting to unsigned char.
//SerializeCommands uses m_savedCommands, which is then used in DeSerializeCommands.
//Hence, a simple cast to MemoryCommand is not sufficient.
// MemoryCommands(which have values above 255) are pushed on m_savedCommands upon casting to unsigned char.
// SerializeCommands uses m_savedCommands, which is then used in DeSerializeCommands.
// Hence, a simple cast to MemoryCommand is not sufficient.
MemoryCommand memoryCommand = static_cast<MemoryCommand>(*commandItr + UCHAR_MAX + 1);
unsigned int indexOfMemory = 0;
switch (memoryCommand)
@ -483,22 +493,25 @@ namespace CalculationManager
void CalculatorManager::MemorizeNumber()
{
m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber));
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{
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();
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>
@ -509,11 +522,14 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory)
{
SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
return;
}
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
}
/// <summary>
@ -525,24 +541,27 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory)
{
SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
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)
@ -563,27 +582,30 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory)
{
SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{
// 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);
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>
@ -600,17 +622,19 @@ namespace CalculationManager
}
/// <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>
/// 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()))
if (m_currentCalculatorEngine->FInErrorState())
{
auto memoryObject = m_memorizedNumbers.at(indexOfMemory);
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
return;
}
auto memoryObject = m_memorizedNumbers.at(indexOfMemory);
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
}
/// <summary>
@ -620,13 +644,15 @@ namespace CalculationManager
/// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory)
{
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{
auto memoryObject = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObject != nullptr)
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject;
}
return;
}
auto memoryObject = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObject != nullptr)
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject;
}
}
@ -647,9 +673,7 @@ namespace CalculationManager
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems(_In_ CALCULATOR_MODE mode)
{
return (mode == CM_STD) ?
m_pStdHistory->GetHistory() :
m_pSciHistory->GetHistory();
return (mode == CM_STD) ? m_pStdHistory->GetHistory() : m_pSciHistory->GetHistory();
}
shared_ptr<HISTORYITEM> const& CalculatorManager::GetHistoryItem(_In_ unsigned int uIdx)
@ -754,7 +778,7 @@ namespace CalculationManager
}
void CalculatorManager::UpdateMaxIntDigits()
{
{
m_currentCalculatorEngine->UpdateMaxIntDigits();
}
@ -778,7 +802,7 @@ namespace CalculationManager
/// How Rational is serialized :
/// Serialized Rational.P(Number) + Serialized Rational.Q(Number)
/// How Number is saved :
/// [0] = Rational.P.Sign
/// [0] = Rational.P.Sign
/// [1] = Rational.P.Mantissa.size
/// [2] = Rational.P.Exp
/// [3] = Rational.P.Mantissa[0]
@ -816,7 +840,7 @@ namespace CalculationManager
/// <summary>
/// Serialize Number to vector of long
/// How Number is saved :
/// [0] = Number.Sign
/// [0] = Number.Sign
/// [1] = Number.Mantissa.size
/// [2] = Number.Exp
/// [3] = Number.Mantissa[0]
@ -843,7 +867,7 @@ namespace CalculationManager
/// <summary>
/// DeserializeNumber vector and construct a Number
/// How Number is saved :
/// [0] = Number.Sign
/// [0] = Number.Sign
/// [1] = Number.Mantissa.size
/// [2] = Number.Exp
/// [3] = Number.Mantissa[0]

View file

@ -27,9 +27,9 @@ namespace CalculationManager
ProgrammerModePrecision = 64
};
// Numbering continues from the Enum Command from Command.h
// 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
// 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
@ -42,7 +42,7 @@ namespace CalculationManager
MemorizedNumberClear = 335
};
class CalculatorManager sealed : public virtual ICalcDisplay
class CalculatorManager final : public ICalcDisplay
{
private:
ICalcDisplay* const m_displayCallback;
@ -91,16 +91,18 @@ namespace CalculationManager
// ICalcDisplay
void SetPrimaryDisplay(_In_ const std::wstring& displayString, _In_ bool isError) override;
void SetIsInError(bool isError) override;
void SetExpressionDisplay(_Inout_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const &tokens, _Inout_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &commands) override;
void SetExpressionDisplay(
_Inout_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<CalculatorVector<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 SetParenDisplayText(const std::wstring& parenthesisCount);
void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override;
void OnNoRightParenAdded() override;
void DisplayPasteError();
void MaxDigitsReached() override;
void BinaryOperatorReceived() override;
void MemoryItemChanged(unsigned int indexOfMemory) override;
CalculatorManager(ICalcDisplay* displayCallback, IResourceProvider* resourceProvider);
~CalculatorManager();
@ -113,10 +115,10 @@ namespace CalculationManager
void DeSerializeCommands(_In_ const std::vector<unsigned char>& serializedData);
void SerializeMemory();
std::vector<long> GetSerializedMemory();
void DeSerializeMemory(const std::vector<long> &serializedMemory);
void DeSerializeMemory(const std::vector<long>& serializedMemory);
void SerializePrimaryDisplay();
std::vector<long> GetSerializedPrimaryDisplay();
void DeSerializePrimaryDisplay(const std::vector<long> &serializedPrimaryDisplay);
void DeSerializePrimaryDisplay(const std::vector<long>& serializedPrimaryDisplay);
Command SerializeSavedDegreeMode();
void MemorizeNumber();
@ -127,7 +129,10 @@ namespace CalculationManager
void MemorizedNumberClearAll();
bool IsEngineRecording();
std::vector<unsigned char> GetSavedCommands(){ return m_savedCommands; }
std::vector<unsigned char> GetSavedCommands()
{
return m_savedCommands;
}
void SetRadix(RADIX_TYPE iRadixType);
void SetMemorizedNumbersString();
std::wstring GetResultForRadix(uint32_t radix, int32_t precision);
@ -140,7 +145,10 @@ namespace CalculationManager
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(_In_ unsigned int uIdx);
bool RemoveHistoryItem(_In_ unsigned int uIdx);
void ClearHistory();
const size_t MaxHistorySize() const { return m_pHistory->MaxHistorySize(); }
size_t MaxHistorySize() const
{
return m_pHistory->MaxHistorySize();
}
CalculationManager::Command GetCurrentDegreeMode();
void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector<std::shared_ptr<HISTORYITEM>> const& history);
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);

View file

@ -8,9 +8,11 @@ namespace CalculationManager
class IResourceProvider
{
public:
virtual ~IResourceProvider() { }
virtual ~IResourceProvider()
{
}
// Should return a string from the resource table for strings used
// 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

View file

@ -1,15 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <string>
#include <vector>
#include <winerror.h>
#include "Ratpack/CalcErr.h"
#include <stdexcept> // for std::out_of_range
#include <sal.h> // for SAL
template <typename TType>
class CalculatorVector
class CalculatorVector
{
public:
HRESULT GetAt(_In_opt_ unsigned int index, _Out_ TType *item)
ResultCode GetAt(_In_opt_ unsigned int index, _Out_ TType* item)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
try
{
*item = m_vector.at(index);
@ -21,15 +28,15 @@ public:
return hr;
}
HRESULT GetSize(_Out_ unsigned int *size)
ResultCode GetSize(_Out_ unsigned int* size)
{
*size = static_cast<unsigned>(m_vector.size());
return S_OK;
}
HRESULT SetAt(_In_ unsigned int index, _In_opt_ TType item)
ResultCode SetAt(_In_ unsigned int index, _In_opt_ TType item)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
try
{
m_vector[index] = item;
@ -41,9 +48,9 @@ public:
return hr;
}
HRESULT RemoveAt(_In_ unsigned int index)
ResultCode RemoveAt(_In_ unsigned int index)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
if (index < m_vector.size())
{
m_vector.erase(m_vector.begin() + index);
@ -55,9 +62,9 @@ public:
return hr;
}
HRESULT InsertAt(_In_ unsigned int index, _In_ TType item)
ResultCode InsertAt(_In_ unsigned int index, _In_ TType item)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
try
{
auto iter = m_vector.begin() + index;
@ -70,9 +77,9 @@ public:
return hr;
}
HRESULT Truncate(_In_ unsigned int index)
ResultCode Truncate(_In_ unsigned int index)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
if (index < m_vector.size())
{
auto startIter = m_vector.begin() + index;
@ -85,9 +92,9 @@ public:
return hr;
}
HRESULT Append(_In_opt_ TType item)
ResultCode Append(_In_opt_ TType item)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
try
{
m_vector.push_back(item);
@ -99,23 +106,23 @@ public:
return hr;
}
HRESULT RemoveAtEnd()
ResultCode RemoveAtEnd()
{
m_vector.erase(--(m_vector.end()));
return S_OK;
}
HRESULT Clear()
ResultCode Clear()
{
m_vector.clear();
return S_OK;
}
HRESULT GetString(_Out_ std::wstring* expression)
ResultCode GetString(_Out_ std::wstring* expression)
{
HRESULT hr = S_OK;
ResultCode hr = S_OK;
unsigned int nTokens = 0;
std::pair <std::wstring, int> currentPair;
std::pair<std::wstring, int> currentPair;
hr = this->GetSize(&nTokens);
if (SUCCEEDED(hr))
{
@ -144,7 +151,7 @@ public:
return hr;
}
HRESULT GetExpressionSuffix(_Out_ std::wstring* suffix)
ResultCode GetExpressionSuffix(_Out_ std::wstring* suffix)
{
*suffix = L" =";
return S_OK;

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
@ -7,9 +7,19 @@ namespace UnitConversionManager
{
enum class Command
{
Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine,
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Decimal,
Negate, Backspace,
Negate,
Backspace,
Clear,
Reset,
None
@ -20,9 +30,19 @@ namespace CurrencyConversionManager
{
enum class Command
{
Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine,
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Decimal,
Negate, Backspace,
Negate,
Backspace,
Clear,
None
};
@ -73,7 +93,7 @@ namespace CalculationManager
CommandROOT = 96,
CommandPWR = 97,
CommandCHOP = 98, // Unary operators must be between CommandCHOP and CommandEQU
CommandCHOP = 98, // Unary operators must be between CommandCHOP and CommandEQU
CommandROL = 99,
CommandROR = 100,
CommandCOM = 101,
@ -85,7 +105,6 @@ namespace CalculationManager
CommandCOSH = 106,
CommandTANH = 107,
CommandLN = 108,
CommandLOG = 109,
CommandSQRT = 110,
@ -94,8 +113,8 @@ namespace CalculationManager
CommandFAC = 113,
CommandREC = 114,
CommandDMS = 115,
CommandCUBEROOT = 116, //x ^ 1/3
CommandPOW10 = 117, // 10 ^ x
CommandCUBEROOT = 116, // x ^ 1/3
CommandPOW10 = 117, // 10 ^ x
CommandPERCENT = 118,
CommandFE = 119,
@ -113,7 +132,7 @@ namespace CalculationManager
CommandOPENP = 128,
CommandCLOSEP = 129,
Command0 = 130, // The controls for 0 through F must be consecutive and in order
Command0 = 130, // The controls for 0 through F must be consecutive and in order
Command1 = 131,
Command2 = 132,
Command3 = 133,
@ -128,7 +147,7 @@ namespace CalculationManager
CommandC = 142,
CommandD = 143,
CommandE = 144,
CommandF = 145, // this is last control ID which must match the string table
CommandF = 145, // this is last control ID which must match the string table
CommandINV = 146,
CommandSET_RESULT = 147,

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <string>
#include "Header Files/CCommand.h"
#include "CalculatorVector.h"
#include "ExpressionCommand.h"
@ -13,8 +13,10 @@ constexpr wchar_t chNegate = L'-';
constexpr wchar_t chExp = L'e';
constexpr wchar_t chPlus = L'+';
CParentheses::CParentheses(_In_ int command) :m_command(command)
{}
CParentheses::CParentheses(_In_ int command)
: m_command(command)
{
}
int CParentheses::GetCommand() const
{
@ -26,7 +28,7 @@ CalculationManager::CommandType CParentheses::GetCommandType() const
return CalculationManager::CommandType::Parentheses;
}
void CParentheses::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
void CParentheses::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}
@ -44,7 +46,7 @@ CUnaryCommand::CUnaryCommand(int command1, int command2)
m_command->Append(command2);
}
const shared_ptr<CalculatorVector<int>> & CUnaryCommand::GetCommands() const
const shared_ptr<CalculatorVector<int>>& CUnaryCommand::GetCommands() const
{
return m_command;
}
@ -67,42 +69,45 @@ void CUnaryCommand::SetCommands(int command1, int command2)
m_command->Append(command2);
}
void CUnaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
void CUnaryCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}
CBinaryCommand::CBinaryCommand(int command) :m_command(command)
{}
CBinaryCommand::CBinaryCommand(int command)
: m_command(command)
{
}
void CBinaryCommand::SetCommand(int command)
{
m_command = command;
void CBinaryCommand::SetCommand(int command)
{
m_command = command;
}
int CBinaryCommand::GetCommand() const
{
return m_command;
{
return m_command;
}
CalculationManager::CommandType CBinaryCommand::GetCommandType() const
{
return CalculationManager::CommandType::BinaryCommand;
{
return CalculationManager::CommandType::BinaryCommand;
}
void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}
COpndCommand::COpndCommand(shared_ptr<CalculatorVector<int>> const &commands, bool fNegative, bool fDecimal, bool fSciFmt) :
m_commands(commands),
m_fNegative(fNegative),
m_fDecimal(fDecimal),
m_fSciFmt(fSciFmt),
m_fInitialized(false),
m_value{}
{}
COpndCommand::COpndCommand(shared_ptr<CalculatorVector<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)
{
@ -110,9 +115,9 @@ void COpndCommand::Initialize(Rational const& rat)
m_fInitialized = true;
}
const shared_ptr<CalculatorVector<int>> & COpndCommand::GetCommands() const
{
return m_commands;
const shared_ptr<CalculatorVector<int>>& COpndCommand::GetCommands() const
{
return m_commands;
}
void COpndCommand::SetCommands(shared_ptr<CalculatorVector<int>> const& commands)
@ -166,7 +171,7 @@ void COpndCommand::RemoveFromEnd()
{
unsigned int nCommands;
m_commands->GetSize(&nCommands);
if (nCommands == 1)
{
ClearAllAndAppendCommand(CalculationManager::Command::Command0);
@ -185,8 +190,8 @@ void COpndCommand::RemoveFromEnd()
}
bool COpndCommand::IsNegative() const
{
return m_fNegative;
{
return m_fNegative;
}
bool COpndCommand::IsSciFmt() const
@ -195,13 +200,13 @@ bool COpndCommand::IsSciFmt() const
}
bool COpndCommand::IsDecimalPresent() const
{
return m_fDecimal;
{
return m_fDecimal;
}
CalculationManager::CommandType COpndCommand::GetCommandType() const
{
return CalculationManager::CommandType::OperandCommand;
{
return CalculationManager::CommandType::OperandCommand;
}
void COpndCommand::ClearAllAndAppendCommand(CalculationManager::Command command)
@ -213,7 +218,7 @@ void COpndCommand::ClearAllAndAppendCommand(CalculationManager::Command command)
m_fDecimal = false;
}
const wstring & COpndCommand::GetToken(wchar_t decimalSymbol)
const wstring& COpndCommand::GetToken(wchar_t decimalSymbol)
{
static const wchar_t chZero = L'0';
@ -283,7 +288,7 @@ const wstring & COpndCommand::GetToken(wchar_t decimalSymbol)
m_token.clear();
m_token.append(&chZero);
}
return m_token;
}
@ -299,7 +304,7 @@ wstring COpndCommand::GetString(uint32_t radix, int32_t precision)
return result;
}
void COpndCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
void COpndCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor)
{
commandVisitor.Visit(*this);
}

View file

@ -12,7 +12,7 @@ public:
CParentheses(_In_ int command);
int GetCommand() const override;
CalculationManager::CommandType GetCommandType() const override;
void Accept(_In_ ISerializeCommandVisitor &commandVisitor) override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
private:
int m_command;
@ -23,11 +23,11 @@ class CUnaryCommand final : public IUnaryCommand
public:
CUnaryCommand(int command);
CUnaryCommand(int command1, int command2);
const std::shared_ptr<CalculatorVector<int>> & GetCommands() const override;
const std::shared_ptr<CalculatorVector<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;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
private:
std::shared_ptr<CalculatorVector<int>> m_command;
@ -40,7 +40,7 @@ public:
void SetCommand(int command) override;
int GetCommand() const override;
CalculationManager::CommandType GetCommandType() const override;
void Accept(_In_ ISerializeCommandVisitor &commandVisitor) override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
private:
int m_command;
@ -49,14 +49,10 @@ private:
class COpndCommand final : public IOpndCommand
{
public:
COpndCommand(
std::shared_ptr<CalculatorVector<int>> const &commands,
bool fNegative,
bool fDecimal,
bool fSciFmt);
COpndCommand(std::shared_ptr<CalculatorVector<int>> const& commands, bool fNegative, bool fDecimal, bool fSciFmt);
void Initialize(CalcEngine::Rational const& rat);
const std::shared_ptr<CalculatorVector<int>> & GetCommands() const override;
const std::shared_ptr<CalculatorVector<int>>& GetCommands() const override;
void SetCommands(std::shared_ptr<CalculatorVector<int>> const& commands) override;
void AppendCommand(int command) override;
void ToggleSign() override;
@ -64,9 +60,9 @@ public:
bool IsNegative() const override;
bool IsSciFmt() const override;
bool IsDecimalPresent() const override;
const std::wstring & GetToken(wchar_t decimalSymbol) override;
const std::wstring& GetToken(wchar_t decimalSymbol) override;
CalculationManager::CommandType GetCommandType() const override;
void Accept(_In_ ISerializeCommandVisitor &commandVisitor) override;
void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override;
std::wstring GetString(uint32_t radix, int32_t precision);
private:
@ -83,8 +79,8 @@ private:
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;
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;
};

View file

@ -1,7 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <memory> // for std::shared_ptr
#include "CalculatorVector.h"
#include "Command.h"
@ -11,7 +13,7 @@ class IExpressionCommand
{
public:
virtual CalculationManager::CommandType GetCommandType() const = 0;
virtual void Accept(_In_ ISerializeCommandVisitor &commandVisitor) = 0;
virtual void Accept(_In_ ISerializeCommandVisitor& commandVisitor) = 0;
};
class IOperatorCommand : public IExpressionCommand
@ -23,7 +25,7 @@ public:
class IUnaryCommand : public IOperatorCommand
{
public:
virtual const std::shared_ptr<CalculatorVector<int>> & GetCommands() const = 0;
virtual const std::shared_ptr<CalculatorVector<int>>& GetCommands() const = 0;
virtual void SetCommands(int command1, int command2) = 0;
};
@ -37,14 +39,14 @@ public:
class IOpndCommand : public IExpressionCommand
{
public:
virtual const std::shared_ptr<CalculatorVector<int>> & GetCommands() const= 0;
virtual const std::shared_ptr<CalculatorVector<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 const std::wstring& GetToken(wchar_t decimalSymbol) = 0;
virtual void SetCommands(std::shared_ptr<CalculatorVector<int>> const& commands) = 0;
};

View file

@ -13,39 +13,40 @@
*
\****************************************************************************/
#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 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_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
#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.
// 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.
@ -53,162 +54,158 @@
// 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_SIGN 80
#define IDC_CLEAR 81
#define IDC_CENTR 82
#define IDC_BACK 83
#define IDC_PNT 84
#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_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_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_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_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_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_MCLEAR 122
#define IDC_RECALL 123
#define IDC_STORE 124
#define IDC_MPLUS 125
#define IDC_MMINUS 126
#define IDC_EXP 127
#define IDC_EXP 127
#define IDC_OPENP 128
#define IDC_CLOSEP 129
#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_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_LASTCONTROL IDC_SET_RESULT
#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
#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
#define IDS_ENGINESTR_FIRST 0
#define IDS_ENGINESTR_MAX 200

View file

@ -20,8 +20,9 @@
#include "../CalculatorVector.h"
#include "../ExpressionCommand.h"
#include "RadixType.h"
#include "History.h" // for History Collector
#include "History.h" // for History Collector
#include "CalcInput.h"
#include "CalcUtils.h"
#include "ICalcDisplay.h"
#include "Rational.h"
#include "RationalMath.h"
@ -30,11 +31,12 @@
// The real exports follows later
// This is expected to be in same order as IDM_QWORD, IDM_DWORD etc.
enum eNUM_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
enum eNUM_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
};
typedef enum eNUM_WIDTH NUM_WIDTH;
static constexpr size_t NUM_WIDTH_LENGTH = 4;
@ -44,62 +46,89 @@ namespace CalculationManager
class IResourceProvider;
}
namespace CalculatorUnitTests
namespace CalculatorEngineTests
{
class CalcEngineTests;
}
class CCalcEngine {
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(WPARAM wID);
void DisplayError (DWORD nError);
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 FInRecordingState() { return m_bRecord; }
bool FInErrorState()
{
return m_bError;
}
bool FInRecordingState()
{
return m_bRecord;
}
void SettingsChanged();
bool IsCurrentTooBigForTrig();
int GetCurrentRadix();
std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision);
void ChangePrecision(int32_t precision) { m_precision = precision; ChangeConstants(m_radix, precision); }
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;
// Static methods for the instance
static void InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider); // Once per load time to call to initialize all shared global variables
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[ids]; }
static std::wstring_view OpCodeToString(int nOpCode) { return GetString(IdStrFromCmdId(nOpCode)); }
static std::wstring_view GetString(int ids)
{
return s_engineStrings[std::to_wstring(ids)];
}
static std::wstring_view GetString(std::wstring 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, ANGLE_TYPE angletype);
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;
ICalcDisplay* m_pCalcDisplay;
CalculationManager::IResourceProvider* const m_resourceProvider;
int m_nOpCode; /* ID value of operation. */
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
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
eNUMOBJ_FMT m_nFE; /* Scientific notation conversion flag. */
eNUMOBJ_FMT 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.
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. */
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;
@ -108,27 +137,28 @@ private:
std::wstring m_numberString;
int m_nTempCom; /* Holding place for the last command. */
int 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.
ANGLE_TYPE 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.
LONG m_dwWordBitWidth; // # of bits in currently selected word size
int m_nTempCom; /* Holding place for the last command. */
int 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.
ANGLE_TYPE 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
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::array<std::wstring, CSTRINGSENGMAX> s_engineStrings; // the string table shared across all instances
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, std::wstring> s_engineStrings; // the string table shared across all instances
wchar_t m_decimalSeparator;
wchar_t m_groupSeparator;
private:
void ProcessCommandWorker(WPARAM wParam);
void HandleErrorCommand(WPARAM idc);
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;
@ -136,20 +166,22 @@ private:
void SetPrimaryDisplay(const std::wstring& szText, bool isError = false);
void ClearTemporaryValues();
CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat);
CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op);
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(RADIX_TYPE radixtype, NUM_WIDTH numwidth);
LONG DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth);
uint32_t NRadixFromRadixType( RADIX_TYPE radixtype);
int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth);
uint32_t NRadixFromRadixType(RADIX_TYPE radixtype);
bool TryToggleBit(CalcEngine::Rational& rat, DWORD wbitno);
bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno);
void CheckAndAddLastBinOpToHistory(bool addToHistory = true);
int IdcSetAngleTypeDecMode(int idc);
void InitChopNumbers();
static void LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider);
static int IdStrFromCmdId(int id) { return id - IDC_FIRSTCONTROL + IDS_FIRSTENGSTR; }
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);
@ -158,5 +190,5 @@ private:
static void ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision);
void BaseOrPrecisionChanged();
friend class CalculatorUnitTests::CalcEngineTests;
friend class CalculatorEngineTests::CalcEngineTests;
};

View file

@ -6,23 +6,33 @@
#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;
constexpr int MAX_STRLEN = 84;
namespace CalcEngine
{
class CalcNumSec
{
public:
CalcNumSec() :
value(),
m_isNegative(false)
{}
CalcNumSec()
: value()
, m_isNegative(false)
{
}
void Clear();
bool IsEmpty() { return value.empty(); }
bool IsEmpty()
{
return value.empty();
}
bool IsNegative() { return m_isNegative; }
void IsNegative(bool isNegative) { m_isNegative = isNegative; }
bool IsNegative()
{
return m_isNegative;
}
void IsNegative(bool isNegative)
{
m_isNegative = isNegative;
}
std::wstring value;
@ -33,21 +43,24 @@ namespace CalcEngine
class CalcInput
{
public:
CalcInput() : CalcInput(L'.')
{}
CalcInput()
: CalcInput(L'.')
{
}
CalcInput(wchar_t decSymbol) :
m_hasExponent(false),
m_hasDecimal(false),
m_decPtIndex(0),
m_decSymbol(decSymbol),
m_base(),
m_exponent()
{}
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, long wordBitWidth, int maxDigits);
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();

View file

@ -3,11 +3,13 @@
#pragma once
bool IsOpInRange(WPARAM op, uint32_t x, uint32_t y);
bool IsBinOpCode(WPARAM opCode);
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(WPARAM opCode);
bool IsDigitOpCode(WPARAM opCode);
bool IsGuiSettingOpCode(WPARAM opCode);
bool IsUnaryOpCode(OpCode opCode);
bool IsDigitOpCode(OpCode opCode);
bool IsGuiSettingOpCode(OpCode opCode);

View file

@ -13,327 +13,281 @@
* Created: 13-Feb-2008
*
\****************************************************************************/
#define IDS_FIRSTENGSTR IDS_ENGINESTR_FIRST
#define IDS_DECIMAL 4
#pragma once
// All unary op function names for easy history reading
// This is where the first string after all the commands in order have been placed, should be placed
// keeping in consecutive helps us to allocate 1 string table and index them
#define IDS_FNSZFIRST (IDC_F -IDC_FIRSTCONTROL)+1
#include <string>
#define IDS_FRAC IDS_FNSZFIRST
#define IDS_SIND IDS_FNSZFIRST+1
#define IDS_COSD IDS_FNSZFIRST+2
#define IDS_TAND IDS_FNSZFIRST+3
#define IDS_ASIND IDS_FNSZFIRST+4
#define IDS_ACOSD IDS_FNSZFIRST+5
#define IDS_ATAND IDS_FNSZFIRST+6
#define IDS_SINR IDS_FNSZFIRST+7
#define IDS_COSR IDS_FNSZFIRST+8
#define IDS_TANR IDS_FNSZFIRST+9
#define IDS_ASINR IDS_FNSZFIRST+10
#define IDS_ACOSR IDS_FNSZFIRST+11
#define IDS_ATANR IDS_FNSZFIRST+12
#define IDS_SING IDS_FNSZFIRST+13
#define IDS_COSG IDS_FNSZFIRST+14
#define IDS_TANG IDS_FNSZFIRST+15
#define IDS_ASING IDS_FNSZFIRST+16
#define IDS_ACOSG IDS_FNSZFIRST+17
#define IDS_ATANG IDS_FNSZFIRST+18
#define IDS_ASINH IDS_FNSZFIRST+19
#define IDS_ACOSH IDS_FNSZFIRST+20
#define IDS_ATANH IDS_FNSZFIRST+21
#define IDS_POWE IDS_FNSZFIRST+22
#define IDS_POW10 IDS_FNSZFIRST+23
#define IDS_SQRT IDS_FNSZFIRST+24
#define IDS_SQR IDS_FNSZFIRST+25
#define IDS_CUBE IDS_FNSZFIRST+26
#define IDS_CUBERT IDS_FNSZFIRST+27
#define IDS_FACT IDS_FNSZFIRST+28
#define IDS_REC IDS_FNSZFIRST+29
#define IDS_DEGREES IDS_FNSZFIRST+30
#define IDS_NEGATE IDS_FNSZFIRST+31
#define IDS_RSH IDS_FNSZFIRST+32
#define IDS_FNSZLAST IDS_RSH
#define IDS_ERRORS_FIRST IDS_FNSZLAST+1
inline constexpr auto IDS_ERRORS_FIRST = 99;
// This is the list of error strings corresponding to SCERR_DIVIDEZERO..
#define IDS_DIVBYZERO IDS_ERRORS_FIRST
#define IDS_DOMAIN IDS_ERRORS_FIRST+1
#define IDS_UNDEFINED IDS_ERRORS_FIRST+2
#define IDS_POS_INFINITY IDS_ERRORS_FIRST+3
#define IDS_NEG_INFINITY IDS_ERRORS_FIRST+4
#define IDS_NOMEM IDS_ERRORS_FIRST+6
#define IDS_TOOMANY IDS_ERRORS_FIRST+7
#define IDS_OVERFLOW IDS_ERRORS_FIRST+8
#define IDS_NORESULT IDS_ERRORS_FIRST+9
#define IDS_INSUFFICIENT_DATA IDS_ERRORS_FIRST+10
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;
#define CSTRINGSENGMAX IDS_INSUFFICIENT_DATA+1
inline constexpr auto CSTRINGSENGMAX = IDS_INSUFFICIENT_DATA + 1;
// Arithmetic expression evaluator error strings
#define IDS_ERR_UNK_CH CSTRINGSENGMAX+1
#define IDS_ERR_UNK_FN CSTRINGSENGMAX+2
#define IDS_ERR_UNEX_NUM CSTRINGSENGMAX+3
#define IDS_ERR_UNEX_CH CSTRINGSENGMAX+4
#define IDS_ERR_UNEX_SZ CSTRINGSENGMAX+5
#define IDS_ERR_MISMATCH_CLOSE CSTRINGSENGMAX+6
#define IDS_ERR_UNEX_END CSTRINGSENGMAX+7
#define IDS_ERR_SG_INV_ERROR CSTRINGSENGMAX+8
#define IDS_ERR_INPUT_OVERFLOW CSTRINGSENGMAX+9
#define IDS_ERR_OUTPUT_OVERFLOW CSTRINGSENGMAX+10
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;
#define SIDS_PLUS_MINUS L"0"
#define SIDS_CLEAR L"1"
#define SIDS_CE L"2"
#define SIDS_BACKSPACE L"3"
#define SIDS_DECIMAL_SEPARATOR L"4"
#define SIDS_EMPTY_STRING L"5"
#define SIDS_AND L"6"
#define SIDS_OR L"7"
#define SIDS_XOR L"8"
#define SIDS_LSH L"9"
#define SIDS_RSH L"10"
#define SIDS_DIVIDE L"11"
#define SIDS_MULTIPLY L"12"
#define SIDS_PLUS L"13"
#define SIDS_MINUS L"14"
#define SIDS_MOD L"15"
#define SIDS_YROOT L"16"
#define SIDS_POW_HAT L"17"
#define SIDS_INT L"18"
#define SIDS_ROL L"19"
#define SIDS_ROR L"20"
#define SIDS_NOT L"21"
#define SIDS_SIN L"22"
#define SIDS_COS L"23"
#define SIDS_TAN L"24"
#define SIDS_SINH L"25"
#define SIDS_COSH L"26"
#define SIDS_TANH L"27"
#define SIDS_LN L"28"
#define SIDS_LOG L"29"
#define SIDS_SQRT L"30"
#define SIDS_XPOW2 L"31"
#define SIDS_XPOW3 L"32"
#define SIDS_NFACTORIAL L"33"
#define SIDS_RECIPROCAL L"34"
#define SIDS_DMS L"35"
#define SIDS_CUBEROOT L"36"
#define SIDS_POWTEN L"37"
#define SIDS_PERCENT L"38"
#define SIDS_SCIENTIFIC_NOTATION L"39"
#define SIDS_PI L"40"
#define SIDS_EQUAL L"41"
#define SIDS_MC L"42"
#define SIDS_MR L"43"
#define SIDS_MS L"44"
#define SIDS_MPLUS L"45"
#define SIDS_MMINUS L"46"
#define SIDS_EXP L"47"
#define SIDS_OPEN_PAREN L"48"
#define SIDS_CLOSE_PAREN L"49"
#define SIDS_0 L"50"
#define SIDS_1 L"51"
#define SIDS_2 L"52"
#define SIDS_3 L"53"
#define SIDS_4 L"54"
#define SIDS_5 L"55"
#define SIDS_6 L"56"
#define SIDS_7 L"57"
#define SIDS_8 L"58"
#define SIDS_9 L"59"
#define SIDS_A L"60"
#define SIDS_B L"61"
#define SIDS_C L"62"
#define SIDS_D L"63"
#define SIDS_E L"64"
#define SIDS_F L"65"
#define SIDS_FRAC L"66"
#define SIDS_SIND L"67"
#define SIDS_COSD L"68"
#define SIDS_TAND L"69"
#define SIDS_ASIND L"70"
#define SIDS_ACOSD L"71"
#define SIDS_ATAND L"72"
#define SIDS_SINR L"73"
#define SIDS_COSR L"74"
#define SIDS_TANR L"75"
#define SIDS_ASINR L"76"
#define SIDS_ACOSR L"77"
#define SIDS_ATANR L"78"
#define SIDS_SING L"79"
#define SIDS_COSG L"80"
#define SIDS_TANG L"81"
#define SIDS_ASING L"82"
#define SIDS_ACOSG L"83"
#define SIDS_ATANG L"84"
#define SIDS_ASINH L"85"
#define SIDS_ACOSH L"86"
#define SIDS_ATANH L"87"
#define SIDS_POWE L"88"
#define SIDS_POWTEN2 L"89"
#define SIDS_SQRT2 L"90"
#define SIDS_SQR L"91"
#define SIDS_CUBE L"92"
#define SIDS_CUBERT L"93"
#define SIDS_FACT L"94"
#define SIDS_RECIPROC L"95"
#define SIDS_DEGREES L"96"
#define SIDS_NEGATE L"97"
#define SIDS_RSH2 L"98"
#define SIDS_DIVIDEBYZERO L"99"
#define SIDS_DOMAIN L"100"
#define SIDS_UNDEFINED L"101"
#define SIDS_POS_INFINITY L"102"
#define SIDS_NEG_INFINITY L"103"
#define SIDS_ABORTED L"104"
#define SIDS_NOMEM L"105"
#define SIDS_TOOMANY L"106"
#define SIDS_OVERFLOW L"107"
#define SIDS_NORESULT L"108"
#define SIDS_INSUFFICIENT_DATA L"109"
// 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_CUBEROOT = L"36";
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
#define SIDS_ERR_UNK_CH L"111"
#define SIDS_ERR_UNK_FN L"112"
#define SIDS_ERR_UNEX_NUM L"113"
#define SIDS_ERR_UNEX_CH L"114"
#define SIDS_ERR_UNEX_SZ L"115"
#define SIDS_ERR_MISMATCH_CLOSE L"116"
#define SIDS_ERR_UNEX_END L"117"
#define SIDS_ERR_SG_INV_ERROR L"118"
#define SIDS_ERR_INPUT_OVERFLOW L"119"
#define SIDS_ERR_OUTPUT_OVERFLOW L"120"
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";
__declspec(selectany) std::wstring g_sids[] =
{
std::wstring(SIDS_PLUS_MINUS),
std::wstring(SIDS_C),
std::wstring(SIDS_CE),
std::wstring(SIDS_BACKSPACE),
std::wstring(SIDS_DECIMAL_SEPARATOR),
std::wstring(SIDS_EMPTY_STRING),
std::wstring(SIDS_AND),
std::wstring(SIDS_OR),
std::wstring(SIDS_XOR),
std::wstring(SIDS_LSH),
std::wstring(SIDS_RSH),
std::wstring(SIDS_DIVIDE),
std::wstring(SIDS_MULTIPLY),
std::wstring(SIDS_PLUS),
std::wstring(SIDS_MINUS),
std::wstring(SIDS_MOD),
std::wstring(SIDS_YROOT),
std::wstring(SIDS_POW_HAT),
std::wstring(SIDS_INT),
std::wstring(SIDS_ROL),
std::wstring(SIDS_ROR),
std::wstring(SIDS_NOT),
std::wstring(SIDS_SIN),
std::wstring(SIDS_COS),
std::wstring(SIDS_TAN),
std::wstring(SIDS_SINH),
std::wstring(SIDS_COSH),
std::wstring(SIDS_TANH),
std::wstring(SIDS_LN),
std::wstring(SIDS_LOG),
std::wstring(SIDS_SQRT),
std::wstring(SIDS_XPOW2),
std::wstring(SIDS_XPOW3),
std::wstring(SIDS_NFACTORIAL),
std::wstring(SIDS_RECIPROCAL),
std::wstring(SIDS_DMS),
std::wstring(SIDS_CUBEROOT),
std::wstring(SIDS_POWTEN),
std::wstring(SIDS_PERCENT),
std::wstring(SIDS_SCIENTIFIC_NOTATION),
std::wstring(SIDS_PI),
std::wstring(SIDS_EQUAL),
std::wstring(SIDS_MC),
std::wstring(SIDS_MR),
std::wstring(SIDS_MS),
std::wstring(SIDS_MPLUS),
std::wstring(SIDS_MMINUS),
std::wstring(SIDS_EXP),
std::wstring(SIDS_OPEN_PAREN),
std::wstring(SIDS_CLOSE_PAREN),
std::wstring(SIDS_0),
std::wstring(SIDS_1),
std::wstring(SIDS_2),
std::wstring(SIDS_3),
std::wstring(SIDS_4),
std::wstring(SIDS_5),
std::wstring(SIDS_6),
std::wstring(SIDS_7),
std::wstring(SIDS_8),
std::wstring(SIDS_9),
std::wstring(SIDS_A),
std::wstring(SIDS_B),
std::wstring(SIDS_C),
std::wstring(SIDS_D),
std::wstring(SIDS_E),
std::wstring(SIDS_F),
std::wstring(SIDS_FRAC),
std::wstring(SIDS_SIND),
std::wstring(SIDS_COSD),
std::wstring(SIDS_TAND),
std::wstring(SIDS_ASIND),
std::wstring(SIDS_ACOSD),
std::wstring(SIDS_ATAND),
std::wstring(SIDS_SINR),
std::wstring(SIDS_COSR),
std::wstring(SIDS_TANR),
std::wstring(SIDS_ASINR),
std::wstring(SIDS_ACOSR),
std::wstring(SIDS_ATANR),
std::wstring(SIDS_SING),
std::wstring(SIDS_COSG),
std::wstring(SIDS_TANG),
std::wstring(SIDS_ASING),
std::wstring(SIDS_ACOSG),
std::wstring(SIDS_ATANG),
std::wstring(SIDS_ASINH),
std::wstring(SIDS_ACOSH),
std::wstring(SIDS_ATANH),
std::wstring(SIDS_POWE),
std::wstring(SIDS_POWTEN2),
std::wstring(SIDS_SQRT2),
std::wstring(SIDS_SQR),
std::wstring(SIDS_CUBE),
std::wstring(SIDS_CUBERT),
std::wstring(SIDS_FACT),
std::wstring(SIDS_RECIPROC),
std::wstring(SIDS_DEGREES),
std::wstring(SIDS_NEGATE),
std::wstring(SIDS_RSH),
std::wstring(SIDS_DIVIDEBYZERO),
std::wstring(SIDS_DOMAIN),
std::wstring(SIDS_UNDEFINED),
std::wstring(SIDS_POS_INFINITY),
std::wstring(SIDS_NEG_INFINITY),
std::wstring(SIDS_ABORTED),
std::wstring(SIDS_NOMEM),
std::wstring(SIDS_TOOMANY),
std::wstring(SIDS_OVERFLOW),
std::wstring(SIDS_NORESULT),
std::wstring(SIDS_INSUFFICIENT_DATA),
std::wstring(SIDS_ERR_UNK_CH),
std::wstring(SIDS_ERR_UNK_FN),
std::wstring(SIDS_ERR_UNEX_NUM),
std::wstring(SIDS_ERR_UNEX_CH),
std::wstring(SIDS_ERR_UNEX_SZ),
std::wstring(SIDS_ERR_MISMATCH_CLOSE),
std::wstring(SIDS_ERR_UNEX_END),
std::wstring(SIDS_ERR_SG_INV_ERROR),
std::wstring(SIDS_ERR_INPUT_OVERFLOW),
std::wstring(SIDS_ERR_OUTPUT_OVERFLOW)
};
// 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, 120> 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_CUBEROOT,
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 };

View file

@ -3,6 +3,7 @@
#pragma once
#include <array>
#include "ICalcDisplay.h"
#include "IHistoryDisplay.h"
#include "Rational.h"
@ -10,12 +11,13 @@
// 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
// 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 {
class CHistoryCollector
{
public:
CHistoryCollector(ICalcDisplay *pCalcDisplay, std::shared_ptr<IHistoryDisplay> pHistoryDisplay, wchar_t decimalSymbol); // Can throw errors
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();
@ -30,24 +32,25 @@ public:
bool FOpndAddedToHistory();
void CompleteHistoryLine(std::wstring_view numStr);
void ClearHistoryLine(std::wstring_view errStr);
int AddCommand(_In_ const std::shared_ptr<IExpressionCommand> & spCommand);
int AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand);
void UpdateHistoryExpression(uint32_t radix, int32_t precision);
void SetDecimalSymbol(wchar_t decimalSymbol);
private:
std::shared_ptr<IHistoryDisplay> m_pHistoryDisplay;
ICalcDisplay *m_pCalcDisplay;
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
// 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_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
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
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<CalculatorVector <std::pair<std::wstring, int>>> m_spTokens;
std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> m_spTokens;
std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> m_spCommands;
private:

View file

@ -7,12 +7,16 @@
#include "../ExpressionCommandInterface.h"
// Callback interface to be implemented by the clients of CCalcEngine
class ICalcDisplay {
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<CalculatorVector<std::pair<std::wstring, int>>> const &tokens, _Inout_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &commands) = 0;
virtual void SetParenDisplayText(const std::wstring& pszText) = 0;
virtual void SetExpressionDisplay(
_Inout_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<CalculatorVector<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;

View file

@ -4,8 +4,12 @@
#pragma once
// Callback interface to be implemented by the clients of CCalcEngine if they require equation history
class IHistoryDisplay {
class IHistoryDisplay
{
public:
virtual ~IHistoryDisplay() {};
virtual unsigned int AddToHistory(_In_ std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const &tokens, _In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &commands, _In_ std::wstring_view result) = 0;
virtual ~IHistoryDisplay(){};
virtual unsigned int AddToHistory(
_In_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const& tokens,
_In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const& commands,
_In_ std::wstring_view result) = 0;
};

View file

@ -3,6 +3,7 @@
#pragma once
#include <vector>
#include "Ratpack/ratpak.h"
namespace CalcEngine

View file

@ -4,7 +4,8 @@
#pragma once
// This is expected to be in same order as IDM_HEX, IDM_DEC, IDM_OCT, IDM_BIN
enum eRADIX_TYPE {
enum eRADIX_TYPE
{
HEX_RADIX,
DEC_RADIX,
OCT_RADIX,

View file

@ -13,6 +13,7 @@ namespace CalcEngine::RationalMath
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);

View file

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
// CalcErr.h
//
// Defines the error codes thrown by ratpak and caught by Calculator
@ -24,7 +26,7 @@
// R - Reserved - not currently used for anything
//
// r - reserved portion of the facility code. Reserved for internal
// use. Used to indicate HRESULT values that are not status
// 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
@ -34,49 +36,50 @@
// 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
typedef int32_t ResultCode;
// CALC_E_DIVIDEBYZERO
//
// The current operation would require a divide by zero to complete
#define CALC_E_DIVIDEBYZERO ((DWORD)0x80000000)
#define CALC_E_DIVIDEBYZERO ((uint32_t)0x80000000)
// CALC_E_DOMAIN
//
// The given input is not within the domain of this function
#define CALC_E_DOMAIN ((DWORD)0x80000001)
#define CALC_E_DOMAIN ((uint32_t)0x80000001)
// CALC_E_INDEFINITE
//
// The result of this function is undefined
#define CALC_E_INDEFINITE ((DWORD)0x80000002)
#define CALC_E_INDEFINITE ((uint32_t)0x80000002)
// CALC_E_POSINFINITY
//
// The result of this function is Positive Infinity.
#define CALC_E_POSINFINITY ((DWORD)0x80000003)
#define CALC_E_POSINFINITY ((uint32_t)0x80000003)
// CALC_E_NEGINFINITY
//
// The result of this function is Negative Infinity
#define CALC_E_NEGINFINITY ((DWORD)0x80000004)
#define 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
#define CALC_E_INVALIDRANGE ((DWORD)0x80000006)
#define CALC_E_INVALIDRANGE ((uint32_t)0x80000006)
// CALC_E_OUTOFMEMORY
//
// There is not enough free memory to complete the requested function
#define CALC_E_OUTOFMEMORY ((DWORD)0x80000007)
#define CALC_E_OUTOFMEMORY ((uint32_t)0x80000007)
// CALC_E_OVERFLOW
//
// The result of this operation is an overflow
#define CALC_E_OVERFLOW ((DWORD)0x80000008)
#define CALC_E_OVERFLOW ((uint32_t)0x80000008)
// CALC_E_NORESULT
//
// The result of this operation is undefined
#define CALC_E_NORESULT ((DWORD)0x80000009)
#define CALC_E_NORESULT ((uint32_t)0x80000009)

View file

@ -2,22 +2,22 @@
// 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.
//
// 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 "pch.h"
#include "ratpak.h"
#include <cstring> // for memmove
void _mulnumx( PNUMBER *pa, PNUMBER b );
void _mulnumx(PNUMBER* pa, PNUMBER b);
//----------------------------------------------------------------------------
//
@ -34,30 +34,30 @@ void _mulnumx( PNUMBER *pa, PNUMBER b );
//
//----------------------------------------------------------------------------
void __inline mulnumx( PNUMBER *pa, PNUMBER b )
void __inline mulnumx(PNUMBER* pa, PNUMBER b)
{
if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 )
{
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.
long sign = (*pa)->sign;
DUPNUM(*pa,b);
(*pa)->sign *= sign;
}
}
else
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;
}
}
}
//----------------------------------------------------------------------------
@ -76,29 +76,29 @@ void __inline mulnumx( PNUMBER *pa, PNUMBER b )
//
//----------------------------------------------------------------------------
void _mulnumx( PNUMBER *pa, PNUMBER b )
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.
long iadigit=0; // Index of digit being used in the first number.
long 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.
long icdigit=0; // Index of digit being calculated in final result.
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;
a = *pa;
ibdigit = a->cdigit + b->cdigit - 1;
createnum( c, ibdigit + 1 );
createnum(c, ibdigit + 1);
c->cdigit = ibdigit;
c->sign = a->sign * b->sign;
@ -106,63 +106,61 @@ void _mulnumx( PNUMBER *pa, PNUMBER b )
ptra = a->mant;
ptrcoffset = c->mant;
for ( iadigit = a->cdigit; iadigit > 0; iadigit-- )
for (iadigit = a->cdigit; iadigit > 0; iadigit--)
{
da = *ptra++;
da = *ptra++;
ptrb = b->mant;
// Shift ptrc, and ptrcoffset, one for each digit
// Shift ptrc, and ptrcoffset, one for each digit
ptrc = ptrcoffset++;
for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- )
for (ibdigit = b->cdigit; ibdigit > 0; ibdigit--)
{
cy = 0;
mcy = (DWORDLONG)da * (*ptrb);
if ( mcy )
mcy = (uint64_t)da * (*ptrb);
if (mcy)
{
icdigit = 0;
if ( ibdigit == 1 && iadigit == 1 )
if (ibdigit == 1 && iadigit == 1)
{
c->cdigit++;
}
}
// If result is nonzero, or while result of carry is nonzero...
while ( mcy || cy )
while (mcy || cy)
{
// update carry from addition(s) and multiply.
cy += (TWO_MANTTYPE)ptrc[icdigit]+((DWORD)mcy&((DWORD)~BASEX));
// update result digit from
ptrc[icdigit++]=(MANTTYPE)((DWORD)cy&((DWORD)~BASEX));
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 )
{
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
}
destroynum( *pa );
*pa=c;
destroynum(*pa);
*pa = c;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: numpowlongx
// FUNCTION: numpowi32x
//
// ARGUMENTS: root as number power as long
// ARGUMENTS: root as number power as int32_t
// number.
//
// RETURN: None root is changed.
@ -174,34 +172,33 @@ void _mulnumx( PNUMBER *pa, PNUMBER b )
//
//-----------------------------------------------------------------------------
void numpowlongx( _Inout_ PNUMBER *proot, _In_ long power )
void numpowi32x(_Inout_ PNUMBER* proot, _In_ int32_t power)
{
PNUMBER lret = longtonum( 1, BASEX );
PNUMBER lret = i32tonum(1, BASEX);
// Once the power remaining is zero we are done.
while ( power > 0 )
{
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 );
}
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 );
mulnumx(proot, *proot);
// move the next bit of the power into place.
power >>= 1;
}
destroynum( *proot );
*proot=lret;
}
destroynum(*proot);
*proot = lret;
}
void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision);
void _divnumx(PNUMBER* pa, PNUMBER b, int32_t precision);
//----------------------------------------------------------------------------
//
@ -218,30 +215,30 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision);
//
//----------------------------------------------------------------------------
void __inline divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
void __inline divnumx(PNUMBER* pa, PNUMBER b, int32_t precision)
{
if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 )
{
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.
long sign = (*pa)->sign;
DUPNUM(*pa,b);
(*pa)->sign *= sign;
}
}
else
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;
}
}
}
//----------------------------------------------------------------------------
@ -257,111 +254,109 @@ void __inline divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
//
//----------------------------------------------------------------------------
void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
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 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.
// guesses one bit too far.
PNUMBER tmp = nullptr; // current guess being worked on for divide.
PNUMBER rem = nullptr; // remainder after applying guess.
long cdigits; // count of digits for answer.
MANTTYPE *ptrc; // ptrc is a pointer to the mantissa of c.
int32_t cdigits; // count of digits for answer.
MANTTYPE* ptrc; // ptrc is a pointer to the mantissa of c.
long thismax = precision + g_ratio; // set a maximum number of internal digits
// to shoot for in the divide.
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
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
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;
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 );
DUPNUM(rem, a);
rem->sign = b->sign;
rem->exp = b->cdigit + b->exp - rem->cdigit;
while ( cdigits++ < thismax && !zernum(rem) )
{
long digit = 0;
while (cdigits++ < thismax && !zernum(rem))
{
int32_t digit = 0;
*ptrc = 0;
while ( !lessnum( rem, b ) )
{
while (!lessnum(rem, b))
{
digit = 1;
DUPNUM( tmp, b );
destroynum( lasttmp );
lasttmp=longtonum( 0, BASEX );
while ( lessnum( tmp, rem ) )
{
destroynum( lasttmp );
DUPNUM(lasttmp,tmp);
addnum( &tmp, tmp, BASEX );
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 ) )
{
}
if (lessnum(rem, tmp))
{
// too far, back up...
destroynum( tmp );
destroynum(tmp);
digit /= 2;
tmp=lasttmp;
lasttmp= nullptr;
}
tmp = lasttmp;
lasttmp = nullptr;
}
tmp->sign *= -1;
addnum( &rem, tmp, BASEX );
destroynum( tmp );
destroynum( lasttmp );
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 (c->mant != ++ptrc)
{
memmove(c->mant, ptrc, (int)(cdigits * sizeof(MANTTYPE)));
}
if ( !cdigits )
{
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
// 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 )
{
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
}
}
destroynum( rem );
destroynum(rem);
destroynum( *pa );
*pa=c;
destroynum(*pa);
*pa = c;
}

File diff suppressed because it is too large Load diff

View file

@ -14,10 +14,8 @@
//
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
//-----------------------------------------------------------------------------
//
// FUNCTION: exprat
@ -41,63 +39,63 @@
//
//-----------------------------------------------------------------------------
void _exprat( PRAT *px, int32_t precision)
void _exprat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
addnum(&(pret->pp),num_one, BASEX);
addnum(&(pret->pq),num_one, BASEX);
DUPRAT(thisterm,pret);
addnum(&(pret->pp), num_one, BASEX);
addnum(&(pret->pq), num_one, BASEX);
DUPRAT(thisterm, pret);
n2=longtonum(0L, BASEX);
n2 = i32tonum(0L, BASEX);
do {
do
{
NEXTTERM(*px, INC(n2) DIVNUM(n2), precision);
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void exprat( PRAT *px, uint32_t radix, int32_t precision)
void exprat(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT pwr= nullptr;
PRAT pint= nullptr;
long intpwr;
PRAT pwr = nullptr;
PRAT pint = nullptr;
int32_t intpwr;
if ( rat_gt( *px, rat_max_exp, precision) || rat_lt( *px, rat_min_exp, precision) )
{
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 );
}
throw(CALC_E_DOMAIN);
}
DUPRAT(pwr,rat_exp);
DUPRAT(pint,*px);
DUPRAT(pwr, rat_exp);
DUPRAT(pint, *px);
intrat(&pint, radix, precision);
intpwr = rattolong(pint, radix, precision);
ratpowlong( &pwr, intpwr, precision);
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);
}
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 );
destroyrat(pwr);
destroyrat(pint);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: lograt, _lograt
@ -125,109 +123,108 @@ void exprat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void _lograt( PRAT *px, int32_t precision)
void _lograt(PRAT* px, int32_t precision)
{
CREATETAYLOR();
createrat(thisterm);
// sub one from x
(*px)->pq->sign *= -1;
addnum(&((*px)->pp),(*px)->pq, BASEX);
addnum(&((*px)->pp), (*px)->pq, BASEX);
(*px)->pq->sign *= -1;
DUPRAT(pret,*px);
DUPRAT(thisterm,*px);
DUPRAT(pret, *px);
DUPRAT(thisterm, *px);
n2=longtonum(1L, BASEX);
n2 = i32tonum(1L, BASEX);
(*px)->pp->sign *= -1;
do {
do
{
NEXTTERM(*px, MULNUM(n2) INC(n2) DIVNUM(n2), precision);
TRIMTOP(*px, precision);
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void lograt( PRAT *px, int32_t precision)
void lograt(PRAT* px, int32_t precision)
{
bool fneglog;
PRAT pwr = nullptr; // pwr is the large scaling factor.
PRAT offset = nullptr; // offset is the incremental scaling factor.
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 );
}
if (rat_le(*px, rat_zero, precision))
{
throw(CALC_E_DOMAIN);
}
// Get number > 1, for scaling
fneglog = rat_lt( *px, rat_one, precision);
if ( fneglog )
{
fneglog = rat_lt(*px, rat_one, precision);
if (fneglog)
{
// WARNING: This is equivalent to doing *px = 1 / *px
PNUMBER pnumtemp= nullptr;
PNUMBER pnumtemp = nullptr;
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 )
{
// Take advantage of px's base BASEX to scale quickly down to
if (LOGRAT2(*px) > 1)
{
// Take advantage of px's base BASEX to scale quickly down to
// a reasonable range.
long intpwr;
intpwr=LOGRAT2(*px)-1;
int32_t intpwr;
intpwr = LOGRAT2(*px) - 1;
(*px)->pq->exp += intpwr;
pwr=longtorat(intpwr*BASEXPWR);
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(pwr, rat_zero);
}
DUPRAT(offset,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);
}
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 )
{
if (fneglog)
{
(*px)->pp->sign *= -1;
}
}
destroyrat(offset);
destroyrat(pwr);
destroyrat(pwr);
}
void log10rat( PRAT *px, int32_t precision)
void log10rat(PRAT* px, int32_t precision)
{
lograt(px, precision);
@ -235,7 +232,7 @@ void log10rat( PRAT *px, int32_t precision)
}
//
// return if the given x is even number. The assumption here is its denominator is 1 and we are testing the numerator is
// 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)
{
@ -247,7 +244,7 @@ bool IsEven(PRAT x, uint32_t radix, int32_t precision)
fracrat(&tmp, radix, precision);
addrat(&tmp, tmp, precision);
subrat(&tmp, rat_one, precision);
if ( rat_lt( tmp, rat_zero, precision))
if (rat_lt(tmp, rat_zero, precision))
{
bRet = true;
}
@ -270,7 +267,7 @@ bool IsEven(PRAT x, uint32_t radix, int32_t precision)
//
//
//---------------------------------------------------------------------------
void powrat(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
void powrat(PRAT* px, 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))
@ -297,19 +294,19 @@ void powrat(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
}
}
void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
void powratNumeratorDenominator(PRAT* px, 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(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 ratpowlong
// 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
@ -318,7 +315,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
// 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))
@ -341,7 +338,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
PRAT originalResult = nullptr;
DUPRAT(originalResult, pxPow);
powratcomp(&originalResult, oneoveryDenom, radix, precision);
// ##################################
// Round the originalResult to roundedResult
// ##################################
@ -375,7 +372,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
else
{
DUPRAT(*px, originalResult);
}
}
destroyrat(oneoveryDenom);
destroyrat(originalResult);
@ -406,84 +403,82 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
//
//
//---------------------------------------------------------------------------
void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
void powratcomp(PRAT* px, PRAT y, uint32_t radix, int32_t precision)
{
long sign = ((*px)->pp->sign * (*px)->pq->sign);
int32_t sign = SIGN(*px);
// Take the absolute value
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if ( zerrat( *px ) )
{
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
if (rat_lt(y, rat_zero, precision))
{
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);
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);
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 ratpowlong deal with it.
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;
long inty;
DUPRAT(iy,y);
int32_t inty;
DUPRAT(iy, y);
subrat(&iy, podd, precision);
inty = rattolong(iy, radix, precision);
inty = rattoi32(iy, radix, precision);
PRAT plnx = nullptr;
DUPRAT(plnx,*px);
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) )
{
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);
ratpowlong(px, inty, precision);
if ( ( inty & 1 ) == 0 )
{
sign=1;
}
destroyrat(iy);
throw(CALC_E_DOMAIN);
}
else
destroyrat(plnx);
ratpowi32(px, inty, precision);
if ((inty & 1) == 0)
{
sign = 1;
}
destroyrat(iy);
}
else
{
// power is a fraction
if ( sign == -1 )
{
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.
@ -491,9 +486,9 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
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(pNumerator, rat_zero); // pNumerator->pq is 1 one
DUPRAT(pDenominator, rat_zero); // pDenominator->pq is 1 one
DUPNUM(pNumerator->pp, y->pp);
@ -502,39 +497,39 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
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;
}
{
fBadExponent = true;
}
if (IsEven(pNumerator, radix, precision)) // numerator is still even
{
{
sign = 1;
}
}
destroyrat(pNumerator);
destroyrat(pDenominator);
if (fBadExponent)
{
throw( CALC_E_DOMAIN );
}
}
else
{
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);
}
destroyrat(podd);
}
destroyrat(pxint);
}
(*px)->pp->sign *= sign;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
@ -13,11 +13,9 @@
// Contains fact(orial) and supporting _gamma functions.
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
#define ABSRAT(x) (((x)->pp->sign=1),((x)->pq->sign=1))
#define ABSRAT(x) (((x)->pp->sign = 1), ((x)->pq->sign = 1))
#define NEGATE(x) ((x)->pp->sign *= -1)
//-----------------------------------------------------------------------------
@ -56,125 +54,124 @@
//
//-----------------------------------------------------------------------------
void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
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;
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;
PRAT ratprec = nullptr;
PRAT ratRadix = nullptr;
long oldprec;
int32_t oldprec;
// Set up constants and initial conditions
oldprec = precision;
ratprec = longtorat( oldprec );
ratprec = i32torat(oldprec);
// Find the best 'A' for convergence to the required precision.
a=longtorat( radix );
a = i32torat(radix);
lograt(&a, precision);
mulrat(&a, ratprec, precision);
// Really is -ln(n)+1, but -ln(n) will be < 1
// 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);
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=longtorat( 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);
ratRadix = longtorat(radix);
DUPRAT(tmp,ratRadix);
lograt( &tmp, precision);
subrat( &term, tmp, precision);
precision += rattolong( 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 = longtonum( 0L, BASEX );
DUPRAT(mpy,a);
powratcomp(&mpy,*pn, radix, 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);
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);
DUPRAT(a2, a);
mulrat(&a2, a, precision);
// sum=(1/n)-(a/(n+1))
DUPRAT(sum,rat_one);
DUPRAT(sum, rat_one);
divrat(&sum, *pn, precision);
DUPRAT(tmp,*pn);
DUPRAT(tmp, *pn);
addrat(&tmp, rat_one, precision);
DUPRAT(term,a);
DUPRAT(term, a);
divrat(&term, tmp, precision);
subrat(&sum, term, precision);
DUPRAT(err,ratRadix);
DUPRAT(err, ratRadix);
NEGATE(ratprec);
powratcomp(&err,ratprec, radix, precision);
powratcomp(&err, ratprec, radix, precision);
divrat(&err, ratRadix, precision);
// Just get something not tiny in term
DUPRAT(term, rat_two );
DUPRAT(term, rat_two);
// Loop until precision is reached, or asked to halt.
while ( !zerrat( term ) && rat_gt( term, err, precision) )
{
while (!zerrat(term) && rat_gt(term, err, precision))
{
addrat(pn, rat_two, precision);
// WARNING: mixing numbers and rationals here.
// WARNING: mixing numbers and rationals here.
// for speed and efficiency.
INC(count);
mulnumx(&(factorial->pp),count);
mulnumx(&(factorial->pp), count);
INC(count)
mulnumx(&(factorial->pp),count);
mulnumx(&(factorial->pp), count);
divrat(&factorial, a2, precision);
DUPRAT(tmp,*pn);
addrat( &tmp, rat_one, 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);
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);
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);
mulrat(&sum, mpy, precision);
// And cleanup
precision = oldprec;
destroyrat(ratprec);
@ -189,70 +186,67 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
destroyrat(factorial);
destroyrat(*pn);
DUPRAT(*pn,sum);
DUPRAT(*pn, sum);
destroyrat(sum);
}
void factrat( PRAT *px, uint32_t radix, int32_t precision)
void factrat(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) )
{
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);
DUPRAT(fact, rat_one);
DUPRAT(neg_rat_one, rat_one);
neg_rat_one->pp->sign *= -1;
DUPRAT( frac, *px );
fracrat( &frac, radix, precision);
DUPRAT(frac, *px);
fracrat(&frac, radix, precision);
// Check for negative integers and throw an error.
if ( ( zerrat(frac) || ( LOGRATRADIX(frac) <= -precision) ) &&
( (*px)->pp->sign * (*px)->pq->sign == -1 ) )
{
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);
}
}
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);
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);
}
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);
}
if (rat_neq(*px, rat_zero, precision))
{
addrat(px, rat_one, precision);
_gamma(px, radix, precision);
mulrat(px, fact, precision);
}
else
{
DUPRAT(*px,fact);
}
{
DUPRAT(*px, fact);
}
destroyrat(fact);
destroyrat(frac);
destroyrat(neg_rat_one);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
@ -15,29 +15,25 @@
// Special Information
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
void ascalerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, int32_t precision)
void ascalerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, int32_t precision)
{
switch ( angletype )
{
switch (angletype)
{
case ANGLE_RAD:
break;
case ANGLE_DEG:
divrat( pa, two_pi, precision);
mulrat( pa, rat_360, precision);
divrat(pa, two_pi, precision);
mulrat(pa, rat_360, precision);
break;
case ANGLE_GRAD:
divrat( pa, two_pi, precision);
mulrat( pa, rat_400, precision);
divrat(pa, two_pi, precision);
mulrat(pa, rat_400, precision);
break;
}
}
}
//-----------------------------------------------------------------------------
//
// FUNCTION: asinrat, _asinrat
@ -65,88 +61,83 @@ void ascalerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, int32_t precision)
//
//-----------------------------------------------------------------------------
void _asinrat( PRAT *px, int32_t precision)
void _asinrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
DUPRAT(pret,*px);
DUPRAT(thisterm,*px);
DUPNUM(n2,num_one);
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) );
{
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
void asinanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
asinrat( pa, radix, precision);
ascalerat( pa, angletype, precision);
asinrat(pa, radix, precision);
ascalerat(pa, angletype, precision);
}
void asinrat( PRAT *px, uint32_t radix, int32_t precision)
void asinrat(PRAT* px, uint32_t radix, int32_t precision)
{
long sgn;
PRAT pret= nullptr;
PRAT phack= nullptr;
sgn = (*px)->pp->sign* (*px)->pq->sign;
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);
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) )
{
if (rat_le(phack, rat_smallest, precision) && rat_ge(phack, rat_negsmallest, precision))
{
destroyrat(phack);
DUPRAT( *px, pi_over_two );
}
DUPRAT(*px, pi_over_two);
}
else
{
{
destroyrat(phack);
if ( rat_gt( *px, pt_eight_five, precision) )
if (rat_gt(*px, pt_eight_five, precision))
{
if (rat_gt(*px, rat_one, precision))
{
if ( rat_gt( *px, rat_one, precision) )
subrat(px, rat_one, precision);
if (rat_gt(*px, rat_smallest, precision))
{
subrat( px, rat_one, precision);
if ( rat_gt( *px, rat_smallest, precision) )
{
throw( CALC_E_DOMAIN );
}
else
{
DUPRAT(*px,rat_one);
}
throw(CALC_E_DOMAIN);
}
DUPRAT(pret,*px);
mulrat( px, pret, precision);
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);
addrat(px, rat_one, precision);
rootrat(px, rat_two, radix, precision);
_asinrat(px, precision);
(*px)->pp->sign *= -1;
addrat( px, pi_over_two, precision);
addrat(px, pi_over_two, precision);
destroyrat(pret);
}
else
{
_asinrat( px, precision);
}
}
else
{
_asinrat(px, precision);
}
}
(*px)->pp->sign = sgn;
(*px)->pq->sign = 1;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: acosrat, _acosrat
@ -173,62 +164,58 @@ void asinrat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void acosanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
void acosanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
acosrat( pa, radix, precision);
ascalerat( pa, angletype, precision);
acosrat(pa, radix, precision);
ascalerat(pa, angletype, precision);
}
void _acosrat( PRAT *px, int32_t precision)
void _acosrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
createrat(thisterm);
thisterm->pp=longtonum( 1L, BASEX );
thisterm->pq=longtonum( 1L, BASEX );
createrat(thisterm);
thisterm->pp = i32tonum(1L, BASEX);
thisterm->pq = i32tonum(1L, BASEX);
DUPNUM(n2,num_one);
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) );
{
NEXTTERM(xx, MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void acosrat( PRAT *px, uint32_t radix, int32_t precision)
void acosrat(PRAT* px, uint32_t radix, int32_t precision)
{
long sgn;
sgn = (*px)->pp->sign*(*px)->pq->sign;
int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if ( rat_equ( *px, rat_one, precision) )
if (rat_equ(*px, rat_one, precision))
{
if (sgn == -1)
{
if ( sgn == -1 )
{
DUPRAT(*px,pi);
}
else
{
DUPRAT( *px, rat_zero );
}
DUPRAT(*px, pi);
}
else
else
{
DUPRAT(*px, rat_zero);
}
}
else
{
(*px)->pp->sign = sgn;
asinrat( px, radix, precision);
asinrat(px, radix, precision);
(*px)->pp->sign *= -1;
addrat(px, pi_over_two, precision);
}
}
}
//-----------------------------------------------------------------------------
@ -262,81 +249,79 @@ void acosrat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void atananglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
void atananglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
atanrat( pa, radix, precision);
ascalerat( pa, angletype, precision);
atanrat(pa, radix, precision);
ascalerat(pa, angletype, precision);
}
void _atanrat( PRAT *px, int32_t precision)
void _atanrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
DUPRAT(pret,*px);
DUPRAT(thisterm,*px);
DUPRAT(pret, *px);
DUPRAT(thisterm, *px);
DUPNUM(n2,num_one);
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) );
do
{
NEXTTERM(xx, MULNUM(n2) INC(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void atanrat( PRAT *px, uint32_t radix, int32_t precision)
void atanrat(PRAT* px, uint32_t radix, int32_t precision)
{
long sgn;
PRAT tmpx= nullptr;
sgn = (*px)->pp->sign * (*px)->pq->sign;
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), pt_eight_five, precision))
{
if (rat_gt((*px), rat_two, precision))
{
if ( rat_gt( (*px), rat_two, precision) )
{
(*px)->pp->sign = sgn;
(*px)->pq->sign = 1;
DUPRAT(tmpx,rat_one);
DUPRAT(tmpx, rat_one);
divrat(&tmpx, (*px), precision);
_atanrat(&tmpx, precision);
tmpx->pp->sign = sgn;
tmpx->pq->sign = 1;
DUPRAT(*px,pi_over_two);
DUPRAT(*px, pi_over_two);
subrat(px, tmpx, precision);
destroyrat( tmpx );
}
else
{
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);
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);
}
_atanrat(px, precision);
}
if (rat_gt(*px, pi_over_two, precision))
{
subrat(px, pi, precision);
}
}

View file

@ -16,11 +16,8 @@
//
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
//-----------------------------------------------------------------------------
//
// FUNCTION: asinhrat
@ -50,47 +47,44 @@
//
//-----------------------------------------------------------------------------
void asinhrat( PRAT *px, uint32_t radix, int32_t precision)
void asinhrat(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT neg_pt_eight_five = nullptr;
DUPRAT(neg_pt_eight_five,pt_eight_five);
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) )
{
if (rat_gt(*px, pt_eight_five, precision) || rat_lt(*px, neg_pt_eight_five, precision))
{
PRAT ptmp = nullptr;
DUPRAT(ptmp,(*px));
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));
DUPRAT(pret, (*px));
DUPRAT(thisterm, (*px));
DUPNUM(n2,num_one);
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) );
{
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
@ -99,7 +93,7 @@ void asinhrat( PRAT *px, uint32_t radix, int32_t precision)
// hyperbolic cose of
// RETURN: acosh of x in PRAT form.
//
// EXPLANATION: This uses
// EXPLANATION: This uses
//
// acosh(x)=ln(x+sqrt(x^2-1))
//
@ -107,24 +101,24 @@ void asinhrat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void acoshrat( PRAT *px, uint32_t radix, int32_t precision)
void acoshrat(PRAT* px, uint32_t radix, int32_t precision)
{
if ( rat_lt( *px, rat_one, precision) )
{
if (rat_lt(*px, rat_one, precision))
{
throw CALC_E_DOMAIN;
}
}
else
{
{
PRAT ptmp = nullptr;
DUPRAT(ptmp,(*px));
DUPRAT(ptmp, (*px));
mulrat(&ptmp, *px, precision);
subrat(&ptmp, rat_one, precision);
rootrat(&ptmp,rat_two, radix, precision);
rootrat(&ptmp, rat_two, radix, precision);
addrat(px, ptmp, precision);
lograt(px, precision);
destroyrat(ptmp);
}
}
}
//-----------------------------------------------------------------------------
@ -144,11 +138,11 @@ void acoshrat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void atanhrat( PRAT *px, int32_t precision)
void atanhrat(PRAT* px, int32_t precision)
{
PRAT ptmp = nullptr;
DUPRAT(ptmp,(*px));
DUPRAT(ptmp, (*px));
subrat(&ptmp, rat_one, precision);
addrat(px, rat_one, precision);
divrat(px, ptmp, precision);
@ -157,4 +151,3 @@ void atanhrat( PRAT *px, int32_t precision)
divrat(px, rat_two, precision);
destroyrat(ptmp);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//---------------------------------------------------------------------------
@ -13,83 +13,82 @@
// Contains routines for and, or, xor, not and other support
//
//---------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
using namespace std;
void lshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
void lshrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision)
{
PRAT pwr= nullptr;
long intb;
PRAT pwr = nullptr;
int32_t intb;
intrat(pa, radix, precision);
if ( !zernum( (*pa)->pp ) )
{
if (!zernum((*pa)->pp))
{
// If input is zero we're done.
if ( rat_gt( b, rat_max_exp, precision) )
{
if (rat_gt(b, rat_max_exp, precision))
{
// Don't attempt lsh of anything big
throw( CALC_E_DOMAIN );
}
intb = rattolong(b, radix, precision);
DUPRAT(pwr,rat_two);
ratpowlong(&pwr, intb, precision);
throw(CALC_E_DOMAIN);
}
intb = rattoi32(b, radix, precision);
DUPRAT(pwr, rat_two);
ratpowi32(&pwr, intb, precision);
mulrat(pa, pwr, precision);
destroyrat(pwr);
}
}
}
void rshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
void rshrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision)
{
PRAT pwr= nullptr;
long intb;
PRAT pwr = nullptr;
int32_t intb;
intrat(pa, radix, precision);
if ( !zernum( (*pa)->pp ) )
{
if (!zernum((*pa)->pp))
{
// If input is zero we're done.
if ( rat_lt( b, rat_min_exp, precision) )
{
if (rat_lt(b, rat_min_exp, precision))
{
// Don't attempt rsh of anything big and negative.
throw( CALC_E_DOMAIN );
}
intb = rattolong(b, radix, precision);
DUPRAT(pwr,rat_two);
ratpowlong(&pwr, intb, precision);
throw(CALC_E_DOMAIN);
}
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 );
void boolrat(PRAT* pa, PRAT b, int func, uint32_t radix, int32_t precision);
void boolnum(PNUMBER* pa, PNUMBER b, int func);
enum {
enum
{
FUNC_AND,
FUNC_OR,
FUNC_XOR
} BOOL_FUNCS;
void andrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
void andrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision)
{
boolrat( pa, b, FUNC_AND, radix, precision);
boolrat(pa, b, FUNC_AND, radix, precision);
}
void orrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
void orrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision)
{
boolrat( pa, b, FUNC_OR, radix, precision);
boolrat(pa, b, FUNC_OR, radix, precision);
}
void xorrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
void xorrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision)
{
boolrat( pa, b, FUNC_XOR, radix, precision);
boolrat(pa, b, FUNC_XOR, radix, precision);
}
//---------------------------------------------------------------------------
@ -104,15 +103,15 @@ void xorrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
//
//---------------------------------------------------------------------------
void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision)
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);
PRAT tmp = nullptr;
intrat(pa, radix, precision);
DUPRAT(tmp, b);
intrat(&tmp, radix, precision);
boolnum( &((*pa)->pp), tmp->pp, func );
boolnum(&((*pa)->pp), tmp->pp, func);
destroyrat(tmp);
}
@ -130,39 +129,34 @@ void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision)
//
//---------------------------------------------------------------------------
void boolnum( PNUMBER *pa, PNUMBER b, int func )
void boolnum(PNUMBER* pa, PNUMBER b, int func)
{
PNUMBER c= nullptr;
PNUMBER a= nullptr;
MANTTYPE *pcha;
MANTTYPE *pchb;
MANTTYPE *pchc;
long cdigits;
long mexp;
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 );
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++ )
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)
{
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;
@ -172,15 +166,51 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func )
case FUNC_XOR:
*pchc++ = da ^ db;
break;
}
}
}
c->sign = a->sign;
while ( c->cdigit > 1 && *(--pchc) == 0 )
{
while (c->cdigit > 1 && *(--pchc) == 0)
{
c->cdigit--;
}
destroynum( *pa );
*pa=c;
}
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(PRAT* pa, 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);
}
//-----------------------------------------------------------------------------
@ -191,29 +221,38 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func )
//
// RETURN: None, changes pointer.
//
// DESCRIPTION: Does the rational equivalent of frac(*pa);
// 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( PRAT *pa, PRAT b )
void modrat(PRAT* pa, PRAT b)
{
PRAT tmp = nullptr;
// contrary to remrat(X, 0) returning 0, modrat(X, 0) must return X
if (zerrat(b))
{
return;
}
if ( zerrat( b ) )
{
throw CALC_E_INDEFINITE;
}
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.
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 );
destroyrat(tmp);
}

View file

@ -2,22 +2,23 @@
// 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
//
//
// 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 "pch.h"
#include <list>
#include <cstring> // for memmove
#include "ratpak.h"
using namespace std;
@ -40,141 +41,132 @@ using namespace std;
//
//----------------------------------------------------------------------------
void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix);
void _addnum(PNUMBER* pa, PNUMBER b, uint32_t radix);
void __inline addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
void __inline addnum(PNUMBER* pa, 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);
}
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)
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.
long cdigits; // cdigits is the max count of the digits results
// used as a counter.
long 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'
long fcompla = 0; // fcompla is a flag to signal a is negative.
long fcomplb = 0; // fcomplb is a flag to signal b is negative.
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;
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 );
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 );
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 )
{
if (a->sign != b->sign)
{
cy = 1;
fcompla = ( a->sign == -1 );
fcomplb = ( b->sign == -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++ )
{
// 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 );
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 );
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;
}
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) )
{
if (cy && !(fcompla || fcomplb))
{
*pchc++ = cy;
c->cdigit++;
}
}
// Compute sign of result
if ( !(fcompla || fcomplb) )
{
if (!(fcompla || fcomplb))
{
c->sign = a->sign;
}
}
else
{
if (cy)
{
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
{
// 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-- )
{
for ((cdigits = c->cdigit), (pchc = c->mant); cdigits > 0; cdigits--)
{
cy = (MANTTYPE)radix - (MANTTYPE)1 - *pchc + cy;
*pchc++ = (MANTTYPE)( cy % (MANTTYPE)radix);
*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 )
{
while (c->cdigit > 1 && *(--pchc) == 0)
{
c->cdigit--;
}
destroynum( *pa );
*pa=c;
}
destroynum(*pa);
*pa = c;
}
//----------------------------------------------------------------------------
@ -192,52 +184,52 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
//
//----------------------------------------------------------------------------
void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix);
void _mulnum(PNUMBER* pa, PNUMBER b, uint32_t radix);
void __inline mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
void __inline mulnum(PNUMBER* pa, 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);
}
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.
long sign = (*pa)->sign;
DUPNUM(*pa,b);
{ // 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.
{ // But we do have to set the sign.
(*pa)->sign *= b->sign;
}
}
}
void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
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.
long iadigit = 0; // Index of digit being used in the first number.
long 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.
long icdigit = 0; // Index of digit being calculated in final result.
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;
a = *pa;
ibdigit = a->cdigit + b->cdigit - 1;
createnum( c, ibdigit + 1 );
createnum(c, ibdigit + 1);
c->cdigit = ibdigit;
c->sign = a->sign * b->sign;
@ -245,58 +237,56 @@ void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
pcha = a->mant;
pchcoffset = c->mant;
for ( iadigit = a->cdigit; iadigit > 0; iadigit-- )
{
da = *pcha++;
for (iadigit = a->cdigit; iadigit > 0; iadigit--)
{
da = *pcha++;
pchb = b->mant;
// Shift pchc, and pchcoffset, one for each digit
// Shift pchc, and pchcoffset, one for each digit
pchc = pchcoffset++;
for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- )
{
for (ibdigit = b->cdigit; ibdigit > 0; ibdigit--)
{
cy = 0;
mcy = (TWO_MANTTYPE)da * *pchb;
if ( mcy )
{
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 )
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);
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 )
{
while (c->cdigit > 1 && c->mant[c->cdigit - 1] == 0)
{
c->cdigit--;
}
}
destroynum( *pa );
*pa=c;
destroynum(*pa);
*pa = c;
}
//----------------------------------------------------------------------------
//
// FUNCTION: remnum
@ -312,55 +302,53 @@ void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
//
//----------------------------------------------------------------------------
void remnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
void remnum(PNUMBER* pa, 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 ) )
while (!lessnum(*pa, b))
{
DUPNUM(tmp, b);
if (lessnum(tmp, *pa))
{
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) )
{
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=longtonum( 0, radix);
destroynum(lasttmp);
lasttmp = i32tonum(0, radix);
while ( lessnum( tmp, *pa ) )
{
DUPNUM( lasttmp, tmp );
addnum( &tmp, tmp, radix);
}
while (lessnum(tmp, *pa))
{
DUPNUM(lasttmp, tmp);
addnum(&tmp, tmp, radix);
}
if ( lessnum( *pa, tmp ) )
{
if (lessnum(*pa, tmp))
{
// too far, back up...
destroynum( tmp );
tmp=lasttmp;
lasttmp= nullptr;
}
destroynum(tmp);
tmp = lasttmp;
lasttmp = nullptr;
}
// Subtract the working remainder from the remainder holder.
tmp->sign = -1*(*pa)->sign;
addnum( pa, tmp, radix);
tmp->sign = -1 * (*pa)->sign;
addnum(pa, tmp, radix);
destroynum( tmp );
destroynum( lasttmp );
}
destroynum(tmp);
destroynum(lasttmp);
}
}
//---------------------------------------------------------------------------
//
// FUNCTION: divnum
@ -375,26 +363,26 @@ void remnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
//
//---------------------------------------------------------------------------
void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision);
void _divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision);
void __inline divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
void __inline divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision)
{
if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 )
{
if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0)
{
// b is not one
_divnum( pa, b, radix, precision);
}
_divnum(pa, b, radix, precision);
}
else
{ // But we do have to set the sign.
{ // But we do have to set the sign.
(*pa)->sign *= b->sign;
}
}
}
void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
void _divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision)
{
PNUMBER a = *pa;
long thismax = precision + 2;
int32_t thismax = precision + 2;
if (thismax < a->cdigit)
{
thismax = a->cdigit;
@ -410,7 +398,7 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
c->exp = (a->cdigit + a->exp) - (b->cdigit + b->exp) + 1;
c->sign = a->sign * b->sign;
MANTTYPE *ptrc = c->mant + thismax;
MANTTYPE* ptrc = c->mant + thismax;
PNUMBER rem = nullptr;
PNUMBER tmp = nullptr;
DUPNUM(rem, a);
@ -418,10 +406,10 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
tmp->sign = a->sign;
rem->exp = b->cdigit + b->exp - rem->cdigit;
// Build a table of multiplications of the divisor, this is quicker for
// Build a table of multiplications of the divisor, this is quicker for
// more than radix 'digits'
list<PNUMBER> numberList{ longtonum(0L, radix) };
for (unsigned long i = 1; i < radix; i++)
list<PNUMBER> numberList{ i32tonum(0L, radix) };
for (uint32_t i = 1; i < radix; i++)
{
PNUMBER newValue = nullptr;
DUPNUM(newValue, numberList.front());
@ -431,8 +419,8 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
}
destroynum(tmp);
long digit;
long cdigits = 0;
int32_t digit;
int32_t cdigits = 0;
while (cdigits++ < thismax && !zernum(rem))
{
digit = radix - 1;
@ -488,7 +476,6 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
*pa = c;
}
//---------------------------------------------------------------------------
//
// FUNCTION: equnum
@ -502,58 +489,56 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
//
//---------------------------------------------------------------------------
bool equnum( PNUMBER a, PNUMBER b )
bool equnum(PNUMBER a, PNUMBER b)
{
long diff;
MANTTYPE *pa;
MANTTYPE *pb;
long cdigits;
long ccdigits;
MANTTYPE da;
MANTTYPE db;
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 )
{
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 ( 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 );
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-- )
for (; cdigits > 0; cdigits--)
{
da = ((cdigits > (ccdigits - a->cdigit)) ? *pa-- : 0);
db = ((cdigits > (ccdigits - b->cdigit)) ? *pb-- : 0);
if (da != db)
{
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;
}
}
}
}
//---------------------------------------------------------------------------
@ -570,54 +555,51 @@ bool equnum( PNUMBER a, PNUMBER b )
//
//---------------------------------------------------------------------------
bool lessnum( PNUMBER a, PNUMBER b )
bool lessnum(PNUMBER a, PNUMBER b)
{
long diff;
MANTTYPE *pa;
MANTTYPE *pb;
long cdigits;
long ccdigits;
MANTTYPE da;
MANTTYPE db;
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 )
{
diff = (a->cdigit + a->exp) - (b->cdigit + b->exp);
if (diff < 0)
{
// The exponent of a is less than b
return true;
}
}
else
{
if (diff > 0)
{
if ( diff > 0 )
{
return false;
}
}
else
{
{
pa = a->mant;
pb = b->mant;
pa += a->cdigit - 1;
pb += b->cdigit - 1;
cdigits = max( a->cdigit, b->cdigit );
cdigits = max(a->cdigit, b->cdigit);
ccdigits = cdigits;
for ( ;cdigits > 0; cdigits-- )
for (; cdigits > 0; cdigits--)
{
da = ((cdigits > (ccdigits - a->cdigit)) ? *pa-- : 0);
db = ((cdigits > (ccdigits - b->cdigit)) ? *pb-- : 0);
diff = da - db;
if (diff)
{
da = ( (cdigits > (ccdigits - a->cdigit) ) ?
*pa-- : 0 );
db = ( (cdigits > (ccdigits - b->cdigit) ) ?
*pb-- : 0 );
diff = da-db;
if ( diff )
{
return( diff < 0 );
}
return (diff < 0);
}
}
// In this case, they are equal.
return false;
}
}
}
}
//----------------------------------------------------------------------------
@ -632,24 +614,24 @@ bool lessnum( PNUMBER a, PNUMBER b )
//
//----------------------------------------------------------------------------
bool zernum( PNUMBER a )
bool zernum(PNUMBER a)
{
long length;
MANTTYPE *pcha;
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
// loop over all the digits until you find a nonzero or until you run
// out of digits
while ( length-- > 0 )
while (length-- > 0)
{
if (*pcha++)
{
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;
}

View file

@ -16,7 +16,6 @@
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
using namespace std;
@ -38,25 +37,25 @@ using namespace std;
//
//-----------------------------------------------------------------------------
void gcdrat( PRAT *pa, int32_t precision)
void gcdrat(PRAT* pa, int32_t precision)
{
PNUMBER pgcd= nullptr;
PRAT a= nullptr;
PNUMBER pgcd = nullptr;
PRAT a = nullptr;
a=*pa;
pgcd = gcd( a->pp, a->pq );
a = *pa;
pgcd = gcd(a->pp, a->pq);
if ( !zernum( pgcd ) )
{
divnumx( &(a->pp), pgcd, precision);
divnumx( &(a->pq), pgcd, precision);
}
if (!zernum(pgcd))
{
divnumx(&(a->pp), pgcd, precision);
divnumx(&(a->pq), pgcd, precision);
}
destroynum( pgcd );
*pa=a;
destroynum(pgcd);
*pa = a;
RENORMALIZE(*pa);
RENORMALIZE(*pa);
}
//-----------------------------------------------------------------------------
@ -71,18 +70,18 @@ void gcdrat( PRAT *pa, int32_t precision)
//
//-----------------------------------------------------------------------------
void fracrat( PRAT *pa , uint32_t radix, int32_t precision)
void fracrat(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 ) )
if (!zernum((*pa)->pp) && !equnum((*pa)->pq, num_one))
{
flatrat(*pa, radix, precision);
}
remnum( &((*pa)->pp), (*pa)->pq, BASEX );
remnum(&((*pa)->pp), (*pa)->pq, BASEX);
//Get *pa back in the integer over integer form.
// Get *pa back in the integer over integer form.
RENORMALIZE(*pa);
}
@ -99,26 +98,25 @@ void fracrat( PRAT *pa , uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void mulrat( PRAT *pa, PRAT b, int32_t precision)
{
void mulrat(PRAT* pa, 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 );
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 );
}
DUPNUM(((*pa)->pq), num_one);
}
#ifdef MULGCD
gcdrat( pa );
gcdrat(pa);
#endif
}
//-----------------------------------------------------------------------------
@ -134,44 +132,41 @@ void mulrat( PRAT *pa, PRAT b, int32_t precision)
//
//-----------------------------------------------------------------------------
void divrat( PRAT *pa, PRAT b, int32_t precision)
void divrat(PRAT* pa, PRAT b, int32_t precision)
{
if ( !zernum( (*pa)->pp ) )
{
if (!zernum((*pa)->pp))
{
// Only do the divide if the top isn't zero.
mulnumx( &((*pa)->pp), b->pq );
mulnumx( &((*pa)->pq), b->pp );
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
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 (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 );
}
throw(CALC_E_INDEFINITE);
}
else
{
// 0/x make a unique 0.
DUPNUM(((*pa)->pq), num_one);
}
}
#ifdef DIVGCD
gcdrat( pa );
#endif
gcdrat(pa);
#endif
}
//-----------------------------------------------------------------------------
@ -187,11 +182,11 @@ void divrat( PRAT *pa, PRAT b, int32_t precision)
//
//-----------------------------------------------------------------------------
void subrat( PRAT *pa, PRAT b, int32_t precision)
void subrat(PRAT* pa, PRAT b, int32_t precision)
{
b->pp->sign *= -1;
addrat( pa, b, precision);
addrat(pa, b, precision);
b->pp->sign *= -1;
}
@ -208,48 +203,45 @@ void subrat( PRAT *pa, PRAT b, int32_t precision)
//
//-----------------------------------------------------------------------------
void addrat( PRAT *pa, PRAT b, int32_t precision)
void addrat(PRAT* pa, PRAT b, int32_t precision)
{
PNUMBER bot= nullptr;
PNUMBER bot = nullptr;
if ( equnum( (*pa)->pq, b->pq ) )
{
// Very special case, q's match.,
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
// 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)->pp->sign *= (*pa)->pq->sign;
(*pa)->pq->sign = 1;
b->pp->sign *= b->pq->sign;
b->pp->sign *= b->pq->sign;
b->pq->sign = 1;
addnum( &((*pa)->pp), b->pp, BASEX );
}
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 );
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)->pp->sign *= (*pa)->pq->sign;
(*pa)->pq->sign = 1;
}
}
#ifdef ADDGCD
gcdrat( pa );
#endif
gcdrat(pa);
#endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: rootrat
@ -263,11 +255,11 @@ void addrat( PRAT *pa, PRAT b, int32_t precision)
//
//-----------------------------------------------------------------------------
void rootrat( PRAT *py, PRAT n, uint32_t radix, int32_t precision)
{
void rootrat(PRAT* py, PRAT n, uint32_t radix, int32_t precision)
{
// Initialize 1/n
PRAT oneovern= nullptr;
DUPRAT(oneovern,rat_one);
PRAT oneovern = nullptr;
DUPRAT(oneovern, rat_one);
divrat(&oneovern, n, precision);
powrat(py, oneovern, radix, precision);
@ -275,7 +267,6 @@ void rootrat( PRAT *py, PRAT n, uint32_t radix, int32_t precision)
destroyrat(oneovern);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: zerrat
@ -289,10 +280,8 @@ void rootrat( PRAT *py, PRAT n, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
bool zerrat( PRAT a )
bool zerrat(PRAT a)
{
return( zernum(a->pp) );
return (zernum(a->pp));
}

File diff suppressed because it is too large Load diff

View file

@ -17,27 +17,33 @@
//
//-----------------------------------------------------------------------------
#include <algorithm>
#include <string>
#include "CalcErr.h"
#include <cstring> // for memmove
#include <sal.h> // for SAL
static constexpr uint32_t BASEXPWR = 31L;// Internal log2(BASEX)
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
// this to 2^32 after solving scaling problems with
// overflow detection esp. in mul
typedef unsigned long MANTTYPE;
typedef unsigned __int64 TWO_MANTTYPE;
typedef uint32_t MANTTYPE;
typedef uint64_t TWO_MANTTYPE;
enum eNUMOBJ_FMT {
FMT_FLOAT, // returns floating point, or exponential if number is too big
FMT_SCIENTIFIC, // always returns scientific notation
FMT_ENGINEERING // always returns engineering notation such that exponent is a multiple of 3
enum eNUMOBJ_FMT
{
FMT_FLOAT, // returns floating point, or exponential if number is too big
FMT_SCIENTIFIC, // always returns scientific notation
FMT_ENGINEERING // always returns engineering notation such that exponent is a multiple of 3
};
enum eANGLE_TYPE {
ANGLE_DEG, // Calculate trig using 360 degrees per revolution
ANGLE_RAD, // Calculate trig using 2 pi radians per revolution
ANGLE_GRAD // Calculate trig using 400 gradients per revolution
enum eANGLE_TYPE
{
ANGLE_DEG, // Calculate trig using 360 degrees per revolution
ANGLE_RAD, // Calculate trig using 2 pi radians per revolution
ANGLE_GRAD // Calculate trig using 400 gradients per revolution
};
@ -51,21 +57,20 @@ typedef enum eANGLE_TYPE ANGLE_TYPE;
//-----------------------------------------------------------------------------
#pragma warning(push)
#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
#pragma warning(disable : 4200) // nonstandard extension used : zero-sized array in struct/union
typedef struct _number
{
long sign; // The sign of the mantissa, +1, or -1
long cdigit; // The number of digits, or what passes for digits in the
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.
long exp; // The offset of digits from the radix point
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.
// 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.
@ -74,10 +79,10 @@ typedef struct _number
//-----------------------------------------------------------------------------
typedef struct _rat
{
{
PNUMBER pp;
PNUMBER pq;
} RAT, *PRAT;
} RAT, *PRAT;
static constexpr uint32_t MAX_LONG_SIZE = 33; // Base 2 requires 32 'digits'
@ -127,28 +132,38 @@ extern PRAT rat_max_exp;
extern PRAT rat_min_exp;
extern PRAT rat_max_fact;
extern PRAT rat_min_fact;
extern PRAT rat_max_long;
extern PRAT rat_min_long;
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);
#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);
#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))
#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))
#define LOGNUM2(pnum) ((pnum)->cdigit + (pnum)->exp)
#define LOGRAT2(prat) (LOGNUM2((prat)->pp) - LOGNUM2((prat)->pq))
#if defined( DEBUG_RATPAK )
// 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.
@ -156,37 +171,39 @@ extern PRAT rat_min_long;
//
//-----------------------------------------------------------------------------
#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
#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
#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
//-----------------------------------------------------------------------------
@ -197,40 +214,47 @@ _destroynum(x),(x)=nullptr
//-----------------------------------------------------------------------------
// 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; \
#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 ) { \
long 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; \
} \
}
#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 ) { \
long 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 = min((x)->pp->exp,(x)->pq->exp);\
(x)->pp->exp -= trim;\
(x)->pq->exp -= trim;\
}
#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 ) )
#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))
//-----------------------------------------------------------------------------
//
@ -239,50 +263,55 @@ memmove( (x)->pp->mant, &((x)->pp->mant[trim]), sizeof(MANTTYPE)*((x)->pp->cdigi
//
//-----------------------------------------------------------------------------
#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=longtonum( 0L, BASEX ); \
pret->pq=longtonum( 0L, BASEX );
#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;
#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 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])
#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);
#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);
#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 )
#define NEXTTERM(p, d, precision) \
mulrat(&thisterm, p, precision); \
d addrat(&pret, thisterm, precision)
//-----------------------------------------------------------------------------
//
@ -292,9 +321,9 @@ memmove( (x)->pp->mant, &((x)->pp->mant[trim]), sizeof(MANTTYPE)*((x)->pp->cdigi
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.
// used to help decide when to stop calculating.
extern long g_ratio; // Internally calculated ratio of internal radix
extern int32_t g_ratio; // Internally calculated ratio of internal radix
//-----------------------------------------------------------------------------
//
@ -308,10 +337,10 @@ 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 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, int format, uint32_t radix, int32_t precision);
// returns a text representation of a PRAT
@ -321,136 +350,141 @@ 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 long numtolong(_In_ PNUMBER pnum, uint32_t radix );
extern long rattolong(_In_ PRAT prat, uint32_t radix, int32_t precision);
ULONGLONG rattoUlonglong(_In_ PRAT prat, uint32_t radix, int32_t precision);
extern PNUMBER _createnum(_In_ ULONG size ); // returns an empty number structure with size digits
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.
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 PRAT
StringToRat(bool mantissaIsNegative, std::wstring_view mantissa, bool exponentIsNegative, std::wstring_view exponent, uint32_t radix, int32_t precision);
extern PNUMBER longfactnum(long inlong, uint32_t radix);
extern PNUMBER longprodnum(long start, long stop, uint32_t radix);
extern PNUMBER longtonum(long inlong, uint32_t radix);
extern PNUMBER Ulongtonum(unsigned long inlong, uint32_t radix);
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(PNUMBER a, uint32_t radix);
// creates a empty/undefined rational representation (p/q)
extern PRAT _createrat( void );
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void acosanglerat(_Inout_ PRAT* px, ANGLE_TYPE 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);
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);
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void asinanglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void asinhrat( _Inout_ PRAT *px, 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);
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void atananglerat(_Inout_ PRAT* px, ANGLE_TYPE 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);
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);
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);
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);
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void cosanglerat(_Inout_ PRAT* px, ANGLE_TYPE 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);
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);
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);
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 void lograt(_Inout_ PRAT* px, int32_t precision);
extern PRAT longtorat( long inlong );
extern PRAT Ulongtorat( unsigned long inulong );
extern PRAT numtorat( _In_ PNUMBER pin, uint32_t radix);
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 );
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void sinanglerat(_Inout_ PRAT* px, ANGLE_TYPE 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);
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, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void tananglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void _dupnum(_In_ PNUMBER dest, _In_ PNUMBER src);
extern void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER* const src);
extern void _destroynum( _In_ PNUMBER pnum );
extern void _destroyrat( _In_ 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 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 numpowlong( _Inout_ PNUMBER *proot, long power, uint32_t radix, int32_t precision);
extern void numpowlongx( _Inout_ PNUMBER *proot, long 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 ratpowlong( _Inout_ PRAT *proot, long 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);
extern void _destroynum(_In_ PNUMBER pnum);
extern void _destroyrat(_In_ 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);

View file

@ -18,35 +18,48 @@
//
//----------------------------------------------------------------------------
#include "pch.h"
#include <string>
#include <cstring> // for memmove
#include <iostream> // for wostream
#include "ratpak.h"
using namespace std;
void _readconstants( void );
void _readconstants(void);
#if defined( GEN_CONST )
#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.c\n" ); \
fprintf( stderr, "NUMBER init_" #v "= {\n" ); \
_dumprawnum(v, wcout); \
fprintf( stderr, "};\n" )
#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 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 = longtonum(v, BASEX); DUMPRAWNUM(v); }
#define INIT_AND_DUMP_RAW_RAT_IF_NULL(r, v) if (r == nullptr) { r = longtorat(v); DUMPRAWRAT(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;
@ -58,51 +71,51 @@ static int cbitsofprecision = RATIO_FOR_DECIMAL * DECIMAL * CALC_DECIMAL_DIGITS_
#endif
bool g_ftrueinfinite = false; // Set to true if you don't want
// chopping internally
// precision used internally
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;
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 ulong
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 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_long= nullptr; // min signed long
PRAT rat_max_long= nullptr; // max signed long
PRAT rat_min_i32 = nullptr; // min signed i32
PRAT rat_max_i32 = nullptr; // max signed i32
//----------------------------------------------------------------------------
//
@ -119,20 +132,20 @@ PRAT rat_max_long= nullptr; // max signed long
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
// 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.
uint64_t limit = static_cast<uint64_t>(BASEX) / static_cast<uint64_t>(radix);
g_ratio = 0;
for (uint32_t digit = 1; digit < limit; digit *= radix )
for (uint32_t digit = 1; digit < limit; digit *= radix)
{
g_ratio++;
}
g_ratio += !g_ratio;
destroyrat(rat_nRadix);
rat_nRadix=longtorat( radix );
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))
@ -166,7 +179,7 @@ void ChangeConstants(uint32_t radix, int32_t precision)
INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_min_fact, -1000);
DUPRAT(rat_smallest, rat_nRadix);
ratpowlong(&rat_smallest, -precision, precision);
ratpowi32(&rat_smallest, -precision, precision);
DUPRAT(rat_negsmallest, rat_smallest);
rat_negsmallest->pp->sign = -1;
DUMPRAWRAT(rat_smallest);
@ -183,29 +196,29 @@ void ChangeConstants(uint32_t radix, int32_t precision)
if (pt_eight_five == nullptr)
{
createrat(pt_eight_five);
pt_eight_five->pp = longtonum(85L, BASEX);
pt_eight_five->pq = longtonum(100L, BASEX);
pt_eight_five->pp = i32tonum(85L, BASEX);
pt_eight_five->pq = i32tonum(100L, BASEX);
DUMPRAWRAT(pt_eight_five);
}
DUPRAT(rat_qword, rat_two);
numpowlong(&(rat_qword->pp), 64, BASEX, precision);
numpowi32(&(rat_qword->pp), 64, BASEX, precision);
subrat(&rat_qword, rat_one, precision);
DUMPRAWRAT(rat_qword);
DUPRAT(rat_dword, rat_two);
numpowlong(&(rat_dword->pp), 32, BASEX, precision);
numpowi32(&(rat_dword->pp), 32, BASEX, precision);
subrat(&rat_dword, rat_one, precision);
DUMPRAWRAT(rat_dword);
DUPRAT(rat_max_long, rat_two);
numpowlong(&(rat_max_long->pp), 31, BASEX, precision);
DUPRAT(rat_min_long, rat_max_long);
subrat(&rat_max_long, rat_one, precision); // rat_max_long = 2^31 -1
DUMPRAWRAT(rat_max_long);
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_long->pp->sign *= -1; // rat_min_long = -2^31
DUMPRAWRAT(rat_min_long);
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;
@ -213,9 +226,9 @@ void ChangeConstants(uint32_t radix, int32_t precision)
cbitsofprecision = g_ratio * radix * precision;
// Apparently when dividing 180 by pi, another (internal) digit of
// Apparently when dividing 180 by pi, another (internal) digit of
// precision is needed.
long extraPrecision = precision + g_ratio;
int32_t extraPrecision = precision + g_ratio;
DUPRAT(pi, rat_half);
asinrat(&pi, radix, extraPrecision);
mulrat(&pi, rat_six, extraPrecision);
@ -251,14 +264,13 @@ void ChangeConstants(uint32_t radix, int32_t precision)
lograt(&ln_two, extraPrecision);
DUMPRAWRAT(ln_two);
destroyrat(rad_to_deg);
rad_to_deg = longtorat(180L);
rad_to_deg = i32torat(180L);
divrat(&rad_to_deg, pi, extraPrecision);
DUMPRAWRAT(rad_to_deg);
destroyrat(rad_to_grad);
rad_to_grad = longtorat(200L);
rad_to_grad = i32torat(200L);
divrat(&rad_to_grad, pi, extraPrecision);
DUMPRAWRAT(rad_to_grad);
}
@ -267,11 +279,10 @@ void ChangeConstants(uint32_t radix, int32_t precision)
_readconstants();
DUPRAT(rat_smallest, rat_nRadix);
ratpowlong(&rat_smallest, -precision, precision);
ratpowi32(&rat_smallest, -precision, precision);
DUPRAT(rat_negsmallest, rat_smallest);
rat_negsmallest->pp->sign = -1;
}
}
//----------------------------------------------------------------------------
@ -285,21 +296,21 @@ void ChangeConstants(uint32_t radix, int32_t precision)
//
//----------------------------------------------------------------------------
void intrat( PRAT *px, uint32_t radix, int32_t precision)
void intrat(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 ) )
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);
modrat( &pret, rat_one );
DUPRAT(pret, *px);
remrat(&pret, rat_one);
subrat( px, pret, precision);
destroyrat( pret );
subrat(px, pret, precision);
destroyrat(pret);
// Simplify the value if possible to resolve rounding errors
flatrat(*px, radix, precision);
@ -317,44 +328,42 @@ void intrat( PRAT *px, uint32_t radix, int32_t precision)
//
//---------------------------------------------------------------------------
bool rat_equ( PRAT a, PRAT b, int32_t precision)
bool rat_equ(PRAT a, PRAT b, int32_t precision)
{
PRAT rattmp= nullptr;
DUPRAT(rattmp,a);
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
rattmp->pp->sign *= -1;
addrat( &rattmp, b, precision);
bool bret = zernum( rattmp->pp );
destroyrat( rattmp );
return( bret );
addrat(&rattmp, b, precision);
bool bret = zernum(rattmp->pp);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_ge
//
// ARGUMENTS: PRAT a, PRAT b and long precision
// ARGUMENTS: PRAT a, PRAT b and int32_t precision
//
// RETURN: true if a is greater than or equal to b
//
//
//---------------------------------------------------------------------------
bool rat_ge( PRAT a, PRAT b, int32_t precision)
bool rat_ge(PRAT a, PRAT b, int32_t precision)
{
PRAT rattmp= nullptr;
DUPRAT(rattmp,a);
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = ( zernum( rattmp->pp ) ||
rattmp->pp->sign * rattmp->pq->sign == 1 );
destroyrat( rattmp );
return( bret );
bool bret = (zernum(rattmp->pp) || SIGN(rattmp) == 1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_gt
@ -366,73 +375,67 @@ bool rat_ge( PRAT a, PRAT b, int32_t precision)
//
//---------------------------------------------------------------------------
bool rat_gt( PRAT a, PRAT b, int32_t precision)
bool rat_gt(PRAT a, PRAT b, int32_t precision)
{
PRAT rattmp= nullptr;
DUPRAT(rattmp,a);
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = ( !zernum( rattmp->pp ) &&
rattmp->pp->sign * rattmp->pq->sign == 1 );
destroyrat( rattmp );
return( bret );
bool bret = (!zernum(rattmp->pp) && SIGN(rattmp) == 1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_le
//
// ARGUMENTS: PRAT a, PRAT b and long precision
// ARGUMENTS: PRAT a, PRAT b and int32_t precision
//
// RETURN: true if a is less than or equal to b
//
//
//---------------------------------------------------------------------------
bool rat_le( PRAT a, PRAT b, int32_t precision)
bool rat_le(PRAT a, PRAT b, int32_t precision)
{
PRAT rattmp= nullptr;
DUPRAT(rattmp,a);
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = ( zernum( rattmp->pp ) ||
rattmp->pp->sign * rattmp->pq->sign == -1 );
destroyrat( rattmp );
return( bret );
bool bret = (zernum(rattmp->pp) || SIGN(rattmp) == -1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_lt
//
// ARGUMENTS: PRAT a, PRAT b and long precision
// ARGUMENTS: PRAT a, PRAT b and int32_t precision
//
// RETURN: true if a is less than b
//
//
//---------------------------------------------------------------------------
bool rat_lt( PRAT a, PRAT b, int32_t precision)
bool rat_lt(PRAT a, PRAT b, int32_t precision)
{
PRAT rattmp= nullptr;
DUPRAT(rattmp,a);
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
addrat(&rattmp, b, precision);
b->pp->sign *= -1;
bool bret = ( !zernum( rattmp->pp ) &&
rattmp->pp->sign * rattmp->pq->sign == -1 );
destroyrat( rattmp );
return( bret );
bool bret = (!zernum(rattmp->pp) && SIGN(rattmp) == -1);
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
//
// FUNCTION: rat_neq
@ -444,17 +447,16 @@ bool rat_lt( PRAT a, PRAT b, int32_t precision)
//
//---------------------------------------------------------------------------
bool rat_neq( PRAT a, PRAT b, int32_t precision)
bool rat_neq(PRAT a, PRAT b, int32_t precision)
{
PRAT rattmp= nullptr;
DUPRAT(rattmp,a);
PRAT rattmp = nullptr;
DUPRAT(rattmp, a);
rattmp->pp->sign *= -1;
addrat( &rattmp, b, precision);
bool bret = !( zernum( rattmp->pp ) );
destroyrat( rattmp );
return( bret );
addrat(&rattmp, b, precision);
bool bret = !(zernum(rattmp->pp));
destroyrat(rattmp);
return (bret);
}
//---------------------------------------------------------------------------
@ -468,27 +470,26 @@ bool rat_neq( PRAT a, PRAT b, int32_t precision)
//
//---------------------------------------------------------------------------
void scale( PRAT *px, PRAT scalefact, uint32_t radix, int32_t precision )
void scale(PRAT* px, 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
DUPRAT(pret, *px);
// Logscale is a quick way to tell how much extra precision is needed for
// scaling by scalefact.
long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) -
(pret->pq->cdigit+pret->pq->exp) );
if ( logscale > 0 )
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);
divrat(&pret, scalefact, precision);
intrat(&pret, radix, precision);
mulrat( &pret, scalefact, precision);
mulrat(&pret, scalefact, precision);
pret->pp->sign *= -1;
addrat( px, pret, precision);
addrat(px, pret, precision);
destroyrat( pret );
destroyrat(pret);
}
//---------------------------------------------------------------------------
@ -502,38 +503,37 @@ void scale( PRAT *px, PRAT scalefact, uint32_t radix, int32_t precision )
//
//---------------------------------------------------------------------------
void scale2pi( PRAT *px, uint32_t radix, int32_t precision )
void scale2pi(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT pret = nullptr;
PRAT my_two_pi = nullptr;
DUPRAT(pret,*px);
DUPRAT(pret, *px);
// Logscale is a quick way to tell how much extra precision is needed for
// Logscale is a quick way to tell how much extra precision is needed for
// scaling by 2 pi.
long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) -
(pret->pq->cdigit+pret->pq->exp) );
if ( logscale > 0 )
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);
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);
DUPRAT(my_two_pi, two_pi);
logscale = 0;
}
divrat( &pret, my_two_pi, precision);
divrat(&pret, my_two_pi, precision);
intrat(&pret, radix, precision);
mulrat( &pret, my_two_pi, precision);
mulrat(&pret, my_two_pi, precision);
pret->pp->sign *= -1;
addrat( px, pret, precision);
addrat(px, pret, precision);
destroyrat( my_two_pi );
destroyrat( pret );
destroyrat(my_two_pi);
destroyrat(pret);
}
//---------------------------------------------------------------------------
@ -546,22 +546,22 @@ void scale2pi( PRAT *px, uint32_t radix, int32_t precision )
//
//---------------------------------------------------------------------------
void inbetween( PRAT *px, PRAT range, int32_t precision)
void inbetween(PRAT* px, PRAT range, int32_t precision)
{
if ( rat_gt(*px,range, precision) )
{
DUPRAT(*px,range);
}
if (rat_gt(*px, range, precision))
{
DUPRAT(*px, range);
}
else
{
range->pp->sign *= -1;
if (rat_lt(*px, range, precision))
{
range->pp->sign *= -1;
if ( rat_lt(*px, range, precision) )
{
DUPRAT(*px,range);
}
range->pp->sign *= -1;
DUPRAT(*px, range);
}
range->pp->sign *= -1;
}
}
//---------------------------------------------------------------------------
@ -575,11 +575,11 @@ void inbetween( PRAT *px, PRAT range, int32_t precision)
//
//---------------------------------------------------------------------------
void _dumprawrat( const wchar_t *varname, PRAT rat, wostream& out)
void _dumprawrat(const wchar_t* varname, PRAT rat, wostream& out)
{
_dumprawnum(varname, rat->pp, out );
_dumprawnum(varname, rat->pq, out );
_dumprawnum(varname, rat->pp, out);
_dumprawnum(varname, rat->pq, out);
}
//---------------------------------------------------------------------------
@ -593,26 +593,26 @@ void _dumprawrat( const wchar_t *varname, PRAT rat, wostream& out)
//
//---------------------------------------------------------------------------
void _dumprawnum(const wchar_t *varname, PNUMBER num, wostream& out)
void _dumprawnum(const wchar_t* varname, PNUMBER num, wostream& out)
{
int i;
out << L"NUMBER " << varname << L" = {\n";
out << L"\t"<< num->sign << 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 ( i = 0; i < num->cdigit; i++ )
{
out << L" "<< num->mant[i] << L",";
}
for (i = 0; i < num->cdigit; i++)
{
out << L" " << num->mant[i] << L",";
}
out << L"}\n";
out << L"};\n";
}
void _readconstants( void )
void _readconstants(void)
{
READRAWNUM(num_one);
@ -652,67 +652,67 @@ void _readconstants( void )
READRAWRAT(rat_min_exp);
READRAWRAT(rat_max_fact);
READRAWRAT(rat_min_fact);
READRAWRAT(rat_min_long);
READRAWRAT(rat_max_long);
READRAWRAT(rat_min_i32);
READRAWRAT(rat_max_i32);
}
//---------------------------------------------------------------------------
//
// FUNCTION: trimit
//
// ARGUMENTS: PRAT *px, long precision
// 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
// 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
// RETURN: none, modifies the pointed to PRAT
//
//---------------------------------------------------------------------------
void trimit( PRAT *px, int32_t precision)
void trimit(PRAT* px, int32_t precision)
{
if ( !g_ftrueinfinite )
{
long trim;
PNUMBER pp=(*px)->pp;
PNUMBER pq=(*px)->pq;
trim = g_ratio * (min((pp->cdigit+pp->exp),(pq->cdigit+pq->exp))-1) - precision;
if ( trim > g_ratio )
{
if (!g_ftrueinfinite)
{
int32_t trim;
PNUMBER pp = (*px)->pp;
PNUMBER pq = (*px)->pq;
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 )
{
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);
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;
}
}
}

View file

@ -14,28 +14,24 @@
//
//----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
void scalerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision )
void scalerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
switch ( angletype )
switch (angletype)
{
case ANGLE_RAD:
scale2pi( pa, radix, precision);
scale2pi(pa, radix, precision);
break;
case ANGLE_DEG:
scale( pa, rat_360, radix, precision);
scale(pa, rat_360, radix, precision);
break;
case ANGLE_GRAD:
scale( pa, rat_400, radix, precision);
scale(pa, rat_400, radix, precision);
break;
}
}
//-----------------------------------------------------------------------------
//
// FUNCTION: sinrat, _sinrat
@ -47,8 +43,8 @@ void scalerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t p
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2j+1
// \ ] j X
// ___ 2j+1
// \ ] j X
// \ -1 * ---------
// / (2j+1)!
// /__]
@ -67,65 +63,65 @@ void scalerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t p
//
//-----------------------------------------------------------------------------
void _sinrat( PRAT *px, int32_t precision)
void _sinrat(PRAT* px, int32_t precision)
{
CREATETAYLOR();
DUPRAT(pret,*px);
DUPRAT(thisterm,*px);
DUPRAT(pret, *px);
DUPRAT(thisterm, *px);
DUPNUM(n2,num_one);
DUPNUM(n2, num_one);
xx->pp->sign *= -1;
do {
NEXTTERM(xx,INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
do
{
NEXTTERM(xx, INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
// Since *px might be epsilon above 1 or below -1, due to TRIMIT we need
// Since *px might be epsilon above 1 or below -1, due to TRIMIT we need
// this trick here.
inbetween(px, rat_one, precision);
// Since *px might be epsilon near zero we must set it to zero.
if ( rat_le(*px, rat_smallest, precision) && rat_ge(*px, rat_negsmallest, precision) )
{
DUPRAT(*px,rat_zero);
}
if (rat_le(*px, rat_smallest, precision) && rat_ge(*px, rat_negsmallest, precision))
{
DUPRAT(*px, rat_zero);
}
}
void sinrat( PRAT *px, uint32_t radix, int32_t precision)
void sinrat(PRAT* px, uint32_t radix, int32_t precision)
{
scale2pi(px, radix, precision);
_sinrat(px, precision);
}
void sinanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
void sinanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
scalerat( pa, angletype, radix, precision);
switch ( angletype )
{
scalerat(pa, angletype, radix, precision);
switch (angletype)
{
case ANGLE_DEG:
if ( rat_gt( *pa, rat_180, precision) )
{
if (rat_gt(*pa, rat_180, precision))
{
subrat(pa, rat_360, precision);
}
divrat( pa, rat_180, precision);
mulrat( pa, pi, precision);
}
divrat(pa, rat_180, precision);
mulrat(pa, pi, precision);
break;
case ANGLE_GRAD:
if ( rat_gt( *pa, rat_200, precision) )
{
subrat(pa,rat_400, precision);
}
divrat( pa, rat_200, precision);
mulrat( pa, pi, precision);
break;
if (rat_gt(*pa, rat_200, precision))
{
subrat(pa, rat_400, precision);
}
_sinrat( pa, precision);
divrat(pa, rat_200, precision);
mulrat(pa, pi, precision);
break;
}
_sinrat(pa, precision);
}
//-----------------------------------------------------------------------------
@ -159,76 +155,76 @@ void sinanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_
//
//-----------------------------------------------------------------------------
void _cosrat( PRAT *px, uint32_t radix, int32_t precision)
void _cosrat(PRAT* px, uint32_t radix, int32_t precision)
{
CREATETAYLOR();
destroynum(pret->pp);
destroynum(pret->pq);
destroynum(pret->pq);
pret->pp=longtonum( 1L, radix);
pret->pq=longtonum( 1L, radix);
pret->pp = i32tonum(1L, radix);
pret->pq = i32tonum(1L, radix);
DUPRAT(thisterm,pret)
n2=longtonum(0L, radix);
DUPRAT(thisterm, pret)
n2 = i32tonum(0L, radix);
xx->pp->sign *= -1;
do {
NEXTTERM(xx,INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
do
{
NEXTTERM(xx, INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
// Since *px might be epsilon above 1 or below -1, due to TRIMIT we need
// Since *px might be epsilon above 1 or below -1, due to TRIMIT we need
// this trick here.
inbetween(px, rat_one, precision);
// Since *px might be epsilon near zero we must set it to zero.
if ( rat_le(*px, rat_smallest, precision) && rat_ge(*px, rat_negsmallest, precision) )
{
DUPRAT(*px,rat_zero);
}
if (rat_le(*px, rat_smallest, precision) && rat_ge(*px, rat_negsmallest, precision))
{
DUPRAT(*px, rat_zero);
}
}
void cosrat( PRAT *px, uint32_t radix, int32_t precision)
void cosrat(PRAT* px, uint32_t radix, int32_t precision)
{
scale2pi(px, radix, precision);
_cosrat(px, radix, precision);
}
void cosanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
void cosanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
scalerat( pa, angletype, radix, precision);
switch ( angletype )
{
scalerat(pa, angletype, radix, precision);
switch (angletype)
{
case ANGLE_DEG:
if ( rat_gt( *pa, rat_180, precision) )
{
PRAT ptmp= nullptr;
DUPRAT(ptmp,rat_360);
if (rat_gt(*pa, rat_180, precision))
{
PRAT ptmp = nullptr;
DUPRAT(ptmp, rat_360);
subrat(&ptmp, *pa, precision);
destroyrat(*pa);
*pa=ptmp;
}
divrat( pa, rat_180, precision);
mulrat( pa, pi, precision);
*pa = ptmp;
}
divrat(pa, rat_180, precision);
mulrat(pa, pi, precision);
break;
case ANGLE_GRAD:
if ( rat_gt( *pa, rat_200, precision) )
{
PRAT ptmp= nullptr;
DUPRAT(ptmp,rat_400);
if (rat_gt(*pa, rat_200, precision))
{
PRAT ptmp = nullptr;
DUPRAT(ptmp, rat_400);
subrat(&ptmp, *pa, precision);
destroyrat(*pa);
*pa=ptmp;
}
divrat( pa, rat_200, precision);
mulrat( pa, pi, precision);
break;
*pa = ptmp;
}
_cosrat( pa, radix, precision);
divrat(pa, rat_200, precision);
mulrat(pa, pi, precision);
break;
}
_cosrat(pa, radix, precision);
}
//-----------------------------------------------------------------------------
@ -243,55 +239,52 @@ void cosanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_
//
//-----------------------------------------------------------------------------
void _tanrat( PRAT *px, uint32_t radix, int32_t precision)
void _tanrat(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT ptmp= nullptr;
PRAT ptmp = nullptr;
DUPRAT(ptmp,*px);
DUPRAT(ptmp, *px);
_sinrat(px, precision);
_cosrat(&ptmp, radix, precision);
if ( zerrat( ptmp ) )
{
if (zerrat(ptmp))
{
destroyrat(ptmp);
throw( CALC_E_DOMAIN );
}
throw(CALC_E_DOMAIN);
}
divrat(px, ptmp, precision);
destroyrat(ptmp);
}
void tanrat( PRAT *px, uint32_t radix, int32_t precision)
void tanrat(PRAT* px, uint32_t radix, int32_t precision)
{
scale2pi(px, radix, precision);
_tanrat(px, radix, precision);
}
void tananglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
void tananglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
{
scalerat( pa, angletype, radix, precision);
switch ( angletype )
{
scalerat(pa, angletype, radix, precision);
switch (angletype)
{
case ANGLE_DEG:
if ( rat_gt( *pa, rat_180, precision) )
{
if (rat_gt(*pa, rat_180, precision))
{
subrat(pa, rat_180, precision);
}
divrat( pa, rat_180, precision);
mulrat( pa, pi, precision);
}
divrat(pa, rat_180, precision);
mulrat(pa, pi, precision);
break;
case ANGLE_GRAD:
if ( rat_gt( *pa, rat_200, precision) )
{
if (rat_gt(*pa, rat_200, precision))
{
subrat(pa, rat_200, precision);
}
divrat( pa, rat_200, precision);
mulrat( pa, pi, precision);
break;
}
_tanrat( pa, radix, precision);
divrat(pa, rat_200, precision);
mulrat(pa, pi, precision);
break;
}
_tanrat(pa, radix, precision);
}

View file

@ -14,25 +14,21 @@
//
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "ratpak.h"
bool IsValidForHypFunc(PRAT px, int32_t precision)
{
PRAT ptmp = nullptr;
bool bRet = true;
DUPRAT(ptmp,rat_min_exp);
DUPRAT(ptmp, rat_min_exp);
divrat(&ptmp, rat_ten, precision);
if ( rat_lt( px, ptmp, precision) )
if (rat_lt(px, ptmp, precision))
{
bRet = false;
}
destroyrat( ptmp );
destroyrat(ptmp);
return bRet;
}
//-----------------------------------------------------------------------------
@ -68,49 +64,49 @@ bool IsValidForHypFunc(PRAT px, int32_t precision)
//
//-----------------------------------------------------------------------------
void _sinhrat( PRAT *px, int32_t precision)
void _sinhrat(PRAT* px, int32_t precision)
{
if ( !IsValidForHypFunc(*px, precision))
{
if (!IsValidForHypFunc(*px, precision))
{
// Don't attempt exp of anything large or small
throw( CALC_E_DOMAIN );
}
throw(CALC_E_DOMAIN);
}
CREATETAYLOR();
DUPRAT(pret,*px);
DUPRAT(thisterm,pret);
DUPRAT(pret, *px);
DUPRAT(thisterm, pret);
DUPNUM(n2,num_one);
DUPNUM(n2, num_one);
do {
NEXTTERM(xx,INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
do
{
NEXTTERM(xx, INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void sinhrat( PRAT *px, uint32_t radix, int32_t precision)
void sinhrat(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT tmpx= nullptr;
PRAT tmpx = nullptr;
if ( rat_ge( *px, rat_one, precision) )
{
DUPRAT(tmpx,*px);
if (rat_ge(*px, rat_one, precision))
{
DUPRAT(tmpx, *px);
exprat(px, radix, precision);
tmpx->pp->sign *= -1;
exprat(&tmpx, radix, precision);
subrat( px, tmpx, precision);
divrat( px, rat_two, precision);
destroyrat( tmpx );
}
subrat(px, tmpx, precision);
divrat(px, rat_two, precision);
destroyrat(tmpx);
}
else
{
_sinhrat( px, precision);
}
{
_sinhrat(px, precision);
}
}
//-----------------------------------------------------------------------------
@ -147,59 +143,59 @@ void sinhrat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void _coshrat( PRAT *px, uint32_t radix, int32_t precision)
void _coshrat(PRAT* px, uint32_t radix, int32_t precision)
{
if ( !IsValidForHypFunc(*px, precision))
{
if (!IsValidForHypFunc(*px, precision))
{
// Don't attempt exp of anything large or small
throw( CALC_E_DOMAIN );
}
throw(CALC_E_DOMAIN);
}
CREATETAYLOR();
pret->pp=longtonum( 1L, radix);
pret->pq=longtonum( 1L, radix);
pret->pp = i32tonum(1L, radix);
pret->pq = i32tonum(1L, radix);
DUPRAT(thisterm,pret)
DUPRAT(thisterm, pret)
n2=longtonum(0L, radix);
n2 = i32tonum(0L, radix);
do {
NEXTTERM(xx,INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
do
{
NEXTTERM(xx, INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} while (!SMALL_ENOUGH_RAT(thisterm, precision));
DESTROYTAYLOR();
}
void coshrat( PRAT *px, uint32_t radix, int32_t precision)
void coshrat(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT tmpx= nullptr;
PRAT tmpx = nullptr;
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if ( rat_ge( *px, rat_one, precision) )
{
DUPRAT(tmpx,*px);
if (rat_ge(*px, rat_one, precision))
{
DUPRAT(tmpx, *px);
exprat(px, radix, precision);
tmpx->pp->sign *= -1;
exprat(&tmpx, radix, precision);
addrat( px, tmpx, precision);
divrat( px, rat_two, precision);
destroyrat( tmpx );
}
addrat(px, tmpx, precision);
divrat(px, rat_two, precision);
destroyrat(tmpx);
}
else
{
_coshrat( px, radix, precision);
}
// Since *px might be epsilon below 1 due to TRIMIT
{
_coshrat(px, radix, precision);
}
// Since *px might be epsilon below 1 due to TRIMIT
// we need this trick here.
if ( rat_lt(*px, rat_one, precision) )
{
DUPRAT(*px,rat_one);
}
if (rat_lt(*px, rat_one, precision))
{
DUPRAT(*px, rat_one);
}
}
//-----------------------------------------------------------------------------
@ -215,17 +211,16 @@ void coshrat( PRAT *px, uint32_t radix, int32_t precision)
//
//-----------------------------------------------------------------------------
void tanhrat( PRAT *px, uint32_t radix, int32_t precision)
void tanhrat(PRAT* px, uint32_t radix, int32_t precision)
{
PRAT ptmp= nullptr;
PRAT ptmp = nullptr;
DUPRAT(ptmp,*px);
DUPRAT(ptmp, *px);
sinhrat(px, radix, precision);
coshrat(&ptmp, radix, precision);
mulnumx(&((*px)->pp),ptmp->pq);
mulnumx(&((*px)->pq),ptmp->pp);
mulnumx(&((*px)->pp), ptmp->pq);
mulnumx(&((*px)->pq), ptmp->pp);
destroyrat(ptmp);
}

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <vector>
#include <unordered_map>
#include <ppltasks.h>
#include <sal.h> // for SAL
#include <memory> // for std::shared_ptr
namespace UnitConversionManager
{
enum class Command;
struct Unit
{
Unit(){}
Unit()
{
}
Unit(int id, std::wstring name, std::wstring abbreviation, bool isConversionSource, bool isConversionTarget, bool isWhimsical)
: id(id), name(name), accessibleName(name), abbreviation(abbreviation), isConversionSource(isConversionSource), isConversionTarget(isConversionTarget), isWhimsical(isWhimsical)
: id(id)
, name(name)
, accessibleName(name)
, abbreviation(abbreviation)
, isConversionSource(isConversionSource)
, isConversionTarget(isConversionTarget)
, isWhimsical(isWhimsical)
{
}
Unit(int id, std::wstring currencyName, std::wstring countryName, std::wstring abbreviation, bool isRtlLanguage, bool isConversionSource, bool isConversionTarget)
: id(id), abbreviation(abbreviation), isConversionSource(isConversionSource), isConversionTarget(isConversionTarget), isWhimsical(false)
Unit(
int id,
std::wstring currencyName,
std::wstring countryName,
std::wstring abbreviation,
bool isRtlLanguage,
bool isConversionSource,
bool isConversionTarget)
: id(id)
, abbreviation(abbreviation)
, isConversionSource(isConversionSource)
, isConversionTarget(isConversionTarget)
, isWhimsical(false)
{
std::wstring nameValue1 = isRtlLanguage ? currencyName : countryName;
std::wstring nameValue2 = isRtlLanguage ? countryName : currencyName;
@ -25,7 +50,9 @@ namespace UnitConversionManager
accessibleName = nameValue1 + L" " + nameValue2;
}
virtual ~Unit() {}
virtual ~Unit()
{
}
int id;
std::wstring name;
@ -35,12 +62,12 @@ namespace UnitConversionManager
bool isConversionTarget;
bool isWhimsical;
bool operator!= (const Unit& that) const
bool operator!=(const Unit& that) const
{
return that.id != id;
}
bool operator== (const Unit& that) const
bool operator==(const Unit& that) const
{
return that.id == id;
}
@ -55,9 +82,14 @@ namespace UnitConversionManager
struct Category
{
Category(){}
Category()
{
}
Category(int id, std::wstring name, bool supportsNegative) : id(id), name(name), supportsNegative(supportsNegative)
Category(int id, std::wstring name, bool supportsNegative)
: id(id)
, name(name)
, supportsNegative(supportsNegative)
{
}
@ -65,12 +97,12 @@ namespace UnitConversionManager
std::wstring name;
bool supportsNegative;
bool operator!= (const Category& that) const
bool operator!=(const Category& that) const
{
return that.id != id;
}
bool operator== (const Category& that) const
bool operator==(const Category& that) const
{
return that.id == id;
}
@ -79,7 +111,8 @@ namespace UnitConversionManager
class UnitHash
{
public:
size_t operator() (const Unit & x) const {
size_t operator()(const Unit& x) const
{
return x.id;
}
};
@ -87,7 +120,8 @@ namespace UnitConversionManager
class CategoryHash
{
public:
size_t operator() (const Category & x) const {
size_t operator()(const Category& x) const
{
return x.id;
}
};
@ -101,12 +135,19 @@ namespace UnitConversionManager
struct ConversionData
{
ConversionData(){}
ConversionData(double ratio, double offset, bool offsetFirst) : ratio(ratio), offset(offset), offsetFirst(offsetFirst)
ConversionData()
{
}
ConversionData(double ratio, double offset, bool offsetFirst)
: ratio(ratio)
, offset(offset)
, offsetFirst(offsetFirst)
{
}
virtual ~ConversionData() {}
virtual ~ConversionData()
{
}
double ratio;
double offset;
@ -130,13 +171,18 @@ namespace UnitConversionManager
};
typedef std::tuple<std::vector<UnitConversionManager::Unit>, UnitConversionManager::Unit, UnitConversionManager::Unit> CategorySelectionInitializer;
typedef std::unordered_map<UnitConversionManager::Unit, std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash>, UnitConversionManager::UnitHash> UnitToUnitToConversionDataMap;
typedef std::unordered_map<UnitConversionManager::Category, std::vector<UnitConversionManager::Unit>, UnitConversionManager::CategoryHash> CategoryToUnitVectorMap;
typedef std::unordered_map<
UnitConversionManager::Unit,
std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash>,
UnitConversionManager::UnitHash>
UnitToUnitToConversionDataMap;
typedef std::unordered_map<UnitConversionManager::Category, std::vector<UnitConversionManager::Unit>, UnitConversionManager::CategoryHash>
CategoryToUnitVectorMap;
class IViewModelCurrencyCallback
{
public:
virtual ~IViewModelCurrencyCallback() { };
virtual ~IViewModelCurrencyCallback(){};
virtual void CurrencyDataLoadFinished(bool didLoad) = 0;
virtual void CurrencySymbolsCallback(_In_ const std::wstring& fromSymbol, _In_ const std::wstring& toSymbol) = 0;
virtual void CurrencyRatiosCallback(_In_ const std::wstring& ratioEquality, _In_ const std::wstring& accRatioEquality) = 0;
@ -147,8 +193,8 @@ namespace UnitConversionManager
class IConverterDataLoader
{
public:
virtual ~IConverterDataLoader() { };
virtual void LoadData() = 0; // prepare data if necessary before calling other functions
virtual ~IConverterDataLoader(){};
virtual void LoadData() = 0; // prepare data if necessary before calling other functions
virtual std::vector<Category> LoadOrderedCategories() = 0;
virtual std::vector<Unit> LoadOrderedUnits(const Category& c) = 0;
virtual std::unordered_map<Unit, ConversionData, UnitHash> LoadOrderedRatios(const Unit& u) = 0;
@ -159,8 +205,10 @@ namespace UnitConversionManager
{
public:
virtual void SetViewModelCallback(const std::shared_ptr<UnitConversionManager::IViewModelCurrencyCallback>& callback) = 0;
virtual std::pair<std::wstring, std::wstring> GetCurrencySymbols(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) = 0;
virtual std::pair<std::wstring, std::wstring> GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) = 0;
virtual std::pair<std::wstring, std::wstring>
GetCurrencySymbols(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) = 0;
virtual std::pair<std::wstring, std::wstring>
GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) = 0;
virtual std::wstring GetCurrencyTimestamp() = 0;
virtual concurrency::task<bool> TryLoadDataFromCacheAsync() = 0;
@ -171,7 +219,7 @@ namespace UnitConversionManager
class IUnitConverterVMCallback
{
public:
virtual ~IUnitConverterVMCallback() { };
virtual ~IUnitConverterVMCallback(){};
virtual void DisplayCallback(const std::wstring& from, const std::wstring& to) = 0;
virtual void SuggestedValueCallback(const std::vector<std::tuple<std::wstring, Unit>>& suggestedValues) = 0;
virtual void MaxDigitsReached() = 0;
@ -180,8 +228,10 @@ namespace UnitConversionManager
class IUnitConverter
{
public:
virtual ~IUnitConverter() { }
virtual void Initialize() = 0; // Use to initialize first time, use deserialize instead to rehydrate
virtual ~IUnitConverter()
{
}
virtual void Initialize() = 0; // Use to initialize first time, use deserialize instead to rehydrate
virtual std::vector<Category> GetCategories() = 0;
virtual CategorySelectionInitializer SetCurrentCategory(const Category& input) = 0;
virtual Category GetCurrentCategory() = 0;
@ -195,6 +245,8 @@ namespace UnitConversionManager
virtual void SetViewModelCallback(_In_ const std::shared_ptr<IUnitConverterVMCallback>& newCallback) = 0;
virtual void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<IViewModelCurrencyCallback>& newCallback) = 0;
virtual concurrency::task<std::pair<bool, std::wstring>> RefreshCurrencyRatios() = 0;
virtual void Calculate() = 0;
virtual void ResetCategoriesAndRatios() = 0;
};
class UnitConverter : public IUnitConverter, public std::enable_shared_from_this<UnitConverter>
@ -218,9 +270,11 @@ namespace UnitConversionManager
void SetViewModelCallback(_In_ const std::shared_ptr<IUnitConverterVMCallback>& newCallback) override;
void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<IViewModelCurrencyCallback>& newCallback) override;
concurrency::task<std::pair<bool, std::wstring>> RefreshCurrencyRatios() override;
void Calculate() override;
void ResetCategoriesAndRatios() override;
// IUnitConverter
static std::vector<std::wstring> StringToVector(const std::wstring& w, const wchar_t * delimiter, bool addRemainder = false);
static std::vector<std::wstring> StringToVector(const std::wstring& w, const wchar_t* delimiter, bool addRemainder = false);
static std::wstring Quote(const std::wstring& s);
static std::wstring Unquote(const std::wstring& s);
@ -228,18 +282,16 @@ namespace UnitConversionManager
bool CheckLoad();
double Convert(double value, ConversionData conversionData);
std::vector<std::tuple<std::wstring, Unit>> CalculateSuggested();
void Reset();
void ClearValues();
void Calculate();
void TrimString(std::wstring& input);
void InitializeSelectedUnits();
std::wstring RoundSignificant(double num, int numSignificant);
Category StringToCategory(const std::wstring& w);
std::wstring CategoryToString(const Category& c, const wchar_t * delimiter);
std::wstring UnitToString(const Unit& u, const wchar_t * delimiter);
std::wstring CategoryToString(const Category& c, const wchar_t* delimiter);
std::wstring UnitToString(const Unit& u, const wchar_t* delimiter);
Unit StringToUnit(const std::wstring& w);
ConversionData StringToConversionData(const std::wstring& w);
std::wstring ConversionDataToString(ConversionData d, const wchar_t * delimiter);
std::wstring ConversionDataToString(ConversionData d, const wchar_t* delimiter);
void UpdateCurrencySymbols();
void UpdateViewModel();
bool AnyUnitIsEmpty();

View file

@ -1,4 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
// Intentionally do not include the pch.h here. For projects that don't
// use precompiled headers, including the header here would force unnecessary compilation.
// The pch will be included through forced include.

View file

@ -1,23 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// The CalcManager project should be able to be compiled with or without a precompiled header
// in - order to support other toolchains besides MSVC. When adding new system headers, make sure
// that the relevant source file includes all headers it needs, but then also add the system headers
// here so that MSVC users see the performance benefit.
#include <assert.h>
#include <windows.h>
#include <winerror.h>
#include <sstream>
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <limits>
#include <regex>
#include <unordered_map>
#include <intsafe.h>
#include <algorithm>
#include <array>
#include <cassert>
#include <intsafe.h>
#include <list>
#include <ppltasks.h>
#include <regex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <winerror.h>

View file

@ -1,11 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

View file

@ -32,23 +32,19 @@ using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
namespace CalculatorApp::ViewModel::ApplicationViewModelProperties
namespace
{
StringReference Mode(L"Mode");
StringReference PreviousMode(L"PreviousMode");
StringReference ClearMemoryVisibility(L"ClearMemoryVisibility");
StringReference AppBarVisibility(L"AppBarVisibility");
StringReference CategoryName(L"CategoryName");
StringReference Categories(L"Categories");
StringReference CategoriesPropertyName(L"Categories");
StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility");
}
ApplicationViewModel::ApplicationViewModel() :
m_CalculatorViewModel(nullptr),
m_DateCalcViewModel(nullptr),
m_ConverterViewModel(nullptr),
m_PreviousMode(ViewMode::None),
m_mode(ViewMode::None),
m_categories(nullptr)
ApplicationViewModel::ApplicationViewModel()
: m_CalculatorViewModel(nullptr)
, m_DateCalcViewModel(nullptr)
, m_ConverterViewModel(nullptr)
, m_PreviousMode(ViewMode::None)
, m_mode(ViewMode::None)
, m_categories(nullptr)
{
SetMenuCategories();
}
@ -60,16 +56,16 @@ void ApplicationViewModel::Mode::set(ViewMode value)
PreviousMode = m_mode;
m_mode = value;
OnModeChanged();
RaisePropertyChanged(ApplicationViewModelProperties::Mode);
RaisePropertyChanged(ModePropertyName);
}
}
void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup^>^ value)
void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup ^> ^ value)
{
if (m_categories != value)
{
m_categories = value;
RaisePropertyChanged(ApplicationViewModelProperties::Categories);
RaisePropertyChanged(CategoriesPropertyName);
}
}
@ -94,7 +90,7 @@ void ApplicationViewModel::Initialize(ViewMode mode)
throw;
}
}
catch (Exception^ e)
catch (Exception ^ e)
{
TraceLogger::GetInstance().LogPlatformException(__FUNCTIONW__, e);
if (!TryRecoverFromNavigationModeFailure())
@ -163,14 +159,13 @@ void ApplicationViewModel::OnModeChanged()
//
// Save the changed mode, so that the new window launches in this mode.
// Don't save until after we have adjusted to the new mode, so we don't save a mode that fails to load.
ApplicationData::Current->LocalSettings->Values->Insert(ApplicationViewModelProperties::Mode, NavCategory::Serialize(m_mode));
ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategory::Serialize(m_mode));
TraceLogger::GetInstance().LogModeChangeEnd(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
RaisePropertyChanged(ApplicationViewModelProperties::ClearMemoryVisibility);
RaisePropertyChanged(ApplicationViewModelProperties::AppBarVisibility);
RaisePropertyChanged(ClearMemoryVisibilityPropertyName);
}
void ApplicationViewModel::OnCopyCommand(Object^ parameter)
void ApplicationViewModel::OnCopyCommand(Object ^ parameter)
{
if (NavCategory::IsConverterViewMode(m_mode))
{
@ -186,13 +181,13 @@ void ApplicationViewModel::OnCopyCommand(Object^ parameter)
}
}
void ApplicationViewModel::OnPasteCommand(Object^ parameter)
void ApplicationViewModel::OnPasteCommand(Object ^ parameter)
{
if (NavCategory::IsConverterViewMode(m_mode))
{
ConverterViewModel->OnPasteCommand(parameter);
}
else
else if (NavCategory::IsCalculatorViewMode(m_mode))
{
CalculatorViewModel->OnPasteCommand(parameter);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
@ -11,30 +11,19 @@ namespace CalculatorApp
{
namespace ViewModel
{
namespace ApplicationViewModelProperties
{
extern Platform::StringReference Mode;
extern Platform::StringReference PreviousMode;
extern Platform::StringReference ClearMemoryVisibility;
extern Platform::StringReference AppBarVisibility;
extern Platform::StringReference CategoryName;
extern Platform::StringReference Categories;
}
[Windows::UI::Xaml::Data::Bindable]
public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
[Windows::UI::Xaml::Data::Bindable] public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
ApplicationViewModel();
void Initialize(CalculatorApp::Common::ViewMode mode); // Use for first init, use deserialize for rehydration
void Initialize(CalculatorApp::Common::ViewMode mode); // Use for first init, use deserialize for rehydration
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel^, CalculatorViewModel);
OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel^, DateCalcViewModel);
OBSERVABLE_PROPERTY_RW(CalculatorApp::ViewModel::UnitConverterViewModel^, ConverterViewModel);
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel);
OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel ^, DateCalcViewModel);
OBSERVABLE_PROPERTY_RW(UnitConverterViewModel ^, ConverterViewModel);
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode);
OBSERVABLE_PROPERTY_RW(Platform::String^, CategoryName);
OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, CategoryName);
COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand);
COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand);
@ -48,6 +37,13 @@ namespace CalculatorApp
void set(CalculatorApp::Common::ViewMode value);
}
static property Platform::String^ ModePropertyName
{
Platform::String^ get()
{
return Platform::StringReference(L"Mode");
}
}
property Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ Categories
{
@ -63,19 +59,8 @@ namespace CalculatorApp
{
Windows::UI::Xaml::Visibility get()
{
return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode)
? Windows::UI::Xaml::Visibility::Visible
: Windows::UI::Xaml::Visibility::Collapsed;
}
}
property Windows::UI::Xaml::Visibility AppBarVisibility
{
Windows::UI::Xaml::Visibility get()
{
return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode)
? Windows::UI::Xaml::Visibility::Visible
: Windows::UI::Xaml::Visibility::Collapsed;
return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode) ? Windows::UI::Xaml::Visibility::Visible
: Windows::UI::Xaml::Visibility::Collapsed;
}
}
@ -84,13 +69,13 @@ namespace CalculatorApp
void OnModeChanged();
void OnCopyCommand(Platform::Object^ parameter);
void OnPasteCommand(Platform::Object^ parameter);
void OnCopyCommand(Platform::Object ^ parameter);
void OnPasteCommand(Platform::Object ^ parameter);
void SetMenuCategories();
CalculatorApp::Common::ViewMode m_mode;
Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ m_categories;
Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup ^> ^ m_categories;
};
}
}

View file

@ -3,107 +3,104 @@
#pragma once
namespace CalculatorApp { namespace Common
namespace CalculatorApp
{
ref class AlwaysSelectedCollectionView sealed:
public Windows::UI::Xaml::DependencyObject,
public Windows::UI::Xaml::Data::ICollectionView
namespace Common
{
internal:
AlwaysSelectedCollectionView(Windows::UI::Xaml::Interop::IBindableVector^ source):
m_currentPosition(-1)
ref class AlwaysSelectedCollectionView sealed : public Windows::UI::Xaml::DependencyObject, public Windows::UI::Xaml::Data::ICollectionView
{
m_source = source;
Windows::UI::Xaml::Interop::IBindableObservableVector^ observable = dynamic_cast<Windows::UI::Xaml::Interop::IBindableObservableVector^>(source);
if (observable)
internal : AlwaysSelectedCollectionView(Windows::UI::Xaml::Interop::IBindableVector ^ source)
: m_currentPosition(-1)
{
observable->VectorChanged +=
ref new Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler(this, &AlwaysSelectedCollectionView::OnSourceBindableVectorChanged);
}
}
m_source = source;
private:
// ICollectionView
// Not implemented methods
virtual WF::IAsyncOperation<Windows::UI::Xaml::Data::LoadMoreItemsResult>^ LoadMoreItemsAsync(unsigned int) = Windows::UI::Xaml::Data::ICollectionView::LoadMoreItemsAsync
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToFirst() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToFirst
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToLast() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToLast
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToNext() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToNext
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToPrevious() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPrevious
{
throw ref new Platform::NotImplementedException();
}
property Windows::Foundation::Collections::IObservableVector<Platform::Object^>^ CollectionGroups
{
virtual Windows::Foundation::Collections::IObservableVector<Platform::Object^>^ get() = Windows::UI::Xaml::Data::ICollectionView::CollectionGroups::get
{
return ref new Platform::Collections::Vector<Platform::Object^>();
}
}
property bool HasMoreItems
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::HasMoreItems::get
{
return false;
}
}
// Implemented methods
virtual bool MoveCurrentTo(Platform::Object^ item) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentTo
{
if (item)
{
unsigned int newCurrentPosition = 0;
bool result = m_source->IndexOf(item, &newCurrentPosition);
if (result)
Windows::UI::Xaml::Interop::IBindableObservableVector ^ observable =
dynamic_cast<Windows::UI::Xaml::Interop::IBindableObservableVector ^>(source);
if (observable)
{
m_currentPosition = newCurrentPosition;
m_currentChanged(this, nullptr);
return true;
observable->VectorChanged += ref new Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler(
this, &AlwaysSelectedCollectionView::OnSourceBindableVectorChanged);
}
}
// The item is not in the collection
// We're going to schedule a call back later so we
// restore the selection to the way we wanted it to begin with
if (m_currentPosition >= 0 && m_currentPosition < static_cast<int>(m_source->Size))
private:
// ICollectionView
// Not implemented methods
virtual WF::IAsyncOperation<
Windows::UI::Xaml::Data::LoadMoreItemsResult> ^ LoadMoreItemsAsync(unsigned int) = Windows::UI::Xaml::Data::ICollectionView::LoadMoreItemsAsync
{
this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler(
[this]()
{
m_currentChanged(this, nullptr);
}));
throw ref new Platform::NotImplementedException();
}
return false;
}
virtual bool MoveCurrentToPosition(int index) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPosition
{
if (index < 0 || index >= static_cast<int>(m_source->Size))
virtual bool MoveCurrentToFirst() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToFirst
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToLast() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToLast
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToNext() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToNext
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToPrevious() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPrevious
{
throw ref new Platform::NotImplementedException();
}
property Windows::Foundation::Collections::IObservableVector<Platform::Object ^> ^ CollectionGroups {
virtual Windows::Foundation::Collections::IObservableVector<
Platform::Object ^> ^ get() = Windows::UI::Xaml::Data::ICollectionView::CollectionGroups::get
{
return ref new Platform::Collections::Vector<Platform::Object ^>();
}
} property bool HasMoreItems
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::HasMoreItems::get
{
return false;
}
}
// Implemented methods
virtual bool MoveCurrentTo(Platform::Object ^ item) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentTo
{
if (item)
{
unsigned int newCurrentPosition = 0;
bool result = m_source->IndexOf(item, &newCurrentPosition);
if (result)
{
m_currentPosition = newCurrentPosition;
m_currentChanged(this, nullptr);
return true;
}
}
// The item is not in the collection
// We're going to schedule a call back later so we
// restore the selection to the way we wanted it to begin with
if (m_currentPosition >= 0 && m_currentPosition < static_cast<int>(m_source->Size))
{
this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this]() {
m_currentChanged(this, nullptr);
}));
}
return false;
}
m_currentPosition = index;
m_currentChanged(this, nullptr);
return true;
}
virtual bool MoveCurrentToPosition(int index) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPosition
{
if (index < 0 || index >= static_cast<int>(m_source->Size))
{
return false;
}
property Platform::Object^ CurrentItem
m_currentPosition = index;
m_currentChanged(this, nullptr);
return true;
}
property Platform::Object^ CurrentItem
{
virtual Platform::Object^ get() = Windows::UI::Xaml::Data::ICollectionView::CurrentItem::get
{
@ -116,30 +113,30 @@ namespace CalculatorApp { namespace Common
}
property int CurrentPosition
{
virtual int get() = Windows::UI::Xaml::Data::ICollectionView::CurrentPosition::get
{
return m_currentPosition;
virtual int get() = Windows::UI::Xaml::Data::ICollectionView::CurrentPosition::get
{
return m_currentPosition;
}
}
}
property bool IsCurrentAfterLast
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentAfterLast::get
property bool IsCurrentAfterLast
{
return m_currentPosition >= static_cast<int>(m_source->Size);
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentAfterLast::get
{
return m_currentPosition >= static_cast<int>(m_source->Size);
}
}
}
property bool IsCurrentBeforeFirst
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentBeforeFirst::get
property bool IsCurrentBeforeFirst
{
return m_currentPosition < 0;
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentBeforeFirst::get
{
return m_currentPosition < 0;
}
}
}
event WF::EventHandler<Platform::Object^>^ CurrentChanged
event WF::EventHandler<Platform::Object^>^ CurrentChanged
{
virtual WF::EventRegistrationToken add(WF::EventHandler<Platform::Object^>^ handler) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanged::add
{
@ -161,67 +158,71 @@ namespace CalculatorApp { namespace Common
m_currentChanging -= token;
}
}
// IVector<Object^>
// Not implemented methods
virtual void Append(Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::Append
{
throw ref new Platform::NotImplementedException();
}
virtual void Clear() = Windows::Foundation::Collections::IVector<Platform::Object^>::Clear
{
throw ref new Platform::NotImplementedException();
}
virtual unsigned int GetMany(unsigned int /*startIndex*/, Platform::WriteOnlyArray<Platform::Object^>^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::GetMany
{
throw ref new Platform::NotImplementedException();
}
virtual Windows::Foundation::Collections::IVectorView<Platform::Object^>^ GetView() = Windows::Foundation::Collections::IVector<Platform::Object^>::GetView
{
throw ref new Platform::NotImplementedException();
}
virtual void InsertAt(unsigned int /*index*/, Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::InsertAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAt(unsigned int /*index*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::RemoveAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAtEnd() = Windows::Foundation::Collections::IVector<Platform::Object^>::RemoveAtEnd
{
throw ref new Platform::NotImplementedException();
}
virtual void ReplaceAll(const Platform::Array<Platform::Object^>^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::ReplaceAll
{
throw ref new Platform::NotImplementedException();
}
virtual void SetAt(unsigned int /*index*/, Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::SetAt
{
throw ref new Platform::NotImplementedException();
}
// Implemented methods
virtual Platform::Object^ GetAt(unsigned int index) = Windows::Foundation::Collections::IVector<Platform::Object^>::GetAt
{
return m_source->GetAt(index);
}
virtual bool IndexOf(Platform::Object^ item, unsigned int* index) = Windows::Foundation::Collections::IVector<Platform::Object^>::IndexOf
{
return m_source->IndexOf(item, index);
}
property unsigned int Size
{
virtual unsigned int get() = Windows::Foundation::Collections::IVector<Platform::Object^>::Size::get
{
return m_source->Size;
throw ref new Platform::NotImplementedException();
}
}
// IObservableVector<Object^>
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ VectorChanged
virtual void Clear() = Windows::Foundation::Collections::IVector<Platform::Object ^>::Clear
{
throw ref new Platform::NotImplementedException();
}
virtual unsigned int GetMany(
unsigned int /*startIndex*/,
Platform::WriteOnlyArray<Platform::Object ^> ^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::GetMany
{
throw ref new Platform::NotImplementedException();
}
virtual Windows::Foundation::Collections::IVectorView<Platform::Object ^> ^ GetView() = Windows::Foundation::Collections::IVector<
Platform::Object ^>::GetView
{
throw ref new Platform::NotImplementedException();
}
virtual void InsertAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::InsertAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAt(unsigned int /*index*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::RemoveAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAtEnd() = Windows::Foundation::Collections::IVector<Platform::Object ^>::RemoveAtEnd
{
throw ref new Platform::NotImplementedException();
}
virtual void
ReplaceAll(const Platform::Array<Platform::Object ^> ^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::ReplaceAll
{
throw ref new Platform::NotImplementedException();
}
virtual void SetAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::SetAt
{
throw ref new Platform::NotImplementedException();
}
// Implemented methods
virtual Platform::Object ^ GetAt(unsigned int index) = Windows::Foundation::Collections::IVector<Platform::Object ^>::GetAt
{
return m_source->GetAt(index);
}
virtual bool IndexOf(Platform::Object ^ item, unsigned int* index) = Windows::Foundation::Collections::IVector<Platform::Object ^>::IndexOf
{
return m_source->IndexOf(item, index);
}
property unsigned int Size
{
virtual unsigned int get() = Windows::Foundation::Collections::IVector<Platform::Object ^>::Size::get
{
return m_source->Size;
}
}
// IObservableVector<Object^>
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ VectorChanged
{
virtual WF::EventRegistrationToken add(Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ handler) = Windows::Foundation::Collections::IObservableVector<Platform::Object^>::VectorChanged::add
{
@ -236,52 +237,57 @@ namespace CalculatorApp { namespace Common
// IIterable<Object^>
// Not implemented
virtual Windows::Foundation::Collections::IIterator<Platform::Object^>^ First() = Windows::Foundation::Collections::IIterable<Platform::Object^>::First
{
throw ref new Platform::NotImplementedException();
}
// Event handlers
void OnSourceBindableVectorChanged(Windows::UI::Xaml::Interop::IBindableObservableVector^ source, Platform::Object^ e)
{
Windows::Foundation::Collections::IVectorChangedEventArgs^ args = safe_cast<Windows::Foundation::Collections::IVectorChangedEventArgs^>(e);
m_vectorChanged(this, args);
}
Windows::UI::Xaml::Interop::IBindableVector^ m_source;
int m_currentPosition;
event WF::EventHandler<Platform::Object^>^ m_currentChanged;
event Windows::UI::Xaml::Data::CurrentChangingEventHandler^ m_currentChanging;
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ m_vectorChanged;
};
public ref class AlwaysSelectedCollectionViewConverter sealed: public Windows::UI::Xaml::Data::IValueConverter
{
public:
AlwaysSelectedCollectionViewConverter()
{ }
private:
virtual Platform::Object^ Convert(
Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{
auto result = dynamic_cast<Windows::UI::Xaml::Interop::IBindableVector^>(value);
if (result)
{
return ref new AlwaysSelectedCollectionView(result);
throw ref new Platform::NotImplementedException();
}
return Windows::UI::Xaml::DependencyProperty::UnsetValue; // Can't convert
}
virtual Platform::Object^ ConvertBack(
Platform::Object^ /*value*/,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
// Event handlers
void OnSourceBindableVectorChanged(Windows::UI::Xaml::Interop::IBindableObservableVector ^ source, Platform::Object ^ e)
{
Windows::Foundation::Collections::IVectorChangedEventArgs ^ args = safe_cast<Windows::Foundation::Collections::IVectorChangedEventArgs ^>(e);
m_vectorChanged(this, args);
}
Windows::UI::Xaml::Interop::IBindableVector ^ m_source;
int m_currentPosition;
event WF::EventHandler<Platform::Object ^> ^ m_currentChanged;
event Windows::UI::Xaml::Data::CurrentChangingEventHandler ^ m_currentChanging;
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object ^> ^ m_vectorChanged;
};
public
ref class AlwaysSelectedCollectionViewConverter sealed : public Windows::UI::Xaml::Data::IValueConverter
{
return Windows::UI::Xaml::DependencyProperty::UnsetValue;
}
};
}}
public:
AlwaysSelectedCollectionViewConverter()
{
}
private:
virtual Platform::Object
^ Convert(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{
auto result = dynamic_cast<Windows::UI::Xaml::Interop::IBindableVector ^>(value);
if (result)
{
return ref new AlwaysSelectedCollectionView(result);
}
return Windows::UI::Xaml::DependencyProperty::UnsetValue; // Can't convert
}
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ /*value*/,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{
return Windows::UI::Xaml::DependencyProperty::UnsetValue;
}
};
}
}

View file

@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "pch.h"
#include "AppResourceProvider.h"
@ -16,18 +14,18 @@ AppResourceProvider::AppResourceProvider()
m_cEngineStringResLoader = ResourceLoader::GetForViewIndependentUse(L"CEngineStrings");
}
AppResourceProvider & AppResourceProvider::GetInstance()
AppResourceProvider& AppResourceProvider::GetInstance()
{
static AppResourceProvider s_instance;
return s_instance;
}
String^ AppResourceProvider::GetResourceString(_In_ String^ key)
String ^ AppResourceProvider::GetResourceString(_In_ String ^ key)
{
return m_stringResLoader->GetString(key);
}
String^ AppResourceProvider::GetCEngineString(_In_ String^ key)
String ^ AppResourceProvider::GetCEngineString(_In_ String ^ key)
{
return m_cEngineStringResLoader->GetString(key);
}

View file

@ -8,13 +8,13 @@ namespace CalculatorApp
class AppResourceProvider
{
public:
static AppResourceProvider & GetInstance();
Platform::String^ GetResourceString(_In_ Platform::String^ key);
Platform::String^ GetCEngineString(_In_ Platform::String^ key);
static AppResourceProvider& GetInstance();
Platform::String ^ GetResourceString(_In_ Platform::String ^ key);
Platform::String ^ GetCEngineString(_In_ Platform::String ^ key);
private:
AppResourceProvider();
Windows::ApplicationModel::Resources::ResourceLoader^ m_stringResLoader;
Windows::ApplicationModel::Resources::ResourceLoader^ m_cEngineStringResLoader;
Windows::ApplicationModel::Resources::ResourceLoader ^ m_stringResLoader;
Windows::ApplicationModel::Resources::ResourceLoader ^ m_cEngineStringResLoader;
};
}

View file

@ -11,16 +11,17 @@
namespace CalculatorApp::Common::Automation
{
public interface class INarratorAnnouncementHost
public
interface class INarratorAnnouncementHost
{
public:
// Is the host available on this OS.
bool IsHostAvailable();
// Make a new instance of a concrete host.
INarratorAnnouncementHost^ MakeHost();
INarratorAnnouncementHost ^ MakeHost();
// Make an announcement using the concrete host's preferred method.
void Announce(NarratorAnnouncement^ announcement);
void Announce(NarratorAnnouncement ^ announcement);
};
}

View file

@ -9,9 +9,10 @@ using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace Windows::UI::Xaml::Controls;
LiveRegionHost::LiveRegionHost() :
m_host(nullptr)
{}
LiveRegionHost::LiveRegionHost()
: m_host(nullptr)
{
}
bool LiveRegionHost::IsHostAvailable()
{
@ -19,12 +20,12 @@ bool LiveRegionHost::IsHostAvailable()
return true;
}
INarratorAnnouncementHost^ LiveRegionHost::MakeHost()
INarratorAnnouncementHost ^ LiveRegionHost::MakeHost()
{
return ref new LiveRegionHost();
}
void LiveRegionHost::Announce(NarratorAnnouncement^ announcement)
void LiveRegionHost::Announce(NarratorAnnouncement ^ announcement)
{
if (m_host == nullptr)
{
@ -33,7 +34,7 @@ void LiveRegionHost::Announce(NarratorAnnouncement^ announcement)
}
AutomationProperties::SetName(m_host, announcement->Announcement);
AutomationPeer^ peer = FrameworkElementAutomationPeer::FromElement(m_host);
AutomationPeer ^ peer = FrameworkElementAutomationPeer::FromElement(m_host);
if (peer != nullptr)
{
peer->RaiseAutomationEvent(AutomationEvents::LiveRegionChanged);

View file

@ -16,17 +16,18 @@ namespace CalculatorApp::Common::Automation
// When the app switches to min version RS3, this class can be removed
// and the app will switch to using the Notification API.
// TODO - MSFT 12735088
public ref class LiveRegionHost sealed : public INarratorAnnouncementHost
public
ref class LiveRegionHost sealed : public INarratorAnnouncementHost
{
public:
LiveRegionHost();
virtual bool IsHostAvailable();
virtual INarratorAnnouncementHost^ MakeHost();
virtual INarratorAnnouncementHost ^ MakeHost();
virtual void Announce(NarratorAnnouncement^ announcement);
virtual void Announce(NarratorAnnouncement ^ announcement);
private:
Windows::UI::Xaml::UIElement^ m_host;
Windows::UI::Xaml::UIElement ^ m_host;
};
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@ -20,27 +20,29 @@ namespace CalculatorApp::Common::Automation
StringReference CategoryNameChanged(L"CategoryNameChanged");
StringReference UpdateCurrencyRates(L"UpdateCurrencyRates");
StringReference DisplayCopied(L"DisplayCopied");
StringReference OpenParenthesisCountChanged(L"OpenParenthesisCountChanged");
StringReference NoParenthesisAdded(L"NoParenthesisAdded");
}
}
NarratorAnnouncement::NarratorAnnouncement(
String^ announcement,
String^ activityId,
String ^ announcement,
String ^ activityId,
AutomationNotificationKind kind,
AutomationNotificationProcessing processing)
:
m_announcement(announcement),
m_activityId(activityId),
m_kind(kind),
m_processing(processing)
{}
: m_announcement(announcement)
, m_activityId(activityId)
, m_kind(kind)
, m_processing(processing)
{
}
String^ NarratorAnnouncement::Announcement::get()
String ^ NarratorAnnouncement::Announcement::get()
{
return m_announcement;
}
String^ NarratorAnnouncement::ActivityId::get()
String ^ NarratorAnnouncement::ActivityId::get()
{
return m_activityId;
}
@ -55,68 +57,48 @@ AutomationNotificationProcessing NarratorAnnouncement::Processing::get()
return m_processing;
}
bool NarratorAnnouncement::IsValid(NarratorAnnouncement^ announcement)
bool NarratorAnnouncement::IsValid(NarratorAnnouncement ^ announcement)
{
return announcement != nullptr
&& announcement->Announcement != nullptr
&& !announcement->Announcement->IsEmpty();
return announcement != nullptr && announcement->Announcement != nullptr && !announcement->Announcement->IsEmpty();
}
NarratorAnnouncement^ CalculatorAnnouncement::GetDisplayUpdatedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetDisplayUpdatedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::DisplayUpdated,
AutomationNotificationKind::Other,
AutomationNotificationProcessing::ImportantMostRecent);
announcement, CalculatorActivityIds::DisplayUpdated, AutomationNotificationKind::Other, AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::MaxDigitsReached,
AutomationNotificationKind::Other,
AutomationNotificationProcessing::ImportantMostRecent);
announcement, CalculatorActivityIds::MaxDigitsReached, AutomationNotificationKind::Other, AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetMemoryClearedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetMemoryClearedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::MemoryCleared,
AutomationNotificationKind::ItemRemoved,
AutomationNotificationProcessing::ImportantMostRecent);
announcement, CalculatorActivityIds::MemoryCleared, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetMemoryItemChangedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetMemoryItemChangedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::MemoryItemChanged,
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::MostRecent);
announcement, CalculatorActivityIds::MemoryItemChanged, AutomationNotificationKind::ActionCompleted, AutomationNotificationProcessing::MostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetMemoryItemAddedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetMemoryItemAddedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::MemoryItemAdded,
AutomationNotificationKind::ItemAdded,
AutomationNotificationProcessing::MostRecent);
announcement, CalculatorActivityIds::MemoryItemAdded, AutomationNotificationKind::ItemAdded, AutomationNotificationProcessing::MostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetHistoryClearedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetHistoryClearedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::HistoryCleared,
AutomationNotificationKind::ItemRemoved,
AutomationNotificationProcessing::MostRecent);
announcement, CalculatorActivityIds::HistoryCleared, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::MostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetCategoryNameChangedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetCategoryNameChangedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
@ -125,7 +107,7 @@ NarratorAnnouncement^ CalculatorAnnouncement::GetCategoryNameChangedAnnouncement
AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
@ -134,11 +116,26 @@ NarratorAnnouncement^ CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement
AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetDisplayCopiedAnnouncement(String^ announcement)
NarratorAnnouncement ^ CalculatorAnnouncement::GetDisplayCopiedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement, CalculatorActivityIds::DisplayCopied, AutomationNotificationKind::ActionCompleted, AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement ^ CalculatorAnnouncement::GetOpenParenthesisCountChangedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::DisplayCopied,
CalculatorActivityIds::OpenParenthesisCountChanged,
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement ^ CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::NoParenthesisAdded,
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
@ -11,7 +11,8 @@ namespace CalculatorApp::Common::Automation
// enums should be removed and the Windows types should be used
// instead.
// TODO - MSFT 12735088
public enum class AutomationNotificationKind
public
enum class AutomationNotificationKind
{
ItemAdded = 0,
ItemRemoved = 1,
@ -20,7 +21,8 @@ namespace CalculatorApp::Common::Automation
Other = 4
};
public enum class AutomationNotificationProcessing
public
enum class AutomationNotificationProcessing
{
ImportantAll = 0,
ImportantMostRecent = 1,
@ -29,20 +31,17 @@ namespace CalculatorApp::Common::Automation
CurrentThenMostRecent = 4
};
public ref class NarratorAnnouncement sealed
public
ref class NarratorAnnouncement sealed
{
public:
property Platform::String^ Announcement
{
Platform::String^ get();
}
property Platform::String
^ Announcement { Platform::String ^ get(); }
property Platform::String^ ActivityId
{
Platform::String^ get();
}
property Platform::String
^ ActivityId { Platform::String ^ get(); }
property AutomationNotificationKind Kind
property AutomationNotificationKind Kind
{
AutomationNotificationKind get();
}
@ -52,7 +51,7 @@ namespace CalculatorApp::Common::Automation
AutomationNotificationProcessing get();
}
static bool IsValid(NarratorAnnouncement^ announcement);
static bool IsValid(NarratorAnnouncement ^ announcement);
private:
// Make CalculatorAnnouncement a friend class so it is the only
@ -60,13 +59,13 @@ namespace CalculatorApp::Common::Automation
friend class CalculatorAnnouncement;
NarratorAnnouncement(
Platform::String^ announcement,
Platform::String^ activityId,
Platform::String ^ announcement,
Platform::String ^ activityId,
AutomationNotificationKind kind,
AutomationNotificationProcessing processing);
Platform::String^ m_announcement;
Platform::String^ m_activityId;
Platform::String ^ m_announcement;
Platform::String ^ m_activityId;
AutomationNotificationKind m_kind;
AutomationNotificationProcessing m_processing;
};
@ -76,19 +75,22 @@ namespace CalculatorApp::Common::Automation
class CalculatorAnnouncement
{
public:
static NarratorAnnouncement^ GetDisplayUpdatedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetMaxDigitsReachedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement ^ GetDisplayUpdatedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetMaxDigitsReachedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement^ GetMemoryClearedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetMemoryItemChangedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetMemoryItemAddedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement ^ GetMemoryClearedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetMemoryItemChangedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetMemoryItemAddedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement^ GetHistoryClearedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement ^ GetHistoryClearedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement^ GetCategoryNameChangedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement ^ GetCategoryNameChangedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement^ GetUpdateCurrencyRatesAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetDisplayCopiedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement ^ GetUpdateCurrencyRatesAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetDisplayCopiedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetOpenParenthesisCountChangedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetNoRightParenthesisAddedAnnouncement(Platform::String ^ announcement);
};
}

View file

@ -9,8 +9,8 @@
using namespace CalculatorApp::Common::Automation;
using namespace std;
INarratorAnnouncementHost^ NarratorAnnouncementHostFactory::s_hostProducer;
vector<INarratorAnnouncementHost^> NarratorAnnouncementHostFactory::s_hosts;
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::s_hostProducer;
vector<INarratorAnnouncementHost ^> NarratorAnnouncementHostFactory::s_hosts;
// This static variable is used only to call the initialization function, to initialize the other static variables.
int NarratorAnnouncementHostFactory::s_init = NarratorAnnouncementHostFactory::Initialize();
@ -32,15 +32,12 @@ void NarratorAnnouncementHostFactory::RegisterHosts()
{
// The host that will be used is the first available host,
// therefore, order of hosts is important here.
NarratorAnnouncementHostFactory::s_hosts = {
ref new NotificationHost(),
ref new LiveRegionHost()
};
NarratorAnnouncementHostFactory::s_hosts = { ref new NotificationHost(), ref new LiveRegionHost() };
}
INarratorAnnouncementHost^ NarratorAnnouncementHostFactory::GetHostProducer()
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::GetHostProducer()
{
for (INarratorAnnouncementHost^ host : NarratorAnnouncementHostFactory::s_hosts)
for (INarratorAnnouncementHost ^ host : NarratorAnnouncementHostFactory::s_hosts)
{
if (host->IsHostAvailable())
{
@ -52,7 +49,7 @@ INarratorAnnouncementHost^ NarratorAnnouncementHostFactory::GetHostProducer()
return nullptr;
}
INarratorAnnouncementHost^ NarratorAnnouncementHostFactory::MakeHost()
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::MakeHost()
{
if (NarratorAnnouncementHostFactory::s_hostProducer == nullptr)
{

View file

@ -14,18 +14,20 @@ namespace CalculatorApp::Common::Automation
class NarratorAnnouncementHostFactory
{
public:
static INarratorAnnouncementHost^ MakeHost();
static INarratorAnnouncementHost ^ MakeHost();
private:
NarratorAnnouncementHostFactory() {}
NarratorAnnouncementHostFactory()
{
}
static int Initialize();
static void RegisterHosts();
static INarratorAnnouncementHost^ GetHostProducer();
static INarratorAnnouncementHost ^ GetHostProducer();
private:
static int s_init;
static INarratorAnnouncementHost^ s_hostProducer;
static std::vector<INarratorAnnouncementHost^> s_hosts;
static INarratorAnnouncementHost ^ s_hostProducer;
static std::vector<INarratorAnnouncementHost ^> s_hosts;
};
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Implementation of the NarratorNotifier class.
@ -13,17 +13,16 @@ using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
DependencyProperty^ NarratorNotifier::s_announcementProperty;
DependencyProperty ^ NarratorNotifier::s_announcementProperty;
NarratorNotifier::NarratorNotifier()
{
m_announcementHost = NarratorAnnouncementHostFactory::MakeHost();
}
void NarratorNotifier::Announce(NarratorAnnouncement^ announcement)
void NarratorNotifier::Announce(NarratorAnnouncement ^ announcement)
{
if (NarratorAnnouncement::IsValid(announcement)
&& m_announcementHost != nullptr)
if (NarratorAnnouncement::IsValid(announcement) && m_announcementHost != nullptr)
{
m_announcementHost->Announce(announcement);
}
@ -32,19 +31,19 @@ void NarratorNotifier::Announce(NarratorAnnouncement^ announcement)
void NarratorNotifier::RegisterDependencyProperties()
{
s_announcementProperty = DependencyProperty::Register(
L"Announcement", // The name of the dependency property.
L"Announcement", // The name of the dependency property.
NarratorAnnouncement::typeid, // The type of the dependency property.
NarratorNotifier::typeid, // The owner of the dependency property.
NarratorNotifier::typeid, // The owner of the dependency property.
ref new PropertyMetadata(
nullptr, // Default value of the dependency property.
ref new PropertyChangedCallback(OnAnnouncementChanged)));
}
void NarratorNotifier::OnAnnouncementChanged(_In_ DependencyObject^ dependencyObject, _In_ DependencyPropertyChangedEventArgs^ e)
void NarratorNotifier::OnAnnouncementChanged(_In_ DependencyObject ^ dependencyObject, _In_ DependencyPropertyChangedEventArgs ^ e)
{
auto instance = safe_cast<NarratorNotifier^>(dependencyObject);
auto instance = safe_cast<NarratorNotifier ^>(dependencyObject);
if (instance != nullptr)
{
instance->Announce(safe_cast<NarratorAnnouncement^>(e->NewValue));
instance->Announce(safe_cast<NarratorAnnouncement ^>(e->NewValue));
}
}

View file

@ -8,12 +8,13 @@
namespace CalculatorApp::Common::Automation
{
public ref class NarratorNotifier sealed : public Windows::UI::Xaml::DependencyObject
public
ref class NarratorNotifier sealed : public Windows::UI::Xaml::DependencyObject
{
public:
NarratorNotifier();
void Announce(NarratorAnnouncement^ announcement);
void Announce(NarratorAnnouncement ^ announcement);
property NarratorAnnouncement^ Announcement
{
@ -26,32 +27,26 @@ namespace CalculatorApp::Common::Automation
static void RegisterDependencyProperties();
static property Windows::UI::Xaml::DependencyProperty^ AnnouncementProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
{
return s_announcementProperty;
}
}
static property Windows::UI::Xaml::DependencyProperty
^ AnnouncementProperty { Windows::UI::Xaml::DependencyProperty ^ get() { return s_announcementProperty; } }
static NarratorAnnouncement^ GetAnnouncement(Windows::UI::Xaml::DependencyObject^ element)
{
return safe_cast<NarratorAnnouncement^>(element->GetValue(s_announcementProperty));
}
static NarratorAnnouncement
^ GetAnnouncement(
Windows::UI::Xaml::DependencyObject ^ element) { return safe_cast<NarratorAnnouncement ^>(element->GetValue(s_announcementProperty)); }
static void SetAnnouncement(Windows::UI::Xaml::DependencyObject^ element, NarratorAnnouncement^ value)
static void SetAnnouncement(Windows::UI::Xaml::DependencyObject ^ element, NarratorAnnouncement ^ value)
{
element->SetValue(s_announcementProperty, value);
}
private:
static void OnAnnouncementChanged(
_In_ Windows::UI::Xaml::DependencyObject^ dependencyObject,
_In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ eventArgs);
_In_ Windows::UI::Xaml::DependencyObject ^ dependencyObject,
_In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ eventArgs);
static Windows::UI::Xaml::DependencyProperty^ s_announcementProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_announcementProperty;
private:
INarratorAnnouncementHost^ m_announcementHost;
INarratorAnnouncementHost ^ m_announcementHost;
};
}

View file

@ -10,23 +10,22 @@ using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace Windows::UI::Xaml::Controls;
NotificationHost::NotificationHost() :
m_host(nullptr)
{}
NotificationHost::NotificationHost()
: m_host(nullptr)
{
}
bool NotificationHost::IsHostAvailable()
{
return ApiInformation::IsMethodPresent(
L"Windows.UI.Xaml.Automation.Peers.AutomationPeer",
L"RaiseNotificationEvent");
return ApiInformation::IsMethodPresent(L"Windows.UI.Xaml.Automation.Peers.AutomationPeer", L"RaiseNotificationEvent");
}
INarratorAnnouncementHost^ NotificationHost::MakeHost()
INarratorAnnouncementHost ^ NotificationHost::MakeHost()
{
return ref new NotificationHost();
}
void NotificationHost::Announce(NarratorAnnouncement^ announcement)
void NotificationHost::Announce(NarratorAnnouncement ^ announcement)
{
if (m_host == nullptr)
{
@ -44,8 +43,7 @@ void NotificationHost::Announce(NarratorAnnouncement^ announcement)
}
}
StandardPeers::AutomationNotificationKind NotificationHost::GetWindowsNotificationKind(
CustomPeers::AutomationNotificationKind customKindType)
StandardPeers::AutomationNotificationKind NotificationHost::GetWindowsNotificationKind(CustomPeers::AutomationNotificationKind customKindType)
{
switch (customKindType)
{
@ -71,8 +69,8 @@ StandardPeers::AutomationNotificationKind NotificationHost::GetWindowsNotificati
return StandardPeers::AutomationNotificationKind::Other;
}
StandardPeers::AutomationNotificationProcessing NotificationHost::GetWindowsNotificationProcessing(
CustomPeers::AutomationNotificationProcessing customProcessingType)
StandardPeers::AutomationNotificationProcessing
NotificationHost::GetWindowsNotificationProcessing(CustomPeers::AutomationNotificationProcessing customProcessingType)
{
switch (customProcessingType)
{

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