├── .gitattributes ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── examples ├── gauss-method │ └── main.cpp └── jacobi-iteration │ └── main.cpp ├── include ├── tmath.hpp └── tmath_test.hpp ├── src ├── abs.cpp ├── cosecant.cpp ├── cosine.cpp ├── cotangent.cpp ├── degrad.cpp ├── equality.cpp ├── explog.cpp ├── factorial.cpp ├── fcm.cpp ├── matrix.cpp ├── power.cpp ├── roots.cpp ├── secant.cpp ├── sine.cpp ├── tangent.cpp └── vector.cpp └── test ├── abs.cpp ├── cosecant.cpp ├── cosine.cpp ├── cotangent.cpp ├── degrad.cpp ├── equality.cpp ├── explog.cpp ├── factorial.cpp ├── fcm.cpp ├── matrix.cpp ├── power.cpp ├── roots.cpp ├── secant.cpp ├── sine.cpp ├── tangent.cpp ├── test_utils.cpp └── vector.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.swp 7 | *.user 8 | *.userosscache 9 | *.sln.docstates 10 | 11 | # Build results 12 | [Dd]ebug/ 13 | [Dd]ebugPublic/ 14 | [Rr]elease/ 15 | [Rr]eleases/ 16 | x64/ 17 | x86/ 18 | build/ 19 | bld/ 20 | [Bb]in/ 21 | [Oo]bj/ 22 | 23 | # Roslyn cache directories 24 | *.ide/ 25 | 26 | # MSTest test Results 27 | [Tt]est[Rr]esult*/ 28 | [Bb]uild[Ll]og.* 29 | 30 | #NUNIT 31 | *.VisualState.xml 32 | TestResult.xml 33 | 34 | # Build Results of an ATL Project 35 | [Dd]ebugPS/ 36 | [Rr]eleasePS/ 37 | dlldata.c 38 | 39 | *_i.c 40 | *_p.c 41 | *_i.h 42 | *.ilk 43 | *.meta 44 | *.obj 45 | *.pch 46 | *.pdb 47 | *.pgc 48 | *.pgd 49 | *.rsp 50 | *.sbr 51 | *.tlb 52 | *.tli 53 | *.tlh 54 | *.tmp 55 | *.tmp_proj 56 | *.log 57 | *.vspscc 58 | *.vssscc 59 | .builds 60 | *.pidb 61 | *.svclog 62 | *.scc 63 | 64 | # Vagrant 65 | .vagrant 66 | 67 | # Chutzpah Test files 68 | _Chutzpah* 69 | 70 | # Visual C++ cache files 71 | ipch/ 72 | *.aps 73 | *.ncb 74 | *.opensdf 75 | *.sdf 76 | *.cachefile 77 | 78 | # Visual Studio profiler 79 | *.psess 80 | *.vsp 81 | *.vspx 82 | 83 | # TFS 2012 Local Workspace 84 | $tf/ 85 | 86 | # Guidance Automation Toolkit 87 | *.gpState 88 | 89 | # ReSharper is a .NET coding add-in 90 | _ReSharper*/ 91 | *.[Rr]e[Ss]harper 92 | *.DotSettings.user 93 | 94 | # JustCode is a .NET coding addin-in 95 | .JustCode 96 | 97 | # TeamCity is a build add-in 98 | _TeamCity* 99 | 100 | # DotCover is a Code Coverage Tool 101 | *.dotCover 102 | 103 | # NCrunch 104 | _NCrunch_* 105 | .*crunch*.local.xml 106 | 107 | # MightyMoose 108 | *.mm.* 109 | AutoTest.Net/ 110 | 111 | # Web workbench (sass) 112 | .sass-cache/ 113 | 114 | # Installshield output folder 115 | [Ee]xpress/ 116 | 117 | # DocProject is a documentation generator add-in 118 | DocProject/buildhelp/ 119 | DocProject/Help/*.HxT 120 | DocProject/Help/*.HxC 121 | DocProject/Help/*.hhc 122 | DocProject/Help/*.hhk 123 | DocProject/Help/*.hhp 124 | DocProject/Help/Html2 125 | DocProject/Help/html 126 | 127 | # Click-Once directory 128 | publish/ 129 | 130 | # Publish Web Output 131 | *.[Pp]ublish.xml 132 | *.azurePubxml 133 | # TODO: Comment the next line if you want to checkin your web deploy settings 134 | # but database connection strings (with potential passwords) will be unencrypted 135 | *.pubxml 136 | *.publishproj 137 | 138 | # NuGet Packages 139 | *.nupkg 140 | # The packages folder can be ignored because of Package Restore 141 | **/packages/* 142 | # except build/, which is used as an MSBuild target. 143 | !**/packages/build/ 144 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 145 | #!**/packages/repositories.config 146 | 147 | # Windows Azure Build Output 148 | csx/ 149 | *.build.csdef 150 | 151 | # Windows Store app package directory 152 | AppPackages/ 153 | 154 | # Others 155 | sql/ 156 | *.Cache 157 | ClientBin/ 158 | [Ss]tyle[Cc]op.* 159 | ~$* 160 | *~ 161 | *.dbmdl 162 | *.dbproj.schemaview 163 | *.pfx 164 | *.publishsettings 165 | node_modules/ 166 | 167 | # RIA/Silverlight projects 168 | Generated_Code/ 169 | 170 | # Backup & report files from converting an old project file 171 | # to a newer Visual Studio version. Backup files are not needed, 172 | # because we have git ;-) 173 | _UpgradeReport_Files/ 174 | Backup*/ 175 | UpgradeLog*.XML 176 | UpgradeLog*.htm 177 | 178 | # SQL Server files 179 | *.mdf 180 | *.ldf 181 | 182 | # Business Intelligence projects 183 | *.rdl.data 184 | *.bim.layout 185 | *.bim_*.settings 186 | 187 | # Microsoft Fakes 188 | FakesAssemblies/ 189 | 190 | # ========================= 191 | # Operating System Files 192 | # ========================= 193 | 194 | # OSX 195 | # ========================= 196 | 197 | .DS_Store 198 | .AppleDouble 199 | .LSOverride 200 | 201 | # Thumbnails 202 | ._* 203 | 204 | # Files that might appear on external disk 205 | .Spotlight-V100 206 | .Trashes 207 | 208 | # Directories potentially created on remote AFP share 209 | .AppleDB 210 | .AppleDesktop 211 | Network Trash Folder 212 | Temporary Items 213 | .apdisk 214 | 215 | # Windows 216 | # ========================= 217 | 218 | # Windows image file caches 219 | Thumbs.db 220 | ehthumbs.db 221 | 222 | # Folder config file 223 | Desktop.ini 224 | 225 | # Recycle Bin used on file shares 226 | $RECYCLE.BIN/ 227 | 228 | # Windows Installer files 229 | *.cab 230 | *.msi 231 | *.msm 232 | *.msp 233 | 234 | # Windows shortcuts 235 | *.lnk 236 | 237 | build/* 238 | objects/* 239 | lib/* 240 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: g++-4.8 3 | sudo: required 4 | dist: trusty 5 | 6 | install: 7 | - sudo apt-get update -qq 8 | - sudo apt-get install gcc-4.8 -y -qq 9 | 10 | script: 11 | - make all 12 | 13 | notifications: 14 | email: false 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | All tmath development occurs in feature branches and all contributions occur via GitHub Pull Requests. 2 | All code must be reviewed, even if it's written by members of the core team, so following the code review process is critical to successful tmath development. 3 | 4 | ## Git workflow 5 | 6 | Please do all of your development in a feature branch, on your own fork of tmath. You should clone tmath normally, like this: 7 | 8 | ``` 9 | git clone git@github.com:lnsp/tmath.git 10 | ``` 11 | 12 | Then, your "remote" should be set up as follows: 13 | 14 | ``` 15 | $ cd tmath 16 | $ git remote -v 17 | origin git@github.com:lnsp/tmath.git (fetch) 18 | origin git@gitHub.com:lnsp/tmath.git (push) 19 | ``` 20 | 21 | Now, use the GitHub UI to fork tmath to your personal GitHub organization. Then, add the remote URL of your fork to git's local remotes: 22 | 23 | ``` 24 | $ git remote add marpaia git@github.com:marpaia/tmath.git 25 | ``` 26 | 27 | Now, your "remote" should be set up as follows: 28 | 29 | ``` 30 | $ git remote -v 31 | marpaia git@github.com:marpaia/tmath.git (fetch) 32 | marpaia git@github.com:marpaia/tmath.git (push) 33 | origin git@github.com:lnsp/tmath.git (fetch) 34 | origin git@gitHub.com:lnsp/tmath.git (push) 35 | ``` 36 | 37 | When you're ready to start working on a new feature, create a new branch: 38 | 39 | ``` 40 | $ git checkout -b my-feature 41 | ``` 42 | 43 | Write your code and when you're ready to put up a Pull Request, push your local branch to your fork: 44 | 45 | ``` 46 | $ git add . 47 | $ git commit -m "my awesome feature!" 48 | $ git push -u marpaia my-feature 49 | ``` 50 | 51 | Visit https://github.com/lnsp/tmath and use the web UI to create a Pull Request. Once your pull request has gone through sufficient review and iteration, please squash all of your commits into one commit. 52 | 53 | ## Pull Request workflow 54 | 55 | In most cases your PR should represent a single body of work. 56 | It is fine to change unrelated small-things like nits or code-format issues but make every effort to submit isolated changes. 57 | This makes documentation, references, regression tracking and if needed, a revert, easier. 58 | 59 | ## Updating Pull Requests 60 | 61 | Pull requests will often need revision, most likely after the required code review from the friendly core development team. 62 | 63 | Our preference is to minimize the number of commits in a pull request and represent each body of change as a single, concise, commit. To do this we ask you to [squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) your git commits before we merge changes. There are two basic workflows for squashing, let's run through examples of each. 64 | 65 | **You create a pull request with several commits** 66 | 67 | If you open a pull request from a branch with 'stacked commits' the request will ask us to merge the lot of them into our master. That is no fun, and we will promptly ask you to squash! If you have 5 commits in the pull request you can squash these into 1 using: 68 | 69 | ``` 70 | $ git rebase -i HEAD~5 71 | ``` 72 | 73 | This tells git to perform an interactive rebase onto the `HEAD-5` commit. The interactive part means your favorite editor will prompt you for actions. To turn 5 commits into 1 we'll `pick` the first, then `squash` the remaining, in this case 4. The 'squashed' 4 will be squashed into the commit we 'pick'. Within the interactive editor, change the last 4 'picks' to an `s`, shorthand for squash. 74 | 75 | For example here are my 5 commits while editing this guide: 76 | 77 | ``` 78 | pick dc849a9 Update contributing with squash instructions 79 | pick 8b1fa6b Minor change to contributing 80 | pick 45baf1a Delete whitespace in contributing 81 | pick bded8d7 Delete more whitespace 82 | pick ab49a55 Fix small mistake 83 | ``` 84 | 85 | I can squash these into a single commit by updating and saving: 86 | 87 | ``` 88 | pick dc849a9 Update contributing with squash instructions 89 | s 8b1fa6b Minor change to contributing 90 | s 45baf1a Delete whitespace in contributing 91 | s bded8d7 Delete more whitespace 92 | s ab49a55 Fix small mistake 93 | ``` 94 | 95 | The next prompt allows us to amend the commit message: 96 | 97 | ``` 98 | # This is a combination of 5 commits. 99 | # The first commit's message is: 100 | Update contributing with squash instructions 101 | # This is the 2nd commit message: 102 | Minor change to contributing 103 | # This is the 3rd commit message: 104 | Delete whitespace in contributing 105 | # This is the 4th commit message: 106 | Delete more whitespace 107 | # This is the 5th commit message: 108 | Fix small mistake 109 | ``` 110 | 111 | I will remove everything except for the first line, as that is the thesis for all 5 commits, and save: 112 | 113 | ``` 114 | # This is a combination of 5 commits. 115 | # The first commit's message is: 116 | Update contributing with squash instructions 117 | ``` 118 | 119 | When you save you can verify your 5 commits are now 1 by inspecting the `git log`. To update your pull request you'll need to force-push since you just rewrote your local history: 120 | 121 | ``` 122 | $ git push -f 123 | ``` 124 | 125 | **You make updates to your pull request** 126 | 127 | If the pull request needs changes, or you decide to update the content, please 'amend' your previous commit: 128 | 129 | ``` 130 | $ git commit --amend 131 | ``` 132 | 133 | Like squashing, this changes the branch history so you'll need to force push the changes to update the pull request: 134 | 135 | ``` 136 | $ git push -f 137 | ``` 138 | 139 | In all cases, if the pull request is triggering automatic build/integration tests, the tests will rerun reflecting your changes. 140 | 141 | ### Linking issues 142 | 143 | Once you submit your pull request, link the GitHub issue which your Pull Request implements. To do this, if the relevant issue is #7, then simply type "#7" somewhere in the Pull Request description or comments. This links the Pull Request with the issue, which makes things easier to track down later on. 144 | 145 | ### Adding the appropriate labels 146 | 147 | To facilitate development, tmath developers adhere to a particular label workflow. The core development team will assign labels as appropriate. 148 | 149 | #### "ready for review" vs "in progress" 150 | 151 | Pull Requests are a great way to track the on-going development of an existing feature. For this reason, if you create a Pull Request and it's not ready for review just yet, attach the "in progress" label. If the Pull Request is ready for review, attach the "ready for review" label. Once the "ready for review" label has been applied, a member of the tmath core team will review your Pull Request. 152 | 153 | #### Topic labels 154 | 155 | Are you creating a new feature? Attach the **feature** label. 156 | 157 | Are you in some way altering build infrastructure? Attach the **build** label. 158 | 159 | Are you fixing a memory leak? Attach the **bugfix** label. 160 | 161 | The pattern here should be pretty obvious. Please put the appropriate effort into attaching the appropriate labels to your Pull Request. 162 | 163 | ## Unit Test expectations 164 | 165 | All code that you submit to tmath should include automated tests. Our test infrastructure is assert based and easy to use. 166 | 167 | ## Memory leak expectations 168 | 169 | tmath runs in the context of long running processes. It's critical that there are no memory leaks in tmath code. All code should be thoroughly tested for leaks. 170 | 171 | When you submit a Pull Request, please consider including the output of a valgrind analysis. 172 | 173 | ## Code of Conduct 174 | 175 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 176 | 177 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 178 | 179 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 180 | 181 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 182 | 183 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 184 | 185 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Lennart Espe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Compiler flags 2 | # build directory 3 | BDIR=build 4 | # object directory 5 | ODIR=objects 6 | # source directory 7 | SDIR=src 8 | # include directory 9 | IDIR=include 10 | # test directory 11 | TDIR=test 12 | # library directory 13 | LDIR=lib 14 | # example source directory 15 | EDIR=examples 16 | # example bin directory 17 | EBIN=examples/bin 18 | 19 | # generated library path 20 | LIB=$(LDIR)/libtmath.a 21 | # include flag 22 | INC=-I$(IDIR) 23 | # other compiler flags 24 | CFLAGS=-std=c++11 -g -gstabs 25 | 26 | TUTILS=tutils 27 | TUTILS_OBJ=$(ODIR)/$(TUTILS).o 28 | 29 | _UNITS= abs.o cosecant.o cosine.o cotangent.o degrad.o equality.o \ 30 | explog.o factorial.o fcm.o power.o roots.o secant.o sine.o \ 31 | tangent.o vector.o matrix.o 32 | OBJECTS=$(patsubst %,$(ODIR)/%,$(_UNITS)) 33 | TESTS=$(patsubst %,$(ODIR)/test_%,$(_UNITS)) 34 | 35 | all: lib tests 36 | @echo "done." 37 | 38 | lib: folders $(LIB) 39 | @echo "build library." 40 | 41 | folders: 42 | @mkdir -p $(BDIR) $(ODIR) $(LDIR) 43 | 44 | tests: folders utils $(TESTS) 45 | @echo "all tests passed." 46 | 47 | # build test utilities 48 | utils: 49 | $(CC) $(INC) $(CFLAGS) -c -o $(TUTILS_OBJ) $(TDIR)/test_utils.cpp 50 | 51 | $(EBIN): 52 | @mkdir -p $(EBIN) 53 | 54 | $(EDIR): $(EBIN) lib 55 | $(CC) $(INC) $(CFLAGS) -o $(EBIN)/gauss $(EDIR)/gauss-method/main.cpp $(LIB) 56 | $(CC) $(INC) $(CFLAGS) -o $(EBIN)/jacobi $(EDIR)/jacobi-iteration/main.cpp $(LIB) 57 | 58 | # build and run tests 59 | $(ODIR)/test_%.o: $(TDIR)/%.cpp 60 | $(CC) $(INC) $(CFLAGS) -o $@ $< $(TUTILS_OBJ) $(LIB) 61 | @$@ 62 | 63 | # build objects 64 | $(ODIR)/%.o: $(SDIR)/%.cpp 65 | $(CC) -c $(INC) -o $@ $< $(CFLAGS) 66 | 67 | # build library 68 | $(LIB): $(OBJECTS) 69 | ar rvs $(LIB) $^ 70 | 71 | # make clean 72 | clean: 73 | @rm -rf $(BDIR) $(ODIR) $(LDIR) $(EBIN) 74 | @echo "workspace cleaned." 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TMath [![Build status](https://travis-ci.org/lnsp/tmath.svg?branch=stable)](https://travis-ci.org/lnsp/tmath) 2 | A small math function collection based on the Taylor expansion series. 3 | 4 | ## Building the project 5 | - Download the source files from the `master`-tree 6 | - To build the project, you need to have `g++` and `make` installed 7 | - And you need to run `export CC=g++` 8 | - If everything is ready, run `make` and ... 9 | - ... your `libtmath.a` library file is ready in the `lib` folder 10 | 11 | ## How to use 12 | Just build it as described above, include the header files and link the library. The library uses the types `TMath::DOUBLE`(`long double`) and `TMath::LONG`(`long long`) for parameters and return values. 13 | 14 | ## What is included? 15 | ### Mathematical functions 16 | 17 | Function | Description 18 | :-------------------------------------: | --------------------------------------------------------- 19 | `sin(DOUBLE x)` | sine of x 20 | `asin(DOUBLE x)` | arcsine of x 21 | `sinh(DOUBLE x)` | hyperbolic sine of x 22 | `cos(DOUBLE x)` | cosine of x 23 | `acos(DOUBLE x)` | arccosine of x 24 | `cosh(DOUBLE x)` | hyperbolic cosine of x 25 | `tan(DOUBLE x)` | tangent of x 26 | `atan(DOUBLE x)` | arctangent of x 27 | `cot(DOUBLE x)` | cotangent of x 28 | `acot(DOUBLE x)` | arccotangent of x 29 | `coth(DOUBLE x)` | hyperbolic cotangent of x 30 | `sec(DOUBLE x)` | secant of x 31 | `asec(DOUBLE x)` | arcsecant of x 32 | `sech(DOUBLE x)` | hyperbolic secant of x 33 | `cosec(DOUBLE x)` | cosecant of x 34 | `acsc(DOUBLE x)` | arccosecant of x 35 | `csch(DOUBLE x)` | hyperbolic cosecant of x 36 | `floor(DOUBLE x)` | next lower integer of x 37 | `ceil(DOUBLE x)` | next higher integer of x 38 | `mod(LONG x, LONG y)` | the remainder of the division x / y 39 | `exp(DOUBLE x)` | natural exponential function 40 | `sqrt(DOUBLE x)` | squareroot of x 41 | `root(DOUBLE x, DOUBLE n)` | n-th root of x 42 | `ln(DOUBLE x)` | natural logarithm of x 43 | `lg(DOUBLE x)` | common logarithm of x 44 | `lb(DOUBLE x)` | binary logarithm of x 45 | `log(DOUBLE x, DOUBLE n)` | logarithm with base n of x 46 | `pow(DOUBLE x, DOUBLE n)` | x to the power of n 47 | `pow(LONG x, LONG n)` | x to the power of n 48 | `pow(DOUBLE x, LONG n)` | x to the power of n 49 | `fac(LONG n)` | factorial of n 50 | `facd(LONG n)` | factorial of n using floating point 51 | `oddfac(LONG n)` | odd-factorial of n 52 | `oddfacd(LONG n)` | odd-factorial of n using floating point 53 | `rad(DOUBLE x)` | degrees to radiant 54 | `deg(DOUBLE x)` | radiant to degrees 55 | `abs(DOUBLE x)` | absolute value of x 56 | `equal(DOUBLE x, DOUBLE y)` | floating-point number equality 57 | `equal(DOUBLE x, DOUBLE y, DOUBLE eps)` | floating-point number equality with a variance of epsilon 58 | 59 | ### Vector class 60 | To initialize a new vector just use initializer lists (like `Vector {1, 2, 3}`) or create a null-vector using `Vector(n)` (where n is the number of dimensions). 61 | 62 | Operation | Description 63 | --------------- | ------------------------------------------------------------- 64 | `a[n]` | Access the n-th element of the vector `a` 65 | `a.at(n)` | Access the n-th element of the vector `a` as a constant 66 | `a + b` | Adds vector `a` and `b` 67 | `a - b` | Subtracts vector `a` from `b` 68 | `a * s` | Scales the vector by the factor `s` 69 | `a / s` | Scales the vector by the factor `1 / s` 70 | `a == b` | Tests if vector `a` is equal to `b` 71 | `a != b` | Tests if vector `a` is not equal to `b` 72 | `a.equal(b, e)` | Tests if the vector `a` is equal to `b` with the accuracy `e` 73 | `a.dot(b)` | Dot product of `a` and `b`. 74 | `a.cross(b)` | Cross product of `a` and `b` 75 | `a.norm()` | Normalized copy of the vector `a` 76 | `a.length()` | Length of vector `a` 77 | `a.dim()` | Dimensions of vector `a` 78 | `a.to_string()` | Generates a string representation of the vector `a` 79 | 80 | ### Matrix class 81 | To initialize a new matrix you can use initializer lists (like `Matrix{{1, 0}, {0, 1}}`) or create a null-matrix using `Matrix(x, y)` (where x is the number of cols and y the number of rows). 82 | 83 | Operation | Description 84 | --------------- | ------------------------------------------------------------- 85 | `m[n]` | Access the n-th row of the matrix 86 | `m[n][x]` | Access the element at row n and col x 87 | `m.at(n)` | Access the n-th row of the matrix as a constant 88 | `m.at(n, x)` | Access the element at row n and col x as a constant 89 | `m * v` | Multiply matrix `m` with vector `v` 90 | `m * a` | Multiply matrix `m` with matrix `a` 91 | `m * s` | Multiply matrix `m` with scalar `s` 92 | `-m` | Negate matrix `m` 93 | `a + b` | Add the matrices 94 | `a - b` | Subtract the matrices 95 | `a.equal(b, e)` | Tests if the matrix `a` is equal to `b` with the accuary `e` 96 | `a == b` | Tests if the matrix `a` is equal to `b` 97 | `a != b` | Tests if the matrix `a` is not equal to `b` 98 | `a.colCount()` | Get the number of matrix cols 99 | `a.rowCount()` | Get the number of matrix rows 100 | `a.to_string()` | Generate a string representation of the matrix 101 | `identity(n)` | Generates an identity matrix of dimension `n` 102 | 103 | ## What is planned? 104 | - Statistics 105 | - Numerics (e.g. solvers for ODE/PDE/LS) 106 | -------------------------------------------------------------------------------- /examples/gauss-method/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmath.hpp" 3 | 4 | #define ERR_DIM_MISMATCH "Matrix-vector dimension mismatch" 5 | #define ERR_NOT_QUADRATIC "Can only solve quadratic systems" 6 | #define ERR_NO_SOLUTION "The system has no unique solution" 7 | 8 | // Solves A * x = b. Returns x. 9 | TMath::Vector solve(TMath::Matrix A, TMath::Vector b) 10 | { 11 | int n = A.rowCount(), m = A.colCount(), p = b.dim(); 12 | if (n != m) throw ERR_NOT_QUADRATIC; 13 | if (n != p) throw ERR_DIM_MISMATCH; 14 | // Decompose into upper-right matrix 15 | for (int i = 0; i < m; i++) { 16 | // Swap out pivot element for better numerics 17 | int maxJ = i; 18 | for (int j = 0; j < n; j++) if (A[j][i] > A[maxJ][i]) maxJ = j; 19 | TMath::Vector tmpA = A[maxJ]; 20 | A[maxJ] = A[i]; 21 | A[i] = tmpA; 22 | TMath::DOUBLE tmpB = b[maxJ]; 23 | b[maxJ] = b[i]; 24 | b[i] = tmpB; 25 | // Make A[i+1...n][i] = 0. 26 | if (A[i][i] == 0.) throw ERR_NO_SOLUTION; 27 | for (int j = i + 1; j < n; j++) { 28 | TMath::DOUBLE f = A[j][i] / A[i][i]; 29 | A[j] = A[j] - A[i] * f; 30 | b[j] = b[j] - b[i] * f; 31 | } 32 | } 33 | // Resubstitute into system 34 | TMath::Vector x(n); 35 | for (int i = n-1; i >= 0; i--) { 36 | TMath::DOUBLE f = 0; 37 | for (int j = n-1; j > i; j--) f += x[j] * A[i][j]; 38 | x[i] = (b[i] - f) / A[i][i]; 39 | } 40 | return x; 41 | } 42 | 43 | int main() 44 | { 45 | std::cout << "TMath :: Gauss solver" << std::endl; 46 | int n; 47 | std::cout << "Enter matrix dimension: "; std::cin >> n; 48 | TMath::Matrix A(n, n); 49 | std::cout << "Enter matrix (row per row, space separated):" << std::endl; 50 | for (int i = 0; i < n; i++) { 51 | for (int j = 0; j < n; j++) { 52 | TMath::DOUBLE f; 53 | std::cin >> f; 54 | A[i][j] = f; 55 | } 56 | } 57 | TMath::Vector b(n); 58 | std::cout << "Enter vector:" << std::endl; 59 | for (int i = 0; i < n; i++) { 60 | TMath::DOUBLE f; 61 | std::cin >> f; 62 | b[i] = f; 63 | } 64 | TMath::Vector x; 65 | try { 66 | x = solve(A, b); 67 | } catch (std::string err) { 68 | std::cout << "error: " << err << std::endl; 69 | return 1; 70 | } 71 | std::cout << "Solution: " << x.to_string() << std::endl; 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /examples/jacobi-iteration/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmath.hpp" 3 | 4 | TMath::Vector solve(TMath::Matrix A, TMath::Vector b, TMath::DOUBLE delta) 5 | { 6 | int n = A.rowCount(), m = A.colCount(), p = b.dim(); 7 | if (n != m || n != p) throw "mismatch dimensions"; 8 | 9 | TMath::Vector x, x_ = b; 10 | do { 11 | x = b; 12 | for (int i = 0; i < n; i++) { 13 | for (int j = 0; j < n; j++) { 14 | if (i == j) continue; 15 | x[i] = x[i] - A[i][j] * x_[j]; 16 | } 17 | x[i] = x[i] / A[i][i]; 18 | } 19 | } while ((x_ - (x_ = x)).length() > delta); 20 | 21 | return x_; 22 | } 23 | 24 | int main() 25 | { 26 | std::cout << "TMath :: Jacobi iteration solver" << std::endl; 27 | int n; 28 | std::cout << "Enter matrix dimension: "; std::cin >> n; 29 | TMath::Matrix A(n, n); 30 | std::cout << "Enter matrix (row per row, space separated):" << std::endl; 31 | for (int i = 0; i < n; i++) { 32 | for (int j = 0; j < n; j++) { 33 | TMath::DOUBLE f; 34 | std::cin >> f; 35 | A[i][j] = f; 36 | } 37 | } 38 | TMath::Vector b(n); 39 | std::cout << "Enter vector:" << std::endl; 40 | for (int i = 0; i < n; i++) { 41 | TMath::DOUBLE f; 42 | std::cin >> f; 43 | b[i] = f; 44 | } 45 | TMath::DOUBLE delta; 46 | std::cout << "Enter delta: "; 47 | std::cin >> delta; 48 | TMath::Vector x; 49 | try { 50 | x = solve(A, b, delta); 51 | } catch (std::string err) { 52 | std::cout << "error: " << err << std::endl; 53 | return 1; 54 | } 55 | std::cout << "Solution: " << x.to_string() << std::endl; 56 | return 0; 57 | } -------------------------------------------------------------------------------- /include/tmath.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TMATH_HPP 2 | #define _TMATH_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace TMath { 10 | // Shortform for long long 11 | typedef long long LONG; 12 | // Shortform for long double 13 | typedef long double DOUBLE; 14 | // A estimation of Pi 15 | const DOUBLE PI = 3.141592653589793238462643383279502884197169399375105820974944592307816406286; 16 | // A estimation of e 17 | const DOUBLE E = 2.718281828459045235360287471352662497757247093699959574966967627724076630354; 18 | // Constant for equality comparison for floating point numbers 19 | const DOUBLE EQUAL_EPSILON = 1e-7; 20 | // Mismatched dimensions error for vectors and matrices 21 | const std::string DIMENSION_ERROR = "Mismatched dimensions"; 22 | const std::string EMPTY_MATRIX_ERROR = "Empty matrix"; 23 | const std::string OUT_OF_BOUNDS = "Index out of bounds"; 24 | // Error if the operation is not applicable 25 | const std::string BAD_OPERATION = "Operation is not applicable"; 26 | // Vector length is equal to zero 27 | const std::string ZERO_LENGTH = "Vector has length 0"; 28 | 29 | LONG floor(const DOUBLE&); 30 | LONG ceil(const DOUBLE&); 31 | DOUBLE mod(const DOUBLE&, const DOUBLE&); 32 | 33 | DOUBLE sin(const DOUBLE&); // sine 34 | DOUBLE asin(const DOUBLE&); // arcsine 35 | DOUBLE sinh(const DOUBLE&); // hyperbolic sine 36 | 37 | DOUBLE cos(const DOUBLE&); // cosine 38 | DOUBLE acos(const DOUBLE&); // arccosine 39 | DOUBLE cosh(const DOUBLE&); //hyperbolic cosine 40 | 41 | DOUBLE tan(const DOUBLE&); // tangent 42 | DOUBLE atan(const DOUBLE&); // arctangent 43 | DOUBLE tanh(const DOUBLE&); // hyperbolic tangent 44 | 45 | DOUBLE cot(const DOUBLE&); // cotangent 46 | DOUBLE acot(const DOUBLE&); // arccotangent 47 | DOUBLE coth(const DOUBLE&); // hyperbolic cotangent 48 | 49 | DOUBLE sec(const DOUBLE&); // secant 50 | DOUBLE asec(const DOUBLE&); // arcsecant 51 | DOUBLE sech(const DOUBLE&); // hyperbolic secant 52 | 53 | DOUBLE csc(const DOUBLE&); // cosecant 54 | DOUBLE acsc(const DOUBLE&); // arccosecant 55 | DOUBLE csch(const DOUBLE&); // hyperbolic cosecant 56 | 57 | DOUBLE rad(const DOUBLE&); // degrees to radians 58 | DOUBLE deg(const DOUBLE&); // radians to degrees 59 | 60 | DOUBLE exp(const DOUBLE&); 61 | DOUBLE sqrt(const DOUBLE&); 62 | DOUBLE root(const DOUBLE&, const DOUBLE&); 63 | DOUBLE ln(const DOUBLE&); 64 | DOUBLE lg(const DOUBLE&); 65 | DOUBLE lb(const DOUBLE&); 66 | DOUBLE log(const DOUBLE&, const DOUBLE&); 67 | 68 | DOUBLE pow(const DOUBLE&, const DOUBLE&); 69 | DOUBLE pow(const DOUBLE&, const LONG&); 70 | LONG pow(const LONG&, const LONG&); 71 | 72 | LONG fac(const LONG&); 73 | DOUBLE facd(const LONG&); 74 | LONG oddfac(const LONG&); 75 | DOUBLE oddfacd(const LONG&); 76 | 77 | DOUBLE abs(const DOUBLE&); 78 | DOUBLE equal(const DOUBLE&, const DOUBLE&); 79 | DOUBLE equal(const DOUBLE&, const DOUBLE&, const DOUBLE&); 80 | 81 | class Vector { 82 | private: 83 | std::vector elements; 84 | int checkDimensions(const Vector&) const; 85 | public: 86 | Vector() {} 87 | Vector(std::initializer_list list) : elements(list) {} 88 | Vector(const int& d) : elements(d) {} 89 | Vector(const Vector& v) : elements(v.elements) {}; 90 | DOUBLE& operator[](const int&); 91 | DOUBLE at(const int&) const; 92 | Vector operator+(const Vector&) const; 93 | Vector operator-() const; 94 | Vector operator-(const Vector&) const; 95 | Vector operator*(const DOUBLE&) const; 96 | Vector operator/(const DOUBLE&) const; 97 | bool equal(const Vector&, const DOUBLE&) const; 98 | bool operator==(const Vector&) const; 99 | bool operator!=(const Vector&) const; 100 | DOUBLE dot(const Vector&) const; 101 | Vector cross(const Vector&) const; 102 | DOUBLE sum() const; 103 | Vector norm() const; 104 | DOUBLE length() const; 105 | int dim() const; 106 | std::string to_string() const; 107 | }; 108 | 109 | class Matrix { 110 | private: 111 | std::vector elements; 112 | std::pair validate(const Matrix&) const; 113 | public: 114 | Matrix(std::initializer_list>); 115 | Matrix(const int& rows, const int& cols); 116 | Matrix(const Matrix& m); 117 | Vector& operator[](const int&); 118 | Vector col(const int&) const; 119 | Vector row(const int&) const; 120 | DOUBLE at(const int&, const int&) const; 121 | bool equal(const Matrix&, const DOUBLE&) const; 122 | bool operator==(const Matrix&) const; 123 | bool operator!=(const Matrix&) const; 124 | Matrix operator+(const Matrix&) const; 125 | Matrix operator-(const Matrix&) const; 126 | Matrix operator-() const; 127 | Vector operator*(const Vector&) const; 128 | Matrix operator*(const DOUBLE&) const; 129 | Matrix operator*(const Matrix&) const; 130 | int rowCount() const; 131 | int colCount() const; 132 | std::string to_string() const; 133 | static Matrix identity(const int&); 134 | }; 135 | } 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /include/tmath_test.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TMATH_TEST_HPP 2 | #define _TMATH_TEST_HPP 3 | 4 | #include 5 | #include 6 | #include "tmath.hpp" 7 | 8 | namespace TMathTest { 9 | const TMath::DOUBLE DEFAULT_TOLERANCE = 0.001; 10 | bool equal(TMath::DOUBLE x, TMath::DOUBLE y, TMath::DOUBLE tolerance); 11 | void assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression); 12 | void assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression, TMath::DOUBLE tolerance); 13 | void assert(TMath::Matrix a, TMath::Matrix b, std::string expression); 14 | void assert(TMath::Matrix a, TMath::Matrix b, std::string expression, TMath::DOUBLE tolerance); 15 | void assert(TMath::Vector a, TMath::Vector b, std::string expression); 16 | void assert(TMath::Vector a, TMath::Vector b, std::string expression, TMath::DOUBLE tolerance); 17 | void assertTrue(bool b, std::string expression); 18 | void assertError(std::function, std::string expression); 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/abs.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | TMath::DOUBLE TMath::abs(const DOUBLE &x) { 4 | if (x < 0) return -x; 5 | else return x; 6 | } -------------------------------------------------------------------------------- /src/cosecant.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================ COSECANT ======================================== */ 4 | TMath::DOUBLE TMath::csc(const DOUBLE &x) 5 | { 6 | return 1 / sin(x); 7 | } 8 | TMath::DOUBLE TMath::acsc(const DOUBLE &x) 9 | { 10 | return asin(1 / x); 11 | } 12 | TMath::DOUBLE TMath::csch(const DOUBLE &x) 13 | { 14 | return 1 / sinh(x); 15 | } -------------------------------------------------------------------------------- /src/cosine.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================ COSINE ======================================== */ 4 | TMath::DOUBLE TMath::cos(const DOUBLE &_x) 5 | { 6 | const DOUBLE x = mod(_x + PI, 2 * PI) - PI; 7 | DOUBLE r = 0; 8 | for (LONG n = 0; n <= 8L; n++) { 9 | r += pow(DOUBLE(-1.0), n) * pow(x, 2 * n) / fac(2 * n); 10 | } 11 | return r; 12 | } 13 | TMath::DOUBLE TMath::acos(const DOUBLE &x) 14 | { 15 | return PI / 2 - asin(x); 16 | } 17 | TMath::DOUBLE TMath::cosh(const DOUBLE &x) 18 | { 19 | return 0.5 * (exp(x) + exp(-x)); 20 | } -------------------------------------------------------------------------------- /src/cotangent.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================ COTANGENT ======================================== */ 4 | TMath::DOUBLE TMath::cot(const DOUBLE &x) 5 | { 6 | return cos(x) / sin(x); 7 | } 8 | TMath::DOUBLE TMath::acot(const DOUBLE &x) 9 | { 10 | return PI / 2 - atan(x); 11 | } 12 | TMath::DOUBLE TMath::coth(const DOUBLE &x) 13 | { 14 | return cosh(x) / sinh(x); 15 | } -------------------------------------------------------------------------------- /src/degrad.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | TMath::DOUBLE TMath::rad(const DOUBLE °) 4 | { 5 | return PI / 180.0 * deg; 6 | } 7 | TMath::DOUBLE TMath::deg(const DOUBLE &rad) 8 | { 9 | return 180.0 / PI * rad; 10 | } -------------------------------------------------------------------------------- /src/equality.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | TMath::DOUBLE TMath::equal(const DOUBLE &x, const DOUBLE &y) { 4 | return equal(x, y, EQUAL_EPSILON); 5 | } 6 | TMath::DOUBLE TMath::equal(const DOUBLE &x, const DOUBLE &y, const DOUBLE &eps) { 7 | return abs(x - y) < eps; 8 | } -------------------------------------------------------------------------------- /src/explog.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* =============================== EXPONENTIAL FUNCTION, SQRT, LOGARITHM ======================= */ 4 | TMath::DOUBLE TMath::exp(const DOUBLE &x) 5 | { 6 | DOUBLE r = 0; 7 | for (LONG n = 0; n <= 15L; n++) 8 | { 9 | r += pow(x, n) / facd(n); 10 | } 11 | return r; 12 | } 13 | TMath::DOUBLE TMath::ln(const DOUBLE &_x) 14 | { 15 | const DOUBLE x = (_x - 1) / (_x + 1); 16 | DOUBLE r = 0; 17 | for (LONG n = 0; n <= 100L; n++) 18 | { 19 | r += 2 * pow(x, 2 * n + 1) / (2 * n + 1); 20 | } 21 | return r; 22 | } 23 | TMath::DOUBLE TMath::lg(const DOUBLE &x) 24 | { 25 | return ln(x) / ln(10); 26 | } 27 | TMath::DOUBLE TMath::lb(const DOUBLE &x) 28 | { 29 | return ln(x) / ln(2); 30 | } 31 | TMath::DOUBLE TMath::log(const DOUBLE &x, const DOUBLE &n) 32 | { 33 | return ln(x) / ln(n); 34 | } -------------------------------------------------------------------------------- /src/factorial.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | TMath::LONG TMath::fac(const LONG &n) { 4 | LONG r = 1; 5 | for (LONG i = 2; i <= n; i++) 6 | { 7 | r *= i; 8 | } 9 | return r; 10 | } 11 | TMath::DOUBLE TMath::facd(const LONG &n) { 12 | DOUBLE r = 1; 13 | for (LONG i = 2; i <= n; i++) { 14 | r *= DOUBLE(i); 15 | } 16 | return r; 17 | } 18 | TMath::LONG TMath::oddfac(const LONG &n) { 19 | LONG r = 1; 20 | for (LONG i = 3; i <= n; i += 2) { 21 | r *= i; 22 | } 23 | return r; 24 | } 25 | TMath::DOUBLE TMath::oddfacd(const LONG &n) { 26 | DOUBLE r = 1; 27 | for (LONG i = 3; i <= n; i += 2) { 28 | r *= DOUBLE(i); 29 | } 30 | return r; 31 | } -------------------------------------------------------------------------------- /src/fcm.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================= FLOOR, CEIL AND MODULO ======================================== */ 4 | TMath::LONG TMath::floor(const DOUBLE &x) 5 | { 6 | LONG truncated = LONG(x); 7 | if (x < 0) { 8 | if (truncated > x) { 9 | return truncated - 1; 10 | } else { 11 | return truncated; 12 | } 13 | } 14 | else { 15 | return truncated; 16 | } 17 | } 18 | TMath::LONG TMath::ceil(const DOUBLE &x) 19 | { 20 | LONG truncated = LONG(x); 21 | if (x < 0) { 22 | return truncated; 23 | } else { 24 | if (truncated < x) { 25 | return truncated + 1; 26 | } else { 27 | return truncated; 28 | } 29 | } 30 | } 31 | TMath::DOUBLE TMath::mod(const DOUBLE &x, const DOUBLE &y) 32 | { 33 | return y * ((x / y) - floor(x / y)); 34 | } 35 | -------------------------------------------------------------------------------- /src/matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | #include 3 | 4 | // Initialize a new 2d matrix with these values. 5 | TMath::Matrix::Matrix(std::initializer_list> list) { 6 | int height = list.size(), index = 0; 7 | if (height < 1) throw TMath::EMPTY_MATRIX_ERROR; 8 | 9 | elements = std::vector(height); 10 | for (auto& row : list) elements[index++] = Vector(row); 11 | 12 | int common = elements[index-1].dim(); 13 | for (auto& row : elements) if (row.dim() != common) throw TMath::DIMENSION_ERROR; 14 | } 15 | 16 | // Initialize a new matrix with a specific rows and cols. 17 | TMath::Matrix::Matrix(const int& rows, const int& cols) { 18 | if (rows < 1 || cols < 1) throw TMath::EMPTY_MATRIX_ERROR; 19 | 20 | elements = std::vector(rows); 21 | for (int index = 0; index < rows; index++) { 22 | elements[index] = Vector(cols); 23 | } 24 | } 25 | 26 | // Initialize a new matrix as a copy of the matrix m. 27 | TMath::Matrix::Matrix(const Matrix& m) { 28 | int height = m.elements.size(); 29 | elements = std::vector(m.elements.size()); 30 | for (int index = 0; index < height; index++) elements[index] = Vector(m.elements[index]); 31 | } 32 | 33 | // Check if the two matrices have the same dimensions. 34 | std::pair TMath::Matrix::validate(const Matrix& m) const { 35 | int w = colCount(), h = rowCount(); 36 | if (m.colCount() != w || m.rowCount() != h) throw TMath::DIMENSION_ERROR; 37 | return std::pair(w, h); 38 | } 39 | 40 | // Access a matrix row. 41 | TMath::Vector& TMath::Matrix::operator[](const int& i) { 42 | if (i >= rowCount() || i < 0) throw OUT_OF_BOUNDS; 43 | return elements[i]; 44 | } 45 | 46 | // Access a matrix row as a constant. 47 | TMath::Vector TMath::Matrix::row(const int& i) const { 48 | if (i >= rowCount() || i < 0) throw OUT_OF_BOUNDS; 49 | return elements[i]; 50 | } 51 | 52 | // Access a matrix col as a constant. 53 | TMath::Vector TMath::Matrix::col(const int& j) const { 54 | if (j >= colCount() || j < 0) throw OUT_OF_BOUNDS; 55 | Vector column(rowCount()); 56 | for (int i = 0; i < rowCount(); i++) { 57 | column[i] = at(i, j); 58 | } 59 | return column; 60 | } 61 | 62 | // Access a matrix item as a constant. 63 | TMath::DOUBLE TMath::Matrix::at(const int& i, const int& j) const { 64 | if (i >= rowCount() || i < 0 || j < 0 || j >= colCount()) throw OUT_OF_BOUNDS; 65 | return elements[i].at(j); 66 | } 67 | 68 | // Test if the matrices are equal or nearly equal as specificed by the epsilon. 69 | bool TMath::Matrix::equal(const Matrix& m, const DOUBLE& eps) const { 70 | std::pair dimensions = validate(m); 71 | 72 | for (int i = 0; i < dimensions.second; i++) for (int j = 0; j < dimensions.first; j++) 73 | if (!TMath::equal(elements[i].at(j), m.elements[i].at(j), eps)) return false; 74 | 75 | return true; 76 | } 77 | 78 | // Test if the matrices are equal. 79 | bool TMath::Matrix::operator==(const Matrix& m) const { 80 | return equal(m, EQUAL_EPSILON); 81 | } 82 | 83 | // Test if the matrices are unequal. 84 | bool TMath::Matrix::operator!=(const Matrix& m) const { 85 | return !equal(m, EQUAL_EPSILON); 86 | } 87 | 88 | // Get the matrix col count. 89 | int TMath::Matrix::colCount() const { 90 | return elements[0].dim(); 91 | } 92 | 93 | // Get the matrix row count. 94 | int TMath::Matrix::rowCount() const { 95 | return elements.size(); 96 | } 97 | 98 | // Add two matrices. 99 | TMath::Matrix TMath::Matrix::operator+(const Matrix& a) const { 100 | int w = colCount(), h = rowCount(); 101 | if (a.colCount() != w || a.rowCount() != h) throw TMath::DIMENSION_ERROR; 102 | 103 | Matrix result(a); 104 | for (int i = 0; i < h; i++) { 105 | for (int j = 0; j < w; j++) { 106 | result[i][j] += elements[i].at(j); 107 | } 108 | } 109 | 110 | return result; 111 | } 112 | 113 | // Subtract two matrices. 114 | TMath::Matrix TMath::Matrix::operator-(const Matrix& a) const { 115 | int w = colCount(), h = rowCount(); 116 | if (a.colCount() != w || a.rowCount() != h) throw TMath::DIMENSION_ERROR; 117 | 118 | Matrix result(*this); 119 | for (int i = 0; i < h; i++) { 120 | for (int j = 0; j < w; j++) { 121 | result[i][j] -= a.elements[i].at(j); 122 | } 123 | } 124 | 125 | return result; 126 | } 127 | 128 | // Invert matrice values. 129 | TMath::Matrix TMath::Matrix::operator-() const { 130 | return *this * -1.0; 131 | } 132 | 133 | // Generate a string representation of the matrix. 134 | std::string TMath::Matrix::to_string() const { 135 | int w = colCount(), h = rowCount(); 136 | std::stringstream stream; 137 | stream << "{["; 138 | for (int i = 0; i < h; i++) { 139 | for (int j = 0; j < w-1; j++) { 140 | stream << elements[i].at(j) << ", "; 141 | } 142 | stream << elements[i].at(w-1); 143 | if (i < h-1) stream << "], ["; 144 | } 145 | stream << "]}"; 146 | return stream.str(); 147 | } 148 | 149 | TMath::Matrix TMath::Matrix::operator*(const DOUBLE& a) const { 150 | Matrix result(*this); 151 | for (int i = 0; i < rowCount(); i++) { 152 | result[i] = result[i] * a; 153 | } 154 | return result; 155 | } 156 | 157 | // Multiply a matrix with a vector. 158 | TMath::Vector TMath::Matrix::operator*(const Vector& a) const { 159 | int w = colCount(), wv = a.dim(), h = rowCount(); 160 | if (w != wv) throw TMath::DIMENSION_ERROR; 161 | 162 | Vector result(h); 163 | for (int i = 0; i < h; i++) { 164 | for (int j = 0; j < w; j++) { 165 | result[i] += elements[i].at(j) * a.at(j); 166 | } 167 | } 168 | 169 | return result; 170 | } 171 | 172 | // Multiply a matrix with a matrix; 173 | TMath::Matrix TMath::Matrix::operator*(const Matrix& a) const { 174 | if (a.rowCount() != colCount()) throw TMath::DIMENSION_ERROR; 175 | 176 | // pre compute cols 177 | std::vector cols; 178 | for (int i = 0; i < a.colCount(); i++) { 179 | cols.push_back(a.col(i)); 180 | } 181 | 182 | // pre compute rows 183 | std::vector rows; 184 | for (int i = 0; i < rowCount(); i++) { 185 | rows.push_back(row(i)); 186 | } 187 | 188 | Matrix result(rowCount(), a.colCount()); 189 | for (int i = 0; i < rowCount(); i++) { 190 | for (int j = 0; j < a.colCount(); j++) { 191 | result[i][j] = rows[i].dot(cols[j]); 192 | } 193 | } 194 | 195 | return result; 196 | } 197 | 198 | TMath::Matrix TMath::Matrix::identity(const int& d) { 199 | TMath::Matrix id(d, d); 200 | for (int i = 0; i < d; i++) id[i][i] = 1.; 201 | return id; 202 | } -------------------------------------------------------------------------------- /src/power.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* =================================== POWER FUNCTIONS =====================================================*/ 4 | TMath::DOUBLE TMath::pow(const DOUBLE &x, const LONG &n) 5 | { 6 | if (n < 0) { 7 | return 1 / pow(x, -n); 8 | } 9 | 10 | DOUBLE r = 1; 11 | for (LONG i = 1; i <= n; i++) 12 | { 13 | r *= x; 14 | } 15 | return r; 16 | } 17 | 18 | TMath::LONG TMath::pow(const LONG &x, const LONG &n) 19 | { 20 | if (n < 0) { 21 | return 1 / pow(x, -n); 22 | } 23 | 24 | LONG r = 1; 25 | for (LONG i = 1; i <= n; i++) 26 | { 27 | r *= x; 28 | } 29 | return r; 30 | } 31 | TMath::DOUBLE TMath::pow(const DOUBLE &x, const DOUBLE &n) 32 | { 33 | return exp(n * ln(x)); 34 | } -------------------------------------------------------------------------------- /src/roots.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | TMath::DOUBLE TMath::sqrt(const DOUBLE &x) 4 | { 5 | return root(x, 2); 6 | } 7 | TMath::DOUBLE TMath::root(const DOUBLE &x, const DOUBLE &n) 8 | { 9 | if (x > 0) { 10 | return pow(x, 1 / n); 11 | } else { 12 | return 0; 13 | } 14 | } -------------------------------------------------------------------------------- /src/secant.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================ SECANT ======================================== */ 4 | TMath::DOUBLE TMath::sec(const DOUBLE &x) 5 | { 6 | return 1 / cos(x); 7 | } 8 | TMath::DOUBLE TMath::asec(const DOUBLE &x) 9 | { 10 | return acos(1 / x); 11 | } 12 | TMath::DOUBLE TMath::sech(const DOUBLE &x) 13 | { 14 | return 1 / cosh(x); 15 | } -------------------------------------------------------------------------------- /src/sine.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================ SINE ======================================== */ 4 | TMath::DOUBLE TMath::sin(const DOUBLE &_x) 5 | { 6 | const DOUBLE x = mod(_x + PI, 2 * PI) - PI; 7 | DOUBLE r = 0; 8 | for (LONG n = 0; n <= 8L; n++) { 9 | r += pow(DOUBLE(-1), n) * pow(x, 2 * n + 1) / fac(2 * n + 1); 10 | } 11 | return r; 12 | } 13 | TMath::DOUBLE TMath::asin(const DOUBLE &x) 14 | { 15 | DOUBLE r = 0; 16 | DOUBLE delta = 1; 17 | for (LONG n = 1; delta > 1e-6; n++) 18 | { 19 | LONG odd = 2 * n - 1; 20 | DOUBLE oddf = oddfacd(odd - 2); 21 | DOUBLE f = facd(odd); 22 | DOUBLE p = pow(x, odd); 23 | DOUBLE d = p / f * oddf * oddf; 24 | delta = abs(d); 25 | r += p / f * oddf * oddf; 26 | } 27 | return r; 28 | } 29 | TMath::DOUBLE TMath::sinh(const DOUBLE &x) 30 | { 31 | return 0.5 * (exp(x) - exp(-x)); 32 | } -------------------------------------------------------------------------------- /src/tangent.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | 3 | /* ================================ TANGENT ======================================== */ 4 | TMath::DOUBLE TMath::tan(const DOUBLE &x) 5 | { 6 | return sin(x) / cos(x); 7 | } 8 | TMath::DOUBLE TMath::atan(const DOUBLE &x) 9 | { 10 | DOUBLE r = 0; 11 | DOUBLE delta = 1; 12 | for (LONG n = 0; delta > 1e-4; n++) 13 | { 14 | LONG odd = 2 * n + 1; 15 | DOUBLE d = DOUBLE(pow(-1LL, n)) * pow(x, odd) / DOUBLE(odd); 16 | delta = abs(d); 17 | r += d; 18 | } 19 | return r; 20 | } 21 | TMath::DOUBLE TMath::tanh(const DOUBLE &x) 22 | { 23 | return sinh(x) / cosh(x); 24 | } -------------------------------------------------------------------------------- /src/vector.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath.hpp" 2 | #include 3 | 4 | // checkDimensions check if the dimensions of the vectors are equal. 5 | int TMath::Vector::checkDimensions(const Vector &a) const { 6 | int mdim = dim(); 7 | if (mdim != a.dim()) throw TMath::DIMENSION_ERROR; 8 | return mdim; 9 | } 10 | 11 | // [n] operator accesses the n-th element of the vector by reference. 12 | TMath::DOUBLE& TMath::Vector::operator[](const int &i) { 13 | if (i >= dim() || i < 0) throw OUT_OF_BOUNDS; 14 | return elements.at(i); 15 | }; 16 | 17 | // at operation accesses the n-th element of the vector by value. 18 | TMath::DOUBLE TMath::Vector::at(const int &i) const { 19 | if (i >= dim() || i < 0) throw OUT_OF_BOUNDS; 20 | return elements.at(i); 21 | } 22 | 23 | // + operator sums up two vectors. 24 | // result = this + a 25 | TMath::Vector TMath::Vector::operator+(const Vector &a) const { 26 | int d = checkDimensions(a); 27 | Vector b(d); 28 | for (unsigned int i = 0; i < d; i++) { 29 | b[i] = elements.at(i) + a.elements.at(i); 30 | } 31 | return b; 32 | }; 33 | 34 | // - operator calculates the difference vector of the two vectors. 35 | // result = this - a 36 | TMath::Vector TMath::Vector::operator-(const Vector &a) const { 37 | int d = checkDimensions(a); 38 | Vector b(d); 39 | for (unsigned int i = 0; i < d; i++) { 40 | b[i] = elements.at(i) - a.elements.at(i); 41 | } 42 | return b; 43 | }; 44 | 45 | // - operator calculates the inversion of the vector. 46 | TMath::Vector TMath::Vector::operator-() const { 47 | int d = dim(); 48 | Vector b(d); 49 | for (unsigned int i = 0; i < d; i++) { 50 | b[i] = -elements.at(i); 51 | } 52 | return b; 53 | } 54 | 55 | // * operator scales the vector by the scalar. 56 | TMath::Vector TMath::Vector::operator*(const DOUBLE &scalar) const { 57 | int d = dim(); 58 | Vector b(d); 59 | for (unsigned int i = 0; i < d; i++) { 60 | b[i] = elements.at(i) * scalar; 61 | } 62 | return b; 63 | }; 64 | 65 | // / operator scales the vector by the inverse value of the scalar. 66 | TMath::Vector TMath::Vector::operator/(const DOUBLE &scalar) const { 67 | int d = dim(); 68 | Vector b(d); 69 | for (unsigned int i = 0; i < d; i++) { 70 | b[i] = elements.at(i) / scalar; 71 | } 72 | return b; 73 | }; 74 | 75 | // equal checks for equality of both vectors. 76 | bool TMath::Vector::equal(const Vector &a, const DOUBLE &eps) const { 77 | int d = checkDimensions(a); 78 | for (unsigned int i = 0; i < d; i++) { 79 | if (!TMath::equal(elements.at(i), a.elements.at(i), eps)) return false; 80 | } 81 | return true; 82 | }; 83 | 84 | // == operator checks for equality with a constant accuracy of EQUAL_EPSILON. 85 | bool TMath::Vector::operator==(const Vector &a) const { 86 | int d = checkDimensions(a); 87 | return this->equal(a, EQUAL_EPSILON); 88 | }; 89 | 90 | // != operator checks for inequality. 91 | bool TMath::Vector::operator!=(const Vector &a) const { 92 | int d = checkDimensions(a); 93 | return !this->equal(a, EQUAL_EPSILON); 94 | }; 95 | 96 | // dot operator calculates the dot product of the two vectors. 97 | TMath::DOUBLE TMath::Vector::dot(const Vector &a) const { 98 | int d = checkDimensions(a); 99 | Vector b(d); 100 | DOUBLE sum = 0; 101 | for (unsigned int i = 0; i < d; i++) sum += elements.at(i) * a.elements.at(i); 102 | return sum; 103 | }; 104 | 105 | // cross operator calculates the cross product of the two vectors. 106 | TMath::Vector TMath::Vector::cross(const Vector &a) const { 107 | int d = checkDimensions(a); 108 | if (d != 3) throw BAD_OPERATION; 109 | Vector b(3); 110 | for (unsigned int i = 0; i < 3; i++) { 111 | unsigned int p = (i+1) % 3, q = (i+2) % 3; 112 | b[i] = elements.at(i) * a.elements.at(q) - elements.at(q) * a.elements.at(p); 113 | } 114 | return b; 115 | }; 116 | 117 | // sum operator calculates the element sum of the vector. 118 | TMath::DOUBLE TMath::Vector::sum() const { 119 | int d = dim(); 120 | DOUBLE sum = 0; 121 | for (unsigned int i = 0; i < d; i++) sum += elements[i]; 122 | return sum; 123 | }; 124 | 125 | // norm operator calculates a normalized vector. 126 | TMath::Vector TMath::Vector::norm() const { 127 | int d = dim(); 128 | if (d == 0) throw BAD_OPERATION; 129 | DOUBLE l = length(); 130 | if (l == 0) throw ZERO_LENGTH; 131 | return *this / l; 132 | } 133 | 134 | // length operator calculates the length of the vector. 135 | TMath::DOUBLE TMath::Vector::length() const { 136 | int d = dim(); 137 | if (d == 0) throw BAD_OPERATION; 138 | DOUBLE sum = 0; 139 | for (unsigned int i = 0; i < d; i++) sum += elements[i] * elements[i]; 140 | return TMath::sqrt(sum); 141 | } 142 | 143 | // dim returns the vector tuple size. 144 | int TMath::Vector::dim() const { 145 | return elements.size(); 146 | } 147 | 148 | // to_string returns a string representation of the vector. 149 | std::string TMath::Vector::to_string() const { 150 | std::stringstream stream; 151 | stream << "{"; 152 | int d = dim(); 153 | for (unsigned int i = 0; i < d - 1; i++) stream << elements[i] << ", "; 154 | if (d > 0) stream << elements[d-1]; 155 | stream << "}"; 156 | return stream.str(); 157 | } -------------------------------------------------------------------------------- /test/abs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the abs function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::abs; 11 | 12 | assert(abs(0.0), 0.0, "abs(0) == 0"); 13 | assert(abs(1.0), 1.0, "abs(1) == 1"); 14 | assert(abs(-1.0), 1.0, "abs(-1) == 1"); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/cosecant.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the cosecant, arccosecant and hyperbolic cosecant function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::csc; 11 | using TMath::acsc; 12 | using TMath::csch; 13 | using TMath::PI; 14 | 15 | assert(csc(PI / 2.0), 1.0, "csc(PI/2) == 1"); 16 | assert(csc(-PI / 2.0), -1.0, "csc(-PI/2) == -1"); 17 | 18 | assert(acsc(1.1884), 1.0, "acsc(1.1884) == 1"); 19 | assert(acsc(-1.1884), -1.0, "acsc(-1.1884) == -1"); 20 | 21 | assert(csch(0.88137), 1.0, "csch(0.88137) == 1.0"); 22 | assert(csch(-0.88137), -1.0, "csch(-0.88137) == -1.0"); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/cosine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the cosine, arccosine and hyperbolic cosine function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::cos; 11 | using TMath::acos; 12 | using TMath::cosh; 13 | using TMath::PI; 14 | 15 | assert(cos(0.0), 1, "cos(0) == 1"); 16 | assert(cos(PI/2.0), 0, "cos(PI/2) == 0"); 17 | assert(cos(PI), -1, "cos(PI) == -1"); 18 | assert(cos(PI * 1.5), 0, "cos(PI * 1.5) == 0"); 19 | 20 | assert(acos(0), PI * 0.5, "acos(0) == PI/2"); 21 | assert(acos(0.70711), PI * 0.25, "acos(1/sqrt(2)) == 1/4 PI"); 22 | assert(acos(-0.70711), PI * 0.75, "acos(1/sqrt(2)) == 3/4 PI"); 23 | 24 | assert(cosh(0), 1, "cosh(0) == 1"); 25 | assert(cosh(1.31696), 2, "cosh(1.31696) == 2"); 26 | assert(cosh(-1.31696), 2, "cosh(-1.31696) == 2"); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/cotangent.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the cotangent, arccotangent and hyperbolic cotangent function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::cot; 11 | using TMath::acot; 12 | using TMath::coth; 13 | using TMath::PI; 14 | 15 | assert(cot(PI / 2.0), 0.0, "cot(PI/2) == 0"); 16 | assert(cot(-PI / 2.0), 0.0, "cot(-PI/2) == 0"); 17 | 18 | assert(acot(0), PI * 0.5, "acot(0) == 1/2 PI"); 19 | assert(acot(1.0), PI * 0.25, "acot(1) == 1/4 PI"); 20 | assert(acot(-1.0), PI * 0.75, "acot(-1) == 3/4 PI"); 21 | 22 | assert(coth(0.54931), 2.0, "coth(0.54931) == 2.0"); 23 | assert(coth(-0.54931), -2.0, "coth(-0.54931) == -2.0"); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/degrad.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the rad-deg conversion functions. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::rad; 11 | using TMath::deg; 12 | using TMath::PI; 13 | 14 | assert(rad(0), 0.0, "rad(0) == 0"); 15 | assert(rad(45), PI * 0.25, "rad(45) == 1/4 PI"); 16 | assert(rad(90), PI * 0.5, "rad(90) == 1/2 PI"); 17 | assert(rad(135), PI * 0.75, "rad(135) == 3/4 PI"); 18 | assert(rad(180), PI, "rad(180) == PI"); 19 | assert(rad(270), PI * 1.5, "rad(270) == 3/2 PI"); 20 | assert(rad(360), PI * 2.0, "rad(360) == 2 PI"); 21 | 22 | assert(deg(0), 0, "deg(0) == 0"); 23 | assert(deg(PI * 0.25), 45, "deg(1/4 PI) == 45"); 24 | assert(deg(PI * 0.5), 90, "deg(1/2 PI) == 90"); 25 | assert(deg(PI * 0.75), 135, "deg(3/4 PI) == 135"); 26 | assert(deg(PI), 180, "deg(PI) == 180"); 27 | assert(deg(PI * 1.5), 270, "deg(3/2 PI) == 270"); 28 | assert(deg(PI * 2.0), 360, "deg(2 * PI) == 360"); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /test/equality.cpp: -------------------------------------------------------------------------------- 1 | /** equal NEEDS TESTS. **/ 2 | 3 | int main(void) { return 0; } -------------------------------------------------------------------------------- /test/explog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the exp, ln, lg, lb and log function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::exp; 11 | using TMath::E; 12 | using TMath::ln; 13 | using TMath::lb; 14 | using TMath::lg; 15 | using TMath::log; 16 | 17 | assert(exp(0.0), 1.0, "exp(0) == 1"); 18 | assert(exp(1.0), E, "exp(1) == e"); 19 | assert(exp(2.0), E * E, "exp(2) == e*e"); 20 | assert(exp(-1.0), 1.0 / E, "exp(-1) == 1/e"); 21 | 22 | assert(ln(1), 0.0, "ln(1) == 0"); 23 | assert(ln(E), 1.0, "ln(e) == 1"); 24 | assert(ln(1.0 / E), -1.0, "ln(1/e) == -1"); 25 | 26 | assert(lb(2), 1.0, "lb(2) == 1"); 27 | assert(lb(4), 2.0, "lb(4) == 2"); 28 | assert(lb(16), 4.0, "lb(128) == 4"); 29 | 30 | assert(lg(10), 1.0, "lg(10) == 1"); 31 | assert(lg(1), 0.0, "lg(1) == 0"); 32 | assert(lg(100), 2.0, "lg(100) == 2", 0.01); 33 | 34 | assert(log(E, E), 1.0, "log_e(e) == 1"); 35 | assert(log(1, E), 0.0, "log_e(1) == 0"); 36 | assert(log(27, 3), 3.0, "log_3(27) == 3"); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /test/factorial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the factorial functions; 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::fac; 11 | using TMath::facd; 12 | using TMath::oddfac; 13 | using TMath::oddfacd; 14 | 15 | assert(fac(1), 1, "fac(1) == 1"); 16 | assert(fac(2), 2, "fac(2) == 2"); 17 | assert(fac(3), 6, "fac(3) == 6"); 18 | assert(fac(4), 24, "fac(4) == 24"); 19 | 20 | assert(facd(1), 1.0, "facd(1) == 1.0"); 21 | assert(facd(2), 2.0, "facd(2) == 2.0"); 22 | assert(facd(3), 6.0, "facd(3) == 6.0"); 23 | assert(facd(4), 24.0, "facd(4) == 24.0"); 24 | 25 | assert(oddfac(1), 1, "oddfac(1) == 1"); 26 | assert(oddfac(2), 1, "oddfac(2) == 1"); 27 | assert(oddfac(3), 3, "oddfac(3) == 3"); 28 | assert(oddfac(4), 3, "oddfac(4) == 3"); 29 | assert(oddfac(5), 15, "oddfac(5) == 15"); 30 | 31 | assert(oddfacd(1), 1.0, "oddfacd(1) == 1.0"); 32 | assert(oddfacd(2), 1.0, "oddfacd(2) == 1.0"); 33 | assert(oddfacd(3), 3.0, "oddfacd(3) == 3.0"); 34 | assert(oddfacd(4), 3.0, "oddfacd(4) == 3.0"); 35 | assert(oddfacd(5), 15.0, "oddfacd(5) == 15.0"); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /test/fcm.cpp: -------------------------------------------------------------------------------- 1 | /* FLOOR, CEIL AND MODULO NEED TESTS. */ 2 | 3 | #include "tmath.hpp" 4 | #include "tmath_test.hpp" 5 | 6 | int main(void) { 7 | using TMathTest::assert; 8 | 9 | // testing floor 10 | using TMath::floor; 11 | assert(floor(0.0), 0, "floor(0.0) == 0"); 12 | assert(floor(0.25), 0, "floor(0.25) == 0"); 13 | assert(floor(1.0), 1, "floor(1.0) == 1"); 14 | assert(floor(-1.0), -1, "floor(-1.0) == -1"); 15 | assert(floor(-1.25), -2, "floor(-1.25) == -2"); 16 | 17 | // testing ceil 18 | using TMath::ceil; 19 | assert(ceil(0.0), 0, "ceil(0.0) == 0"); 20 | assert(ceil(0.25), 1, "ceil(0.25) == 1"); 21 | assert(ceil(1.0), 1, "ceil(1.0) == 1"); 22 | assert(ceil(-1.0), -1, "ceil(-1.0) == -1"); 23 | assert(ceil(-1.25), -1, "ceil(-1.25) == -1"); 24 | 25 | // testing mod 26 | using TMath::mod; 27 | assert(mod(3.0, 4.0), 3.0, "mod(3.0, 4.0) == 3.0"); 28 | assert(mod(4.0, 4.0), 0.0, "mod(4.0, 4.0) == 0.0"); 29 | assert(mod(-2.0, 3.0), 1.0, "mod(-2.0, 3.0) == 1.0"); 30 | assert(mod(0.25, 0.75), 0.25, "mod(0.25, 0.75) == 0.25"); 31 | assert(mod(-0.9, -0.6), -0.3, "mod(-0.9, -0.6) == -0.3"); 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /test/matrix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the matrix functionality. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMathTest::assertTrue; 11 | using TMathTest::assertError; 12 | using TMath::DOUBLE; 13 | using TMath::Matrix; 14 | using TMath::Vector; 15 | 16 | Matrix nullMatrix1(1, 1); 17 | Matrix nullMatrix2{{0}}; 18 | Matrix oneMatrix{{1}}; 19 | Matrix identityMatrix{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; 20 | Matrix reverseMatrix{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}; 21 | Matrix valueMatrix{{2, 0, 0}, {0, 2, 0}, {0, 0, 2}}; 22 | Matrix nullMatrix3(3, 3); 23 | Vector nullVector1{0}; 24 | Vector nullVector3{0, 0, 0}; 25 | Vector oneVector1{1}; 26 | Vector oneVector2{1, 0, 0}; 27 | Vector oneVector3{1, 1, 1}; 28 | Vector countVector{1, 2, 3}; 29 | 30 | // Check for constructor errors 31 | assert(nullMatrix1, nullMatrix2, "{{0}} == Matrix(1, 1)"); 32 | assertTrue(!(nullMatrix1 != nullMatrix2), "!{{0}} != Matrix(1, 1)"); 33 | assertError([&](){ nullMatrix1 == identityMatrix; }, "Dimension mismatch by 1x1 == 3x3"); 34 | assertError([&](){ nullMatrix1 != identityMatrix; }, "Dimension mismatch by 1x1 == 3x3"); 35 | assertError([&](){ Matrix(0, 0); }, "Empty matrix constructor using dimensions"); 36 | assertError([&](){ Matrix{}; }, "Empty matrix constructor using initializer list"); 37 | 38 | // Check for copy constructor 39 | assert(identityMatrix, Matrix(identityMatrix), "m == Matrix(m)"); 40 | assert(nullMatrix1, Matrix(nullMatrix2), "{{0}} == Matrix({{0}})"); 41 | 42 | // Check for access operator 43 | assertTrue(nullMatrix1[0][0] == 0, "{{0}}[0][0] == 0"); 44 | assertTrue(identityMatrix[0][0] == 1, "Identity[0][0] == 1"); 45 | assertTrue(identityMatrix[1][0] == 0, "Identity[1][0] == 0"); 46 | assertTrue(identityMatrix[1][1] == 1, "Identity[1][1] == 1"); 47 | 48 | // Check for width and heiht 49 | assert(nullMatrix1.colCount(), 1, "{{0}}.colCount() == 1"); 50 | assert(nullMatrix2.rowCount(), 1, "Matrix(1, 1).rowCount() == 1"); 51 | assert(identityMatrix.colCount(), 3, "Identity.colCount() == 3"); 52 | assert(identityMatrix.rowCount(), 3, "Identity.rowCount() == 3"); 53 | 54 | // Check for to_string 55 | assertTrue(nullMatrix1.to_string() == "{[0]}", "str({{0}}) == '{[0]}'"); 56 | assertTrue(identityMatrix.to_string() == "{[1, 0, 0], [0, 1, 0], [0, 0, 1]}", "str(Identity) == '{[1, 0, 0], [0, 1, 0], [0, 0, 1]}'"); 57 | 58 | // Check for matrix + matrix 59 | assertError([&](){ nullMatrix1 + identityMatrix; }, "Dimension mismatch by 1x1 + 3x3"); 60 | assert(nullMatrix1 + nullMatrix2, nullMatrix1, "{{0}} + Matrix(1, 1) == {{0}}"); 61 | assert(identityMatrix + identityMatrix, valueMatrix, "Identity + Identity = 2*Identity"); 62 | assert(reverseMatrix + identityMatrix, nullMatrix3, "Identity + (-Identity) = Matrix(3, 3)"); 63 | 64 | // Check for matrix - matrix 65 | assertError([&](){ nullMatrix1 - identityMatrix; }, "Dimension mismatch by 1x1 - 3x3"); 66 | assert(nullMatrix1 - nullMatrix2, nullMatrix1, "{{0}} - Matrix(1, 1) == {{0}}"); 67 | assert(identityMatrix - identityMatrix, nullMatrix3, "Identity - Identity = Matrix(3, 3)"); 68 | assert(identityMatrix - reverseMatrix, valueMatrix, "Identity - (-Identity) = 2*Identity"); 69 | 70 | // Check for at 71 | assertError([&](){ nullMatrix1.row(2); }, "Can not access index out of matrix Matrix(1, 1)[2]"); 72 | assertError([&](){ nullMatrix1.col(2); }, "Can not access index out of matrix Matrix(1, 1)[2]"); 73 | assertError([&](){ nullMatrix2.at(2, 2); }, "Can not access index out of matrix {{0}}[2, 2]"); 74 | assert(nullMatrix1.row(0), nullVector1, "Matrix(1, 1)[0] == Vector{0}"); 75 | assert(nullMatrix1.col(0), nullVector1, "Matrix(1, 1)[0] == Vector{0}"); 76 | assert(identityMatrix.row(0), oneVector2, "Identity[0] == Vector{1, 0, 0}"); 77 | assert(identityMatrix.col(0), oneVector2, "Identity[0] == Vector{1, 0, 0}"); 78 | assert(nullMatrix1.at(0, 0), 0, "Matrix(1, 1)[0, 0] == 0"); 79 | assert(identityMatrix.at(2, 2), 1, "Identity[2, 2] == 1"); 80 | 81 | // Check for matrix * vector 82 | assertError([&](){ nullMatrix2 * oneVector2; }, "Can not multiply Matrix(1, 1) with Vector(3)"); 83 | assert(nullMatrix1 * oneVector1, nullVector1, "Matrix(1, 1) * Vector{1} == Vector{0}"); 84 | assert(nullMatrix1 * nullVector1, nullVector1, "Matrix(1, 1) * Vector{0} == Vector{0}"); 85 | assert(identityMatrix * countVector, countVector, "Identity * Vector{1, 2, 3} == Vector{1, 2, 3}"); 86 | assert(reverseMatrix * countVector, -countVector, "ReverseIdentity * Vector{1, 2, 3} == Vector{-1, -2, -3}"); 87 | 88 | // Check for matrix * matrix 89 | assertError([&](){ identityMatrix * nullMatrix1; }, "Can not multiply Matrix(1, 1) with Matrix(3, 3)"); 90 | assertError([&](){ nullMatrix1 * identityMatrix; }, "Can not multiply Matrix(3, 3) with Matrix(1, 1)"); 91 | Matrix valueMatrix1{{3, 2, 1}, {1, 0, 2}}; 92 | Matrix valueMatrix2{{1, 2}, {0, 1}, {4, 0}}; 93 | Matrix valueMatrix3{{1, 2, 3}}; 94 | Matrix valueMatrix4{{1}, {2}, {3}}; 95 | Matrix resultMatrix1{{7, 8}, {9, 2}}; 96 | Matrix resultMatrix2{{14}}; 97 | assert(valueMatrix1 * valueMatrix2, resultMatrix1, "2x3 * 3x2 == 2x2"); 98 | assert(valueMatrix3 * valueMatrix4, resultMatrix2, "1x3 * 3x1 == 1x1"); 99 | assert(valueMatrix3 * identityMatrix, valueMatrix3, "1x3 * Identity == 1x3"); 100 | assert(identityMatrix * valueMatrix4, valueMatrix4, "Identity * 3x1 == 3x1"); 101 | 102 | // Check for matrix * scalar and -matrix 103 | assert(identityMatrix * 2.0, valueMatrix, "Identity * 2 == {{2, 0, 0}, {0, 2, 0}, {0, 0, 2}}"); 104 | assert(nullMatrix1 * 0.0, nullMatrix1, "{{0}} * 0 == {{0}}"); 105 | assert(nullMatrix1 * 1.0, nullMatrix1, "{{0}} * 1 == {{0}}"); 106 | assert(identityMatrix * -1.0, reverseMatrix, "-Identity == Reverse"); 107 | assert(valueMatrix * 0.5, identityMatrix, "0.5 * {{2, 0, 0}, {0, 2, 0}, {0, 0, 2}} == Identity"); 108 | assert(-identityMatrix, reverseMatrix, "-Identity == Reverse"); 109 | assert(-nullMatrix1, nullMatrix1, "-{{0}} == {{0}}"); 110 | 111 | // Check for matrix identity 112 | assert(identityMatrix, Matrix::identity(3), "Identity(3) = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}"); 113 | assert(oneMatrix, Matrix::identity(1), "Identity(1) = {{1}}"); 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /test/power.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the power functions. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::pow; 11 | 12 | assert(pow(2.0L, 2.0L), 4.0L, "pow(2, 2) == 4"); 13 | assert(pow(2.0L, 0.5L), 1.41421356237L, "pow(2, 0.5) == 1.414"); 14 | assert(pow(2.0L, -1.0L), 0.5L, "pow(2, -1) == 0.5"); 15 | assert(pow(2.0L, 0.0L), 1.0L, "pow(2, 0) == 1"); 16 | 17 | assert(pow(2LL, 2LL), 4LL, "pow(2, 2) == 4"); 18 | assert(pow(1LL, -1LL), 1LL, "pow(1, -1) == 1"); 19 | assert(pow(2LL, 0LL), 1LL, "pow(2, 0) == 1"); 20 | 21 | assert(pow(0.5L, 2LL), 0.25L, "pow(0.5, 2) == 0.25"); 22 | assert(pow(0.5L, -1LL), 2.0L, "pow(0.5, -1) == 2"); 23 | assert(pow(0.5L, 0LL), 1.0L, "pow(0.5, 0) == 1"); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/roots.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the root functions. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::root; 11 | using TMath::sqrt; 12 | 13 | assert(root(27.0L, 3.0L), 3.0L, "root(27, 3) == 3"); 14 | assert(root(1.0L, 1.0L), 1.0L, "root(1, 1) == 1"); 15 | 16 | assert(sqrt(4.0L), 2.0L, "sqrt(4) == 2"); 17 | assert(sqrt(9.0L), 3.0L, "sqrt(9) == 3"); 18 | assert(sqrt(1.0L), 1.0L, "sqrt(1) == 1"); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/secant.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the secant, arcsecant and hyperbolic secant function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::sec; 11 | using TMath::asec; 12 | using TMath::sech; 13 | using TMath::PI; 14 | 15 | assert(sec(0), 1.0, "sec(0) == 1"); 16 | assert(sec(-PI), -1.0, "sec(-PI) == -1"); 17 | assert(sec(PI), -1.0, "sec(PI) == -1"); 18 | 19 | assert(asec(1.41421356237L), PI * 0.25, "asec(sqrt(2)) == 1/4 PI"); 20 | assert(asec(-1.41421356237L), PI * 0.75, "asec(-sqrt(2)) == 3/4 PI"); 21 | 22 | assert(sech(0), 1.0, "sech(0) == 1"); 23 | assert(sech(1.31696), 0.5, "sech(1.31696) == 0.5"); 24 | assert(sech(-1.31696), 0.5, "sech(-1.31696) == 0.5"); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/sine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the sine, arcsine and hyperbolic sine function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::sin; 11 | using TMath::asin; 12 | using TMath::sinh; 13 | using TMath::PI; 14 | 15 | assert(sin(0), 0, "sin(0) == 0"); 16 | assert(sin(PI/2.0), 1.0, "sin(PI/2) == 1"); 17 | assert(sin(PI), 0.0, "sin(PI) == 0"); 18 | assert(sin(1.5 * PI), -1.0, "sin(1.5 * PI) == -1"); 19 | assert(sin(2.0 * PI), 0.0, "sin(2 * PI) == 0"); 20 | 21 | assert(asin(0), 0, "asin(0) == 0"); 22 | assert(asin(0.5), PI/6.0, "asin(0.5) == PI/6"); 23 | assert(asin(-0.5), -PI/6.0, "asin(-0.5) == -PI/6"); 24 | 25 | assert(sinh(0), 0, "sinh(0) == 0"); 26 | assert(sinh(0.88137), 1.0, "sinh(0.88137) == 1"); 27 | assert(sinh(-0.88137), -1.0, "sinh(-0.88137) == -1"); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /test/tangent.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the tangent, arctangent and hyperbolic tangent function. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMath::tan; 11 | using TMath::atan; 12 | using TMath::tanh; 13 | using TMath::PI; 14 | 15 | assert(tan(0), 0, "tan(0) == 0"); 16 | assert(tan(PI/4.0), 1.0, "tan(PI/4) == 1"); 17 | assert(tan(-PI/4.0), -1.0, "tan(-PI/4) == -1"); 18 | 19 | assert(atan(0), 0, "atan(0) == 0"); 20 | assert(atan(1), PI/4.0, "atan(1) == PI/4"); 21 | assert(atan(-1), -PI/4.0, "atan(-1) == -PI/4"); 22 | 23 | assert(tanh(0), 0, "tanh(0) == 0"); 24 | assert(tanh(0.549306), 0.5, "tanh(0.549306) == 0.5"); 25 | assert(tanh(-0.549306), -0.5, "tanh(-0.549306) == -0.5"); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/test_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "tmath_test.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | bool TMathTest::equal(TMath::DOUBLE x, TMath::DOUBLE y, TMath::DOUBLE tolerance) { 8 | if (x - tolerance <= y && x + tolerance >= y) return true; 9 | else return false; 10 | } 11 | 12 | void TMathTest::assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression) { 13 | assert(value, correct, expression, TMathTest::DEFAULT_TOLERANCE); 14 | } 15 | 16 | void TMathTest::assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression, TMath::DOUBLE tolerance) { 17 | if (!equal(value, correct, tolerance)) { 18 | std::cout << "Assert: " << expression << " failed" << std::endl; 19 | std::cout << value << " is not nearly equal " << correct << std::endl; 20 | exit(1); 21 | } else { 22 | double deviation = value - correct; 23 | deviation = deviation < 0 ? -deviation : deviation; 24 | std::cout << "Test (" << expression << ") passed with deviation of " << deviation << std::endl; 25 | } 26 | } 27 | 28 | void TMathTest::assert(TMath::Matrix a, TMath::Matrix b, std::string expression) { 29 | assert(a, b, expression, TMathTest::DEFAULT_TOLERANCE); 30 | } 31 | 32 | void TMathTest::assert(TMath::Matrix a, TMath::Matrix b, std::string expression, TMath::DOUBLE tolerance) { 33 | if (!a.equal(b, tolerance)) { 34 | std::cout << "Assert: " << expression << " failed" << std::endl; 35 | std::cout << a.to_string() << " is not equal to " << b.to_string() << std::endl; 36 | exit(1); 37 | } else { 38 | std::cout << "Test (" << expression << ") passed" << std::endl; 39 | } 40 | } 41 | 42 | void TMathTest::assert(TMath::Vector a, TMath::Vector b, std::string expression) { 43 | assert(a, b, expression, TMathTest::DEFAULT_TOLERANCE); 44 | } 45 | 46 | void TMathTest::assert(TMath::Vector a, TMath::Vector b, std::string expression, TMath::DOUBLE tolerance) { 47 | if (!a.equal(b, tolerance)) { 48 | std::cout << "Assert: " << expression << " failed" << std::endl; 49 | std::cout << a.to_string() << " is not equal to " << b.to_string() << std::endl; 50 | exit(1); 51 | } else { 52 | std::cout << "Test (" << expression << ") passed" << std::endl; 53 | } 54 | } 55 | 56 | void TMathTest::assertTrue(bool b, std::string expression) { 57 | if (!b) { 58 | std::cout << "Assert: " << expression << " failed" << std::endl; 59 | exit(1); 60 | } else { 61 | std::cout << "Test (" << expression << ") passed" << std::endl; 62 | } 63 | } 64 | 65 | void TMathTest::assertError(std::function func, std::string expression) { 66 | try { 67 | func(); 68 | std::cout << "Assert: " << expression << " failed" << std::endl; 69 | exit(1); 70 | } catch (std::string err) { 71 | std::cout << "Error test (" << expression << ") passed with message '" << err << "'" << std::endl; 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /test/vector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test checks the vector functionality. 3 | */ 4 | 5 | #include "tmath.hpp" 6 | #include "tmath_test.hpp" 7 | 8 | int main(int argc, char const *argv[]) { 9 | using TMathTest::assert; 10 | using TMathTest::assertTrue; 11 | using TMathTest::assertError; 12 | using TMath::DOUBLE; 13 | using TMath::Vector; 14 | 15 | Vector nullVector1 {0, 0, 0}; 16 | Vector nullVector2(3); 17 | Vector smallVector(0); 18 | 19 | // check equality operator 20 | assert(nullVector1, nullVector2, "{0, 0, 0} == Vector(3)"); 21 | assertError([&](){ nullVector1 == smallVector; }, "{0, 0, 0} == Vector(0)"); 22 | 23 | Vector identityVector1 = {1, 0, 0}; 24 | Vector identityVector2 = {0, 1, 0}; 25 | Vector identityVector3 = {0, 0, 1}; 26 | 27 | // check unequality operator 28 | assertTrue(identityVector1 != identityVector2, "{1, 0, 0} != {0, 1, 0}"); 29 | assertError([&](){ identityVector1 != smallVector; }, "{1, 0, 0} != Vector(0)"); 30 | 31 | Vector vectorSum1 = identityVector1 + identityVector2; 32 | Vector vectorSum2 = vectorSum1 + identityVector3; 33 | Vector vectorSum3 = {1, 1, 1}; 34 | 35 | // check add operator 36 | assert(vectorSum2, vectorSum3, "{1, 0, 0} + {0, 1, 0} + {0, 0, 1} == {1, 1, 1}"); 37 | assertError([&]() { vectorSum1 + smallVector; }, "{1, 0, 0} + Vector(0)"); 38 | 39 | Vector vectorSub1 = vectorSum1 - identityVector1; 40 | Vector vectorSub2 = vectorSub1 - identityVector2; 41 | 42 | // check subtraction operator 43 | assert(vectorSub1, identityVector2, "{1, 1, 0} - {1, 0, 0} == {0, 1, 0}"); 44 | assertError([&](){ vectorSub1 - smallVector; }, "{0, 1, 0} - Vector(0)"); 45 | 46 | Vector vectorScalar1 { 2, 2, 2 }; 47 | Vector vectorScalar2 { 0.5, 0.5, 0.5 }; 48 | Vector vectorScalar3 { -1, -1, -1 }; 49 | DOUBLE scalar1 = 2.0; 50 | DOUBLE scalar2 = 0.0; 51 | DOUBLE scalar3 = -1.0; 52 | 53 | // check scalar multiplication 54 | assert(vectorSum3 * scalar1, vectorScalar1, "{1, 1, 1} * 2.0 == {2.0, 2.0, 2.0}"); 55 | assert(vectorSum3 / scalar1, vectorScalar2, "{1, 1, 1} / 2.0 == {0.5, 0.5, 0.5}"); 56 | assert(vectorSum3 * scalar2, nullVector1, "{1, 1, 1} * 0 == {0, 0, 0}"); 57 | assert(vectorSum3 * scalar3, vectorScalar3, "{1, 1, 1} * -1 == {-1, -1, -1}"); 58 | 59 | // check vector inversion 60 | assert(-vectorSum3, vectorScalar3, "-{1, 1, 1} == {-1, -1, -1}"); 61 | 62 | // check dot product operator 63 | DOUBLE dotProduct1 = 1; 64 | DOUBLE dotProduct2 = 0; 65 | DOUBLE dotProduct3 = 3; 66 | 67 | assert(vectorSum3.dot(identityVector1), dotProduct1, "{1, 1, 1} (dot) {1, 0, 0} == 1"); 68 | assert(identityVector1.dot(identityVector2), dotProduct2, "{1, 0, 0} (dot) {0, 1, 0} == 0"); 69 | assert(vectorSum3.dot(vectorSum3), dotProduct3, "{1, 1, 1} (dot) {1, 1, 1} == 3"); 70 | assertError([&](){ vectorSum3.dot(smallVector); }, "{1, 1, 1} (dot) Vector(0)"); 71 | 72 | // check cross product operator 73 | Vector crossProduct1 {0, 0, 0}; 74 | Vector crossProduct2 {0, 1, -1}; 75 | Vector crossProduct3 {-1, 0, 1}; 76 | 77 | assert(vectorSum3.cross(vectorSum3), crossProduct1, "{1, 1, 1} x {1, 1, 1} == {0, 0, 0}"); 78 | assert(vectorSum3.cross(identityVector1), crossProduct2, "{1, 1, 1} x {1, 0, 0} == {0, 1, -1}"); 79 | assert(vectorSum3.cross(identityVector2), crossProduct3, "{1, 1, 1} x {0, 1, 0} == {-1, 0, 1}"); 80 | assertError([&](){ vectorSum3.cross(smallVector);}, "{1, 1, 1} x Vector(0)"); 81 | 82 | // check sum operation 83 | DOUBLE sum1 = 1; 84 | DOUBLE sum2 = 3; 85 | DOUBLE sum3 = 0; 86 | 87 | assert(identityVector1.sum(), sum1, "sum({1, 0, 0}) == 1"); 88 | assert(vectorSum3.sum(), sum2, "sum({1, 1, 1}) == 3"); 89 | assert(nullVector1.sum(), sum3, "sum({0, 0, 0}) == 0"); 90 | 91 | // check length operation 92 | DOUBLE length1 = 1; 93 | DOUBLE length2 = TMath::sqrt(3); 94 | DOUBLE length3 = 0; 95 | 96 | assert(identityVector1.length(), length1, "length({1, 0, 0}) == 1"); 97 | assert(vectorSum3.length(), length2, "length({1, 1, 1}) == sqrt(3)"); 98 | assert(nullVector1.length(), length3, "length({0, 0, 0}) == 0"); 99 | assertError([&](){ smallVector.length(); }, "length({})"); 100 | 101 | // check norm operation 102 | Vector normVector1 {2, 2, 1}; 103 | Vector normedVector1 {2.0/3.0, 2.0/3.0, 1.0/3.0}; 104 | assert(identityVector1.norm(), identityVector1, "norm({1, 0, 0}) == {1, 0, 0}"); 105 | assert(identityVector2.norm(), identityVector2, "norm({0, 1, 0}) == {0, 1, 0}"); 106 | assert(identityVector3.norm(), identityVector3, "norm({0, 0, 1}) == {0, 0, 1}"); 107 | assert(normVector1.norm(), normedVector1, "norm({2, 2, 1}) == {2/3, 2/3, 1/3}"); 108 | assertError([&](){ smallVector.norm(); }, "norm(Vector(0))"); 109 | 110 | // check at operation 111 | assertError([&](){ smallVector.at(1); }, "Can not access element at index Vector(0)[1]"); 112 | assert(nullVector1.at(0), 0, "Vector(0)[0] == 0"); 113 | assert(identityVector2.at(1), 1, "Identity[1] == 1"); 114 | 115 | return 0; 116 | } 117 | --------------------------------------------------------------------------------